OSDN Git Service

[VM][FM7] Fix state save/load.
[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 HD6844::HD6844(VM *parent_vm, EMU *parent_emu) : DEVICE(parent_vm, parent_emu)
19 {
20         int i;
21         p_emu = parent_emu;
22         p_vm = parent_vm;
23         for(i = 0; i < 4; i++) {
24                 src[i] = dest[i] = NULL;
25                 initialize_output_signals(&(interrupt_line[i]));
26         }
27         initialize_output_signals(&(drq_line[0]));
28         initialize_output_signals(&(drq_line[1]));
29 }
30
31 HD6844::~HD6844()
32 {
33 }
34
35 void HD6844::reset()
36 {
37         int ch;
38         for(ch = 0; ch < 4; ch++) {
39                 addr_reg[ch] = 0xffff;
40                 words_reg[ch] = 0xffff;
41                 fixed_addr[ch] = 0x0000;
42                 data_reg[ch] = 0x00;
43                 first_transfer[ch] = false;
44                 
45                 channel_control[ch] = 0;
46                 transfering[ch] = false;
47                 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
48                 event_dmac[ch] = -1;
49                 cycle_steal[ch] = false;
50                 halt_flag[ch] = false;
51         }
52         write_signals(&(drq_line[0]), 0); 
53         write_signals(&(drq_line[1]), 0); 
54         priority_reg = 0x00;
55         interrupt_reg = 0x00;
56         datachain_reg = 0x00;
57         num_reg = 0x00;
58 }
59
60 void HD6844::initialize()
61 {
62         addr_offset = 0;
63         int ch;
64         for(ch = 0; ch < 4; ch++) {
65                 event_dmac[ch] = -1;
66         }
67    
68 }
69
70 void HD6844::write_data8(uint32_t addr, uint32_t data)
71 {
72         uint8_t ch = addr & 0x03;
73         pair_t tmpd;
74         uint32_t channel = (addr >> 2) & 3;
75
76         tmpd.d = 0;
77         if(addr < 0x10) {
78                 switch(ch) {
79                         case 0:
80                                 tmpd.w.l = addr_reg[channel];
81                                 tmpd.b.h = data & 0xff;
82                                 addr_reg[channel] = tmpd.d;
83                                 break;
84                         case 1:
85                                 tmpd.w.l = addr_reg[channel];
86                                 tmpd.b.l = data & 0xff;
87                                 addr_reg[channel] = tmpd.d;
88                                 break;
89                         case 2:
90                                 tmpd.w.l = words_reg[channel];            
91                                 tmpd.b.h = data & 0xff;
92                                 words_reg[channel] = tmpd.w.l;
93                                 break;
94                         case 3:
95                                 tmpd.w.l = words_reg[channel];            
96                                 tmpd.b.l = data & 0xff;
97                                 words_reg[channel] = tmpd.w.l;
98                                 break;
99                 }
100         } else if((addr >= 0x10) && (addr < 0x14)) { // $10-$13
101                 channel_control[addr - 0x10] = (channel_control[addr - 0x10] & 0xc0 ) | (data & 0x0f);
102         } else if(addr == 0x14) {
103                 priority_reg = data & 0x8f;
104         } else if(addr == 0x15) {
105                 interrupt_reg = (interrupt_reg & 0x80) | (data & 0x0f);
106         } else if(addr == 0x16) {
107                 datachain_reg = (datachain_reg & 0xf0) | (data & 0x0f);
108         }
109 }
110
111
112 uint32_t HD6844::read_data8(uint32_t addr)
113 {
114         uint8_t ch = addr & 0x03;
115         pair_t tmpd;
116         uint32_t channel = (addr >> 2) & 3; 
117         uint32_t retval = 0xff;
118         
119         tmpd.d = 0;
120         if(addr < 0x10) {
121                 switch(ch) {
122                         case 0:
123                                 tmpd.d = addr_reg[channel];
124                                 retval = tmpd.b.h & 0x00ff;
125                                 break;
126                         case 1:
127                                 tmpd.d = addr_reg[channel];
128                                 retval = tmpd.b.l & 0x00ff;
129                                 break;
130                         case 2:
131                                 tmpd.w.l = words_reg[channel];
132                                 retval = tmpd.b.h & 0x00ff;
133                                 break;
134                         case 3:
135                                 tmpd.w.l = words_reg[channel];
136                                 retval = tmpd.b.l & 0x00ff;
137                                 break;
138                 }
139         } else if((addr >= 0x10) && (addr < 0x14)) { // $10-$13
140                 retval = channel_control[addr - 0x10];
141                 channel_control[addr - 0x10] &= 0x7f;
142         } else if(addr == 0x14) {
143                 retval = priority_reg;
144         } else if(addr == 0x15) {
145                 int i;
146                 retval = ((datachain_reg >> 4) | 0x80) & interrupt_reg;
147                 interrupt_reg &= 0x7f;
148                 datachain_reg &= 0x0f;
149                 for(i = 0; i < 4; i++) write_signals(&(interrupt_line[i]), 0x00);
150         } else if(addr == 0x16) {
151                 retval = datachain_reg & 0x0f;
152         }
153         return retval;
154 }
155
156 uint32_t HD6844::read_signal(int id)
157 {
158         switch(id) {
159                 case HD6844_SET_CONST_OFFSET:
160                         return addr_offset;
161                         break;
162                 case HD6844_SRC_FIXED_ADDR_CH0:
163                         return fixed_addr[0];
164                         break;
165                 case HD6844_SRC_FIXED_ADDR_CH1:
166                         return fixed_addr[1];
167                         break;
168                 case HD6844_SRC_FIXED_ADDR_CH2:
169                         return fixed_addr[2];
170                         break;
171                 case HD6844_SRC_FIXED_ADDR_CH3:
172                         return fixed_addr[3];
173                         break;
174                 case HD6844_ADDR_REG_0:
175                         return addr_reg[0];
176                         break;
177                 case HD6844_ADDR_REG_1:
178                         return addr_reg[1];
179                         break;
180                 case HD6844_ADDR_REG_2:
181                         return addr_reg[2];
182                         break;
183                 case HD6844_ADDR_REG_3:
184                         return addr_reg[3];
185                         break;
186                 case HD6844_WORDS_REG_0:
187                         return words_reg[0];
188                         break;
189                 case HD6844_WORDS_REG_1:
190                         return words_reg[1];
191                         break;
192                 case HD6844_WORDS_REG_2:
193                         return words_reg[2];
194                         break;
195                 case HD6844_WORDS_REG_3:
196                         return words_reg[3];
197                         break;
198                 case HD6844_IS_TRANSFER_0:
199                         return transfering[0] ? 0xffffffff : 0;
200                         break;
201                 case HD6844_IS_TRANSFER_1:
202                         return transfering[1] ? 0xffffffff : 0;
203                         break;
204                 case HD6844_IS_TRANSFER_2:
205                         return transfering[2] ? 0xffffffff : 0;
206                         break;
207                 case HD6844_IS_TRANSFER_3:
208                         return transfering[3] ? 0xffffffff : 0;
209                         break;
210                 default:
211                         break;
212         }
213         return 0x0;
214 }
215   
216 void HD6844::write_signal(int id, uint32_t data, uint32_t mask)
217 {
218         //bool val_b = ((data & mask) != 0);
219         uint32_t ch = (data & mask) & 0x03;
220         
221         switch(id) {
222                 case HD6844_SET_CONST_OFFSET:
223                         addr_offset = data;
224                         break;
225                 case HD6844_SRC_FIXED_ADDR_CH0:
226                         fixed_addr[0] = data;
227                         break;
228                 case HD6844_SRC_FIXED_ADDR_CH1:
229                         fixed_addr[1] = data;
230                         break;
231                 case HD6844_SRC_FIXED_ADDR_CH2:
232                         fixed_addr[2] = data;
233                         break;
234                 case HD6844_SRC_FIXED_ADDR_CH3:
235                         fixed_addr[3] = data;
236                         break;
237                 case HD6844_TRANSFER_START:
238                         if(transfering[ch]) return;
239                         if((words_reg[ch] == 0) || (words_reg[ch] == 0xffff)) return;
240                         channel_control[ch] = channel_control[ch] & 0x8f;
241                         first_transfer[ch] = true;
242                         cycle_steal[ch] = false;
243                         if((channel_control[ch] & 0x02) == 0) cycle_steal[ch] = true;   
244                         if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
245                         event_dmac[ch] = -1;
246                         if(event_dmac[ch] < 0) register_event(this, HD6844_EVENT_START_TRANSFER + ch,
247                                                               50.0, false, &event_dmac[ch]);
248                         //emu->out_debug_log(_T("DMAC: Start Transfer CH=%d $%04x Words, CMDREG=%02x"), ch, words_reg[ch], channel_control[ch]);
249                         break;
250                 case HD6844_ACK_DRQ1:
251                         write_signals(&(drq_line[0]), 0xffffffff);
252                         break;
253                 case HD6844_ACK_DRQ2:
254                         write_signals(&(drq_line[1]), 0xffffffff);
255                         break;
256                 case HD6844_DO_TRANSFER:
257                         if(!transfering[ch]) return;
258
259                         if(((words_reg[ch] & 0x07) == 1) || (first_transfer[ch])){
260                                 first_transfer[ch] = false;
261                                 if(!cycle_steal[ch]) {
262                                         write_signals(&(drq_line[1]), 0xffffffff);
263                                 } else {
264                                         if((channel_control[ch] & 0x04) != 0) {
265                                                 write_signals(&(drq_line[0]), 0xffffffff);
266                                         } else {
267                                                 write_signals(&(drq_line[1]), 0xffffffff);
268                                         }
269                                 }
270                                 halt_flag[ch] = true;
271                                 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
272                                 event_dmac[ch] = -1;
273                                 register_event(this, HD6844_EVENT_DO_TRANSFER + ch,
274                                                            (double)(0x08 / 2), false, NULL); // HD68B44
275                         } else {
276                                 halt_flag[ch] = false;
277                                 if(!cycle_steal[ch]) {
278                                         write_signals(&(drq_line[1]), 0xffffffff);
279                                 } 
280                                 do_transfer(ch);
281                         }
282                         break;
283                 default:
284                         break;
285         }
286 }
287
288 void HD6844::do_transfer(int ch)
289 {
290         ch = ch & 3;
291         if(!transfering[ch]) return;
292         if((priority_reg & 0x01) == 0) {
293                 transfering[ch] = false;
294                 if(event_dmac[ch] >= 0) {
295                         cancel_event(this, event_dmac[ch]);
296                         event_dmac[ch] = -1;
297                 }
298                 
299                 if((channel_control[ch] & 0x04) != 0) {
300                         write_signals(&(drq_line[0]), 0);
301                 } else {
302                         write_signals(&(drq_line[1]), 0);
303                 }
304                 cycle_steal[ch] = false;
305                 return;
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                 if((channel_control[ch] & 0x04) != 0) {
314                         write_signals(&(drq_line[0]), 0);
315                 } else {
316                         write_signals(&(drq_line[1]), 0);
317                 }
318                 cycle_steal[ch] = false;
319                 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x80;  
320                 return;
321         }
322         if((channel_control[ch] & 0x01) == 0) {
323                 data_reg[ch] = src[ch]->read_io8(fixed_addr[ch]) & 0xff;
324                 dest[ch]->write_dma_io8((uint32_t)addr_reg[ch] + addr_offset, data_reg[ch]);
325         } else {
326                 data_reg[ch] = dest[ch]->read_dma_io8((uint32_t)addr_reg[ch] + addr_offset) & 0xff;
327                 src[ch]->write_io8(fixed_addr[ch], data_reg[ch]);
328         }
329         words_reg[ch]--;
330         if((channel_control[ch] & 0x08) != 0) {
331                 addr_reg[ch]--;
332         } else {
333                 addr_reg[ch]++;
334         }
335         addr_reg[ch] = addr_reg[ch] & 0xffff;
336         if(cycle_steal[ch] && halt_flag[ch]) {
337                 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
338                 event_dmac[ch] = -1;
339                 halt_flag[ch] = false;
340                 register_event(this, HD6844_EVENT_END_TRANSFER + ch,
341                               (double)(0x08 / 2 * 2), false, &event_dmac[ch]); // Really?
342         }
343         if(words_reg[ch] == 0) {
344                 if((datachain_reg & 0x01) != 0) {
345                         uint16_t tmp;
346                         uint8_t chain_ch = (datachain_reg & 0x06) >> 1; 
347                         if((datachain_reg & 0x08) != 0) {
348                                 //emu->out_debug_log(_T("DMAC: chain 1->2->3->0(1/2) \n"));
349                                 if(chain_ch > 2) chain_ch = 2;
350                                 tmp = addr_reg[chain_ch];
351                                 addr_reg[chain_ch] = addr_reg[(chain_ch + 3) & 3];
352                                 addr_reg[(chain_ch + 3) & 3] = addr_reg[(chain_ch + 2) & 3];
353                                 addr_reg[(chain_ch + 2) & 3] = addr_reg[(chain_ch + 1) & 3];
354                                 addr_reg[(chain_ch + 1) & 3] = tmp;
355
356                                 words_reg[chain_ch] = words_reg[(chain_ch + 3) & 3];
357                                 words_reg[(chain_ch + 3) & 3] = words_reg[(chain_ch + 2) & 3];
358                                 words_reg[(chain_ch + 2) & 3] = words_reg[(chain_ch + 1) & 3];
359                                 words_reg[(chain_ch + 1) & 3] = 0;
360                         } else {
361                                 if(chain_ch > 1) chain_ch = 1;
362                                 //emu->out_debug_log(_T("DMAC: chain 3->0(1) \n"));
363                                 tmp = addr_reg[chain_ch];
364                                 addr_reg[chain_ch] = addr_reg[3];
365                                 addr_reg[3] = tmp;
366
367                                 words_reg[chain_ch] = words_reg[3];
368                                 words_reg[3] = 0;
369                         }
370                 } else {
371                         transfering[ch] = false;
372                         if(event_dmac[ch] >= 0) {
373                                 cancel_event(this, event_dmac[ch]);
374                                 event_dmac[ch] = -1;
375                         }
376                         write_signals(&(drq_line[1]), 0);
377                         cycle_steal[ch] = false;
378                         channel_control[ch] = (channel_control[ch] & 0x0f) | 0x80;
379                         datachain_reg = datachain_reg | 0x10;
380                         if((interrupt_reg & (0x01 << ch)) != 0) {
381                                 interrupt_reg |= 0x80;
382                                 write_signals(&(interrupt_line[ch]), 0xffffffff);
383                         }                                 
384                         //p_emu->out_debug_log(_T("HD6844: Complete transfer ch %d\n"), ch);
385                 }
386         }
387 }       
388
389 void HD6844::event_callback(int event_id, int err)
390 {
391         int ch;
392
393         if((event_id >= HD6844_EVENT_START_TRANSFER) && (event_id < (HD6844_EVENT_START_TRANSFER + 4))) {
394                 ch = event_id - HD6844_EVENT_START_TRANSFER;
395                 event_dmac[ch] = -1;
396                 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x40;
397                 transfering[ch] = true;
398         } else  if((event_id >= HD6844_EVENT_DO_TRANSFER) && (event_id < (HD6844_EVENT_DO_TRANSFER + 4))) {
399                 ch = event_id - HD6844_EVENT_DO_TRANSFER;
400                 event_dmac[ch] = -1;
401                 do_transfer(ch);
402         } else if((event_id >= HD6844_EVENT_END_TRANSFER) && (event_id < (HD6844_EVENT_END_TRANSFER + 4))) {
403                 ch = event_id - HD6844_EVENT_END_TRANSFER;
404                 event_dmac[ch] = -1;
405                 if(cycle_steal[ch]) {
406                         if((channel_control[ch] & 0x04) != 0) {
407                                 write_signals(&(drq_line[0]), 0);
408                         } else {
409                                 write_signals(&(drq_line[1]), 0);
410                         }
411                 }
412         }
413 }
414
415 #define STATE_VERSION 1
416 void HD6844::save_state(FILEIO *state_fio)
417 {
418         int i;
419         state_fio->FputUint32_BE(STATE_VERSION);
420         state_fio->FputInt32_BE(this_device_id);
421         p_emu->out_debug_log("Save State: HD6844: id=%d ver=%d\n", this_device_id, STATE_VERSION);
422         { // V1
423                 for(i = 0; i < 4; i++) {
424                         state_fio->FputUint32_BE(addr_reg[i]);
425                         state_fio->FputUint16_BE(words_reg[i]);
426                         state_fio->FputUint8(channel_control[i]);
427                 }
428                 state_fio->FputUint8(priority_reg);
429                 state_fio->FputUint8(interrupt_reg);
430                 state_fio->FputUint8(datachain_reg);
431                 state_fio->FputUint8(num_reg);
432                 state_fio->FputUint32_BE(addr_offset);
433                 for(i = 0; i < 4; i++) {
434                         state_fio->FputUint32_BE(fixed_addr[i]);
435                         state_fio->FputUint8(data_reg[i]);
436                         state_fio->FputBool(transfering[i]);
437                         state_fio->FputBool(first_transfer[i]);
438                         state_fio->FputBool(cycle_steal[i]);
439                         state_fio->FputBool(halt_flag[i]);
440                         state_fio->FputInt32_BE(event_dmac[i]);
441                 }
442         }
443 }
444
445 bool HD6844::load_state(FILEIO *state_fio)
446 {
447         uint32_t version;
448         int i;
449         version = state_fio->FgetUint32_BE();
450         if(this_device_id != state_fio->FgetInt32_BE()) return false;
451         p_emu->out_debug_log("Load State: HD6844: id=%d ver=%d\n", this_device_id, version);
452         if(version >= 1) {
453                 for(i = 0; i < 4; i++) {
454                         addr_reg[i] = state_fio->FgetUint32_BE();
455                         words_reg[i] = state_fio->FgetUint16_BE();
456                         channel_control[i] = state_fio->FgetUint8();
457                 }
458                 priority_reg = state_fio->FgetUint8();
459                 interrupt_reg = state_fio->FgetUint8();
460                 datachain_reg = state_fio->FgetUint8();
461                 num_reg = state_fio->FgetUint8();
462                 addr_offset = state_fio->FgetUint32_BE();
463                 for(i = 0; i < 4; i++) {
464                         fixed_addr[i] = state_fio->FgetUint32_BE();
465                         data_reg[i] = state_fio->FgetUint8();
466                         transfering[i] = state_fio->FgetBool();
467                         first_transfer[i] = state_fio->FgetBool();
468                         cycle_steal[i] = state_fio->FgetBool();
469                         halt_flag[i] = state_fio->FgetBool();
470                         event_dmac[i] = state_fio->FgetInt32_BE();
471                 }
472                 if(version == 1) return true;
473         }
474         return false;
475 }