OSDN Git Service

[VM][FMTOWNS][DMAC][WIP] Fix around address and counter registers.
[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 #define EVENT_DMAC_CYCLE        1
7
8 void TOWNS_DMAC::initialize()
9 {
10         UPD71071::initialize();
11         for(int ch = 0; ch < 4; ch++) {
12                 is_started[ch] = false;
13                 address_aligns_16bit[ch] = true;
14                 is_16bit_transfer[ch] = false;
15                 is_16bit[ch] = false;
16         }
17         event_dmac_cycle = -1;
18 }
19
20 void TOWNS_DMAC::reset()
21 {
22         UPD71071::reset();
23         dma_wrap = true;
24         div_count = 0;
25         for(int ch = 0; ch < 4; ch++) {
26                 end_req[ch] = false;
27                 is_started[ch] = false;
28                 calc_transfer_status(ch);
29         }
30         clear_event(this, event_dmac_cycle);
31
32         for(int ch = 0; ch < 4; ch++) {
33                 //write_signals(&outputs_towns_tc[ch], ((tc & (1 << ch)) != 0) ? 0xffffffff : 0);
34                 write_signals(&outputs_ube[ch], (is_16bit[ch]) ? 0xffffffff : 0);
35         }
36 }
37
38
39 void TOWNS_DMAC::call_dma(int ch)
40 {
41         bool is_use_debugger = false;
42         __LIKELY_IF(__USE_DEBUGGER) {
43                 __LIKELY_IF(d_debugger != NULL) {
44                         is_use_debugger = d_debugger->now_device_debugging;
45                 }
46         }
47         do_dma_per_channel(ch, is_use_debugger, false);
48 }
49
50
51 void TOWNS_DMAC::write_io16(uint32_t addr, uint32_t data)
52 {
53         __UNLIKELY_IF(b16 == 0) {
54                 write_io8(addr, data);
55                 return;
56         }
57         switch(addr & 0x0e) {
58         case 0x02:
59                 dma[selch].bcreg = data;
60                 if(base == 0x00) {
61                         dma[selch].creg = data;
62                 }
63                 // Reset TC bit for towns, by Tsugaru commit ab067790479064efce693f7317af13696cb68d96 .         tc &= ~(1 << selch);
64                 write_signals(&outputs_towns_tc[selch], 0);
65                 break;
66         case 0x04: // ADDR LOW
67                 dma[selch].bareg = (dma[selch].bareg & 0xffff0000) | (data & 0xffff);
68                 if(base == 0x00) {
69                         dma[selch].areg = dma[selch].bareg; // OK? This is from Tsugaru. 20230710 K.O
70                 }
71                 break;
72         case 0x06: // ADDR HIGH
73                 dma[selch].bareg = (dma[selch].bareg & 0x0000ffff) | ((data & 0xffff) << 16);
74                 if(base == 0x00) {
75                         dma[selch].areg = dma[selch].bareg; // OK? This is from Tsugaru. 20230710 K.O
76                 }
77                 break;
78         case 0x08: // Control
79                 cmd = data;
80                 if(/*(cmd != cmd_bak) && */((cmd & 0x04) == 0)) {
81                         check_start_condition();
82                 } else {
83                         check_running();
84                 }
85                 break;
86         default:
87                 write_io8((addr & 0x0e) + 0, data & 0x00ff);
88                 write_io8((addr & 0x0e) + 1, (data & 0xff00) >> 8); // OK?
89                 break;
90         }
91 }
92
93 void TOWNS_DMAC::write_io8(uint32_t addr, uint32_t data)
94 {
95 //      if((addr & 0x0f) == 0x0c) out_debug_log("WRITE REG: %08X %08X", addr, data);
96 //      out_debug_log("WRITE REG: %04X %02X", addr, data);
97         data &= 0xff;
98         uint8_t cmd_bak = cmd;
99         bool need_transfer = false;
100         switch(addr & 0x0f) {
101         case 0x00:
102                 UPD71071::write_io8(0, data);
103                 if(data & 1) {
104                         clear_event(this, event_dmac_cycle);
105                 }
106                 for(int ch = 0; ch < 4; ch++) {
107                         if(data & 1) {
108                                 end_req[ch] = false;
109                                 is_started[ch] = false;
110                         }
111                         calc_transfer_status(ch);
112                 }
113                 check_running();
114                 for(int ch = 0; ch < 4; ch++) {
115                         write_signals(&outputs_ube[ch], (is_16bit[ch]) ? 0xffffffff : 0);
116                 }
117                 out_debug_log(_T("RESET from I/O; B16=%s"), ((b16 & 2) != 0) ? _T("16bit") : _T("8bit"));
118                 break;
119         case 0x02:
120                 // Reset TC bit for towns, by Tsugaru commit ab067790479064efce693f7317af13696cb68d96 .         tc &= ~(1 << selch);
121                 write_signals(&outputs_towns_tc[selch], 0);
122                 //UPD71071::write_io8(addr, data);
123                 dma[selch].bcreg = (dma[selch].bcreg & 0xff00) | data;
124                 if(base == 0x00) {
125                         dma[selch].creg = dma[selch].bcreg; // OK?
126                 }
127                 break;
128         case 0x03:
129                 write_signals(&outputs_towns_tc[selch], 0);
130                 //UPD71071::write_io8(addr, data);
131                 dma[selch].bcreg = (dma[selch].bcreg & 0x00ff) | (data << 8);
132                 if(base == 0x00) {
133                         dma[selch].creg = dma[selch].bcreg; // OK?
134                 }
135                 break;
136         case 0x04:
137                 dma[selch].bareg = (dma[selch].bareg & 0xffffff00) | data;
138                 if(base == 0x00) {
139                         dma[selch].areg = dma[selch].bareg;
140                 }
141                 #if 0
142                 if(is_started[selch]) {
143                         if(check_address_16bit_bus_changed(selch)) {
144                                 set_ube_line(selch);
145                         }
146                 }
147                 #endif
148                 break;
149         case 0x05:
150                 dma[selch].bareg = (dma[selch].bareg & 0xffff00ff) | (data << 8);
151                 if(base == 0x00) {
152                         dma[selch].areg = dma[selch].bareg;
153                 }
154                 break;
155         case 0x06:
156                 dma[selch].bareg = (dma[selch].bareg & 0xff00ffff) | (data << 16);
157                 if(base == 0x00) {
158                         dma[selch].areg = dma[selch].bareg;
159                 }
160                 break;
161         case 0x07:
162                 dma[selch].bareg = (dma[selch].bareg & 0x00ffffff) | (data << 24);
163                 if(base == 0x00) {
164                         dma[selch].areg = dma[selch].bareg;
165                 }
166                 break;
167                 // CMD
168         case 0x08:
169         case 0x09:
170                 UPD71071::write_io8(addr, data);
171         #if 1
172                 if(/*(cmd != cmd_bak) && */((cmd & 0x04) == 0)) {
173                         check_start_condition();
174                 } else {
175                         check_running();
176                 }
177                 #if 0
178                 if(cmd != cmd_bak) {
179                         out_debug_log(_T("CMD CHANGED from %04X to 0x%04X : MAYBE START to TRANSFER"),
180                                                   cmd_bak, cmd);
181                         static const _TCHAR *dir[4] = {
182                                 _T("VERIFY"), _T("I/O->MEM"), _T("MEM->I/O"), _T("INVALID")
183                         };
184                         for(int ch = 0; ch < 4; ch++) {
185
186                                 out_debug_log(_T("CH%d AREG=%08X CREG=%04X BAREG=%08X BCREG=%04X REQ=%d MASK=%d MODE=%02X %s"),
187                                                           ch, dma[ch].areg, dma[ch].creg, dma[ch].bareg, dma[ch].bcreg,
188                                                           ((req | sreq) >> ch) & 1,
189                                                           (mask >> ch) & 1,
190                                                           dma[ch].mode,
191                                                           dir[(dma[ch].mode >> 2) & 3]);
192                         }
193                 }
194                 #endif
195         #endif
196                 break;
197                 // MODE
198         case 0x0a:
199                 // BIT 7,6 : TRANSFER MODE
200                 //   DEMAND    = 00
201                 //   SINGLE    = 01
202                 //   BLOCK     = 10
203                 //   CASCADE   = 11
204                 // BIT 5    : ADIR
205                 //   INC       = 0
206                 //   DEC       = 1
207                 // BIT 4    : AUTI
208                 //   AUTO INIT = 1
209                 // BIT 3, 2 : TDIR
210                 //   VERIFY    = 00
211                 //   IO to MEM = 01
212                 //   MEM to IO = 10
213                 //   DONT      = 11
214                 // BIT 0    : W/B
215                 //   BYTE = 0
216                 //   WORD = 1
217                 UPD71071::write_io8(addr, data);
218
219                 #if 1
220                 /* DO NOTHING */
221                 #endif
222                 #if 0
223                 out_debug_log(_T("MODE CHANGED at CH.%d to 0x%02X Request 16bit=%s CMD=%02X"), selch, dma[selch].mode,
224                                           (is_16bit_transfer[selch]) ? _T("Yes") : _T("NO"),
225                                           cmd);
226                 static const _TCHAR *dir[4] = {
227                         _T("VERIFY"), _T("I/O->MEM"), _T("MEM->I/O"), _T("INVALID")
228                 };
229                 out_debug_log(_T("CH%d AREG=%08X CREG=%04X BAREG=%08X BCREG=%04X REQ=%d MASK=%d MODE=%02X %s"),
230                                           selch, dma[selch].areg, dma[selch].creg, dma[selch].bareg, dma[selch].bcreg,
231                                           ((req | sreq) >> selch) & 1,
232                                           (mask >> selch) & 1,
233                                           dma[selch].mode,
234                                           dir[(dma[selch].mode >> 2) & 3]);
235                 #endif
236                 break;
237                 // MASK
238         case 0x0e:
239                 {
240                         const uint8_t sreq_b = sreq;
241                         if(((sreq = data) & 0x0f) != 0) {
242                                 if(((sreq_b ^ sreq) & 0x0f) != 0) {
243                                         // SREQ CHANGED.
244                                         check_start_condition();
245                                 }
246                         }
247                 }
248                 break;
249                 // MASK
250         case 0x0f:
251                 #if 1
252                 {
253                         const uint8_t _mask_b = mask;
254                         const uint8_t bit = 1 << selch;
255                         UPD71071::write_io8(addr, data);
256
257                         // Check when mask[selch] has changed,
258                         if(((mask ^ _mask_b) & bit) != 0) {
259                                 check_start_condition();
260                                 check_running();
261                         }
262                 }
263                 #endif
264                 // Add trigger of transfer by SREQ.
265                 //need_transfer = (!(_SINGLE_MODE_DMA) && ((cmd & 0x04) == 0));
266                 break;
267         default:
268                 UPD71071::write_io8(addr, data);
269                 break;
270         }
271 //      if((need_transfer) && ((cmd & 4) == 0)) {
272 //              do_dma();
273 //      }
274 }
275
276 uint32_t TOWNS_DMAC::read_io8(uint32_t addr)
277 {
278         uint32_t val = 0xff;
279         switch(addr & 0x0f) {
280         case 0x07:
281                 if(base) {
282                         val = (dma[selch].bareg >> 24) & 0xff;
283                 } else {
284                         val = (dma[selch].areg >> 24) & 0xff;
285                 }
286                 break;
287         case 0x0b:
288                 val = UPD71071::read_io8(addr);
289                 // Q: Is reset TC* ? 20230429 K.O
290                 //for(int ch = 0; ch < 4; ch++) {
291                 //      write_signals(&outputs_towns_tc[ch], 0);
292                 //}
293                 break;
294         default:
295                 val = UPD71071::read_io8(addr);
296                 break;
297         }
298         return val;
299 }
300
301 uint32_t TOWNS_DMAC::read_io16(uint32_t addr)
302 {
303         __UNLIKELY_IF(b16 == 0) {
304                 return read_io8(addr);
305         }
306         switch(addr & 0x0e) {
307         case 0x02:
308                 if(base != 0) {
309                         return dma[selch].bcreg;
310                 } else {
311                         return dma[selch].creg;
312                 }
313                 break;
314         case 0x04:
315                 if(base != 0) {
316                         return dma[selch].bareg & 0x0000ffff;
317                 } else {
318                         return dma[selch].areg  & 0x0000ffff;
319                 }
320                 break;
321         case 0x06:
322                 if(base != 0) {
323                         return (dma[selch].bareg & 0xffff0000) >> 16;
324                 } else {
325                         return (dma[selch].areg  & 0xffff0000) >> 16;
326                 }
327                 break;
328         case 0x08:
329                 return cmd;
330                 break;
331         default:
332                 break;
333         }
334         uint32_t val = 0;
335         val = read_io8((addr & 0x0e) + 0) & 0x00ff;
336         val = val | ((read_io8((addr & 0x0e) + 1) & 0xff) << 8); // OK?
337         return val;
338 }
339
340 void TOWNS_DMAC::inc_dec_ptr_a_byte(uint32_t& addr, const bool inc)
341 {
342         // Note: FM-Towns may extend to 32bit.
343         // Note: By Tsugaru, commit e5920fdc1ba89ba10172f0954ecf1107bb592919,
344         // ADIR bit (bit 5 of mode register)
345         // has not supported by TOWNS DMAC.
346         // Very tanks to YAMAKAWA-San. - 20230617 K.O
347         //
348         // Commiting message is below:
349         //      Author:     CaptainYS <PEB01130@nifty.com>
350         //      AuthorDate: Sat Feb 29 23:43:52 2020 -0500
351         //      Commit:     CaptainYS <PEB01130@nifty.com>
352         //      CommitDate: Sat Feb 29 23:43:52 2020 -0500
353         //
354         //      Parent:     9390f5be
355         //                                      Found Device-DMACh correspondence in [2] pp. 56.
356         //                                      Still trying to find the correct sequence of CD-ROM drive
357         //                                      data transfer.
358         //                                      Unit test still temporarily broken.
359
360 //      uint32_t incdec = (inc) ? 1 : UINT32_MAX;
361         const uint32_t incdec = 1;
362         __LIKELY_IF(dma_wrap) {
363                 uint32_t high_a = addr & 0xff000000;
364                 addr = (addr + incdec) & 0x00ffffff;
365                 addr = addr | high_a;
366         } else {
367                 addr = (addr + incdec) & 0xffffffff;
368         }
369 }
370
371 void TOWNS_DMAC::inc_dec_ptr_two_bytes(uint32_t& addr, const bool inc)
372 {
373         // Note: FM-Towns may extend to 32bit.
374
375         //uint32_t incdec = (inc) ? 2 : (UINT32_MAX - 1);
376         const uint32_t incdec = 2;
377         __LIKELY_IF(dma_wrap) {
378                 uint32_t high_a = addr & 0xff000000;
379                 addr = (addr + incdec) & 0x00ffffff;
380                 addr = addr | high_a;
381         } else {
382                 addr = (addr + incdec) & 0xffffffff;
383         }
384 }
385
386 uint32_t TOWNS_DMAC::read_8bit_from_device(DEVICE* dev, uint32_t addr, int* wait)
387 {
388         __UNLIKELY_IF(dev == nullptr) {
389                 if(wait != nullptr) {
390                         *wait = 0; // ToDo
391                 }
392                 return 0xff;
393         }
394         uint32_t val;
395         val = dev->read_dma_io8w(addr, wait);
396         return val;
397 }
398
399 void TOWNS_DMAC::write_8bit_to_device(DEVICE* dev, uint32_t addr, uint32_t data, int* wait)
400 {
401         __UNLIKELY_IF(dev == nullptr) {
402                 if(wait != nullptr) {
403                         *wait = 0; // ToDo
404                 }
405                 return;
406         }
407         dev->write_dma_io8w(addr, data, wait);
408 }
409
410 uint32_t TOWNS_DMAC::read_8bit_from_memory(uint32_t addr, int* wait, const bool is_use_debugger)
411 {
412         __UNLIKELY_IF((is_use_debugger) && (d_debugger != NULL)) {
413                 return d_debugger->read_via_debugger_data8w(addr, wait);
414         } else {
415                 return read_via_debugger_data8w(addr, wait);
416         }
417 }
418
419 void TOWNS_DMAC::write_8bit_to_memory(uint32_t addr, uint32_t data, int* wait, const bool is_use_debugger)
420 {
421         __UNLIKELY_IF((is_use_debugger) && (d_debugger != NULL)) {
422                 d_debugger->write_via_debugger_data8w(addr, data, wait);
423         } else {
424                 write_via_debugger_data8w(addr, data, wait);
425         }
426 }
427
428 uint32_t TOWNS_DMAC::read_16bit_from_device(DEVICE* dev, uint32_t addr, int* wait)
429 {
430         __UNLIKELY_IF(dev == nullptr) {
431                 if(wait != nullptr) {
432                         *wait = 0; // ToDo
433                 }
434                 return 0xffff;
435         }
436         uint32_t val;
437         val = dev->read_dma_io16w(addr, wait);
438         return val;
439 }
440
441 void TOWNS_DMAC::write_16bit_to_device(DEVICE* dev, uint32_t addr, uint32_t data, int* wait)
442 {
443         __UNLIKELY_IF(dev == nullptr) {
444                 if(wait != nullptr) {
445                         *wait = 0; // ToDo
446                 }
447                 return;
448         }
449         dev->write_dma_io16w(addr, data, wait);
450 }
451
452 uint32_t TOWNS_DMAC::read_16bit_from_memory(uint32_t addr, int* wait, const bool is_use_debugger)
453 {
454         __UNLIKELY_IF((is_use_debugger) && (d_debugger != NULL)) {
455                 return d_debugger->read_via_debugger_data16w(addr, wait);
456         } else {
457                 return read_via_debugger_data16w(addr, wait);
458         }
459 }
460
461 void TOWNS_DMAC::write_16bit_to_memory(uint32_t addr, uint32_t data, int* wait, const bool is_use_debugger)
462 {
463         __UNLIKELY_IF((is_use_debugger) && (d_debugger != NULL)) {
464                 d_debugger->write_via_debugger_data16w(addr, data, wait);
465         } else {
466                 write_via_debugger_data16w(addr, data, wait);
467         }
468 }
469
470 void TOWNS_DMAC::check_start_condition()
471 {
472         for(int ch = 0; ch < 4; ch++) {
473                 uint8_t bit = 1 << ch;
474                 if(((mask & bit) == 0) && (((req | sreq) & bit) != 0)) {
475                         if(!(is_started[ch])) {
476                                 is_started[ch] = true;
477                                 calc_transfer_status(selch);
478                                 write_signals(&outputs_ube[selch], (is_16bit[selch]) ? 0xffffffff : 0x00000000);
479                                 end_req[selch] = false;
480                                 __UNLIKELY_IF((event_dmac_cycle < 0) && !(_SINGLE_MODE_DMA)) {
481                                         register_event(this, EVENT_DMAC_CYCLE, dmac_cycle_us, true, &event_dmac_cycle);
482                                 }
483                         }
484                 } else {
485                         if(is_started[ch]) {
486                                 is_started[ch] = false;
487                                 check_running();
488                         }
489                 }
490         }
491 }
492
493 void TOWNS_DMAC::do_dma_16bit(DEVICE* dev, const uint8_t tr_mode, uint32_t& memory_address, const bool compressed, const bool extended, bool is_use_debugger, int& wait)
494 {
495         uint16_t val;
496         int wait_w = 0;
497         int wait_r = 0;
498         const int wait_compressed = (compressed) ? 5 : 7;
499         switch(tr_mode & 0x0c) {
500         case 0x00: // VERIFY
501                 val = read_16bit_from_device(dev, 0, &wait_r);
502                 tmp = val;
503                 read_16bit_from_memory(memory_address, &wait_w, is_use_debugger);
504                 break;
505         case 0x04: // DEVICE TO MEMORY
506                 val = read_16bit_from_device(dev, 0, &wait_r);
507                 tmp = val;
508                 write_16bit_to_memory(memory_address, val, &wait_w, is_use_debugger);
509                 break;
510         case 0x08: // MEMORY TO DEVICE
511                 val = read_16bit_from_memory(memory_address, &wait_r, is_use_debugger);
512                 tmp = val;
513                 write_16bit_to_device(dev, 0, val, &wait_w);
514                 break;
515         case 0x0c: // MEMORY TO MEMORY : still unimplemented
516                 break;
517         default:
518                 break;
519         }
520         wait += wait_compressed;
521         if(extended) {
522                 wait = wait + wait_r + wait_w;
523         }
524 //                              inc_dec_ptr_two_bytes(memory_adderss, !(tr_mode & 0x20));
525         inc_dec_ptr_two_bytes(memory_address, true);
526 }
527
528 void TOWNS_DMAC::do_dma_8bit(DEVICE* dev, const uint8_t tr_mode, uint32_t& memory_address, const bool compressed, const bool extended, bool is_use_debugger, int& wait)
529 {
530         uint32_t val;
531         int wait_w = 0;
532         int wait_r = 0;
533         const int wait_compressed = (compressed) ? 5 : 7;
534         switch(tr_mode & 0x0c) {
535         case 0x00: // VERIFY
536                 val = read_8bit_from_device(dev, 0, &wait_r);
537                 tmp = ((tmp & 0xff00) >> 8) | ((val & 0xff) << 8);
538                 read_8bit_from_memory(memory_address, &wait_w, is_use_debugger);
539                 break;
540         case 0x04: // DEVICE TO MEMORY
541                 val = read_8bit_from_device(dev, 0, &wait_r);
542                 tmp = ((tmp & 0xff00) >> 8) | ((val & 0xff) << 8);
543                 write_8bit_to_memory(memory_address, val, &wait_w, is_use_debugger);
544                 break;
545         case 0x08: // MEMORY TO DEVICE
546                 val = read_8bit_from_memory(memory_address, &wait_r, is_use_debugger);
547                 tmp = ((tmp & 0xff00) >> 8) | ((val & 0xff) << 8);
548                 write_8bit_to_device(dev, 0, val, &wait_w);
549                 break;
550         case 0x0c: // MEMORY TO MEMORY : still unimplemented
551                 break;
552         default:
553                 break;
554         }
555         wait += wait_compressed;
556         if(extended) {
557                 wait = wait + wait_r + wait_w;
558         }
559 //                              inc_dec_ptr_a_byte(memory_address, !(tr_mode & 0x20));
560         inc_dec_ptr_a_byte(memory_address, true);
561 }
562
563 bool TOWNS_DMAC::do_dma_per_channel(int ch, bool is_use_debugger, bool force_exit)
564 {
565         int c = ch & 3;
566         uint8_t bit = 1 << c;
567
568         if(/*((req | sreq) & bit) && !(mask & bit) && */(is_started[c])) {
569                 // execute dma
570                 // This is workaround for FM-Towns's SCSI.
571
572                 bool __is_16bit = (is_16bit_transfer[c] || force_16bit_transfer[c]);
573                 if(__is_16bit != is_16bit[c]) {
574                         is_16bit[c] = __is_16bit;
575                         write_signals(&outputs_ube[c], (__is_16bit) ? 0xffffffff : 0x00000000); // Reset UBE
576                 }
577
578                 int wait = 0;
579                 bool compressed = ((cmd & 0x08) != 0);
580                 bool extended = ((cmd & 0x20) != 0);
581                 //while(((req | sreq) & bit) && (dma[c].creg <= dma[c].bcreg)) {
582                 if(((req | sreq) & bit) && (dma[c].creg <= dma[c].bcreg)) {
583                         set_ack(c, false);
584
585                         __UNLIKELY_IF(!running) {
586                                 wait += 2; // S0
587                                 running = true;
588                         }
589
590                         if(__is_16bit) {
591                                 // ToDo: Will check WORD transfer mode for FM-Towns.(mode.bit0 = '1).
592                                 // 16bit transfer mode
593                                 do_dma_16bit(dma[c].dev, dma[c].mode, dma[c].areg, compressed, extended, is_use_debugger, wait);
594                         } else {
595                                 // 8bit transfer mode
596                                 do_dma_8bit(dma[c].dev, dma[c].mode, dma[c].areg, compressed, extended, is_use_debugger, wait);
597                         }
598                         __UNLIKELY_IF(d_cpu != NULL) {
599                                 d_cpu->set_extra_clock(wait);
600                                 wait = 0;
601                         }
602                         // Note: At FM-Towns, SCSI's DMAC will be set after
603                         //       SCSI bus phase become DATA IN/DATA OUT.
604                         //       Before bus phase became DATA IN/DATA OUT,
605                         //       DMAC mode and state was unstable (and ASSERTED
606                         //       DRQ came from SCSI before this state change).
607                         // ToDo: Stop correctly before setting.
608                         // CHECK COUNT DOWN REACHED.
609                         bool is_tc = false;
610                         set_ack(c, true);
611                         dma[c].creg--; // OK?
612                         __UNLIKELY_IF(dma[c].creg > dma[c].bcreg) {
613                                 is_tc = true;
614                         }
615                         uint8_t _mode = dma[c].mode & 0xc0;
616
617                         __UNLIKELY_IF((end_req[c]) && (_mode != 0x40)){ // END_REQ ASSERTED EXCEPTS SINGLE TRANSFER.
618                                 do_end_sequence(c, false);
619                                 __LIKELY_IF(_SINGLE_MODE_DMA) {
620                                         //      running = false;
621                                         return true;
622                                 }
623                         } else __UNLIKELY_IF(is_tc) {
624                                 // TC
625                                 do_end_sequence(c, true);
626                                 __LIKELY_IF((_SINGLE_MODE_DMA) || (_mode == 0x40)) {
627                                         //      running = false;
628                                         return true;
629                                 }
630                                 return false;
631                         } else {
632                                 // IF NOT COUNTDOWN REACHED.
633                                 switch(_mode) {
634                                 case 0x00: // DEMAND
635                                         // WHY STOP:
636                                         // - COUNTDOWN REACHED.
637                                         // - END_REQ[c] asserted.
638                                         // - DMA REQ MADE INACTIVE.
639                                         // -> CLEAR REQ and SREQ bit, ASSERT TC REGISTER.
640                                         __UNLIKELY_IF((req & bit) == 0) {
641                                                 do_end_sequence(c, false);
642                                                 __UNLIKELY_IF(_SINGLE_MODE_DMA) {
643                                                         return false;
644                                                 }
645                                         }
646                                         break;
647                                 case 0x40: // SINGLE
648                                         // WHY STOP:
649                                         // - COUNTDOWN REACHED.
650                                         // - STOP PER BYTE/WORD TRANSFER.
651                                         //   SOMETHING DON'T ASSERT TC, EXCEPTS COUNT DOWN REACHED TO 0.
652                                         // -> CLEAR REQ and SREQ bit.
653                                         req &= ~bit;
654                                         sreq &= ~bit;
655                                         running = false;
656                                         break;
657                                 case 0x80: // BURST
658                                         // WHY STOP:
659                                         // - END_REQ[c] asserted.
660                                         // - COUNTDOWN REACHED.
661                                         // -> DO NOTHING.
662                                         break;
663                                 case 0xC0: // CASCADE
664                                 default:
665                                         break;
666                                 }
667                                 __LIKELY_IF(_SINGLE_MODE_DMA) {
668                                         return true;
669                                 }
670                         }
671                         __UNLIKELY_IF(force_exit) {
672                                 return false;;
673                         }
674                 }
675         }
676         return false;
677 }
678
679 void TOWNS_DMAC::do_dma_internal()
680 {
681         __LIKELY_IF((event_dmac_cycle < 0) || (_SINGLE_MODE_DMA)) {
682                 if(div_count < 2) {
683                         div_count++;
684                         return;
685                 }
686         }
687         div_count = 0;
688
689         // run dma
690         bool is_use_debugger = false;
691         if(__USE_DEBUGGER) {
692                 __LIKELY_IF(d_debugger != NULL) {
693                         is_use_debugger = d_debugger->now_device_debugging;
694                 }
695         }
696         for(int c = 0; c < 4; c++) {
697                 if(do_dma_per_channel(c, is_use_debugger, false)) {
698                         break;
699                 }
700         }
701 }
702
703 void TOWNS_DMAC::do_dma()
704 {
705         // check DDMA
706         do_dma_internal();
707         __UNLIKELY_IF(_SINGLE_MODE_DMA) {
708                 __LIKELY_IF(d_dma) {
709                         d_dma->do_dma();
710                 }
711         }
712 }
713
714 void TOWNS_DMAC::event_callback(int event_id, int err)
715 {
716         __LIKELY_IF(event_id == EVENT_DMAC_CYCLE) {
717                 do_dma_internal();
718         }
719 }
720 uint32_t TOWNS_DMAC::read_signal(int id)
721 {
722         if(id == SIG_TOWNS_DMAC_WRAP) {
723                 return (dma_wrap) ? 0xffffffff : 0;
724         }
725         return UPD71071::read_signal(id);
726 }
727
728 void TOWNS_DMAC::write_signal(int id, uint32_t data, uint32_t _mask)
729 {
730         if(id == SIG_TOWNS_DMAC_WRAP) {
731                 dma_wrap = ((data & _mask) != 0) ? true : false;
732 //              this->write_signal(SIG_TOWNS_DMAC_ADDR_MASK, data, mask);
733         } else if((id >= SIG_TOWNS_DMAC_EOT_CH0) && (id <= SIG_TOWNS_DMAC_EOT_CH3)) {
734                 int ch = (id - SIG_TOWNS_DMAC_EOT_CH0) & 3;
735                 if(((data & _mask) != 0) && !(end_req[ch])){
736                         end_req[ch] = true;
737                         out_debug_log(_T("END#%d ASSERTED"), ch);
738                         if(!(_SINGLE_MODE_DMA)) {
739                                 if((dma[ch].mode & 0xc0) != 0x40) { // WITHOUT SINGLE
740                                         do_end_sequence(ch, false); // Check immediately.
741                                 }
742                         }
743                 }
744         } else {
745                 __LIKELY_IF((id >= SIG_UPD71071_CH0) && (id <= SIG_UPD71071_CH3)) {
746         //              out_debug_log(_T("DRQ#%d %s"), ch, ((data & _mask) != 0) ? _T("ON ") : _T("OFF"));
747                         int ch = (id - SIG_UPD71071_CH0) & 3;
748                         uint8_t bit = 1 << ch;
749                         uint8_t _mode = dma[ch].mode & 0xc0;
750                         if(data & _mask) {
751                                 if(!(req & bit)) {
752                                         req |= bit;
753                                         if(!(_SINGLE_MODE_DMA)) {
754                                                 check_start_condition();
755                                                 call_dma(ch); // OK?
756                                         }
757                                 }
758                         } else {
759                                 uint8_t _b = req & bit;
760                                 req &= ~bit;
761                                 if(!(_SINGLE_MODE_DMA) && (_b)) { // ON -> OFF
762                                         check_start_condition();
763                                         check_running();
764                                 }
765                         }
766                 } else {
767                         // Fallthrough.
768                         UPD71071::write_signal(id, data, _mask);
769                 }
770         }
771 }
772
773
774 // note: if SINGLE_MODE_DMA is defined, do_dma() is called in every machine cycle
775 bool TOWNS_DMAC::get_debug_regs_info(_TCHAR *buffer, size_t buffer_len)
776 {
777         static const _TCHAR *dir[4] = {
778                 _T("VERIFY"), _T("I/O->MEM"), _T("MEM->I/O"), _T("INVALID")
779         };
780         if(buffer == NULL) return false;
781         _TCHAR sbuf[4][512] = {0};
782         for(int i = 0; i < 4; i++) {
783                 my_stprintf_s(sbuf[i], 512,
784                   _T("CH%d AREG=%08X CREG=%04X BAREG=%08X BCREG=%04X REQ=%d MASK=%d MODE=%02X %s\n"),
785                                           i,
786                                           dma[i].areg,
787                                           dma[i].creg,
788                                           dma[i].bareg,
789                                           dma[i].bcreg,
790                                           ((req | sreq) >> 0) & 1,
791                                           (mask >> 0) & 1,
792                                           dma[i].mode,
793                                           dir[(dma[i].mode >> 2) & 3]
794                         );
795         }
796         {
797                 my_stprintf_s(buffer, buffer_len,
798                                           _T("16Bit=%s ADDR_WRAP=%s \n")
799                                           _T("SELECT CH=%d BASE=%02X REQ=%02X SREQ=%02X MASK=%02X TC=%02X ")
800                                           _T("CMD=%04X TMP=%04X\n")
801                                           _T("%s")
802                                           _T("%s")
803                                           _T("%s")
804                                           _T("%s"),
805                                           (b16 != 0) ? _T("YES") : _T("NO"), (dma_wrap) ? _T("YES") : _T("NO"),
806                                           selch, base, req, sreq, mask, tc,
807                                           cmd, tmp,
808                                           sbuf[0],
809                                           sbuf[1],
810                                           sbuf[2],
811                                           sbuf[3]);
812                 return true;
813         }
814         return false;
815 }
816
817 #define STATE_VERSION   10
818
819 bool TOWNS_DMAC::process_state(FILEIO *state_fio, bool loading)
820 {
821         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
822                 return false;
823         }
824         if(!state_fio->StateCheckInt32(this_device_id)) {
825                 return false;
826         }
827         if(!(UPD71071::process_state(state_fio, loading))) {
828                 return false;
829         }
830         state_fio->StateValue(dma_wrap);
831         state_fio->StateArray(is_started, sizeof(is_started), 1);
832         state_fio->StateArray(end_req, sizeof(end_req), 1);
833         state_fio->StateValue(div_count);
834
835         state_fio->StateValue(event_dmac_cycle);
836
837         if(loading) {
838                 for(int ch = 0; ch < 4; ch++) {
839                         calc_transfer_status(ch);
840                 }
841         }
842         return true;
843 }
844
845
846 }