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"
21 for(ch = 0; ch < 4; ch++) {
22 addr_reg[ch] = 0xffff;
23 words_reg[ch] = 0xffff;
24 fixed_addr[ch] = 0x0000;
26 first_transfer[ch] = false;
28 channel_control[ch] = 0;
29 transfering[ch] = false;
30 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
32 cycle_steal[ch] = false;
33 halt_flag[ch] = false;
35 for(int i = 0; i < 2; i++) write_signals(&(busreq_line[i]), 0);
36 write_signals(&interrupt_line, 0);
43 void HD6844::initialize()
48 for(ch = 0; ch < 4; ch++) {
51 __USE_CHAINING = true;
52 __USE_MULTIPLE_CHAINING = true;
53 __FM77AV40 = osd->check_feature(_T("_FM77AV40"));
54 __FM77AV40EX = osd->check_feature(_T("_FM77AV40EX"));
55 __FM77AV40EX |= osd->check_feature(_T("_FM77AV40SX"));
57 if(__FM77AV40 || __FM77AV40EX) __USE_MULTIPLE_CHAINING = false;
58 if(__FM77AV40EX) __USE_CHAINING = false;
61 void HD6844::write_data8(uint32_t addr, uint32_t data)
63 uint8_t ch = addr & 0x03;
65 uint32_t channel = (addr >> 2) & 3;
71 tmpd.w.l = addr_reg[channel];
72 tmpd.b.h = data & 0xff;
73 addr_reg[channel] = tmpd.d;
76 tmpd.w.l = addr_reg[channel];
77 tmpd.b.l = data & 0xff;
78 addr_reg[channel] = tmpd.d;
81 tmpd.w.l = words_reg[channel];
82 tmpd.b.h = data & 0xff;
83 words_reg[channel] = tmpd.w.l;
86 tmpd.w.l = words_reg[channel];
87 tmpd.b.l = data & 0xff;
88 words_reg[channel] = tmpd.w.l;
91 } else if((addr >= 0x10) && (addr < 0x14)) { // $10-$13
92 channel_control[addr - 0x10] = (channel_control[addr - 0x10] & 0xc0 ) | (data & 0x0f);
93 } else if(addr == 0x14) {
94 priority_reg = data & 0x8f;
95 } else if(addr == 0x15) {
96 interrupt_reg = (interrupt_reg & 0x80) | (data & 0x0f);
97 } else if(addr == 0x16) {
98 datachain_reg = (datachain_reg & 0xf0) | (data & 0x0f);
103 uint32_t HD6844::read_data8(uint32_t addr)
105 uint8_t ch = addr & 0x03;
107 uint32_t channel = (addr >> 2) & 3;
108 uint32_t retval = 0xff;
110 if(__FM77AV40EX) { // FM77AV40EX has only one channel.
111 if((addr < 0x14) && (channel != 0)) return 0x00;;
117 tmpd.d = addr_reg[channel];
118 retval = tmpd.b.h & 0x00ff;
121 tmpd.d = addr_reg[channel];
122 retval = tmpd.b.l & 0x00ff;
125 tmpd.w.l = words_reg[channel];
126 retval = tmpd.b.h & 0x00ff;
129 tmpd.w.l = words_reg[channel];
130 retval = tmpd.b.l & 0x00ff;
133 } else if((addr >= 0x10) && (addr < 0x14)) { // $10-$13
134 retval = channel_control[addr - 0x10];
135 channel_control[addr - 0x10] &= 0x7f;
136 } else if(addr == 0x14) {
137 retval = priority_reg;
138 } else if(addr == 0x15) {
140 retval = ((datachain_reg >> 4) | 0x80) & interrupt_reg;
141 interrupt_reg &= 0x7f;
142 datachain_reg &= 0x0f;
144 //write_signals(&interrupt_line, 0x00); // Clear interrupt
145 } else if(addr == 0x16) {
146 retval = datachain_reg & 0x0f;
151 uint32_t HD6844::read_signal(int id)
154 case HD6844_SET_CONST_OFFSET:
157 case HD6844_SRC_FIXED_ADDR_CH0:
158 return fixed_addr[0];
160 case HD6844_SRC_FIXED_ADDR_CH1:
161 return fixed_addr[1];
163 case HD6844_SRC_FIXED_ADDR_CH2:
164 return fixed_addr[2];
166 case HD6844_SRC_FIXED_ADDR_CH3:
167 return fixed_addr[3];
169 case HD6844_ADDR_REG_0:
172 case HD6844_ADDR_REG_1:
175 case HD6844_ADDR_REG_2:
178 case HD6844_ADDR_REG_3:
181 case HD6844_WORDS_REG_0:
184 case HD6844_WORDS_REG_1:
187 case HD6844_WORDS_REG_2:
190 case HD6844_WORDS_REG_3:
193 case HD6844_IS_TRANSFER_0:
194 return transfering[0] ? 0xffffffff : 0;
196 case HD6844_IS_TRANSFER_1:
197 return transfering[1] ? 0xffffffff : 0;
199 case HD6844_IS_TRANSFER_2:
200 return transfering[2] ? 0xffffffff : 0;
202 case HD6844_IS_TRANSFER_3:
203 return transfering[3] ? 0xffffffff : 0;
211 void HD6844::write_signal(int id, uint32_t data, uint32_t mask)
213 //bool val_b = ((data & mask) != 0);
214 uint32_t ch = (data & mask) & 0x03;
217 case HD6844_SET_CONST_OFFSET:
220 case HD6844_SRC_FIXED_ADDR_CH0:
221 fixed_addr[0] = data;
223 case HD6844_SRC_FIXED_ADDR_CH1:
224 fixed_addr[1] = data;
226 case HD6844_SRC_FIXED_ADDR_CH2:
227 fixed_addr[2] = data;
229 case HD6844_SRC_FIXED_ADDR_CH3:
230 fixed_addr[3] = data;
232 case HD6844_TRANSFER_START:
233 if(transfering[ch]) return;
234 if((priority_reg & 0x01) == 0) return; // 20180117
235 //if((words_reg[ch] == 0) || (words_reg[ch] == 0xffff)) return;
236 if(words_reg[ch] == 0) return;
237 channel_control[ch] = channel_control[ch] & 0x8f;
238 first_transfer[ch] = true;
239 cycle_steal[ch] = false;
240 if((channel_control[ch] & 0x02) == 0) cycle_steal[ch] = true;
241 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
243 if(event_dmac[ch] < 0) register_event(this, HD6844_EVENT_START_TRANSFER + ch,
244 50.0, false, &event_dmac[ch]);
245 //this->out_debug_log(_T("DMAC: Start Transfer CH=%d $%04x Words, CMDREG=%02x"), ch, words_reg[ch], channel_control[ch]);
247 case HD6844_ACK_BUSREQ_CLIENT:
248 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0xffffffff);
250 case HD6844_ACK_BUSREQ_HOST:
251 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff);
253 case HD6844_DO_TRANSFER:
254 if(!transfering[ch]) return;
256 if(((words_reg[ch] & 0x07) == 1) || (first_transfer[ch])){
257 first_transfer[ch] = false;
258 if(!cycle_steal[ch]) {
259 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff);
261 if((channel_control[ch] & 0x04) != 0) {
262 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0xffffffff);
264 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff);
267 halt_flag[ch] = true;
268 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
270 register_event(this, HD6844_EVENT_DO_TRANSFER + ch,
271 (double)(0x08 / 2), false, NULL); // HD68B44
273 halt_flag[ch] = false;
274 if(!cycle_steal[ch]) {
275 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff); // Stop (HOST)line.
285 void HD6844::do_irq(void)
287 bool irq_stat = ((interrupt_reg & 0x80) != 0);
288 bool req_irq = false;
289 for(int cch = 0;cch < 4; cch++) {
290 if((interrupt_reg & (1 << cch)) != 0) {
291 if((channel_control[cch] & 0x80) != 0) {
292 interrupt_reg |= 0x80;
297 if(!(req_irq) && (irq_stat)) {
298 write_signals(&interrupt_line, 0);
299 } else if((req_irq) && !(irq_stat)) {
300 write_signals(&interrupt_line, 0xffffffff);
304 void HD6844::do_transfer_end(int ch)
306 if(words_reg[ch] == 0) {
307 transfering[ch] = false;
308 if(event_dmac[ch] >= 0) {
309 cancel_event(this, event_dmac[ch]);
312 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0); // release host_bus.
313 cycle_steal[ch] = false;
314 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x80;
315 datachain_reg = datachain_reg | 0x10;
317 //this->out_debug_log(_T("HD6844: Complete transfer ch %d\n"), ch);
321 void HD6844::do_transfer(int ch)
324 if(!transfering[ch]) return;
325 if((priority_reg & 0x01) == 0) {
327 transfering[ch] = false;
328 if(event_dmac[ch] >= 0) {
329 cancel_event(this, event_dmac[ch]);
333 if((channel_control[ch] & 0x04) != 0) {
334 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0);
336 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0);
338 cycle_steal[ch] = false;
342 if(words_reg[ch] == 0) {
343 transfering[ch] = false;
344 if(event_dmac[ch] >= 0) {
345 cancel_event(this, event_dmac[ch]);
348 if((channel_control[ch] & 0x04) != 0) {
349 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0);
351 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0);
353 cycle_steal[ch] = false;
354 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x80;
357 if((channel_control[ch] & 0x01) == 0) {
358 data_reg[ch] = src[ch]->read_io8(fixed_addr[ch]) & 0xff;
359 dest[ch]->write_dma_io8((uint32_t)addr_reg[ch] + addr_offset, data_reg[ch]);
361 data_reg[ch] = dest[ch]->read_dma_io8((uint32_t)addr_reg[ch] + addr_offset) & 0xff;
362 src[ch]->write_io8(fixed_addr[ch], data_reg[ch]);
365 if((channel_control[ch] & 0x08) != 0) {
370 addr_reg[ch] = addr_reg[ch] & 0xffff;
371 if(cycle_steal[ch] && halt_flag[ch]) {
372 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
374 halt_flag[ch] = false;
375 register_event(this, HD6844_EVENT_END_TRANSFER + ch,
376 (double)(0x08 / 2 * 2), false, &event_dmac[ch]); // Really?
378 if(words_reg[ch] == 0) {
379 if(((datachain_reg & 0x01) == 1) && __USE_CHAINING) {
381 uint8_t chain_ch = (datachain_reg & 0x06) >> 1;
382 //20180117 K.O Is use multiple chaining?
383 if(((datachain_reg & 0x08) != 0) && __USE_MULTIPLE_CHAINING) {
384 //this->out_debug_log(_T("DMAC: chain 1->2->3->0(1/2) \n"));
385 //if(chain_ch > 2) chain_ch = 2;
387 tmp = addr_reg[chain_ch];
389 addr_reg[chain_ch] = addr_reg[(chain_ch + 3) & 3];
390 addr_reg[(chain_ch + 3) & 3] = addr_reg[(chain_ch + 2) & 3];
391 addr_reg[(chain_ch + 2) & 3] = addr_reg[(chain_ch + 1) & 3];
393 words_reg[chain_ch] = words_reg[(chain_ch + 3) & 3];
394 words_reg[(chain_ch + 3) & 3] = words_reg[(chain_ch + 2) & 3];
395 words_reg[(chain_ch + 2) & 3] = words_reg[(chain_ch + 1) & 3];
397 //addr_reg[(chain_ch + 1) & 3] = tmp;
398 words_reg[(chain_ch + 1) & 3] = 0;
401 // 20180117 K.O Is reset address reg?
402 //if(chain_ch > 1) chain_ch = 1;
404 tmp = addr_reg[chain_ch];
406 addr_reg[chain_ch] = addr_reg[3];
407 words_reg[chain_ch] = words_reg[3];
420 void HD6844::event_callback(int event_id, int err)
424 if((event_id >= HD6844_EVENT_START_TRANSFER) && (event_id < (HD6844_EVENT_START_TRANSFER + 4))) {
425 ch = event_id - HD6844_EVENT_START_TRANSFER;
427 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x40;
428 transfering[ch] = true;
429 } else if((event_id >= HD6844_EVENT_DO_TRANSFER) && (event_id < (HD6844_EVENT_DO_TRANSFER + 4))) {
430 ch = event_id - HD6844_EVENT_DO_TRANSFER;
433 } else if((event_id >= HD6844_EVENT_END_TRANSFER) && (event_id < (HD6844_EVENT_END_TRANSFER + 4))) {
434 ch = event_id - HD6844_EVENT_END_TRANSFER;
436 if(cycle_steal[ch]) {
437 if((channel_control[ch] & 0x04) != 0) {
438 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0);
440 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0);
446 #define STATE_VERSION 2
447 void HD6844::save_state(FILEIO *state_fio)
450 state_fio->FputUint32_BE(STATE_VERSION);
451 state_fio->FputInt32_BE(this_device_id);
452 this->out_debug_log(_T("Save State: HD6844: id=%d ver=%d\n"), this_device_id, STATE_VERSION);
454 //if(!(__FM77AV40EX)) { // FM77AV40 HAS ONE channle and must be reset per save.
455 for(i = 0; i < 4; i++) {
456 state_fio->FputUint32_BE(addr_reg[i]);
457 state_fio->FputUint16_BE(words_reg[i]);
458 state_fio->FputUint8(channel_control[i]);
461 state_fio->FputUint8(priority_reg);
462 state_fio->FputUint8(interrupt_reg);
463 state_fio->FputUint8(datachain_reg);
464 state_fio->FputUint8(num_reg);
465 state_fio->FputUint32_BE(addr_offset);
466 for(i = 0; i < 4; i++) {
467 state_fio->FputUint32_BE(fixed_addr[i]);
468 state_fio->FputUint8(data_reg[i]);
469 state_fio->FputBool(transfering[i]);
470 state_fio->FputBool(first_transfer[i]);
471 state_fio->FputBool(cycle_steal[i]);
472 state_fio->FputBool(halt_flag[i]);
473 state_fio->FputInt32_BE(event_dmac[i]);
478 bool HD6844::load_state(FILEIO *state_fio)
482 version = state_fio->FgetUint32_BE();
483 if(this_device_id != state_fio->FgetInt32_BE()) return false;
484 this->out_debug_log(_T("Load State: HD6844: id=%d ver=%d\n"), this_device_id, version);
486 //if(__FM77AV40EX) { if(__SINGLE_CHANNEL) channel = 0;
487 // for(i = 0; i < 4; i++) {
488 // addr_reg = 0xffff;
489 // words_reg[i] = 0xffff;
490 // channel_control = 0x00;
493 for(i = 0; i < 4; i++) {
494 addr_reg[i] = state_fio->FgetUint32_BE();
495 words_reg[i] = state_fio->FgetUint16_BE();
496 channel_control[i] = state_fio->FgetUint8();
499 priority_reg = state_fio->FgetUint8();
500 interrupt_reg = state_fio->FgetUint8();
501 datachain_reg = state_fio->FgetUint8();
502 num_reg = state_fio->FgetUint8();
503 addr_offset = state_fio->FgetUint32_BE();
504 for(i = 0; i < 4; i++) {
505 fixed_addr[i] = state_fio->FgetUint32_BE();
506 data_reg[i] = state_fio->FgetUint8();
507 transfering[i] = state_fio->FgetBool();
508 first_transfer[i] = state_fio->FgetBool();
509 cycle_steal[i] = state_fio->FgetBool();
510 halt_flag[i] = state_fio->FgetBool();
511 event_dmac[i] = state_fio->FgetInt32_BE();
513 if(version == 1) return true;