OSDN Git Service

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