12
this.channel_page = new Uint8Array(8);
13
this.channel_pagehi = new Uint8Array(8);
14
this.channel_addr = new Uint16Array(8);
15
this.channel_addr_init = new Uint16Array(8);
16
this.channel_count = new Uint16Array(8);
17
this.channel_count_init = new Uint16Array(8);
18
this.channel_mask = new Uint8Array(8);
19
this.channel_mode = new Uint8Array(8);
20
this.unmask_listeners = [];
22
this.lsb_msb_flipflop = 0;
26
io.register_write(0x00, this, this.port_addr_write.bind(this, 0));
27
io.register_write(0x02, this, this.port_addr_write.bind(this, 1));
28
io.register_write(0x04, this, this.port_addr_write.bind(this, 2));
29
io.register_write(0x06, this, this.port_addr_write.bind(this, 3));
30
io.register_write(0x01, this, this.port_count_write.bind(this, 0));
31
io.register_write(0x03, this, this.port_count_write.bind(this, 1));
32
io.register_write(0x05, this, this.port_count_write.bind(this, 2));
33
io.register_write(0x07, this, this.port_count_write.bind(this, 3));
35
io.register_read(0x00, this, this.port_addr_read.bind(this, 0));
36
io.register_read(0x02, this, this.port_addr_read.bind(this, 1));
37
io.register_read(0x04, this, this.port_addr_read.bind(this, 2));
38
io.register_read(0x06, this, this.port_addr_read.bind(this, 3));
39
io.register_read(0x01, this, this.port_count_read.bind(this, 0));
40
io.register_read(0x03, this, this.port_count_read.bind(this, 1));
41
io.register_read(0x05, this, this.port_count_read.bind(this, 2));
42
io.register_read(0x07, this, this.port_count_read.bind(this, 3));
44
io.register_write(0xC0, this, this.port_addr_write.bind(this, 4));
45
io.register_write(0xC4, this, this.port_addr_write.bind(this, 5));
46
io.register_write(0xC8, this, this.port_addr_write.bind(this, 6));
47
io.register_write(0xCC, this, this.port_addr_write.bind(this, 7));
48
io.register_write(0xC2, this, this.port_count_write.bind(this, 4));
49
io.register_write(0xC6, this, this.port_count_write.bind(this, 5));
50
io.register_write(0xCA, this, this.port_count_write.bind(this, 6));
51
io.register_write(0xCE, this, this.port_count_write.bind(this, 7));
53
io.register_read(0xC0, this, this.port_addr_read.bind(this, 4));
54
io.register_read(0xC4, this, this.port_addr_read.bind(this, 5));
55
io.register_read(0xC8, this, this.port_addr_read.bind(this, 6));
56
io.register_read(0xCC, this, this.port_addr_read.bind(this, 7));
57
io.register_read(0xC2, this, this.port_count_read.bind(this, 4));
58
io.register_read(0xC6, this, this.port_count_read.bind(this, 5));
59
io.register_read(0xCA, this, this.port_count_read.bind(this, 6));
60
io.register_read(0xCE, this, this.port_count_read.bind(this, 7));
62
io.register_write(0x87, this, this.port_page_write.bind(this, 0));
63
io.register_write(0x83, this, this.port_page_write.bind(this, 1));
64
io.register_write(0x81, this, this.port_page_write.bind(this, 2));
65
io.register_write(0x82, this, this.port_page_write.bind(this, 3));
66
io.register_write(0x8F, this, this.port_page_write.bind(this, 4));
67
io.register_write(0x8B, this, this.port_page_write.bind(this, 5));
68
io.register_write(0x89, this, this.port_page_write.bind(this, 6));
69
io.register_write(0x8A, this, this.port_page_write.bind(this, 7));
71
io.register_read(0x87, this, this.port_page_read.bind(this, 0));
72
io.register_read(0x83, this, this.port_page_read.bind(this, 1));
73
io.register_read(0x81, this, this.port_page_read.bind(this, 2));
74
io.register_read(0x82, this, this.port_page_read.bind(this, 3));
75
io.register_read(0x8F, this, this.port_page_read.bind(this, 4));
76
io.register_read(0x8B, this, this.port_page_read.bind(this, 5));
77
io.register_read(0x89, this, this.port_page_read.bind(this, 6));
78
io.register_read(0x8A, this, this.port_page_read.bind(this, 7));
80
io.register_write(0x487, this, this.port_pagehi_write.bind(this, 0));
81
io.register_write(0x483, this, this.port_pagehi_write.bind(this, 1));
82
io.register_write(0x481, this, this.port_pagehi_write.bind(this, 2));
83
io.register_write(0x482, this, this.port_pagehi_write.bind(this, 3));
84
io.register_write(0x48B, this, this.port_pagehi_write.bind(this, 5));
85
io.register_write(0x489, this, this.port_pagehi_write.bind(this, 6));
86
io.register_write(0x48A, this, this.port_pagehi_write.bind(this, 7));
88
io.register_read(0x487, this, this.port_pagehi_read.bind(this, 0));
89
io.register_read(0x483, this, this.port_pagehi_read.bind(this, 1));
90
io.register_read(0x481, this, this.port_pagehi_read.bind(this, 2));
91
io.register_read(0x482, this, this.port_pagehi_read.bind(this, 3));
92
io.register_read(0x48B, this, this.port_pagehi_read.bind(this, 5));
93
io.register_read(0x489, this, this.port_pagehi_read.bind(this, 6));
94
io.register_read(0x48A, this, this.port_pagehi_read.bind(this, 7));
96
io.register_write(0x0A, this, this.port_singlemask_write.bind(this, 0));
97
io.register_write(0xD4, this, this.port_singlemask_write.bind(this, 4));
98
io.register_write(0x0F, this, this.port_multimask_write.bind(this, 0));
99
io.register_write(0xDE, this, this.port_multimask_write.bind(this, 4));
101
io.register_read(0x0F, this, this.port_multimask_read.bind(this, 0));
102
io.register_read(0xDE, this, this.port_multimask_read.bind(this, 4));
104
io.register_write(0x0B, this, this.port_mode_write.bind(this, 0));
105
io.register_write(0xD6, this, this.port_mode_write.bind(this, 4));
107
io.register_write(0x0C, this, this.portC_write);
108
io.register_write(0xD8, this, this.portC_write);
111
DMA.prototype.get_state = function()
117
this.channel_addr_init,
119
this.channel_count_init,
122
this.lsb_msb_flipflop,
126
DMA.prototype.set_state = function(state)
128
this.channel_page = state[0];
129
this.channel_pagehi = state[1];
130
this.channel_addr = state[2];
131
this.channel_addr_init = state[3];
132
this.channel_count = state[4];
133
this.channel_count_init = state[5];
134
this.channel_mask = state[6];
135
this.channel_mode = state[7];
136
this.lsb_msb_flipflop = state[8];
139
DMA.prototype.port_count_write = function(channel, data_byte)
141
dbg_log("count write [" + channel + "] = " + h(data_byte), LOG_DMA);
143
this.channel_count[channel] =
144
this.flipflop_get(this.channel_count[channel], data_byte, false);
146
this.channel_count_init[channel] =
147
this.flipflop_get(this.channel_count_init[channel], data_byte, true);
150
DMA.prototype.port_count_read = function(channel)
152
dbg_log("count read [" + channel + "] -> " + h(this.channel_count[channel]), LOG_DMA);
153
return this.flipflop_read(this.channel_count[channel]);
156
DMA.prototype.port_addr_write = function(channel, data_byte)
158
dbg_log("addr write [" + channel + "] = " + h(data_byte), LOG_DMA);
160
this.channel_addr[channel] =
161
this.flipflop_get(this.channel_addr[channel], data_byte, false);
163
this.channel_addr_init[channel] =
164
this.flipflop_get(this.channel_addr_init[channel], data_byte, true);
167
DMA.prototype.port_addr_read = function(channel)
169
dbg_log("addr read [" + channel + "] -> " + h(this.channel_addr[channel]), LOG_DMA);
170
return this.flipflop_read(this.channel_addr[channel]);
173
DMA.prototype.port_pagehi_write = function(channel, data_byte)
175
dbg_log("pagehi write [" + channel + "] = " + h(data_byte), LOG_DMA);
176
this.channel_pagehi[channel] = data_byte;
179
DMA.prototype.port_pagehi_read = function(channel)
181
dbg_log("pagehi read [" + channel + "]", LOG_DMA);
182
return this.channel_pagehi[channel];
185
DMA.prototype.port_page_write = function(channel, data_byte)
187
dbg_log("page write [" + channel + "] = " + h(data_byte), LOG_DMA);
188
this.channel_page[channel] = data_byte;
191
DMA.prototype.port_page_read = function(channel)
193
dbg_log("page read [" + channel + "]", LOG_DMA);
194
return this.channel_page[channel];
197
DMA.prototype.port_singlemask_write = function(channel_offset, data_byte)
199
var channel = (data_byte & 0x3) + channel_offset;
200
var value = data_byte & 0x4 ? 1 : 0;
201
dbg_log("singlechannel mask write [" + channel + "] = " + value, LOG_DMA);
202
this.update_mask(channel, value);
205
DMA.prototype.port_multimask_write = function(channel_offset, data_byte)
207
dbg_log("multichannel mask write: " + h(data_byte), LOG_DMA);
208
for(var i = 0; i < 4; i++)
210
this.update_mask(channel_offset + i, data_byte & (1 << i));
214
DMA.prototype.port_multimask_read = function(channel_offset)
217
value |= this.channel_mask[channel_offset + 0];
218
value |= this.channel_mask[channel_offset + 1] << 1;
219
value |= this.channel_mask[channel_offset + 2] << 2;
220
value |= this.channel_mask[channel_offset + 3] << 3;
221
dbg_log("multichannel mask read: " + h(value), LOG_DMA);
225
DMA.prototype.port_mode_write = function(channel_offset, data_byte)
227
var channel = (data_byte & 0x3) + channel_offset;
228
dbg_log("mode write [" + channel + "] = " + h(data_byte), LOG_DMA);
229
this.channel_mode[channel] = data_byte;
232
DMA.prototype.portC_write = function(data_byte)
234
dbg_log("flipflop reset", LOG_DMA);
235
this.lsb_msb_flipflop = 0;
238
DMA.prototype.on_unmask = function(fn, this_value)
240
this.unmask_listeners.push({
242
this_value: this_value,
246
DMA.prototype.update_mask = function(channel, value)
248
if(this.channel_mask[channel] !== value)
250
this.channel_mask[channel] = value;
254
dbg_log("firing on_unmask(" + channel + ")", LOG_DMA);
255
for(var i = 0; i < this.unmask_listeners.length; i++)
257
this.unmask_listeners[i].fn.call(
258
this.unmask_listeners[i].this_value,
267
DMA.prototype.do_read = function(buffer, start, len, channel, fn)
269
var read_count = this.count_get_8bit(channel),
270
addr = this.address_get_8bit(channel);
272
dbg_log("DMA write channel " + channel, LOG_DMA);
273
dbg_log("to " + h(addr) + " len " + h(read_count), LOG_DMA);
277
dbg_log("DMA should read more than provided: " + h(len) + " " + h(read_count), LOG_DMA);
280
if(start + read_count > buffer.byteLength)
282
dbg_log("DMA read outside of buffer", LOG_DMA);
288
this.channel_addr[channel] += read_count;
290
buffer.get(start, read_count, function(data)
292
cpu.write_blob(data, addr);
300
DMA.prototype.do_write = function(buffer, start, len, channel, fn)
302
var read_count = (this.channel_count[channel] + 1) & 0xFFFF,
303
bytes_per_count = channel >= 5 ? 2 : 1,
304
read_bytes = read_count * bytes_per_count,
305
addr = this.address_get_8bit(channel),
308
autoinit = this.channel_mode[channel] & 0x10;
310
dbg_log("DMA write channel " + channel, LOG_DMA);
311
dbg_log("to " + h(addr) + " len " + h(read_bytes), LOG_DMA);
315
dbg_log("DMA should read more than provided", LOG_DMA);
316
read_count = Math.floor(len / bytes_per_count);
317
read_bytes = read_count * bytes_per_count;
320
else if(len > read_bytes)
322
dbg_log("DMA attempted to read more than provided", LOG_DMA);
326
if(start + read_bytes > buffer.byteLength)
328
dbg_log("DMA write outside of buffer", LOG_DMA);
333
this.channel_addr[channel] += read_count;
334
this.channel_count[channel] -= read_count;
337
if(!unfinished && autoinit)
339
dbg_log("DMA autoinit", LOG_DMA);
340
this.channel_addr[channel] = this.channel_addr_init[channel];
341
this.channel_count[channel] = this.channel_count_init[channel];
345
this.cpu.mem8.subarray(addr, addr + read_bytes),
348
if(want_more && autoinit)
350
dbg_log("DMA continuing from start", LOG_DMA);
351
this.do_write(buffer, start + read_bytes, len - read_bytes, channel, fn);
362
DMA.prototype.address_get_8bit = function(channel)
364
var addr = this.channel_addr[channel];
373
addr |= this.channel_page[channel] << 16;
374
addr |= this.channel_pagehi[channel] << 24;
379
DMA.prototype.count_get_8bit = function(channel)
381
var count = this.channel_count[channel] + 1;
391
DMA.prototype.flipflop_get = function(old_dword, new_byte, continuing)
395
this.lsb_msb_flipflop ^= 1;
398
if(this.lsb_msb_flipflop)
401
return old_dword & ~0xFF | new_byte;
406
return old_dword & ~0xFF00 | new_byte << 8;
410
DMA.prototype.flipflop_read = function(dword)
412
this.lsb_msb_flipflop ^= 1;
414
if(this.lsb_msb_flipflop)
422
return (dword >> 8) & 0xFF;