2 * DMAC HD6844/MC6844 [hd6844.h]
4 * Author: K.Ohta <whatisthis.sowhat _at_ gmail.com>
7 * Jun 18, 2015 : Initial
11 #include "../memory.h"
13 #include "../../emu.h"
18 HD6844::HD6844(VM *parent_vm, EMU *parent_emu) : DEVICE(parent_vm, parent_emu)
23 for(i = 0; i < 4; i++) {
24 src[i] = dest[i] = NULL;
25 initialize_output_signals(&(interrupt_line[i]));
27 initialize_output_signals(&(drq_line[0]));
28 initialize_output_signals(&(drq_line[1]));
38 for(ch = 0; ch < 4; ch++) {
39 addr_reg[ch] = 0xffff;
40 words_reg[ch] = 0xffff;
41 fixed_addr[ch] = 0x0000;
43 first_transfer[ch] = false;
45 channel_control[ch] = 0;
46 transfering[ch] = false;
47 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
49 cycle_steal[ch] = false;
50 halt_flag[ch] = false;
52 write_signals(&(drq_line[0]), 0);
53 write_signals(&(drq_line[1]), 0);
60 void HD6844::initialize()
64 for(ch = 0; ch < 4; ch++) {
70 void HD6844::write_data8(uint32_t addr, uint32_t data)
72 uint8_t ch = addr & 0x03;
74 uint32_t channel = (addr >> 2) & 3;
80 tmpd.w.l = addr_reg[channel];
81 tmpd.b.h = data & 0xff;
82 addr_reg[channel] = tmpd.d;
85 tmpd.w.l = addr_reg[channel];
86 tmpd.b.l = data & 0xff;
87 addr_reg[channel] = tmpd.d;
90 tmpd.w.l = words_reg[channel];
91 tmpd.b.h = data & 0xff;
92 words_reg[channel] = tmpd.w.l;
95 tmpd.w.l = words_reg[channel];
96 tmpd.b.l = data & 0xff;
97 words_reg[channel] = tmpd.w.l;
100 } else if((addr >= 0x10) && (addr < 0x14)) { // $10-$13
101 channel_control[addr - 0x10] = (channel_control[addr - 0x10] & 0xc0 ) | (data & 0x0f);
102 } else if(addr == 0x14) {
103 priority_reg = data & 0x8f;
104 } else if(addr == 0x15) {
105 interrupt_reg = (interrupt_reg & 0x80) | (data & 0x0f);
106 } else if(addr == 0x16) {
107 datachain_reg = (datachain_reg & 0xf0) | (data & 0x0f);
112 uint32_t HD6844::read_data8(uint32_t addr)
114 uint8_t ch = addr & 0x03;
116 uint32_t channel = (addr >> 2) & 3;
117 uint32_t retval = 0xff;
123 tmpd.d = addr_reg[channel];
124 retval = tmpd.b.h & 0x00ff;
127 tmpd.d = addr_reg[channel];
128 retval = tmpd.b.l & 0x00ff;
131 tmpd.w.l = words_reg[channel];
132 retval = tmpd.b.h & 0x00ff;
135 tmpd.w.l = words_reg[channel];
136 retval = tmpd.b.l & 0x00ff;
139 } else if((addr >= 0x10) && (addr < 0x14)) { // $10-$13
140 retval = channel_control[addr - 0x10];
141 channel_control[addr - 0x10] &= 0x7f;
142 } else if(addr == 0x14) {
143 retval = priority_reg;
144 } else if(addr == 0x15) {
146 retval = ((datachain_reg >> 4) | 0x80) & interrupt_reg;
147 interrupt_reg &= 0x7f;
148 datachain_reg &= 0x0f;
149 for(i = 0; i < 4; i++) write_signals(&(interrupt_line[i]), 0x00);
150 } else if(addr == 0x16) {
151 retval = datachain_reg & 0x0f;
156 uint32_t HD6844::read_signal(int id)
159 case HD6844_SET_CONST_OFFSET:
162 case HD6844_SRC_FIXED_ADDR_CH0:
163 return fixed_addr[0];
165 case HD6844_SRC_FIXED_ADDR_CH1:
166 return fixed_addr[1];
168 case HD6844_SRC_FIXED_ADDR_CH2:
169 return fixed_addr[2];
171 case HD6844_SRC_FIXED_ADDR_CH3:
172 return fixed_addr[3];
174 case HD6844_ADDR_REG_0:
177 case HD6844_ADDR_REG_1:
180 case HD6844_ADDR_REG_2:
183 case HD6844_ADDR_REG_3:
186 case HD6844_WORDS_REG_0:
189 case HD6844_WORDS_REG_1:
192 case HD6844_WORDS_REG_2:
195 case HD6844_WORDS_REG_3:
198 case HD6844_IS_TRANSFER_0:
199 return transfering[0] ? 0xffffffff : 0;
201 case HD6844_IS_TRANSFER_1:
202 return transfering[1] ? 0xffffffff : 0;
204 case HD6844_IS_TRANSFER_2:
205 return transfering[2] ? 0xffffffff : 0;
207 case HD6844_IS_TRANSFER_3:
208 return transfering[3] ? 0xffffffff : 0;
216 void HD6844::write_signal(int id, uint32_t data, uint32_t mask)
218 //bool val_b = ((data & mask) != 0);
219 uint32_t ch = (data & mask) & 0x03;
222 case HD6844_SET_CONST_OFFSET:
225 case HD6844_SRC_FIXED_ADDR_CH0:
226 fixed_addr[0] = data;
228 case HD6844_SRC_FIXED_ADDR_CH1:
229 fixed_addr[1] = data;
231 case HD6844_SRC_FIXED_ADDR_CH2:
232 fixed_addr[2] = data;
234 case HD6844_SRC_FIXED_ADDR_CH3:
235 fixed_addr[3] = data;
237 case HD6844_TRANSFER_START:
238 if(transfering[ch]) return;
239 if((words_reg[ch] == 0) || (words_reg[ch] == 0xffff)) return;
240 channel_control[ch] = channel_control[ch] & 0x8f;
241 first_transfer[ch] = true;
242 cycle_steal[ch] = false;
243 if((channel_control[ch] & 0x02) == 0) cycle_steal[ch] = true;
244 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
246 if(event_dmac[ch] < 0) register_event(this, HD6844_EVENT_START_TRANSFER + ch,
247 50.0, false, &event_dmac[ch]);
248 //emu->out_debug_log(_T("DMAC: Start Transfer CH=%d $%04x Words, CMDREG=%02x"), ch, words_reg[ch], channel_control[ch]);
250 case HD6844_ACK_DRQ1:
251 write_signals(&(drq_line[0]), 0xffffffff);
253 case HD6844_ACK_DRQ2:
254 write_signals(&(drq_line[1]), 0xffffffff);
256 case HD6844_DO_TRANSFER:
257 if(!transfering[ch]) return;
259 if(((words_reg[ch] & 0x07) == 1) || (first_transfer[ch])){
260 first_transfer[ch] = false;
261 if(!cycle_steal[ch]) {
262 write_signals(&(drq_line[1]), 0xffffffff);
264 if((channel_control[ch] & 0x04) != 0) {
265 write_signals(&(drq_line[0]), 0xffffffff);
267 write_signals(&(drq_line[1]), 0xffffffff);
270 halt_flag[ch] = true;
271 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
273 register_event(this, HD6844_EVENT_DO_TRANSFER + ch,
274 (double)(0x08 / 2), false, NULL); // HD68B44
276 halt_flag[ch] = false;
277 if(!cycle_steal[ch]) {
278 write_signals(&(drq_line[1]), 0xffffffff);
288 void HD6844::do_transfer(int ch)
291 if(!transfering[ch]) return;
292 if((priority_reg & 0x01) == 0) {
293 transfering[ch] = false;
294 if(event_dmac[ch] >= 0) {
295 cancel_event(this, event_dmac[ch]);
299 if((channel_control[ch] & 0x04) != 0) {
300 write_signals(&(drq_line[0]), 0);
302 write_signals(&(drq_line[1]), 0);
304 cycle_steal[ch] = false;
307 if(words_reg[ch] == 0) {
308 transfering[ch] = false;
309 if(event_dmac[ch] >= 0) {
310 cancel_event(this, event_dmac[ch]);
313 if((channel_control[ch] & 0x04) != 0) {
314 write_signals(&(drq_line[0]), 0);
316 write_signals(&(drq_line[1]), 0);
318 cycle_steal[ch] = false;
319 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x80;
322 if((channel_control[ch] & 0x01) == 0) {
323 data_reg[ch] = src[ch]->read_io8(fixed_addr[ch]) & 0xff;
324 dest[ch]->write_dma_io8((uint32_t)addr_reg[ch] + addr_offset, data_reg[ch]);
326 data_reg[ch] = dest[ch]->read_dma_io8((uint32_t)addr_reg[ch] + addr_offset) & 0xff;
327 src[ch]->write_io8(fixed_addr[ch], data_reg[ch]);
330 if((channel_control[ch] & 0x08) != 0) {
335 addr_reg[ch] = addr_reg[ch] & 0xffff;
336 if(cycle_steal[ch] && halt_flag[ch]) {
337 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
339 halt_flag[ch] = false;
340 register_event(this, HD6844_EVENT_END_TRANSFER + ch,
341 (double)(0x08 / 2 * 2), false, &event_dmac[ch]); // Really?
343 if(words_reg[ch] == 0) {
344 if((datachain_reg & 0x01) != 0) {
346 uint8_t chain_ch = (datachain_reg & 0x06) >> 1;
347 if((datachain_reg & 0x08) != 0) {
348 //emu->out_debug_log(_T("DMAC: chain 1->2->3->0(1/2) \n"));
349 if(chain_ch > 2) chain_ch = 2;
350 tmp = addr_reg[chain_ch];
351 addr_reg[chain_ch] = addr_reg[(chain_ch + 3) & 3];
352 addr_reg[(chain_ch + 3) & 3] = addr_reg[(chain_ch + 2) & 3];
353 addr_reg[(chain_ch + 2) & 3] = addr_reg[(chain_ch + 1) & 3];
354 addr_reg[(chain_ch + 1) & 3] = tmp;
356 words_reg[chain_ch] = words_reg[(chain_ch + 3) & 3];
357 words_reg[(chain_ch + 3) & 3] = words_reg[(chain_ch + 2) & 3];
358 words_reg[(chain_ch + 2) & 3] = words_reg[(chain_ch + 1) & 3];
359 words_reg[(chain_ch + 1) & 3] = 0;
361 if(chain_ch > 1) chain_ch = 1;
362 //emu->out_debug_log(_T("DMAC: chain 3->0(1) \n"));
363 tmp = addr_reg[chain_ch];
364 addr_reg[chain_ch] = addr_reg[3];
367 words_reg[chain_ch] = words_reg[3];
371 transfering[ch] = false;
372 if(event_dmac[ch] >= 0) {
373 cancel_event(this, event_dmac[ch]);
376 write_signals(&(drq_line[1]), 0);
377 cycle_steal[ch] = false;
378 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x80;
379 datachain_reg = datachain_reg | 0x10;
380 if((interrupt_reg & (0x01 << ch)) != 0) {
381 interrupt_reg |= 0x80;
382 write_signals(&(interrupt_line[ch]), 0xffffffff);
384 //p_emu->out_debug_log(_T("HD6844: Complete transfer ch %d\n"), ch);
389 void HD6844::event_callback(int event_id, int err)
393 if((event_id >= HD6844_EVENT_START_TRANSFER) && (event_id < (HD6844_EVENT_START_TRANSFER + 4))) {
394 ch = event_id - HD6844_EVENT_START_TRANSFER;
396 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x40;
397 transfering[ch] = true;
398 } else if((event_id >= HD6844_EVENT_DO_TRANSFER) && (event_id < (HD6844_EVENT_DO_TRANSFER + 4))) {
399 ch = event_id - HD6844_EVENT_DO_TRANSFER;
402 } else if((event_id >= HD6844_EVENT_END_TRANSFER) && (event_id < (HD6844_EVENT_END_TRANSFER + 4))) {
403 ch = event_id - HD6844_EVENT_END_TRANSFER;
405 if(cycle_steal[ch]) {
406 if((channel_control[ch] & 0x04) != 0) {
407 write_signals(&(drq_line[0]), 0);
409 write_signals(&(drq_line[1]), 0);
415 #define STATE_VERSION 1
416 void HD6844::save_state(FILEIO *state_fio)
419 state_fio->FputUint32_BE(STATE_VERSION);
420 state_fio->FputInt32_BE(this_device_id);
421 p_emu->out_debug_log("Save State: HD6844: id=%d ver=%d\n", this_device_id, STATE_VERSION);
423 for(i = 0; i < 4; i++) {
424 state_fio->FputUint32_BE(addr_reg[i]);
425 state_fio->FputUint16_BE(words_reg[i]);
426 state_fio->FputUint8(channel_control[i]);
428 state_fio->FputUint8(priority_reg);
429 state_fio->FputUint8(interrupt_reg);
430 state_fio->FputUint8(datachain_reg);
431 state_fio->FputUint8(num_reg);
432 state_fio->FputUint32_BE(addr_offset);
433 for(i = 0; i < 4; i++) {
434 state_fio->FputUint32_BE(fixed_addr[i]);
435 state_fio->FputUint8(data_reg[i]);
436 state_fio->FputBool(transfering[i]);
437 state_fio->FputBool(first_transfer[i]);
438 state_fio->FputBool(cycle_steal[i]);
439 state_fio->FputBool(halt_flag[i]);
440 state_fio->FputInt32_BE(event_dmac[i]);
445 bool HD6844::load_state(FILEIO *state_fio)
449 version = state_fio->FgetUint32_BE();
450 if(this_device_id != state_fio->FgetInt32_BE()) return false;
451 p_emu->out_debug_log("Load State: HD6844: id=%d ver=%d\n", this_device_id, version);
453 for(i = 0; i < 4; i++) {
454 addr_reg[i] = state_fio->FgetUint32_BE();
455 words_reg[i] = state_fio->FgetUint16_BE();
456 channel_control[i] = state_fio->FgetUint8();
458 priority_reg = state_fio->FgetUint8();
459 interrupt_reg = state_fio->FgetUint8();
460 datachain_reg = state_fio->FgetUint8();
461 num_reg = state_fio->FgetUint8();
462 addr_offset = state_fio->FgetUint32_BE();
463 for(i = 0; i < 4; i++) {
464 fixed_addr[i] = state_fio->FgetUint32_BE();
465 data_reg[i] = state_fio->FgetUint8();
466 transfering[i] = state_fio->FgetBool();
467 first_transfer[i] = state_fio->FgetBool();
468 cycle_steal[i] = state_fio->FgetBool();
469 halt_flag[i] = state_fio->FgetBool();
470 event_dmac[i] = state_fio->FgetInt32_BE();
472 if(version == 1) return true;