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"
17 #include "../../statesub.h"
22 for(ch = 0; ch < 4; ch++) {
23 addr_reg[ch] = 0xffff;
24 words_reg[ch] = 0xffff;
25 fixed_addr[ch] = 0x0000;
27 first_transfer[ch] = false;
29 channel_control[ch] = 0;
30 transfering[ch] = false;
31 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
33 cycle_steal[ch] = false;
34 halt_flag[ch] = false;
36 for(int i = 0; i < 2; i++) write_signals(&(busreq_line[i]), 0);
37 write_signals(&interrupt_line, 0);
44 void HD6844::initialize()
49 for(ch = 0; ch < 4; ch++) {
52 __USE_CHAINING = true;
53 __USE_MULTIPLE_CHAINING = true;
54 __FM77AV40 = osd->check_feature(_T("_FM77AV40"));
55 __FM77AV40EX = osd->check_feature(_T("_FM77AV40EX"));
56 __FM77AV40EX |= osd->check_feature(_T("_FM77AV40SX"));
58 if(__FM77AV40 || __FM77AV40EX) __USE_MULTIPLE_CHAINING = false;
59 if(__FM77AV40EX) __USE_CHAINING = false;
62 void HD6844::write_data8(uint32_t addr, uint32_t data)
64 uint8_t ch = addr & 0x03;
66 uint32_t channel = (addr >> 2) & 3;
72 tmpd.w.l = addr_reg[channel];
73 tmpd.b.h = data & 0xff;
74 addr_reg[channel] = tmpd.d;
77 tmpd.w.l = addr_reg[channel];
78 tmpd.b.l = data & 0xff;
79 addr_reg[channel] = tmpd.d;
82 tmpd.w.l = words_reg[channel];
83 tmpd.b.h = data & 0xff;
84 words_reg[channel] = tmpd.w.l;
87 tmpd.w.l = words_reg[channel];
88 tmpd.b.l = data & 0xff;
89 words_reg[channel] = tmpd.w.l;
92 } else if((addr >= 0x10) && (addr < 0x14)) { // $10-$13
93 channel_control[addr - 0x10] = (channel_control[addr - 0x10] & 0xc0 ) | (data & 0x0f);
94 } else if(addr == 0x14) {
95 priority_reg = data & 0x8f;
96 } else if(addr == 0x15) {
97 interrupt_reg = (interrupt_reg & 0x80) | (data & 0x0f);
98 } else if(addr == 0x16) {
99 datachain_reg = (datachain_reg & 0xf0) | (data & 0x0f);
104 uint32_t HD6844::read_data8(uint32_t addr)
106 uint8_t ch = addr & 0x03;
108 uint32_t channel = (addr >> 2) & 3;
109 uint32_t retval = 0xff;
111 if(__FM77AV40EX) { // FM77AV40EX has only one channel.
112 if((addr < 0x14) && (channel != 0)) return 0x00;;
118 tmpd.d = addr_reg[channel];
119 retval = tmpd.b.h & 0x00ff;
122 tmpd.d = addr_reg[channel];
123 retval = tmpd.b.l & 0x00ff;
126 tmpd.w.l = words_reg[channel];
127 retval = tmpd.b.h & 0x00ff;
130 tmpd.w.l = words_reg[channel];
131 retval = tmpd.b.l & 0x00ff;
134 } else if((addr >= 0x10) && (addr < 0x14)) { // $10-$13
135 retval = channel_control[addr - 0x10];
136 channel_control[addr - 0x10] &= 0x7f;
137 } else if(addr == 0x14) {
138 retval = priority_reg;
139 } else if(addr == 0x15) {
141 retval = ((datachain_reg >> 4) | 0x80) & interrupt_reg;
142 interrupt_reg &= 0x7f;
143 datachain_reg &= 0x0f;
145 //write_signals(&interrupt_line, 0x00); // Clear interrupt
146 } else if(addr == 0x16) {
147 retval = datachain_reg & 0x0f;
152 uint32_t HD6844::read_signal(int id)
155 case HD6844_SET_CONST_OFFSET:
158 case HD6844_SRC_FIXED_ADDR_CH0:
159 return fixed_addr[0];
161 case HD6844_SRC_FIXED_ADDR_CH1:
162 return fixed_addr[1];
164 case HD6844_SRC_FIXED_ADDR_CH2:
165 return fixed_addr[2];
167 case HD6844_SRC_FIXED_ADDR_CH3:
168 return fixed_addr[3];
170 case HD6844_ADDR_REG_0:
173 case HD6844_ADDR_REG_1:
176 case HD6844_ADDR_REG_2:
179 case HD6844_ADDR_REG_3:
182 case HD6844_WORDS_REG_0:
185 case HD6844_WORDS_REG_1:
188 case HD6844_WORDS_REG_2:
191 case HD6844_WORDS_REG_3:
194 case HD6844_IS_TRANSFER_0:
195 return transfering[0] ? 0xffffffff : 0;
197 case HD6844_IS_TRANSFER_1:
198 return transfering[1] ? 0xffffffff : 0;
200 case HD6844_IS_TRANSFER_2:
201 return transfering[2] ? 0xffffffff : 0;
203 case HD6844_IS_TRANSFER_3:
204 return transfering[3] ? 0xffffffff : 0;
212 void HD6844::write_signal(int id, uint32_t data, uint32_t mask)
214 //bool val_b = ((data & mask) != 0);
215 uint32_t ch = (data & mask) & 0x03;
218 case HD6844_SET_CONST_OFFSET:
221 case HD6844_SRC_FIXED_ADDR_CH0:
222 fixed_addr[0] = data;
224 case HD6844_SRC_FIXED_ADDR_CH1:
225 fixed_addr[1] = data;
227 case HD6844_SRC_FIXED_ADDR_CH2:
228 fixed_addr[2] = data;
230 case HD6844_SRC_FIXED_ADDR_CH3:
231 fixed_addr[3] = data;
233 case HD6844_TRANSFER_START:
234 if(transfering[ch]) return;
235 if((priority_reg & 0x01) == 0) return; // 20180117
236 //if((words_reg[ch] == 0) || (words_reg[ch] == 0xffff)) return;
237 if(words_reg[ch] == 0) return;
238 channel_control[ch] = channel_control[ch] & 0x8f;
239 first_transfer[ch] = true;
240 cycle_steal[ch] = false;
241 if((channel_control[ch] & 0x02) == 0) cycle_steal[ch] = true;
242 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
244 if(event_dmac[ch] < 0) register_event(this, HD6844_EVENT_START_TRANSFER + ch,
245 50.0, false, &event_dmac[ch]);
246 //this->out_debug_log(_T("DMAC: Start Transfer CH=%d $%04x Words, CMDREG=%02x"), ch, words_reg[ch], channel_control[ch]);
248 case HD6844_ACK_BUSREQ_CLIENT:
249 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0xffffffff);
251 case HD6844_ACK_BUSREQ_HOST:
252 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff);
254 case HD6844_DO_TRANSFER:
255 if(!transfering[ch]) return;
257 if(((words_reg[ch] & 0x07) == 1) || (first_transfer[ch])){
258 first_transfer[ch] = false;
259 if(!cycle_steal[ch]) {
260 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff);
262 if((channel_control[ch] & 0x04) != 0) {
263 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0xffffffff);
265 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff);
268 halt_flag[ch] = true;
269 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
271 register_event(this, HD6844_EVENT_DO_TRANSFER + ch,
272 (double)(0x08 / 2), false, NULL); // HD68B44
274 halt_flag[ch] = false;
275 if(!cycle_steal[ch]) {
276 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff); // Stop (HOST)line.
286 void HD6844::do_irq(void)
288 bool irq_stat = ((interrupt_reg & 0x80) != 0);
289 bool req_irq = false;
290 for(int cch = 0;cch < 4; cch++) {
291 if((interrupt_reg & (1 << cch)) != 0) {
292 if((channel_control[cch] & 0x80) != 0) {
293 interrupt_reg |= 0x80;
298 if(!(req_irq) && (irq_stat)) {
299 write_signals(&interrupt_line, 0);
300 } else if((req_irq) && !(irq_stat)) {
301 write_signals(&interrupt_line, 0xffffffff);
305 void HD6844::do_transfer_end(int ch)
307 if(words_reg[ch] == 0) {
308 transfering[ch] = false;
309 if(event_dmac[ch] >= 0) {
310 cancel_event(this, event_dmac[ch]);
313 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0); // release host_bus.
314 cycle_steal[ch] = false;
315 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x80;
316 datachain_reg = datachain_reg | 0x10;
318 //this->out_debug_log(_T("HD6844: Complete transfer ch %d\n"), ch);
322 void HD6844::do_transfer(int ch)
325 if(!transfering[ch]) return;
326 if((priority_reg & 0x01) == 0) {
328 transfering[ch] = false;
329 if(event_dmac[ch] >= 0) {
330 cancel_event(this, event_dmac[ch]);
334 if((channel_control[ch] & 0x04) != 0) {
335 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0);
337 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0);
339 cycle_steal[ch] = false;
343 if(words_reg[ch] == 0) {
344 transfering[ch] = false;
345 if(event_dmac[ch] >= 0) {
346 cancel_event(this, event_dmac[ch]);
349 if((channel_control[ch] & 0x04) != 0) {
350 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0);
352 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0);
354 cycle_steal[ch] = false;
355 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x80;
358 if((channel_control[ch] & 0x01) == 0) {
359 data_reg[ch] = src[ch]->read_io8(fixed_addr[ch]) & 0xff;
360 dest[ch]->write_dma_io8((uint32_t)addr_reg[ch] + addr_offset, data_reg[ch]);
362 data_reg[ch] = dest[ch]->read_dma_io8((uint32_t)addr_reg[ch] + addr_offset) & 0xff;
363 src[ch]->write_io8(fixed_addr[ch], data_reg[ch]);
366 if((channel_control[ch] & 0x08) != 0) {
371 addr_reg[ch] = addr_reg[ch] & 0xffff;
372 if(cycle_steal[ch] && halt_flag[ch]) {
373 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
375 halt_flag[ch] = false;
376 register_event(this, HD6844_EVENT_END_TRANSFER + ch,
377 (double)(0x08 / 2 * 2), false, &event_dmac[ch]); // Really?
379 if(words_reg[ch] == 0) {
380 if(((datachain_reg & 0x01) == 1) && __USE_CHAINING) {
382 uint8_t chain_ch = (datachain_reg & 0x06) >> 1;
383 //20180117 K.O Is use multiple chaining?
384 if(((datachain_reg & 0x08) != 0) && __USE_MULTIPLE_CHAINING) {
385 //this->out_debug_log(_T("DMAC: chain 1->2->3->0(1/2) \n"));
386 //if(chain_ch > 2) chain_ch = 2;
388 tmp = addr_reg[chain_ch];
390 addr_reg[chain_ch] = addr_reg[(chain_ch + 3) & 3];
391 addr_reg[(chain_ch + 3) & 3] = addr_reg[(chain_ch + 2) & 3];
392 addr_reg[(chain_ch + 2) & 3] = addr_reg[(chain_ch + 1) & 3];
394 words_reg[chain_ch] = words_reg[(chain_ch + 3) & 3];
395 words_reg[(chain_ch + 3) & 3] = words_reg[(chain_ch + 2) & 3];
396 words_reg[(chain_ch + 2) & 3] = words_reg[(chain_ch + 1) & 3];
398 //addr_reg[(chain_ch + 1) & 3] = tmp;
399 words_reg[(chain_ch + 1) & 3] = 0;
402 // 20180117 K.O Is reset address reg?
403 //if(chain_ch > 1) chain_ch = 1;
405 tmp = addr_reg[chain_ch];
407 addr_reg[chain_ch] = addr_reg[3];
408 words_reg[chain_ch] = words_reg[3];
421 void HD6844::event_callback(int event_id, int err)
425 if((event_id >= HD6844_EVENT_START_TRANSFER) && (event_id < (HD6844_EVENT_START_TRANSFER + 4))) {
426 ch = event_id - HD6844_EVENT_START_TRANSFER;
428 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x40;
429 transfering[ch] = true;
430 } else if((event_id >= HD6844_EVENT_DO_TRANSFER) && (event_id < (HD6844_EVENT_DO_TRANSFER + 4))) {
431 ch = event_id - HD6844_EVENT_DO_TRANSFER;
434 } else if((event_id >= HD6844_EVENT_END_TRANSFER) && (event_id < (HD6844_EVENT_END_TRANSFER + 4))) {
435 ch = event_id - HD6844_EVENT_END_TRANSFER;
437 if(cycle_steal[ch]) {
438 if((channel_control[ch] & 0x04) != 0) {
439 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0);
441 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0);
447 #define STATE_VERSION 4
449 void HD6844::decl_state(void)
451 enter_decl_state(STATE_VERSION);
453 DECL_STATE_ENTRY_INT(this_device_id);
454 DECL_STATE_ENTRY_UINT32_ARRAY(addr_reg, 4);
455 DECL_STATE_ENTRY_UINT16_ARRAY(words_reg, 4);
456 DECL_STATE_ENTRY_UINT8_ARRAY(channel_control, 4);
458 DECL_STATE_ENTRY_UINT8(priority_reg);
459 DECL_STATE_ENTRY_UINT8(interrupt_reg);
460 DECL_STATE_ENTRY_UINT8(datachain_reg);
461 DECL_STATE_ENTRY_UINT8(num_reg);
462 DECL_STATE_ENTRY_UINT32(addr_offset);
464 DECL_STATE_ENTRY_BOOL_ARRAY(transfering, 4);
465 DECL_STATE_ENTRY_BOOL_ARRAY(first_transfer, 4);
466 DECL_STATE_ENTRY_BOOL_ARRAY(cycle_steal, 4);
467 DECL_STATE_ENTRY_BOOL_ARRAY(halt_flag, 4);
469 DECL_STATE_ENTRY_UINT32_ARRAY(fixed_addr, 4);
470 DECL_STATE_ENTRY_UINT8_ARRAY(data_reg, 4);
471 DECL_STATE_ENTRY_INT32_ARRAY(event_dmac, 4);
476 void HD6844::save_state(FILEIO *state_fio)
478 if(state_entry != NULL) {
479 state_entry->save_state(state_fio);
480 out_debug_log(_T("Save State: HD6844: id=%d ver=%d"), this_device_id, STATE_VERSION);
484 bool HD6844::load_state(FILEIO *state_fio)
487 if(state_entry != NULL) {
488 mb = state_entry->load_state(state_fio);
489 out_debug_log(_T("Load State: HD6844: id=%d stat=%s"), this_device_id, (mb) ? _T("OK") : _T("NG"));