OSDN Git Service

5dc2d862b1028aa50ca097a459ccd16a254a721a
[csp-qt/common_source_project-fm7.git] / source / src / vm / z80dma.cpp
1 /*
2         Skelton for retropc emulator
3
4         Origin : MAME Z80DMA / Xmillenium
5         Author : Takeda.Toshiya
6                  Y.S. (Xmil106RS)
7         Date   : 2011.04.96-
8
9         [ Z80DMA ]
10 */
11
12 #include "z80dma.h"
13 #include "debugger.h"
14
15 //#define DMA_DEBUG
16
17 #define CMD_RESET                               0xc3
18 #define CMD_RESET_PORT_A_TIMING                 0xc7
19 #define CMD_RESET_PORT_B_TIMING                 0xcb
20 #define CMD_LOAD                                0xcf
21 #define CMD_CONTINUE                            0xd3
22 #define CMD_DISABLE_INTERRUPTS                  0xaf
23 #define CMD_ENABLE_INTERRUPTS                   0xab
24 #define CMD_RESET_AND_DISABLE_INTERRUPTS        0xa3
25 #define CMD_ENABLE_AFTER_RETI                   0xb7
26 #define CMD_READ_STATUS_BYTE                    0xbf
27 #define CMD_REINITIALIZE_STATUS_BYTE            0x8b
28 #define CMD_INITIATE_READ_SEQUENCE              0xa7
29 #define CMD_FORCE_READY                         0xb3
30 #define CMD_ENABLE_DMA                          0x87
31 #define CMD_DISABLE_DMA                         0x83
32 #define CMD_READ_MASK_FOLLOWS                   0xbb
33
34 #define TM_TRANSFER             1
35 #define TM_SEARCH               2
36 #define TM_SEARCH_TRANSFER      3
37
38 #define OM_BYTE                 0
39 #define OM_CONTINUOUS           1
40 #define OM_BURST                2
41
42 #define INT_RDY                 0
43 #define INT_MATCH               1
44 #define INT_END_OF_BLOCK        2
45
46 #define GET_REGNUM(r)           (int)(&(r) - &(WR0))
47
48 #define WR0                     regs.m[0][0]
49 #define WR1                     regs.m[1][0]
50 #define WR2                     regs.m[2][0]
51 #define WR3                     regs.m[3][0]
52 #define WR4                     regs.m[4][0]
53 #define WR5                     regs.m[5][0]
54 #define WR6                     regs.m[6][0]
55
56 #define PORTA_ADDRESS_L         regs.m[0][1]
57 #define PORTA_ADDRESS_H         regs.m[0][2]
58
59 #define BLOCKLEN_L              regs.m[0][3]
60 #define BLOCKLEN_H              regs.m[0][4]
61
62 #define PORTA_TIMING            regs.m[1][1]
63 #define PORTB_TIMING            regs.m[2][1]
64
65 #define MASK_BYTE               regs.m[3][1]
66 #define MATCH_BYTE              regs.m[3][2]
67
68 #define PORTB_ADDRESS_L         regs.m[4][1]
69 #define PORTB_ADDRESS_H         regs.m[4][2]
70 #define INTERRUPT_CTRL          regs.m[4][3]
71 #define INTERRUPT_VECTOR        regs.m[4][4]
72 #define PULSE_CTRL              regs.m[4][5]
73
74 #define READ_MASK               regs.m[6][1]
75
76 #define PORTA_ADDRESS           ((PORTA_ADDRESS_H << 8) | PORTA_ADDRESS_L)
77 #define PORTB_ADDRESS           ((PORTB_ADDRESS_H << 8) | PORTB_ADDRESS_L)
78 #define BLOCKLEN                ((BLOCKLEN_H << 8) | BLOCKLEN_L)
79
80 #define PORTA_INC               (WR1 & 0x10)
81 #define PORTB_INC               (WR2 & 0x10)
82 #define PORTA_FIXED             (((WR1 >> 4) & 2) == 2)
83 #define PORTB_FIXED             (((WR2 >> 4) & 2) == 2)
84 #define PORTA_MEMORY            (((WR1 >> 3) & 1) == 0)
85 #define PORTB_MEMORY            (((WR2 >> 3) & 1) == 0)
86
87 #define PORTA_CYCLE_LEN         (((PORTA_TIMING & 3) != 3) ? (4 - (PORTA_TIMING & 3)) : PORTA_MEMORY ? 3 : 4)
88 #define PORTB_CYCLE_LEN         (((PORTB_TIMING & 3) != 3) ? (4 - (PORTB_TIMING & 3)) : PORTB_MEMORY ? 3 : 4)
89
90 #define PORTA_IS_SOURCE         ((WR0 >> 2) & 1)
91 #define PORTB_IS_SOURCE         (!PORTA_IS_SOURCE)
92 #define TRANSFER_MODE           (WR0 & 3)
93
94 #define MATCH_F_SET             (status &= ~0x10)
95 #define MATCH_F_CLEAR           (status |= 0x10)
96 #define EOB_F_SET               (status &= ~0x20)
97 #define EOB_F_CLEAR             (status |= 0x20)
98
99 #define STOP_ON_MATCH           ((WR3 >> 2) & 1)
100
101 #define OPERATING_MODE          ((WR4 >> 5) & 3)
102
103 #define READY_ACTIVE_HIGH       ((WR5 >> 3) & 1)
104 #define CHECK_WAIT_SIGNAL       ((WR5 >> 4) & 1)
105 #define AUTO_RESTART            ((WR5 >> 5) & 1)
106
107 #define INTERRUPT_ENABLE        (WR3 & 0x20)
108 #define INT_ON_MATCH            (INTERRUPT_CTRL & 0x01)
109 #define INT_ON_END_OF_BLOCK     (INTERRUPT_CTRL & 0x02)
110 #define INT_ON_READY            (INTERRUPT_CTRL & 0x40)
111 #define STATUS_AFFECTS_VECTOR   (INTERRUPT_CTRL & 0x20)
112
113 void Z80DMA::initialize()
114 {
115         DEVICE::initialize();
116         _SINGLE_MODE_DMA = osd->check_feature(_T("SINGLE_MODE_DMA"));
117         _DMA_DEBUG = osd->check_feature(_T("DMA_DEBUG"));
118         _X1TURBO_FEATURE = osd->check_feature(_T("_X1TURBO_FEATURE"));
119 //      _DMA_DEBUG = true; // TMP
120         if(d_debugger != NULL) {
121                 d_debugger->set_device_name(_T("Debugger (Z80DMA)"));
122                 d_debugger->set_context_mem(this);
123                 d_debugger->set_context_io(this);
124         }
125 }
126
127 void Z80DMA::reset()
128 {
129         WR3 &= ~0x20; // disable interrupt
130         status = 0x30;
131         
132         PORTA_TIMING |= 3;
133         PORTB_TIMING |= 3;
134         
135         wr_num = wr_ptr = 0;
136         rr_num = rr_ptr = 0;
137         
138         enabled = false;
139         ready = 0;
140         force_ready = false;
141         
142         iei = oei = true;
143         req_intr = in_service = false;
144         vector = 0;
145         
146         upcount = 0;
147         blocklen = 0;
148         dma_stop = false;
149         bus_master = false;
150 }
151
152 void Z80DMA::write_io8(uint32_t addr, uint32_t data)
153 {
154         if(wr_num == 0) {
155                 if((data & 0x87) == 0) {
156 //#ifdef DMA_DEBUG
157                         if(_DMA_DEBUG) this->out_debug_log(_T("Z80DMA: WR2=%2x\n"), data);
158 //#endif
159                         WR2 = data;
160                         if(data & 0x40) {
161                                 wr_tmp[wr_num++] = GET_REGNUM(PORTB_TIMING);
162                         }
163                 } else if((data & 0x87) == 4) {
164 //#ifdef DMA_DEBUG
165                         if(_DMA_DEBUG) this->out_debug_log(_T("Z80DMA: WR1=%2x\n"), data);
166 //#endif
167                         WR1 = data;
168                         if(data & 0x40) {
169                                 wr_tmp[wr_num++] = GET_REGNUM(PORTA_TIMING);
170                         }
171                 } else if((data & 0x80) == 0) {
172 //#ifdef DMA_DEBUG
173                         if(_DMA_DEBUG) this->out_debug_log(_T("Z80DMA: WR0=%2x\n"), data);
174 //#endif
175                         WR0 = data;
176                         if(data & 0x08) {
177                                 wr_tmp[wr_num++] = GET_REGNUM(PORTA_ADDRESS_L);
178                         }
179                         if(data & 0x10) {
180                                 wr_tmp[wr_num++] = GET_REGNUM(PORTA_ADDRESS_H);
181                         }
182                         if(data & 0x20) {
183                                 wr_tmp[wr_num++] = GET_REGNUM(BLOCKLEN_L);
184                         }
185                         if(data & 0x40) {
186                                 wr_tmp[wr_num++] = GET_REGNUM(BLOCKLEN_H);
187                         }
188                 } else if((data & 0x83) == 0x80) {
189 //#ifdef DMA_DEBUG
190                         if(_DMA_DEBUG) this->out_debug_log(_T("Z80DMA: WR3=%2x\n"), data);
191 //#endif
192                         WR3 = data;
193                         if(data & 0x08) {
194                                 wr_tmp[wr_num++] = GET_REGNUM(MASK_BYTE);
195                         }
196                         if(data & 0x10) {
197                                 wr_tmp[wr_num++] = GET_REGNUM(MATCH_BYTE);
198                         }
199                         enabled = ((data & 0x40) != 0);
200                 } else if((data & 0x83) == 0x81) {
201 //#ifdef DMA_DEBUG
202                         if(_DMA_DEBUG)  this->out_debug_log(_T("Z80DMA: WR4=%2x\n"), data);
203 //#endif
204                         WR4 = data;
205                         if(data & 0x04) {
206                                 wr_tmp[wr_num++] = GET_REGNUM(PORTB_ADDRESS_L);
207                         }
208                         if(data & 0x08) {
209                                 wr_tmp[wr_num++] = GET_REGNUM(PORTB_ADDRESS_H);
210                         }
211                         if(data & 0x10) {
212                                 wr_tmp[wr_num++] = GET_REGNUM(INTERRUPT_CTRL);
213                         }
214                 } else if((data & 0xc7) == 0x82) {
215 //#ifdef DMA_DEBUG
216                         if(_DMA_DEBUG) this->out_debug_log(_T("Z80DMA: WR5=%2x\n"), data);
217 //#endif
218                         WR5 = data;
219                         // RDY signal sense is a LEVEL, not an EDDGE (thanks Mr.Sato)
220                         if(now_ready() && INT_ON_READY) {
221                                 request_intr(INT_RDY);
222                         }
223                 } else if((data & 0x83) == 0x83) {
224 //#ifdef DMA_DEBUG
225                         if(_DMA_DEBUG) this->out_debug_log(_T("Z80DMA: WR6=%2x\n"), data);
226 //#endif
227                         WR6 = data;
228                         enabled = false;
229                         
230                         // check dma stop (from Xmil106RS)
231                         switch (data) {
232                         case CMD_CONTINUE:
233                         case CMD_READ_STATUS_BYTE:
234                         case CMD_INITIATE_READ_SEQUENCE:
235                         case CMD_ENABLE_DMA:
236                         case CMD_DISABLE_DMA:
237                         case CMD_READ_MASK_FOLLOWS:
238                                 break;
239                         default:
240                                 dma_stop = false;
241                                 break;
242                         }
243                         
244                         // run command
245                         switch (data) {
246                         case CMD_ENABLE_AFTER_RETI:
247                                 break;
248                         case CMD_READ_STATUS_BYTE:
249                                 // force to read status (from Xmillenium)
250                                 READ_MASK = 1;
251                                 update_read_buffer();
252                                 break;
253                         case CMD_RESET_AND_DISABLE_INTERRUPTS:
254                                 WR3 &= ~0x20;
255                                 req_intr = false;
256                                 update_intr();
257                                 force_ready = false;
258                                 break;
259                         case CMD_INITIATE_READ_SEQUENCE:
260                                 update_read_buffer();
261                                 break;
262                         case CMD_RESET:
263                                 enabled = false;
264                                 force_ready = false;
265                                 req_intr = in_service = false;
266                                 update_intr();
267                                 status = 0x30;
268                                 // reset timing
269                                 PORTA_TIMING |= 3;
270                                 PORTB_TIMING |= 3;
271                                 // reset upcount
272                                 WR3 &= ~0x20;
273                                 upcount = 0;
274                                 // reset auto repeat and wait functions
275                                 WR5 &= ~0x30;
276                                 break;
277                         case CMD_LOAD:
278                                 force_ready = false;
279                                 addr_a = PORTA_ADDRESS;
280                                 addr_b = PORTB_ADDRESS;
281                                 upcount = 0;//BLOCKLEN;
282                                 status |= 0x30;
283                                 break;
284                         case CMD_DISABLE_DMA:
285                                 enabled = false;
286                                 break;
287                         case CMD_ENABLE_DMA:
288                                 enabled = true;
289 //#ifndef SINGLE_MODE_DMA
290                                 if(!_SINGLE_MODE_DMA) do_dma();
291 //#endif
292                                 break;
293                         case CMD_READ_MASK_FOLLOWS:
294                                 wr_tmp[wr_num++] = GET_REGNUM(READ_MASK);
295                                 break;
296                         case CMD_CONTINUE:
297                                 upcount = (dma_stop && upcount != blocklen) ? -1 : 0;
298                                 enabled = true;
299                                 status |= 0x30;
300 //#ifndef SINGLE_MODE_DMA
301                                 if(!_SINGLE_MODE_DMA) do_dma();
302 //#endif
303                                 break;
304                         case CMD_RESET_PORT_A_TIMING:
305                                 PORTA_TIMING |= 3;
306                                 break;
307                         case CMD_RESET_PORT_B_TIMING:
308                                 PORTB_TIMING |= 3;
309                                 break;
310                         case CMD_FORCE_READY:
311                                 force_ready = true;
312                                 // RDY signal sense is a LEVEL, not an EDDGE (thanks Mr.Sato)
313                                 if(now_ready() && INT_ON_READY) {
314                                         request_intr(INT_RDY);
315                                 }
316 //#ifndef SINGLE_MODE_DMA
317                                 if(!_SINGLE_MODE_DMA) do_dma();
318 //#endif
319                                 break;
320                         case CMD_ENABLE_INTERRUPTS:
321                                 WR3 |= 0x20;
322                                 // RDY signal sense is a LEVEL, not an EDDGE (thanks Mr.Sato)
323                                 if(now_ready() && INT_ON_READY) {
324                                         request_intr(INT_RDY);
325                                 }
326                                 break;
327                         case CMD_DISABLE_INTERRUPTS:
328                                 WR3 &= ~0x20;
329                                 break;
330                         case CMD_REINITIALIZE_STATUS_BYTE:
331                                 status |= 0x30;
332                                 req_intr = false;
333                                 update_intr();
334                                 break;
335                         }
336                 }
337                 wr_ptr = 0;
338         } else {
339                 int nreg = wr_tmp[wr_ptr];
340 //#ifdef DMA_DEBUG
341                 if(_DMA_DEBUG) this->out_debug_log(_T("Z80DMA: WR[%d,%d]=%2x\n"), nreg >> 3, nreg & 7, data);
342 //#endif
343                 regs.t[nreg] = data;
344                 
345                 if(++wr_ptr >= wr_num) {
346                         wr_num = 0;
347                 }
348                 if(nreg == GET_REGNUM(INTERRUPT_CTRL)) {
349                         wr_num=0;
350                         if(data & 0x08) {
351                                 wr_tmp[wr_num++] = GET_REGNUM(PULSE_CTRL);
352                         }
353                         if(data & 0x10) {
354                                 wr_tmp[wr_num++] = GET_REGNUM(INTERRUPT_VECTOR);
355                         }
356                         wr_ptr = 0;
357                         // RDY signal sense is a LEVEL, not an EDDGE (thanks Mr.Sato)
358                         if(now_ready() && INT_ON_READY) {
359                                 request_intr(INT_RDY);
360                         }
361                 } else if(wr_tmp[wr_num] == GET_REGNUM(READ_MASK)) {
362                         // from Xmillenium
363                         upcount--;
364                         update_read_buffer();
365                         upcount++;
366                 }
367         }
368 }
369
370 uint32_t Z80DMA::read_io8(uint32_t addr)
371 {
372         // return status if read buffer is empty (from Xmillenium)
373         if(rr_num == 0) {
374                 return status | (now_ready() ? 0 : 2) | (req_intr ? 0 : 8);
375         }
376         uint32_t data = rr_tmp[rr_ptr];
377         
378 //#ifdef DMA_DEBUG
379         if(_DMA_DEBUG) this->out_debug_log(_T("Z80DMA: RR[%d]=%2x\n"), rr_ptr, data);
380 //#endif
381         if(++rr_ptr >= rr_num) {
382                 rr_ptr = 0;
383         }
384         return data;
385 }
386
387 void Z80DMA::write_signal(int id, uint32_t data, uint32_t mask)
388 {
389         // ready signal (wired-or)
390         bool prev_ready = now_ready();
391         
392         if(data & mask) {
393                 ready |= (1 << id);
394         } else {
395                 ready &= ~(1 << id);
396         }
397         if(!prev_ready && now_ready()) {
398                 if(INT_ON_READY) {
399                         request_intr(INT_RDY);
400                 }
401 //#ifndef SINGLE_MODE_DMA
402                 if(!_SINGLE_MODE_DMA) do_dma();
403 //#endif
404         }
405 }
406
407 bool Z80DMA::now_ready()
408 {
409         if(force_ready) {
410                 return true;
411         }
412         // FIXME: DRQ active is really L, but FDC class sends H
413         if(READY_ACTIVE_HIGH) {
414                 return (ready == 0);
415         } else {
416                 return (ready != 0);
417         }
418 }
419
420 void Z80DMA::update_read_buffer()
421 {
422         // note: return current count and address (from Xmillenium)
423         rr_ptr = rr_num = 0;
424         if(READ_MASK & 0x01) {
425                 rr_tmp[rr_num++] = status | (now_ready() ? 0 : 2) | (req_intr ? 0 : 8);
426         }
427         if(READ_MASK & 0x02) {
428                 rr_tmp[rr_num++] = upcount & 0xff;//BLOCKLEN_L;
429         }
430         if(READ_MASK & 0x04) {
431                 rr_tmp[rr_num++] = upcount >> 8;//BLOCKLEN_H;
432         }
433         if(READ_MASK & 0x08) {
434                 rr_tmp[rr_num++] = addr_a & 0xff;//PORTA_ADDRESS_L;
435         }
436         if(READ_MASK & 0x10) {
437                 rr_tmp[rr_num++] = addr_a >> 8;//PORTA_ADDRESS_H;
438         }
439         if(READ_MASK & 0x20) {
440                 rr_tmp[rr_num++] = addr_b & 0xff;//PORTB_ADDRESS_L;
441         }
442         if(READ_MASK & 0x40) {
443                 rr_tmp[rr_num++] = addr_b >> 8;//PORTB_ADDRESS_H;
444         }
445 }
446
447 void Z80DMA::write_via_debugger_data8w(uint32_t addr, uint32_t data, int* wait)
448 {
449         d_mem->write_dma_data8w(addr, data, wait);
450 }
451
452 uint32_t Z80DMA::read_via_debugger_data8w(uint32_t addr, int* wait)
453 {
454         return d_mem->read_dma_data8w(addr, wait);
455 }
456
457 void Z80DMA::write_via_debugger_io8w(uint32_t addr, uint32_t data, int* wait)
458 {
459         d_io->write_dma_io8w(addr, data, wait);
460 }
461
462 uint32_t Z80DMA::read_via_debugger_io8w(uint32_t addr, int* wait)
463 {
464         return d_io->read_dma_io8w(addr, wait);
465 }
466
467 void Z80DMA::write_memory(uint32_t addr, uint32_t data, int* wait)
468 {
469         if(d_debugger != NULL && d_debugger->now_device_debugging) {
470                 d_debugger->write_via_debugger_data8w(addr, data, wait);
471         } else {
472                 this->write_via_debugger_data8w(addr, data, wait);
473         }
474 }
475
476 uint32_t Z80DMA::read_memory(uint32_t addr, int* wait)
477 {
478         if(d_debugger != NULL && d_debugger->now_device_debugging) {
479                 return d_debugger->read_via_debugger_data8w(addr, wait);
480         } else {
481                 return this->read_via_debugger_data8w(addr, wait);
482         }
483 }
484
485 void Z80DMA::write_ioport(uint32_t addr, uint32_t data, int* wait)
486 {
487         if(d_debugger != NULL && d_debugger->now_device_debugging) {
488                 d_debugger->write_via_debugger_io8w(addr, data, wait);
489         } else {
490                 this->write_via_debugger_io8w(addr, data, wait);
491         }
492 }
493
494 uint32_t Z80DMA::read_ioport(uint32_t addr, int* wait)
495 {
496         if(d_debugger != NULL && d_debugger->now_device_debugging) {
497                 return d_debugger->read_via_debugger_io8w(addr, wait);
498         } else {
499                 return this->read_via_debugger_io8w(addr, wait);
500         }
501 }
502
503 // note: if SINGLE_MODE_DMA is defined, do_dma() is called in every machine cycle
504
505 void Z80DMA::do_dma()
506 {
507         if(!enabled) {
508                 return;
509         }
510         bool occured = false;
511         bool finished = false;
512         bool found = false;
513         
514         // from Xmillenium (thanks Y.S.)
515         if(BLOCKLEN == 0) {
516                 blocklen = 65537;
517         } else if(BLOCKLEN == 0xffff) {
518                 blocklen = (int)65536;
519         } else {
520                 blocklen = BLOCKLEN + 1;
521         }
522         // Workaround of MinGW's (older) GCC.
523         // messages: crosses initialization of 'int wait_w' etc.
524         uint32_t data = 0;
525         int wait_r = 0, wait_w = 0;
526         
527 //#ifndef SINGLE_MODE_DMA
528 restart:
529 //#endif
530         while(enabled && now_ready() && !(upcount == blocklen || found)) {
531                 if(dma_stop) {
532                         if(upcount < blocklen) {
533                                 upcount++;
534                         }
535                         dma_stop = false;
536                         goto inc_ports;
537                 }
538                 
539                 // request bus
540                 request_bus();
541                 
542                 // read
543                 data = 0;
544                 wait_r = wait_w = 0;
545                 
546                 if(PORTA_IS_SOURCE) {
547                         if(PORTA_MEMORY) {
548                                 data = read_memory(addr_a, &wait_r);
549 //#ifdef DMA_DEBUG
550                                 if(_DMA_DEBUG) this->out_debug_log(_T("Z80DMA: RAM[%4x]=%2x -> "), addr_a, data);
551 //#endif
552                         } else {
553                                 data = read_ioport(addr_a, &wait_r);
554 //#ifdef DMA_DEBUG
555                                 if(_DMA_DEBUG) this->out_debug_log(_T("Z80DMA: INP(%4x)=%2x -> "), addr_a, data);
556 //#endif
557                         }
558                         if(d_cpu != NULL) {
559                                 if(CHECK_WAIT_SIGNAL) {
560                                         d_cpu->set_extra_clock(PORTA_CYCLE_LEN + wait_r);
561                                 } else {
562                                         d_cpu->set_extra_clock(PORTA_CYCLE_LEN);
563                                 }
564                         }
565                 } else {
566                         if(PORTB_MEMORY) {
567                                 data = read_memory(addr_b, &wait_r);
568 //#ifdef DMA_DEBUG
569                                 if(_DMA_DEBUG) this->out_debug_log(_T("Z80DMA: RAM[%4x]=%2x -> "), addr_b, data);
570 //#endif
571                         } else {
572                                 data = read_ioport(addr_b, &wait_r);
573 //#ifdef DMA_DEBUG
574                                 if(_DMA_DEBUG) this->out_debug_log(_T("Z80DMA: INP(%4x)=%2x -> "), addr_b, data);
575 //#endif
576                         }
577                         if(d_cpu != NULL) {
578                                 if(CHECK_WAIT_SIGNAL) {
579                                         d_cpu->set_extra_clock(PORTB_CYCLE_LEN + wait_r);
580                                 } else {
581                                         d_cpu->set_extra_clock(PORTB_CYCLE_LEN);
582                                 }
583                         }
584                 }
585                 
586                 // write
587                 if(TRANSFER_MODE == TM_TRANSFER || TRANSFER_MODE == TM_SEARCH_TRANSFER) {
588                         if(PORTA_IS_SOURCE) {
589                                 if(PORTB_MEMORY) {
590 //#ifdef DMA_DEBUG
591                                         if(_DMA_DEBUG) this->out_debug_log(_T("RAM[%4x]\n"), addr_b);
592 //#endif
593                                         write_signals(&outputs_wrote_mem, addr_b);
594                                         write_memory(addr_b, data, &wait_w);
595                                 } else {
596 //#ifdef DMA_DEBUG
597                                         if(_DMA_DEBUG) this->out_debug_log(_T("OUT(%4x)\n"), addr_b);
598 //#endif
599                                         write_ioport(addr_b, data, &wait_w);
600                                 }
601                                 if(d_cpu != NULL) {
602                                         if(CHECK_WAIT_SIGNAL) {
603                                                 d_cpu->set_extra_clock(PORTB_CYCLE_LEN + wait_w);
604                                         } else {
605                                                 d_cpu->set_extra_clock(PORTB_CYCLE_LEN);
606                                         }
607                                 }
608                         } else {
609                                 if(PORTA_MEMORY) {
610 //#ifdef DMA_DEBUG
611                                         if(_DMA_DEBUG) this->out_debug_log(_T("RAM[%4x]\n"), addr_a);
612 //#endif
613                                         write_signals(&outputs_wrote_mem, addr_a);
614                                         write_memory(addr_a, data, &wait_w);
615                                 } else {
616 //#ifdef DMA_DEBUG
617                                         if(_DMA_DEBUG) this->out_debug_log(_T("OUT(%4x)\n"), addr_a);
618 //#endif
619                                         write_ioport(addr_a, data, &wait_w);
620                                 }
621                                 if(d_cpu != NULL) {
622                                         if(CHECK_WAIT_SIGNAL) {
623                                                 d_cpu->set_extra_clock(PORTA_CYCLE_LEN + wait_w);
624                                         } else {
625                                                 d_cpu->set_extra_clock(PORTA_CYCLE_LEN);
626                                         }
627                                 }
628                         }
629                 }
630                 
631                 // release bus
632                 if(OPERATING_MODE == OM_BYTE) {
633                         release_bus();
634                 }
635                 
636                 // search
637                 if(TRANSFER_MODE == TM_SEARCH || TRANSFER_MODE == TM_SEARCH_TRANSFER) {
638                         if((data & MASK_BYTE) == (MATCH_BYTE & MASK_BYTE)) {
639                                 found = true;
640                         }
641                 }
642                 upcount++;
643                 occured = true;
644                 
645                 if(found || (BLOCKLEN == 0 && !now_ready())) {
646                         if(upcount < blocklen) {
647                                 upcount--;
648                         }
649                         dma_stop = true;
650                         break;
651                 }
652 inc_ports:
653                 if(PORTA_IS_SOURCE) {
654                         addr_a += PORTA_FIXED ? 0 : PORTA_INC ? 1 : -1;
655                 } else {
656                         addr_b += PORTB_FIXED ? 0 : PORTB_INC ? 1 : -1;
657                 }
658                 if(TRANSFER_MODE == TM_TRANSFER || TRANSFER_MODE == TM_SEARCH_TRANSFER) {
659                         if(PORTA_IS_SOURCE) {
660                                 addr_b += PORTB_FIXED ? 0 : PORTB_INC ? 1 : -1;
661                         } else {
662                                 addr_a += PORTA_FIXED ? 0 : PORTA_INC ? 1 : -1;
663                         }
664                 }
665 //#ifdef SINGLE_MODE_DMA
666                 if(_SINGLE_MODE_DMA) {
667                         if(OPERATING_MODE == OM_BYTE) {
668                                 break;
669                         }
670                 }
671 //#endif
672         }
673         
674 //#ifdef DMA_DEBUG
675         if(_DMA_DEBUG) {
676                 if(occured) {
677                         this->out_debug_log(_T("Z80DMA: COUNT=%d BLOCKLEN=%d FOUND=%d\n"), upcount, blocklen, found ? 1 : 0);
678                 }
679         }
680 //#endif
681         if(occured && (upcount == blocklen || found)) {
682                 // auto restart
683                 if(AUTO_RESTART && upcount == blocklen && !force_ready) {
684 //#ifdef DMA_DEBUG
685                         if(_DMA_DEBUG) this->out_debug_log(_T("Z80DMA: AUTO RESTART !!!\n"));
686 //#endif
687                         upcount = 0;
688 //#ifndef SINGLE_MODE_DMA
689                         if(!_SINGLE_MODE_DMA) goto restart;
690 //#endif
691                 }
692                 
693                 // update status
694                 status = 1;
695                 if(!found) {
696                         status |= 0x10;
697                 }
698                 if(upcount != blocklen) {
699                         status |= 0x20;
700                 }
701                 enabled = false;
702                 
703                 // request interrupt
704                 int level = 0;
705                 if(upcount == blocklen) {
706                         // transfer/search done
707                         if(INT_ON_END_OF_BLOCK) {
708                                 level |= INT_END_OF_BLOCK;
709                         }
710                         finished = true;
711                 }
712                 if(found) {
713                         // match found
714                         if(INT_ON_MATCH) {
715                                 level |= INT_MATCH;
716                         }
717                         if(STOP_ON_MATCH) {
718                                 finished = true;
719                         }
720                 }
721                 if(level) {
722                         request_intr(level);
723                 }
724         }
725         
726         // release bus
727         if(finished || OPERATING_MODE == OM_BYTE || (OPERATING_MODE == OM_BURST && !now_ready())) {
728                 release_bus();
729         }
730 }
731
732 void Z80DMA::request_bus()
733 {
734         if(!bus_master) {
735                 if(d_cpu != NULL) {
736 //#ifdef SINGLE_MODE_DMA
737                         if(_SINGLE_MODE_DMA) d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
738 //#endif
739                         d_cpu->set_extra_clock(3);
740                 }
741                 bus_master = true;
742         }
743 }
744
745 void Z80DMA::release_bus()
746 {
747         if(bus_master) {
748                 if(d_cpu != NULL) {
749 //#ifdef SINGLE_MODE_DMA
750                         if(_SINGLE_MODE_DMA) d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 0);
751 //#endif
752                         if(OPERATING_MODE == OM_BYTE) {
753                                 d_cpu->set_extra_clock(1);
754                         } else {
755                                 d_cpu->set_extra_clock(2);
756                         }
757                 }
758                 bus_master = false;
759         }
760 }
761
762 void Z80DMA::request_intr(int level)
763 {
764         if(!in_service && INTERRUPT_ENABLE) {
765                 req_intr = true;
766                 
767                 if(STATUS_AFFECTS_VECTOR) {
768                         vector = (uint8_t)((INTERRUPT_VECTOR & 0xf9) | (level << 1));
769                 } else {
770                         vector = (uint8_t)INTERRUPT_VECTOR;
771                 }
772                 update_intr();
773         }
774 }
775
776 void Z80DMA::set_intr_iei(bool val)
777 {
778         if(iei != val) {
779                 iei = val;
780                 update_intr();
781         }
782 }
783
784 #define set_intr_oei(val) { \
785         if(oei != val) { \
786                 oei = val; \
787                 if(d_child != NULL) { \
788                         d_child->set_intr_iei(oei); \
789                 } \
790         } \
791 }
792
793 void Z80DMA::update_intr()
794 {
795         bool next;
796         
797         // set oei signal
798         if((next = iei) == true) {
799                 if(in_service) {
800                         next = false;
801                 }
802         }
803         set_intr_oei(next);
804         
805         // set int signal
806         if((next = iei) == true) {
807                 next = (!in_service && req_intr);
808         }
809         if(d_cpu != NULL) {
810                 d_cpu->set_intr_line(next, true, intr_bit);
811         }
812 }
813
814 uint32_t Z80DMA::get_intr_ack()
815 {
816         // ack (M1=IORQ=L)
817         if(in_service) {
818                 // invalid interrupt status
819                 return 0xff;
820         } else if(req_intr) {
821                 req_intr = false;
822                 in_service = true;
823                 enabled = false;
824                 update_intr();
825                 return vector;
826         }
827         if(d_child != NULL) {
828                 return d_child->get_intr_ack();
829         }
830         return 0xff;
831 }
832
833 void Z80DMA::notify_intr_reti()
834 {
835         // detect RETI
836         if(in_service) {
837                 in_service = false;
838                 update_intr();
839                 return;
840         }
841         if(d_child != NULL) {
842                 d_child->notify_intr_reti();
843         }
844 }
845
846 bool Z80DMA::get_debug_regs_info(_TCHAR *buffer, size_t buffer_len)
847 {
848 /*
849 PORT-A(MEM,FFFF)->PORT-B(I/O,FFFF) CNT=65536 BLK=65536 STAT=00 ENABLE=1 READY=1
850 */
851         my_stprintf_s(buffer, buffer_len,
852         _T("PORT-A(%s,%04X)%sPORT-B(%s,%04X) CNT=%d BLK=%d STAT=%02X ENABLE=%d READY=%d"),
853         PORTA_MEMORY ? "MEM" : "I/O", addr_a,
854         PORTA_IS_SOURCE ? "->" : "<-",
855         PORTB_MEMORY ? "MEM" : "I/O", addr_b,
856         upcount, blocklen,
857         status | (now_ready() ? 0 : 2) | (req_intr ? 0 : 8),
858         enabled, now_ready());
859         return true;
860 }
861
862 #define STATE_VERSION   2
863
864 bool Z80DMA::process_state(FILEIO* state_fio, bool loading)
865 {
866         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
867                 return false;
868         }
869         if(!state_fio->StateCheckInt32(this_device_id)) {
870                 return false;
871         }
872         state_fio->StateArray(&regs.m[0][0], sizeof(regs.m), 1);
873         state_fio->StateArray(&regs.t[0], sizeof(regs.t), 1);
874         state_fio->StateValue(status);
875         state_fio->StateArray(wr_tmp, sizeof(wr_tmp), 1);
876         state_fio->StateValue(wr_num);
877         state_fio->StateValue(wr_ptr);
878         state_fio->StateArray(rr_tmp, sizeof(rr_tmp), 1);
879         state_fio->StateValue(rr_num);
880         state_fio->StateValue(rr_ptr);
881         state_fio->StateValue(enabled);
882         state_fio->StateValue(ready);
883         state_fio->StateValue(force_ready);
884         state_fio->StateValue(addr_a);
885         state_fio->StateValue(addr_b);
886         state_fio->StateValue(upcount);
887         state_fio->StateValue(blocklen);
888         state_fio->StateValue(dma_stop);
889         state_fio->StateValue(bus_master);
890         state_fio->StateValue(req_intr);
891         state_fio->StateValue(in_service);
892         state_fio->StateValue(vector);
893         state_fio->StateValue(iei);
894         state_fio->StateValue(oei);
895         state_fio->StateValue(intr_bit);
896         return true;
897 }