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"
20 for(ch = 0; ch < 4; ch++) {
21 addr_reg[ch] = 0xffff;
22 words_reg[ch] = 0xffff;
23 fixed_addr[ch] = 0x0000;
25 first_transfer[ch] = false;
27 channel_control[ch] = 0;
28 transfering[ch] = false;
29 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
31 cycle_steal[ch] = false;
32 halt_flag[ch] = false;
34 for(int i = 0; i < 2; i++) write_signals(&(busreq_line[i]), 0);
35 write_signals(&interrupt_line, 0);
42 void HD6844::initialize()
47 for(ch = 0; ch < 4; ch++) {
50 __USE_CHAINING = true;
51 __USE_MULTIPLE_CHAINING = true;
52 __FM77AV40 = osd->check_feature(_T("_FM77AV40"));
53 __FM77AV40EX = osd->check_feature(_T("_FM77AV40EX"));
54 __FM77AV40EX |= osd->check_feature(_T("_FM77AV40SX"));
56 if(__FM77AV40 || __FM77AV40EX) __USE_MULTIPLE_CHAINING = false;
57 if(__FM77AV40EX) __USE_CHAINING = false;
60 void HD6844::write_data8(uint32_t addr, uint32_t data)
62 uint8_t ch = addr & 0x03;
64 uint32_t channel = (addr >> 2) & 3;
70 tmpd.w.l = addr_reg[channel];
71 tmpd.b.h = data & 0xff;
72 addr_reg[channel] = tmpd.d;
75 tmpd.w.l = addr_reg[channel];
76 tmpd.b.l = data & 0xff;
77 addr_reg[channel] = tmpd.d;
80 tmpd.w.l = words_reg[channel];
81 tmpd.b.h = data & 0xff;
82 words_reg[channel] = tmpd.w.l;
85 tmpd.w.l = words_reg[channel];
86 tmpd.b.l = data & 0xff;
87 words_reg[channel] = tmpd.w.l;
90 } else if((addr >= 0x10) && (addr < 0x14)) { // $10-$13
91 channel_control[addr - 0x10] = (channel_control[addr - 0x10] & 0xc0 ) | (data & 0x0f);
92 } else if(addr == 0x14) {
93 priority_reg = data & 0x8f;
94 } else if(addr == 0x15) {
95 interrupt_reg = (interrupt_reg & 0x80) | (data & 0x0f);
96 } else if(addr == 0x16) {
97 datachain_reg = (datachain_reg & 0xf0) | (data & 0x0f);
102 uint32_t HD6844::read_data8(uint32_t addr)
104 uint8_t ch = addr & 0x03;
106 uint32_t channel = (addr >> 2) & 3;
107 uint32_t retval = 0xff;
109 if(__FM77AV40EX) { // FM77AV40EX has only one channel.
110 if((addr < 0x14) && (channel != 0)) return 0x00;;
116 tmpd.d = addr_reg[channel];
117 retval = tmpd.b.h & 0x00ff;
120 tmpd.d = addr_reg[channel];
121 retval = tmpd.b.l & 0x00ff;
124 tmpd.w.l = words_reg[channel];
125 retval = tmpd.b.h & 0x00ff;
128 tmpd.w.l = words_reg[channel];
129 retval = tmpd.b.l & 0x00ff;
132 } else if((addr >= 0x10) && (addr < 0x14)) { // $10-$13
133 retval = channel_control[addr - 0x10];
134 channel_control[addr - 0x10] &= 0x7f;
135 } else if(addr == 0x14) {
136 retval = priority_reg;
137 } else if(addr == 0x15) {
139 retval = ((datachain_reg >> 4) | 0x80) & interrupt_reg;
140 interrupt_reg &= 0x7f;
141 datachain_reg &= 0x0f;
143 //write_signals(&interrupt_line, 0x00); // Clear interrupt
144 } else if(addr == 0x16) {
145 retval = datachain_reg & 0x0f;
150 uint32_t HD6844::read_signal(int id)
153 case HD6844_SET_CONST_OFFSET:
156 case HD6844_SRC_FIXED_ADDR_CH0:
157 return fixed_addr[0];
159 case HD6844_SRC_FIXED_ADDR_CH1:
160 return fixed_addr[1];
162 case HD6844_SRC_FIXED_ADDR_CH2:
163 return fixed_addr[2];
165 case HD6844_SRC_FIXED_ADDR_CH3:
166 return fixed_addr[3];
168 case HD6844_ADDR_REG_0:
171 case HD6844_ADDR_REG_1:
174 case HD6844_ADDR_REG_2:
177 case HD6844_ADDR_REG_3:
180 case HD6844_WORDS_REG_0:
183 case HD6844_WORDS_REG_1:
186 case HD6844_WORDS_REG_2:
189 case HD6844_WORDS_REG_3:
192 case HD6844_IS_TRANSFER_0:
193 return transfering[0] ? 0xffffffff : 0;
195 case HD6844_IS_TRANSFER_1:
196 return transfering[1] ? 0xffffffff : 0;
198 case HD6844_IS_TRANSFER_2:
199 return transfering[2] ? 0xffffffff : 0;
201 case HD6844_IS_TRANSFER_3:
202 return transfering[3] ? 0xffffffff : 0;
210 void HD6844::write_signal(int id, uint32_t data, uint32_t mask)
212 //bool val_b = ((data & mask) != 0);
213 uint32_t ch = (data & mask) & 0x03;
216 case HD6844_SET_CONST_OFFSET:
219 case HD6844_SRC_FIXED_ADDR_CH0:
220 fixed_addr[0] = data;
222 case HD6844_SRC_FIXED_ADDR_CH1:
223 fixed_addr[1] = data;
225 case HD6844_SRC_FIXED_ADDR_CH2:
226 fixed_addr[2] = data;
228 case HD6844_SRC_FIXED_ADDR_CH3:
229 fixed_addr[3] = data;
231 case HD6844_TRANSFER_START:
232 if(transfering[ch]) return;
233 if((priority_reg & 0x01) == 0) return; // 20180117
234 //if((words_reg[ch] == 0) || (words_reg[ch] == 0xffff)) return;
235 if(words_reg[ch] == 0) return;
236 channel_control[ch] = channel_control[ch] & 0x8f;
237 first_transfer[ch] = true;
238 cycle_steal[ch] = false;
239 if((channel_control[ch] & 0x02) == 0) cycle_steal[ch] = true;
240 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
242 if(event_dmac[ch] < 0) register_event(this, HD6844_EVENT_START_TRANSFER + ch,
243 50.0, false, &event_dmac[ch]);
244 //this->out_debug_log(_T("DMAC: Start Transfer CH=%d $%04x Words, CMDREG=%02x"), ch, words_reg[ch], channel_control[ch]);
246 case HD6844_ACK_BUSREQ_CLIENT:
247 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0xffffffff);
249 case HD6844_ACK_BUSREQ_HOST:
250 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff);
252 case HD6844_DO_TRANSFER:
253 if(!transfering[ch]) return;
255 if(((words_reg[ch] & 0x07) == 1) || (first_transfer[ch])){
256 first_transfer[ch] = false;
257 if(!cycle_steal[ch]) {
258 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff);
260 if((channel_control[ch] & 0x04) != 0) {
261 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0xffffffff);
263 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff);
266 halt_flag[ch] = true;
267 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
269 register_event(this, HD6844_EVENT_DO_TRANSFER + ch,
270 (double)(0x08 / 2), false, NULL); // HD68B44
272 halt_flag[ch] = false;
273 if(!cycle_steal[ch]) {
274 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff); // Stop (HOST)line.
284 void HD6844::do_irq(void)
286 bool irq_stat = ((interrupt_reg & 0x80) != 0);
287 bool req_irq = false;
288 for(int cch = 0;cch < 4; cch++) {
289 if((interrupt_reg & (1 << cch)) != 0) {
290 if((channel_control[cch] & 0x80) != 0) {
291 interrupt_reg |= 0x80;
296 if(!(req_irq) && (irq_stat)) {
297 write_signals(&interrupt_line, 0);
298 } else if((req_irq) && !(irq_stat)) {
299 write_signals(&interrupt_line, 0xffffffff);
303 void HD6844::do_transfer_end(int ch)
305 if(words_reg[ch] == 0) {
306 transfering[ch] = false;
307 if(event_dmac[ch] >= 0) {
308 cancel_event(this, event_dmac[ch]);
311 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0); // release host_bus.
312 cycle_steal[ch] = false;
313 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x80;
314 datachain_reg = datachain_reg | 0x10;
316 //this->out_debug_log(_T("HD6844: Complete transfer ch %d\n"), ch);
320 void HD6844::do_transfer(int ch)
323 if(!transfering[ch]) return;
324 if((priority_reg & 0x01) == 0) {
326 transfering[ch] = false;
327 if(event_dmac[ch] >= 0) {
328 cancel_event(this, event_dmac[ch]);
332 if((channel_control[ch] & 0x04) != 0) {
333 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0);
335 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0);
337 cycle_steal[ch] = false;
341 if(words_reg[ch] == 0) {
342 transfering[ch] = false;
343 if(event_dmac[ch] >= 0) {
344 cancel_event(this, event_dmac[ch]);
347 if((channel_control[ch] & 0x04) != 0) {
348 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0);
350 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0);
352 cycle_steal[ch] = false;
353 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x80;
356 if((channel_control[ch] & 0x01) == 0) {
357 data_reg[ch] = src[ch]->read_io8(fixed_addr[ch]) & 0xff;
358 dest[ch]->write_dma_io8((uint32_t)addr_reg[ch] + addr_offset, data_reg[ch]);
360 data_reg[ch] = dest[ch]->read_dma_io8((uint32_t)addr_reg[ch] + addr_offset) & 0xff;
361 src[ch]->write_io8(fixed_addr[ch], data_reg[ch]);
364 if((channel_control[ch] & 0x08) != 0) {
369 addr_reg[ch] = addr_reg[ch] & 0xffff;
370 if(cycle_steal[ch] && halt_flag[ch]) {
371 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
373 halt_flag[ch] = false;
374 register_event(this, HD6844_EVENT_END_TRANSFER + ch,
375 (double)(0x08 / 2 * 2), false, &event_dmac[ch]); // Really?
377 if(words_reg[ch] == 0) {
378 if(((datachain_reg & 0x01) == 1) && __USE_CHAINING) {
380 uint8_t chain_ch = (datachain_reg & 0x06) >> 1;
381 //20180117 K.O Is use multiple chaining?
382 if(((datachain_reg & 0x08) != 0) && __USE_MULTIPLE_CHAINING) {
383 //this->out_debug_log(_T("DMAC: chain 1->2->3->0(1/2) \n"));
384 //if(chain_ch > 2) chain_ch = 2;
386 tmp = addr_reg[chain_ch];
388 addr_reg[chain_ch] = addr_reg[(chain_ch + 3) & 3];
389 addr_reg[(chain_ch + 3) & 3] = addr_reg[(chain_ch + 2) & 3];
390 addr_reg[(chain_ch + 2) & 3] = addr_reg[(chain_ch + 1) & 3];
392 words_reg[chain_ch] = words_reg[(chain_ch + 3) & 3];
393 words_reg[(chain_ch + 3) & 3] = words_reg[(chain_ch + 2) & 3];
394 words_reg[(chain_ch + 2) & 3] = words_reg[(chain_ch + 1) & 3];
396 //addr_reg[(chain_ch + 1) & 3] = tmp;
397 words_reg[(chain_ch + 1) & 3] = 0;
400 // 20180117 K.O Is reset address reg?
401 //if(chain_ch > 1) chain_ch = 1;
403 tmp = addr_reg[chain_ch];
405 addr_reg[chain_ch] = addr_reg[3];
406 words_reg[chain_ch] = words_reg[3];
419 void HD6844::event_callback(int event_id, int err)
423 if((event_id >= HD6844_EVENT_START_TRANSFER) && (event_id < (HD6844_EVENT_START_TRANSFER + 4))) {
424 ch = event_id - HD6844_EVENT_START_TRANSFER;
426 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x40;
427 transfering[ch] = true;
428 } else if((event_id >= HD6844_EVENT_DO_TRANSFER) && (event_id < (HD6844_EVENT_DO_TRANSFER + 4))) {
429 ch = event_id - HD6844_EVENT_DO_TRANSFER;
432 } else if((event_id >= HD6844_EVENT_END_TRANSFER) && (event_id < (HD6844_EVENT_END_TRANSFER + 4))) {
433 ch = event_id - HD6844_EVENT_END_TRANSFER;
435 if(cycle_steal[ch]) {
436 if((channel_control[ch] & 0x04) != 0) {
437 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0);
439 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0);
445 #define STATE_VERSION 5
447 bool HD6844::process_state(FILEIO *state_fio, bool loading)
450 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
453 if(!state_fio->StateCheckInt32(this_device_id)) {
456 for(int i = 0; i < 4; i++) {
457 state_fio->StateUint32(addr_reg[i]);
458 state_fio->StateUint16(words_reg[i]);
459 state_fio->StateUint8(channel_control[i]);
461 state_fio->StateUint8(priority_reg);
462 state_fio->StateUint8(interrupt_reg);
463 state_fio->StateUint8(datachain_reg);
464 state_fio->StateUint8(num_reg);
465 state_fio->StateUint32(addr_offset);
467 for(int i = 0; i < 4; i++) {
468 state_fio->StateBool(transfering[i]);
469 state_fio->StateBool(first_transfer[i]);
470 state_fio->StateBool(cycle_steal[i]);
471 state_fio->StateBool(halt_flag[i]);
473 state_fio->StateUint32(fixed_addr[i]);
474 state_fio->StateUint8(data_reg[i]);
475 state_fio->StateInt32(event_dmac[i]);