OSDN Git Service

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