OSDN Git Service

[VM][FM77AV][DISK] Fix transfer timing for FM-77AV, rotation of FDDs is 600 RPM.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fm7 / hd6844.cpp
1
2 #include "../memory.h"
3 #include "../vm.h"
4 #include "../../emu.h"
5
6 #include "hd6844.h"
7
8
9 HD6844::HD6844(VM *parent_vm, EMU *parent_emu) : DEVICE(parent_vm, parent_emu)
10 {
11         p_emu = parent_emu;
12         p_vm = parent_vm;
13         init_output_signals(&interrupt_line);
14         init_output_signals(&halt_line);
15 }
16
17 HD6844::~HD6844()
18 {
19 }
20
21 void HD6844::reset()
22 {
23         int ch;
24         for(ch = 0; ch < 4; ch++) {
25                 addr_reg[ch] = 0xffff;
26                 words_reg[ch] = 0xffff;
27                 fixed_addr[ch] = 0x0000;
28                 data_reg[ch] = 0x00;
29                 first_transfer[ch] = false;
30                 
31                 channel_control[ch] = 0;
32                 transfering[ch] = false;
33                 if(event_dmac[ch] >= 0) cancel_event(this, event_dmac[ch]);
34                 event_dmac[ch] = -1;
35         }
36         priority_reg = 0x00;
37         interrupt_reg = 0x00;
38         datachain_reg = 0x00;
39         num_reg = 0x00;
40         cycle_steal = false;
41 }
42
43 void HD6844::initialize()
44 {
45         addr_offset = 0;
46         int ch;
47         for(ch = 0; ch < 4; ch++) {
48                 event_dmac[ch] = -1;
49         }
50    
51 }
52
53 void HD6844::write_data8(uint32 addr, uint32 data)
54 {
55         uint8 ch = addr & 0x03;
56         pair tmpd;
57         uint32 channel = (addr >> 2) & 3;
58
59         tmpd.d = 0;
60         if(addr < 0x10) {
61                 switch(addr & 3) {
62                         case 0:
63                                 tmpd.w.l = addr_reg[channel];
64                                 tmpd.w.h = 0;
65                                 tmpd.b.h = data & 0xff;
66                                 addr_reg[channel] = tmpd.d;
67                                 break;
68                         case 1:
69                                 tmpd.w.l = addr_reg[channel];
70                                 tmpd.b.l = data & 0xff;
71                                 addr_reg[channel] = tmpd.d;
72                                 break;
73                         case 2:
74                                 tmpd.w.l = words_reg[channel];            
75                                 tmpd.b.h = data & 0xff;
76                                 words_reg[channel] = tmpd.w.l;
77                                 break;
78                         case 3:
79                                 tmpd.w.l = words_reg[channel];            
80                                 tmpd.b.l = data & 0xff;
81                                 words_reg[channel] = tmpd.w.l;
82                                 break;
83                 }
84         } else if((addr >= 0x10) && (addr < 0x14)) { // $10-$13
85                 channel_control[addr - 0x10] = (channel_control[addr - 0x10] & 0xc0 ) | (data & 0x0f);
86         } else if(addr == 0x14) {
87                 priority_reg = data & 0x8f;
88         } else if(addr == 0x15) {
89                 interrupt_reg = (interrupt_reg & 0x80) | (data & 0x0f);
90         } else if(addr == 0x16) {
91                 datachain_reg = (datachain_reg & 0xf0) | (data & 0x0f);
92         }
93 }
94
95
96 uint32 HD6844::read_data8(uint32 addr)
97 {
98         uint8 ch = addr & 0x03;
99         pair tmpd;
100         uint32 channel = (addr >> 2) & 3; 
101         uint32 retval = 0xff;
102         
103         tmpd.d = 0;
104         if(addr < 0x10) {
105                 switch(addr & 3) {
106                         case 0:
107                                 tmpd.d = addr_reg[channel];
108                                 retval = tmpd.b.h & 0x00ff;
109                                 break;
110                         case 1:
111                                 tmpd.d = addr_reg[channel];
112                                 retval = tmpd.b.l & 0x00ff;
113                                 break;
114                         case 2:
115                                 tmpd.w.l = words_reg[channel];
116                                 retval = tmpd.b.h & 0x00ff;
117                                 break;
118                         case 3:
119                                 tmpd.w.l = words_reg[channel];
120                                 retval = tmpd.b.l & 0x00ff;
121                                 break;
122                 }
123         } else if((addr >= 0x10) && (addr < 0x14)) { // $10-$13
124                 retval = channel_control[addr - 0x10];
125                 channel_control[addr - 0x10] &= 0x7f;
126         } else if(addr == 0x14) {
127                 retval = priority_reg;
128         } else if(addr == 0x15) {
129                 retval = ((datachain_reg >> 4) | 0x80) & interrupt_reg;
130                 interrupt_reg &= 0x7f;
131                 datachain_reg &= 0x0f;
132                 write_signals(&interrupt_line, 0x00);
133         } else if(addr == 0x16) {
134                 retval = datachain_reg & 0x0f;
135         }
136         return retval;
137 }
138
139 uint32 HD6844::read_signal(int id)
140 {
141         switch(id) {
142                 case HD6844_SET_CONST_OFFSET:
143                         return addr_offset;
144                         break;
145                 case HD6844_SRC_FIXED_ADDR_CH0:
146                         return fixed_addr[0];
147                         break;
148                 case HD6844_SRC_FIXED_ADDR_CH1:
149                         return fixed_addr[1];
150                         break;
151                 case HD6844_SRC_FIXED_ADDR_CH2:
152                         return fixed_addr[2];
153                         break;
154                 case HD6844_SRC_FIXED_ADDR_CH3:
155                         return fixed_addr[3];
156                         break;
157                 case HD6844_ADDR_REG_0:
158                         return addr_reg[0];
159                         break;
160                 case HD6844_ADDR_REG_1:
161                         return addr_reg[1];
162                         break;
163                 case HD6844_ADDR_REG_2:
164                         return addr_reg[2];
165                         break;
166                 case HD6844_ADDR_REG_3:
167                         return addr_reg[3];
168                         break;
169                 case HD6844_WORDS_REG_0:
170                         return words_reg[0];
171                         break;
172                 case HD6844_WORDS_REG_1:
173                         return words_reg[1];
174                         break;
175                 case HD6844_WORDS_REG_2:
176                         return words_reg[2];
177                         break;
178                 case HD6844_WORDS_REG_3:
179                         return words_reg[3];
180                         break;
181                 case HD6844_IS_TRANSFER_0:
182                         return transfering[0] ? 0xffffffff : 0;
183                         break;
184                 case HD6844_IS_TRANSFER_1:
185                         return transfering[1] ? 0xffffffff : 0;
186                         break;
187                 case HD6844_IS_TRANSFER_2:
188                         return transfering[2] ? 0xffffffff : 0;
189                         break;
190                 case HD6844_IS_TRANSFER_3:
191                         return transfering[3] ? 0xffffffff : 0;
192                         break;
193                 default:
194                         break;
195         }
196         return 0x0;
197 }
198   
199 void HD6844::write_signal(int id, uint32 data, uint32 mask)
200 {
201         bool val_b = ((data & mask) != 0);
202         uint32 ch = (data & mask) & 0x03;
203         
204         switch(id) {
205                 case HD6844_SET_CONST_OFFSET:
206                         addr_offset = data;
207                         break;
208                 case HD6844_SRC_FIXED_ADDR_CH0:
209                         fixed_addr[0] = data;
210                         break;
211                 case HD6844_SRC_FIXED_ADDR_CH1:
212                         fixed_addr[1] = data;
213                         break;
214                 case HD6844_SRC_FIXED_ADDR_CH2:
215                         fixed_addr[2] = data;
216                         break;
217                 case HD6844_SRC_FIXED_ADDR_CH3:
218                         fixed_addr[3] = data;
219                         break;
220                 case HD6844_TRANSFER_START:
221                         if(transfering[ch]) return;
222                         if((words_reg[ch] == 0) || (words_reg[ch] == 0xffff)) return;
223                         channel_control[ch] = channel_control[ch] & 0x8f;
224                         first_transfer[ch] = true;
225                         if(event_dmac[ch] < 0) register_event(this, HD6844_EVENT_START_TRANSFER + ch,
226                                                               50.0, false, &event_dmac[ch]);
227                         break;
228                 case HD6844_DO_TRANSFER:
229                         if(!transfering[ch]) return;
230                         if(((channel_control[ch] & 0x02) != 0) && (!cycle_steal)) cycle_steal = true;
231                         if(!cycle_steal) {
232                                 this->write_signals(&halt_line, 0xffffffff);
233                         }
234                         if(((words_reg[ch] & 0x0f) == 1) || (first_transfer[ch])){
235                                 first_transfer[ch] = false;
236                                 register_event(this, HD6844_EVENT_DO_TRANSFER + ch,
237                                                            (double)(0x10 / 2), false, NULL); // HD68B44
238                         } else {
239                                 do_transfer(ch);
240                         }
241                         break;
242                 default:
243                         break;
244         }
245 }
246
247 void HD6844::do_transfer(int ch)
248 {
249         if(!transfering[ch]) return;
250         if((priority_reg & 0x01) == 0) {
251                 transfering[ch] = false;
252                 if(!cycle_steal) this->write_signals(&halt_line, 0);
253                 cycle_steal = false;
254                 return;
255         }
256         if(words_reg[ch] == 0) {
257                 transfering[ch] = false;
258                 if(!cycle_steal) this->write_signals(&halt_line, 0);
259                 cycle_steal = false;
260                 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x80;  
261                 return;
262         }
263         //if(((channel_control[ch] & 0x02) != 0) && (!cycle_steal)) cycle_steal = true;
264         
265         if((channel_control[ch] & 0x01) == 0) {
266                 data_reg[ch] = src[ch]->read_io8(fixed_addr[ch]) & 0xff;
267                 dest[ch]->write_dma_io8((uint32)addr_reg[ch] + addr_offset, data_reg[ch]);
268                 //p_emu->out_debug_log(_T("HD6844: FIXED -> SRC: %04x, %02x\n"), addr_reg[ch] + addr_offset, data_reg[ch]);
269         } else {
270                 data_reg[ch] = dest[ch]->read_dma_io8((uint32)addr_reg[ch] + addr_offset) & 0xff;
271                 src[ch]->write_io8(fixed_addr[ch], data_reg[ch]);
272                 //p_emu->out_debug_log(_T("HD6844: SRC -> FIXED: %04x, %02x\n"), addr_reg[ch] + addr_offset, data_reg[ch]);
273         }
274         words_reg[ch]--;
275         if((channel_control[ch] & 0x08) != 0) {
276                 addr_reg[ch]--;
277         } else {
278                 addr_reg[ch]++;
279         }
280         addr_reg[ch] = addr_reg[ch] & 0xffff;
281         if(!cycle_steal) this->write_signals(&halt_line, 0);
282         
283         if(words_reg[ch] == 0) {
284                 if((datachain_reg & 0x07) == 0x01) {
285                         addr_reg[0] = addr_reg[3];
286                         addr_reg[1] = addr_reg[0];
287                         addr_reg[2] = addr_reg[1];
288                         addr_reg[3] = addr_reg[2];
289                         
290                         words_reg[0] = words_reg[3];
291                         words_reg[1] = words_reg[0];
292                         words_reg[2] = words_reg[1];
293                         words_reg[3] = 0;
294                 } else {
295                         transfering[ch] = false;
296                         cycle_steal = false;
297                         channel_control[ch] = (channel_control[ch] & 0x0f) | 0x80;
298                         datachain_reg = datachain_reg | 0x10;
299                         if((interrupt_reg & 0x01) != 0) {
300                                 interrupt_reg |= 0x80;
301                                 write_signals(&interrupt_line, 0xffffffff);
302                         }                                 
303                         //p_emu->out_debug_log(_T("HD6844: Complete transfer ch %d\n"), ch);
304                 }
305         }
306 }       
307
308 void HD6844::event_callback(int event_id, int err)
309 {
310         int ch;
311
312         if((event_id >= HD6844_EVENT_START_TRANSFER) && (event_id < (HD6844_EVENT_START_TRANSFER + 4))) {
313                 ch = event_id - HD6844_EVENT_START_TRANSFER;
314                 event_dmac[ch] = -1;
315                 channel_control[ch] = (channel_control[ch] & 0x0f) | 0x40;
316                 transfering[ch] = true;
317                 //p_emu->out_debug_log(_T("HD6844: Start to transfer ch %d Words = $%04x $%04x $%04x $%04x:\n"), ch, words_reg[0], words_reg[1], words_reg[2], words_reg[3]);
318         } else  if((event_id >= HD6844_EVENT_DO_TRANSFER) && (event_id < (HD6844_EVENT_DO_TRANSFER + 4))) {
319                 ch = event_id - HD6844_EVENT_DO_TRANSFER;
320                 do_transfer(ch);
321         }
322 }