OSDN Git Service

[VM][FMTOWNS][CDROM][DMAC] Apply before commit: Use ACK bus arbiytation to transfer.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmtowns / dmac.cpp
1
2 #include "./dmac.h"
3 #include "debugger.h"
4
5 namespace FMTOWNS {
6 void TOWNS_DMAC::initialize()
7 {
8         UPD71071::initialize();
9 }
10
11 void TOWNS_DMAC::reset()
12 {
13         UPD71071::reset();
14         dma_wrap_reg = 0xff;
15         dma_addr_mask = 0xffffffff; // OK?
16 //      dma_addr_mask = 0x000fffff; // OK?
17         for(int i = 0; i < 4; i++) {
18                 creg_set[i] = false;
19                 bcreg_set[i] = false;
20         }
21 //      b16 = 2; // Fixed 16bit.
22 }
23
24 void TOWNS_DMAC::write_io16(uint32_t addr, uint32_t data)
25 {
26         pair32_t _d, _bd;
27         if(b16 != 0) {
28                 switch(addr & 0x0f) {
29                 case 0x02:
30                 case 0x03:
31                         if(base == 0) {
32                                 creg_set[selch] = true;
33                                 dma[selch].creg = data & 0xffff;
34                         }
35                         dma[selch].bcreg = data & 0xffff;
36                         bcreg_set[selch] = true;
37                         return;
38                         break;
39                 case 0x04:
40                 case 0x05:
41                 case 0x06:
42                 case 0x07:
43                         _d.d = dma[selch].areg;
44                         _bd.d = dma[selch].bareg;
45                         if((addr & 0x0f) < 6) {
46                                 if(base == 0) {
47                                         _d.w.l = (data & 0xffff);
48                                         dma[selch].areg = _d.d;
49                                 }
50                                 _bd.w.l = (data & 0xffff);
51                                 dma[selch].bareg = _bd.d;
52                         } else {
53                                 if(base == 0) {
54                                         _d.w.h = (data & 0xffff);
55                                         dma[selch].areg = _d.d;
56                                 }
57                                 _bd.w.h = (data & 0xffff);
58                                 dma[selch].bareg = _bd.d;
59                         }
60                         break;
61                 case 0x08:
62                 case 0x09:
63                         cmd = data & 0xffff;
64                         if(((data & 0x04) != (cmd & 0x04)) && (selch == 3)) {
65                                 if((data & 0x04) == 0) {
66                                         out_debug_log(_T("TRANSFER: CMD=%04X -> %04X CH=%d\nADDR=%08X"), cmd, (cmd & 0xff00) | (data & 0xff), selch, dma[selch].areg);
67                                 }
68                         }
69                         break;
70                 default:
71 //                      write_io8(addr & 0x0e, data);
72                         write_io8(addr, data);
73                         break;
74                 }
75         } else {
76                 write_io8(addr, data);
77 //              write_io8((addr & 0x0e) + 0, data);
78 //              write_io8((addr & 0x0e) + 1, data);
79         }
80 }
81
82 void TOWNS_DMAC::write_io8(uint32_t addr, uint32_t data)
83 {
84 //      if((addr & 0x0f) == 0x0c) out_debug_log("WRITE REG: %08X %08X", addr, data);
85 //      out_debug_log("WRITE REG: %04X %02X", addr, data);
86         uint naddr;
87         pair32_t _d;
88         pair32_t _bd;
89         switch(addr & 0x0f) {
90         case 0x00:
91 //              out_debug_log(_T("RESET REG(00h) to %02X"), data);
92                 break;
93         case 0x02:
94         case 0x03:
95                 // Note: This is *temporaly* workaround for 16bit transfer mode with 8bit bus.
96                 // 20200318 K.O
97                 if(base == 0) {
98                         creg_set[selch] = true;
99                 }
100                 bcreg_set[selch] = true;
101                 break;
102         case 0x07:
103                 _d.d  = dma[selch].areg;
104                 _bd.d = dma[selch].bareg;
105                 _d.b.h3  = data;
106                 _bd.b.h3 = data;
107                 if(base == 0) {
108                         dma[selch].areg = _d.d;
109                 }
110                 dma[selch].bareg = _bd.d;
111                 return;
112                 break;
113         case 0x08:
114                 if(((data & 0x04) != (cmd & 0x04)) && (selch == 3)) {
115                         if((data & 0x04) != 0) break;
116                         out_debug_log(_T("TRANSFER: CMD=%04X -> %04X CH=%d\nADDR=%08X"), cmd, (cmd & 0xff00) | (data & 0xff), selch, dma[selch].areg);
117                 }
118                 break;
119         case 0x0a:
120                 if((selch == 3)) {
121                         out_debug_log(_T("SET MODE[%d] to %02X"), selch, data);
122                 }
123                 break;
124         case 0x0e:
125                 if(((data | req) & 0x08) != 0) {
126                         //      out_debug_log(_T("TRANSFER ENABLE@REG0E DATA=%02X"), data);
127                 }
128                 break;
129         case 0x0f:
130                 // Note: This is *temporaly* workaround for 16bit transfer mode with 8bit bus.
131                 // 20200318 K.O
132 #if !defined(USE_QUEUED_SCSI_TRANSFER)
133                 if((dma[selch].is_16bit) && !(inputs_ube[selch])) {
134                         if(creg_set[selch]) {
135                                 dma[selch].creg <<= 1;
136                                 dma[selch].creg++;
137                                 creg_set[selch] = false;
138                         }
139                         if(bcreg_set[selch]) {
140                                 dma[selch].bcreg <<= 1;
141                                 dma[selch].bcreg++;
142                                 bcreg_set[selch] = false;
143                         }
144                 }
145                 bcreg_set[selch] = false;
146                 creg_set[selch] = false;
147 #endif
148                 break;
149         default:
150                 break;
151         }
152         UPD71071::write_io8(addr, data);
153 }
154
155 uint32_t TOWNS_DMAC::read_io16(uint32_t addr)
156 {
157         if(b16 != 0) {
158                 switch(addr & 0x0f) {
159                 case 0x02:
160                 case 0x03:
161                         if(base == 0) {
162                                 return (dma[selch].creg & 0xffff);
163                         } else {
164                                 return (dma[selch].bcreg & 0xffff);
165                         }
166                         break;
167                 case 0x04:
168                 case 0x05:
169                         if(base == 0) {
170                                 return (dma[selch].areg & 0xffff);
171                         } else {
172                                 return (dma[selch].bareg & 0xffff);
173                         }
174                         break;
175                 case 0x06:
176                 case 0x07:
177                         if(base == 0) {
178                                 return ((dma[selch].areg >> 16) & 0xffff);
179                         } else {
180                                 return ((dma[selch].bareg >> 16) & 0xffff);
181                         }
182                         break;
183                 case 0x08:
184                 case 0x09:
185                         return (uint32_t)(cmd & 0xffff);
186                         break;
187                 default:
188                         return read_io8(addr);
189 //                      return read_io8(addr & 0x0e);
190                         break;
191                 }
192         } else {
193                 pair16_t _d;
194                 _d.w = 0;
195                 _d.b.l = read_io8(addr);
196 //              _d.b.l = read_io8((addr & 0x0e) + 0);
197 //              _d.b.h = read_io8((addr & 0x0e) + 1);
198                 return (uint32_t)(_d.w);
199         }
200 }
201
202 uint32_t TOWNS_DMAC::read_io8(uint32_t addr)
203 {
204         uint32_t val;
205         pair32_t _d;
206         switch(addr & 0x0f) {
207         case 0x01:
208                 return (base << 3) | (1 << (selch & 3));
209                 break;
210         case 0x02:
211         case 0x03:
212                 if(base == 0) {
213                         _d.d = dma[selch].creg;
214 #if !defined(USE_QUEUED_SCSI_TRANSFER)
215                         if((dma[selch].is_16bit) && !(inputs_ube[selch])) {
216                                 if(!(creg_set[selch])) {
217                                         _d.d >>= 1;
218                                 }
219                         }
220 #endif
221                 } else {
222                         _d.d = dma[selch].bcreg;
223 #if !defined(USE_QUEUED_SCSI_TRANSFER)
224                         if((dma[selch].is_16bit) && !(inputs_ube[selch])) {
225                                 if(!(bcreg_set[selch])) {
226                                         _d.d >>= 1;
227                                 }
228                         }
229 #endif
230                 }
231                 switch(addr & 0x0f) {
232                 case 2:
233                         return _d.b.l;
234                         break;
235                 case 3:
236                         return _d.b.h;
237                         break;
238                 }
239                 break;
240         case 0x07:
241                 if(base == 0) {
242                         _d.d = dma[selch].areg;
243                 } else {
244                         _d.d = dma[selch].bareg;
245                 }
246                 return (uint32_t)(_d.b.h3);
247                 break;
248         }
249         return UPD71071::read_io8(addr);
250 }
251         
252 void TOWNS_DMAC::do_dma_inc_dec_ptr_8bit(int c)
253 {
254         // Note: FM-Towns may extend to 32bit.
255         if(dma_wrap_reg != 0) {
256                 uint32_t high_a = dma[c].areg & 0xff000000;
257                 if(dma[c].mode & 0x20) {
258                         dma[c].areg = dma[c].areg - 1;
259                 } else {
260                         dma[c].areg = dma[c].areg + 1;
261                 }
262                 dma[c].areg = ((dma[c].areg & 0x00ffffff) | high_a) & dma_addr_mask;
263         } else {
264                 if(dma[c].mode & 0x20) {
265                         dma[c].areg = (dma[c].areg - 1) & dma_addr_mask;
266                 } else {
267                         dma[c].areg = (dma[c].areg + 1) & dma_addr_mask;
268                 }
269         }
270 }
271
272 void TOWNS_DMAC::do_dma_inc_dec_ptr_16bit(int c)
273 {
274         // Note: FM-Towns may extend to 32bit.
275         if(dma_wrap_reg != 0) {
276                 uint32_t high_a = dma[c].areg & 0xff000000;
277                 if(dma[c].mode & 0x20) {
278                         dma[c].areg = dma[c].areg - 2;
279                 } else {
280                         dma[c].areg = dma[c].areg + 2;
281                 }
282                 dma[c].areg = ((dma[c].areg & 0x00ffffff) | high_a) & dma_addr_mask;
283         } else {
284                 if(dma[c].mode & 0x20) {
285                         dma[c].areg = (dma[c].areg - 2) & dma_addr_mask;
286                 } else {
287                         dma[c].areg = (dma[c].areg + 2) & dma_addr_mask;
288                 }
289         }
290 }
291
292 bool TOWNS_DMAC::do_dma_epilogue(int c)
293 {
294         if(dma[c].creg == 0) {  // OK?
295                 // TC
296                 if(c == 3) {
297                         out_debug_log(_T("TRANSFER COMPLETED CH.3: AREG=%08X BAREG=%08X CREG=%08X BCREG=%08X"),
298                                                   (dma[c].areg & 0xffffffff) ,
299                                                   (dma[c].bareg & 0xffffffff) ,
300                                                   dma[c].creg & 0x00ffffff,
301                                                   dma[c].bcreg & 0x00ffffff
302                                 );
303                                                   
304                 }
305         }
306         return UPD71071::do_dma_epilogue(c);
307 }
308         
309 uint32_t TOWNS_DMAC::read_signal(int id)
310 {
311         if(SIG_TOWNS_DMAC_WRAP_REG) {
312                 return dma_wrap_reg;
313         } else if(id == SIG_TOWNS_DMAC_ADDR_MASK) {
314                 return dma_addr_mask;
315         }
316         return UPD71071::read_signal(id);
317 }
318
319 void TOWNS_DMAC::write_signal(int id, uint32_t data, uint32_t _mask)
320 {
321         if(id == SIG_TOWNS_DMAC_WRAP_REG) {
322                 dma_wrap_reg = data;
323 //              this->write_signal(SIG_TOWNS_DMAC_ADDR_MASK, data, mask);
324         } else if(id == SIG_TOWNS_DMAC_ADDR_MASK) {
325                 // From eFMR50 / memory.cpp / update_dma_addr_mask()
326                 dma_addr_mask = data;
327         } else {
328                 // Fallthrough.
329 //              if(id == SIG_UPD71071_CH1) {
330 //                      out_debug_log(_T("DRQ from SCSI %02X %02X"), data, mask);
331 //              }
332                 UPD71071::write_signal(id, data, _mask);
333         }
334 }               
335
336 void TOWNS_DMAC::do_dma_dev_to_mem_8bit(int c)
337 {
338         // io -> memory
339         uint32_t val;
340         uint32_t addr = dma[c].areg;
341         reset_ube(c);
342         val = dma[c].dev->read_dma_io8(0);
343         
344         // update temporary register
345         tmp = (tmp >> 8) | (val << 8);
346         
347         if(_USE_DEBUGGER) {
348                 if(d_debugger != NULL && d_debugger->now_device_debugging) {
349                         d_debugger->write_via_debugger_data8(addr, val);
350                 } else {
351                         write_via_debugger_data8(addr, val);
352                 }
353         } else {
354                 write_via_debugger_data8(addr, val);
355         }                                                       
356 }
357
358 void TOWNS_DMAC::do_dma_mem_to_dev_8bit(int c)
359 {
360         // memory -> io
361         uint32_t val;
362         uint32_t addr = dma[c].areg;
363         reset_ube(c);
364         if(_USE_DEBUGGER) {
365                 if(d_debugger != NULL && d_debugger->now_device_debugging) {
366                         val = d_debugger->read_via_debugger_data8(addr);
367                 } else {
368                         val = read_via_debugger_data8(addr);
369                 }
370         } else {
371                 val = read_via_debugger_data8(addr);
372         }
373         // update temporary register
374         tmp = (tmp >> 8) | (val << 8);
375         
376         dma[c].dev->write_dma_io8(0, val);
377 }
378
379 void TOWNS_DMAC::do_dma_dev_to_mem_16bit(int c)
380 {
381         // io -> memory
382         uint32_t val;
383         uint32_t addr = dma[c].areg;
384         set_ube(c);
385         val = dma[c].dev->read_dma_io16(0);
386         // update temporary register
387         tmp = val;
388 /*      
389         if((addr & 1) != 0) {
390                 // If odd address, write a byte.
391                 uint32_t tval = (val >> 8) & 0xff;
392                 if(_USE_DEBUGGER) {
393                         if(d_debugger != NULL && d_debugger->now_device_debugging) {
394                                 d_debugger->write_via_debugger_data8(addr, tval);
395                         } else {
396                                 write_via_debugger_data8(addr, tval);
397                         }
398                 } else {
399                         write_via_debugger_data8(addr, tval);
400                 }
401         } else {
402 */
403                 // 16bit
404                 if(_USE_DEBUGGER) {
405                         if(d_debugger != NULL && d_debugger->now_device_debugging) {
406                                 d_debugger->write_via_debugger_data16(addr, val);
407                         } else {
408                                 write_via_debugger_data16(addr, val);
409                         }
410                 } else {
411                         write_via_debugger_data16(addr, val);
412                 }
413 //      }
414 }
415
416 void TOWNS_DMAC::do_dma_mem_to_dev_16bit(int c)
417 {
418         // memory -> io
419         uint32_t val;
420         uint32_t addr = dma[c].areg;
421         set_ube(c);
422         if(_USE_DEBUGGER) {
423                 if(d_debugger != NULL && d_debugger->now_device_debugging) {
424                         val = d_debugger->read_via_debugger_data16(addr);
425                 } else {
426                         val = this->read_via_debugger_data16(addr);
427                 }
428         } else {
429                 val = this->read_via_debugger_data16(addr);
430         }
431 //      if((addr & 1) != 0) {
432 //              // If odd address, read a high byte.
433 //              val = (val >> 8) & 0xff;
434 //      }
435         // update temporary register
436         tmp = val;
437         
438         dma[c].dev->write_dma_io16(0, val);
439 }
440
441         
442 // note: if SINGLE_MODE_DMA is defined, do_dma() is called in every machine cycle
443 bool TOWNS_DMAC::get_debug_regs_info(_TCHAR *buffer, size_t buffer_len)
444 {       
445         static const _TCHAR *dir[4] = {
446                 _T("VERIFY"), _T("I/O->MEM"), _T("MEM->I/O"), _T("INVALID")
447         };
448         if(buffer == NULL) return false;
449         _TCHAR sbuf[4][512] = {0};
450         for(int i = 0; i < 4; i++) {
451                 my_stprintf_s(sbuf[i], 512,
452                   _T("CH%d AREG=%08X CREG=%04X BAREG=%08X BCREG=%04X REQ=%d MASK=%d MODE=%02X %s\n"),
453                                           i,
454                                           dma[i].areg,
455                                           dma[i].creg,
456                                           dma[i].bareg,
457                                           dma[i].bcreg,
458                                           ((req | sreq) >> 0) & 1,
459                                           (mask >> 0) & 1,
460                                           dma[i].mode,
461                                           dir[(dma[i].mode >> 2) & 3]
462                         );
463         }
464         {
465                 my_stprintf_s(buffer, buffer_len,
466                                           _T("16Bit=%s ADDR_MASK=%08X ADDR_WRAP=%02X \n")
467                                           _T("SELECT CH=%d BASE=%02X REQ=%02X SREQ=%02X MASK=%02X TC=%02X ")
468                                           _T("CMD=%04X TMP=%04X\n")
469                                           _T("%s")
470                                           _T("%s")
471                                           _T("%s")
472                                           _T("%s"),
473                                           (b16 != 0) ? _T("YES") : _T("NO"), dma_addr_mask, dma_wrap_reg,
474                                           selch, base, req, sreq, mask, tc,
475                                           cmd, tmp,
476                                           sbuf[0],
477                                           sbuf[1],
478                                           sbuf[2],
479                                           sbuf[3]);
480                 return true;
481         }
482         return false;
483 }
484         
485 #define STATE_VERSION   3
486         
487 bool TOWNS_DMAC::process_state(FILEIO *state_fio, bool loading)
488 {
489         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
490                 return false;
491         }
492         if(!state_fio->StateCheckInt32(this_device_id)) {
493                 return false;
494         }
495         if(!(UPD71071::process_state(state_fio, loading))) {
496                 return false;
497         }
498         state_fio->StateValue(dma_wrap_reg);
499         state_fio->StateValue(dma_addr_mask);
500         state_fio->StateArray(creg_set, sizeof(creg_set), 1);
501         state_fio->StateArray(bcreg_set, sizeof(bcreg_set), 1);
502
503         return true;
504 }
505 }