OSDN Git Service

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