OSDN Git Service

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