OSDN Git Service

254c6d3734d2bac8fa575b97f9261abeb9683178
[csp-qt/common_source_project-fm7.git] / source / src / vm / fm7 / hd6844.cpp
1 /*
2  * DMAC HD6844/MC6844 [hd6844.h]
3  *
4  * Author: K.Ohta <whatisthis.sowhat _at_ gmail.com>
5  * License: GPLv2
6  * History:
7  *   Jun 18, 2015 : Initial
8  *
9  */
10
11 //#include "../memory.h"
12 //#include "../vm.h"
13 //#include "../../emu.h"
14
15 #include "hd6844.h"
16
17 #include "../../statesub.h"
18
19 void HD6844::reset()
20 {
21         int ch;
22         for(ch = 0; ch < 4; ch++) {
23                 addr_reg[ch] = 0xffff;
24                 words_reg[ch] = 0xffff;
25                 fixed_addr[ch] = 0x0000;
26                 data_reg[ch] = 0x00;
27                 first_transfer[ch] = false;
28                 
29                 channel_control[ch] = 0;
30                 transfering[ch] = false;
31                 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
32                 event_dmac[ch] = -1;
33                 cycle_steal[ch] = false;
34                 halt_flag[ch] = false;
35         }
36         for(int i = 0; i < 2; i++) write_signals(&(busreq_line[i]), 0);
37         write_signals(&interrupt_line, 0);
38         priority_reg = 0x00;
39         interrupt_reg = 0x00;
40         datachain_reg = 0x00;
41         num_reg = 0x00;
42 }
43
44 void HD6844::initialize()
45 {
46         DEVICE::initialize();
47         addr_offset = 0;
48         int ch;
49         for(ch = 0; ch < 4; ch++) {
50                 event_dmac[ch] = -1;
51         }
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"));
57
58         if(__FM77AV40 || __FM77AV40EX) __USE_MULTIPLE_CHAINING = false;
59         if(__FM77AV40EX) __USE_CHAINING = false;
60 }
61
62 void HD6844::write_data8(uint32_t addr, uint32_t data)
63 {
64         uint8_t ch = addr & 0x03;
65         pair_t tmpd;
66         uint32_t channel = (addr >> 2) & 3;
67
68         tmpd.d = 0;
69         if(addr < 0x10) {
70                 switch(ch) {
71                         case 0:
72                                 tmpd.w.l = addr_reg[channel];
73                                 tmpd.b.h = data & 0xff;
74                                 addr_reg[channel] = tmpd.d;
75                                 break;
76                         case 1:
77                                 tmpd.w.l = addr_reg[channel];
78                                 tmpd.b.l = data & 0xff;
79                                 addr_reg[channel] = tmpd.d;
80                                 break;
81                         case 2:
82                                 tmpd.w.l = words_reg[channel];            
83                                 tmpd.b.h = data & 0xff;
84                                 words_reg[channel] = tmpd.w.l;
85                                 break;
86                         case 3:
87                                 tmpd.w.l = words_reg[channel];            
88                                 tmpd.b.l = data & 0xff;
89                                 words_reg[channel] = tmpd.w.l;
90                                 break;
91                 }
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);
100         }
101 }
102
103
104 uint32_t HD6844::read_data8(uint32_t addr)
105 {
106         uint8_t ch = addr & 0x03;
107         pair_t tmpd;
108         uint32_t channel = (addr >> 2) & 3; 
109         uint32_t retval = 0xff;
110
111         if(__FM77AV40EX) { // FM77AV40EX has only one channel.
112                 if((addr < 0x14) && (channel != 0)) return 0x00;;
113         }
114         tmpd.d = 0;
115         if(addr < 0x10) {
116                 switch(ch) {
117                         case 0:
118                                 tmpd.d = addr_reg[channel];
119                                 retval = tmpd.b.h & 0x00ff;
120                                 break;
121                         case 1:
122                                 tmpd.d = addr_reg[channel];
123                                 retval = tmpd.b.l & 0x00ff;
124                                 break;
125                         case 2:
126                                 tmpd.w.l = words_reg[channel];
127                                 retval = tmpd.b.h & 0x00ff;
128                                 break;
129                         case 3:
130                                 tmpd.w.l = words_reg[channel];
131                                 retval = tmpd.b.l & 0x00ff;
132                                 break;
133                 }
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) {
140                 int i;
141                 retval = ((datachain_reg >> 4) | 0x80) & interrupt_reg;
142                 interrupt_reg &= 0x7f;
143                 datachain_reg &= 0x0f;
144                 do_irq();
145                 //write_signals(&interrupt_line, 0x00); // Clear interrupt
146         } else if(addr == 0x16) {
147                 retval = datachain_reg & 0x0f;
148         }
149         return retval;
150 }
151
152 uint32_t HD6844::read_signal(int id)
153 {
154         switch(id) {
155                 case HD6844_SET_CONST_OFFSET:
156                         return addr_offset;
157                         break;
158                 case HD6844_SRC_FIXED_ADDR_CH0:
159                         return fixed_addr[0];
160                         break;
161                 case HD6844_SRC_FIXED_ADDR_CH1:
162                         return fixed_addr[1];
163                         break;
164                 case HD6844_SRC_FIXED_ADDR_CH2:
165                         return fixed_addr[2];
166                         break;
167                 case HD6844_SRC_FIXED_ADDR_CH3:
168                         return fixed_addr[3];
169                         break;
170                 case HD6844_ADDR_REG_0:
171                         return addr_reg[0];
172                         break;
173                 case HD6844_ADDR_REG_1:
174                         return addr_reg[1];
175                         break;
176                 case HD6844_ADDR_REG_2:
177                         return addr_reg[2];
178                         break;
179                 case HD6844_ADDR_REG_3:
180                         return addr_reg[3];
181                         break;
182                 case HD6844_WORDS_REG_0:
183                         return words_reg[0];
184                         break;
185                 case HD6844_WORDS_REG_1:
186                         return words_reg[1];
187                         break;
188                 case HD6844_WORDS_REG_2:
189                         return words_reg[2];
190                         break;
191                 case HD6844_WORDS_REG_3:
192                         return words_reg[3];
193                         break;
194                 case HD6844_IS_TRANSFER_0:
195                         return transfering[0] ? 0xffffffff : 0;
196                         break;
197                 case HD6844_IS_TRANSFER_1:
198                         return transfering[1] ? 0xffffffff : 0;
199                         break;
200                 case HD6844_IS_TRANSFER_2:
201                         return transfering[2] ? 0xffffffff : 0;
202                         break;
203                 case HD6844_IS_TRANSFER_3:
204                         return transfering[3] ? 0xffffffff : 0;
205                         break;
206                 default:
207                         break;
208         }
209         return 0x0;
210 }
211   
212 void HD6844::write_signal(int id, uint32_t data, uint32_t mask)
213 {
214         //bool val_b = ((data & mask) != 0);
215         uint32_t ch = (data & mask) & 0x03;
216         
217         switch(id) {
218                 case HD6844_SET_CONST_OFFSET:
219                         addr_offset = data;
220                         break;
221                 case HD6844_SRC_FIXED_ADDR_CH0:
222                         fixed_addr[0] = data;
223                         break;
224                 case HD6844_SRC_FIXED_ADDR_CH1:
225                         fixed_addr[1] = data;
226                         break;
227                 case HD6844_SRC_FIXED_ADDR_CH2:
228                         fixed_addr[2] = data;
229                         break;
230                 case HD6844_SRC_FIXED_ADDR_CH3:
231                         fixed_addr[3] = data;
232                         break;
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]);
243                         event_dmac[ch] = -1;
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]);
247                         break;
248                 case HD6844_ACK_BUSREQ_CLIENT:
249                         write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0xffffffff);
250                         break;
251                 case HD6844_ACK_BUSREQ_HOST:
252                         write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff);
253                         break;
254                 case HD6844_DO_TRANSFER:
255                         if(!transfering[ch]) return;
256
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);
261                                 } else {
262                                         if((channel_control[ch] & 0x04) != 0) {
263                                                 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0xffffffff);
264                                         } else {
265                                                 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff);
266                                         }
267                                 }
268                                 halt_flag[ch] = true;
269                                 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
270                                 event_dmac[ch] = -1;
271                                 register_event(this, HD6844_EVENT_DO_TRANSFER + ch,
272                                                            (double)(0x08 / 2), false, NULL); // HD68B44
273                         } else {
274                                 halt_flag[ch] = false;
275                                 if(!cycle_steal[ch]) {
276                                         write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0xffffffff); // Stop (HOST)line.
277                                 } 
278                                 do_transfer(ch);
279                         }
280                         break;
281                 default:
282                         break;
283         }
284 }
285
286 void HD6844::do_irq(void)
287 {
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;
294                                 req_irq = true;
295                         }
296                 }
297         }
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);
302         }
303 }
304
305 void HD6844::do_transfer_end(int ch)
306 {
307         if(words_reg[ch] == 0) {
308                 transfering[ch] = false;
309                 if(event_dmac[ch] >= 0) {
310                         cancel_event(this, event_dmac[ch]);
311                         event_dmac[ch] = -1;
312                 }
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;
317                 do_irq();
318                 //this->out_debug_log(_T("HD6844: Complete transfer ch %d\n"), ch);
319         }       
320 }
321
322 void HD6844::do_transfer(int ch)
323 {
324         ch = ch & 3;
325         if(!transfering[ch]) return;
326         if((priority_reg & 0x01) == 0) {
327 #if 0
328                 transfering[ch] = false;
329                 if(event_dmac[ch] >= 0) {
330                         cancel_event(this, event_dmac[ch]);
331                         event_dmac[ch] = -1;
332                 }
333                 
334                 if((channel_control[ch] & 0x04) != 0) {
335                         write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0);
336                 } else {
337                         write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0);
338                 }
339                 cycle_steal[ch] = false;
340 #endif
341                 return;
342         }
343         if(words_reg[ch] == 0) {
344                 transfering[ch] = false;
345                 if(event_dmac[ch] >= 0) {
346                         cancel_event(this, event_dmac[ch]);
347                         event_dmac[ch] = -1;
348                 }
349                 if((channel_control[ch] & 0x04) != 0) {
350                         write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0);
351                 } else {
352                         write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0);
353                 }
354                 cycle_steal[ch] = false;
355                 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x80;  
356                 return;
357         }
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]);
361         } else {
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]);
364         }
365         words_reg[ch]--;
366         if((channel_control[ch] & 0x08) != 0) {
367                 addr_reg[ch]--;
368         } else {
369                 addr_reg[ch]++;
370         }
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]);
374                 event_dmac[ch] = -1;
375                 halt_flag[ch] = false;
376                 register_event(this, HD6844_EVENT_END_TRANSFER + ch,
377                               (double)(0x08 / 2 * 2), false, &event_dmac[ch]); // Really?
378         }
379         if(words_reg[ch] == 0) {
380                 if(((datachain_reg & 0x01) == 1) && __USE_CHAINING) {
381                         uint16_t tmp;
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;
387 # if 1
388                                 tmp = addr_reg[chain_ch];
389 # endif
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];
393                                         
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];
397 # if 1
398                                 //addr_reg[(chain_ch + 1) & 3] = tmp;
399                                 words_reg[(chain_ch + 1) & 3] = 0;
400 # endif
401                         } else {
402                                 // 20180117 K.O Is reset address reg?
403                                 //if(chain_ch > 1) chain_ch = 1;
404 #if 1
405                                 tmp = addr_reg[chain_ch];
406 #endif
407                                 addr_reg[chain_ch] = addr_reg[3];
408                                 words_reg[chain_ch] = words_reg[3];
409 #if 1
410                                 //addr_reg[3] = tmp;
411                                 words_reg[3] = 0;
412 #endif
413                                 //do_irq();  // OK?
414                         }                               
415                 } else {
416                         do_transfer_end(ch);
417                 }
418         }
419 }       
420
421 void HD6844::event_callback(int event_id, int err)
422 {
423         int ch;
424
425         if((event_id >= HD6844_EVENT_START_TRANSFER) && (event_id < (HD6844_EVENT_START_TRANSFER + 4))) {
426                 ch = event_id - HD6844_EVENT_START_TRANSFER;
427                 event_dmac[ch] = -1;
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;
432                 event_dmac[ch] = -1;
433                 do_transfer(ch);
434         } else if((event_id >= HD6844_EVENT_END_TRANSFER) && (event_id < (HD6844_EVENT_END_TRANSFER + 4))) {
435                 ch = event_id - HD6844_EVENT_END_TRANSFER;
436                 event_dmac[ch] = -1;
437                 if(cycle_steal[ch]) {
438                         if((channel_control[ch] & 0x04) != 0) {
439                                 write_signals(&(busreq_line[HD6844_BUSREQ_CLIENT]), 0);
440                         } else {
441                                 write_signals(&(busreq_line[HD6844_BUSREQ_HOST]), 0);
442                         }
443                 }
444         }
445 }
446
447 #define STATE_VERSION 4
448
449 void HD6844::decl_state(void)
450 {
451         enter_decl_state(STATE_VERSION);
452
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);
457         
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);
463                 
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);
468                 
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);
472
473         leave_decl_state();
474 }
475
476 void HD6844::save_state(FILEIO *state_fio)
477 {
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);
481         }
482 }
483
484 bool HD6844::load_state(FILEIO *state_fio)
485 {
486         bool mb = false;
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"));
490         }
491         return mb;
492 }