workaround a problem with the harmattan gcc
[drnoksnes] / dma.cpp
1 /*
2  * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3  *
4  * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5  *                           Jerremy Koot (jkoot@snes9x.com)
6  *
7  * Super FX C emulator code 
8  * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
9  *                           Gary Henderson.
10  * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
11  *
12  * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
13  * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
14  * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
15  *
16  * DOS port code contains the works of other authors. See headers in
17  * individual files.
18  *
19  * Snes9x homepage: http://www.snes9x.com
20  *
21  * Permission to use, copy, modify and distribute Snes9x in both binary and
22  * source form, for non-commercial purposes, is hereby granted without fee,
23  * providing that this license information and copyright notice appear with
24  * all copies and any derived work.
25  *
26  * This software is provided 'as-is', without any express or implied
27  * warranty. In no event shall the authors be held liable for any damages
28  * arising from the use of this software.
29  *
30  * Snes9x is freeware for PERSONAL USE only. Commercial users should
31  * seek permission of the copyright holders first. Commercial use includes
32  * charging money for Snes9x or software derived from Snes9x.
33  *
34  * The copyright holders request that bug fixes and improvements to the code
35  * should be forwarded to them so everyone can benefit from the modifications
36  * in future versions.
37  *
38  * Super NES and Super Nintendo Entertainment System are trademarks of
39  * Nintendo Co., Limited and its subsidiary companies.
40  */
41 #include "snes9x.h"
42
43 #include "memmap.h"
44 #include "ppu.h"
45 #include "cpuexec.h"
46 #include "missing.h"
47 #include "dma.h"
48 #include "apu.h"
49 #include "gfx.h"
50 #ifdef USE_SA1
51 #include "sa1.h"
52 #endif
53
54 //SDD1
55 #include "sdd1emu.h"
56 uint8 buffer[0x10000];
57 //SDD1//
58
59 extern int HDMA_ModeByteCounts [8];
60 extern uint8 *HDMAMemPointers [8];
61 extern uint8 *HDMABasePointers [8];
62
63 #if defined(__linux__) || defined(__WIN32__) || defined(__GP2X__) || defined(__GIZ__)
64 static int S9xCompareSDD1IndexEntries (const void *p1, const void *p2)
65 {
66     return (*(uint32 *) p1 - *(uint32 *) p2);
67 }
68 #endif
69
70 /**********************************************************************************************/
71 /* S9xDoDMA()                                                                                   */
72 /* This function preforms the general dma transfer                                            */
73 /**********************************************************************************************/
74 void S9xDoDMA (uint8 Channel)
75 {
76     uint8 Work;
77
78     if (Channel > 7 || CPU.InDMA)
79         return;
80
81     CPU.InDMA = TRUE;
82     bool8 in_sa1_dma = FALSE;
83     uint8 *in_sdd1_dma = NULL;
84     SDMA *d = &DMA[Channel];
85
86     int count = d->TransferBytes;
87
88     if (count == 0)
89         count = 0x10000;
90
91     int inc = d->AAddressFixed ? 0 : (!d->AAddressDecrement ? 1 : -1);
92
93     switch (d->BAddress)
94     {
95     case 0x18:
96     case 0x19:
97         if (IPPU.RenderThisFrame)
98             FLUSH_REDRAW ();
99         break;
100     }
101
102     if (Settings.SDD1)
103     {
104         if (d->AAddressFixed && Memory.FillRAM [0x4801] > 0)
105         {
106             // Hacky support for pre-decompressed S-DD1 data
107             inc = !d->AAddressDecrement ? 1 : -1;
108             uint32 address = (((d->ABank << 16) | d->AAddress) & 0xfffff) << 4;
109
110             address |= Memory.FillRAM [0x4804 + ((d->ABank - 0xc0) >> 4)];
111                 if(Settings.SDD1Pack)
112                 {
113                         uint8* in_ptr=GetBasePointer(((d->ABank << 16) | d->AAddress));
114                         in_ptr+=d->AAddress;
115
116                         SDD1_decompress(buffer,in_ptr,d->TransferBytes);
117                         in_sdd1_dma=buffer;
118                 }
119                 else
120                 {
121 #if defined (__linux__)
122             void *ptr = bsearch (&address, Memory.SDD1Index, 
123                                  Memory.SDD1Entries, 12, S9xCompareSDD1IndexEntries);
124             if (ptr)
125                 in_sdd1_dma = *(uint32 *) ((uint8 *) ptr + 4) + Memory.SDD1Data;
126 #else
127             uint8 *ptr = Memory.SDD1Index;
128
129             for (uint32 e = 0; e < Memory.SDD1Entries; e++, ptr += 12)
130             {
131                 if (address == *(uint32 *) ptr)
132                 {
133                     in_sdd1_dma = *(uint32 *) (ptr + 4) + Memory.SDD1Data;
134                     break;
135                 }
136             }
137 #endif
138
139 /*                      if (!in_sdd1_dma)
140             {
141                 // No matching decompressed data found. Must be some new 
142                 // graphics not encountered before. Log it if it hasn't been
143                 // already.
144                 uint8 *p = Memory.SDD1LoggedData;
145                 bool8 found = FALSE;
146                 uint8 SDD1Bank = Memory.FillRAM [0x4804 + ((d->ABank - 0xc0) >> 4)] | 0xf0;
147
148                 for (uint32 i = 0; i < Memory.SDD1LoggedDataCount; i++, p += 8)
149                 {
150                     if (*p == d->ABank ||
151                         *(p + 1) == (d->AAddress >> 8) &&
152                         *(p + 2) == (d->AAddress & 0xff) &&
153                         *(p + 3) == (count >> 8) &&
154                         *(p + 4) == (count & 0xff) &&
155                         *(p + 7) == SDD1Bank)
156                     {
157                         found = TRUE;
158                         break;
159                     }
160                 }
161                 if (!found && Memory.SDD1LoggedDataCount < MEMMAP_MAX_SDD1_LOGGED_ENTRIES)
162                 {
163                     *p = d->ABank;
164                     *(p + 1) = d->AAddress >> 8;
165                     *(p + 2) = d->AAddress & 0xff;
166                     *(p + 3) = count >> 8;
167                     *(p + 4) = count & 0xff;
168                     *(p + 7) = SDD1Bank;
169                     Memory.SDD1LoggedDataCount += 1;
170                 }
171             }
172 */              }
173         }
174         Memory.FillRAM [0x4801] = 0;
175     }
176
177 #ifdef USE_SA1
178     if (d->BAddress == 0x18 && SA1.in_char_dma && (d->ABank & 0xf0) == 0x40)
179 #else
180     if (d->BAddress == 0x18 && (d->ABank & 0xf0) == 0x40)
181 #endif
182     {
183         // Perform packed bitmap to PPU character format conversion on the
184         // data before transmitting it to V-RAM via-DMA.
185         int num_chars = 1 << ((Memory.FillRAM [0x2231] >> 2) & 7);
186         int depth = (Memory.FillRAM [0x2231] & 3) == 0 ? 8 :
187                     (Memory.FillRAM [0x2231] & 3) == 1 ? 4 : 2;
188
189         int bytes_per_char = 8 * depth;
190         int bytes_per_line = depth * num_chars;
191         int char_line_bytes = bytes_per_char * num_chars;
192         uint32 addr = (d->AAddress / char_line_bytes) * char_line_bytes;
193         uint8 *base = GetBasePointer ((d->ABank << 16) + addr) + addr;
194         uint8 *buffer = &Memory.ROM [CMemory::MAX_ROM_SIZE - 0x10000];
195         uint8 *p = buffer;
196         uint32 inc = char_line_bytes - (d->AAddress % char_line_bytes);
197         uint32 char_count = inc / bytes_per_char;
198
199         in_sa1_dma = TRUE;
200         
201 //printf ("%08x,", base); fflush (stdout);
202 //printf ("depth = %d, count = %d, bytes_per_char = %d, bytes_per_line = %d, num_chars = %d, char_line_bytes = %d\n",
203 //depth, count, bytes_per_char, bytes_per_line, num_chars, char_line_bytes);
204         int i;
205
206         switch (depth)
207         {
208         case 2:
209             for (i = 0; i < count; i += inc, base += char_line_bytes, 
210                  inc = char_line_bytes, char_count = num_chars)
211             {
212                 uint8 *line = base + (num_chars - char_count) * 2;
213                 for (uint32 j = 0; j < char_count && p - buffer < count; 
214                      j++, line += 2)
215                 {
216                     uint8 *q = line;
217                     for (int l = 0; l < 8; l++, q += bytes_per_line)
218                     {
219                         for (int b = 0; b < 2; b++)
220                         {
221                             uint8 r = *(q + b);
222                             *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1);
223                             *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1);
224                             *(p + 0) = (*(p + 0) << 1) | ((r >> 2) & 1);
225                             *(p + 1) = (*(p + 1) << 1) | ((r >> 3) & 1);
226                             *(p + 0) = (*(p + 0) << 1) | ((r >> 4) & 1);
227                             *(p + 1) = (*(p + 1) << 1) | ((r >> 5) & 1);
228                             *(p + 0) = (*(p + 0) << 1) | ((r >> 6) & 1);
229                             *(p + 1) = (*(p + 1) << 1) | ((r >> 7) & 1);
230                         }
231                         p += 2;
232                     }
233                 }
234             }
235             break;
236         case 4:
237             for (i = 0; i < count; i += inc, base += char_line_bytes, 
238                  inc = char_line_bytes, char_count = num_chars)
239             {
240                 uint8 *line = base + (num_chars - char_count) * 4;
241                 for (uint32 j = 0; j < char_count && p - buffer < count; 
242                      j++, line += 4)
243                 {
244                     uint8 *q = line;
245                     for (int l = 0; l < 8; l++, q += bytes_per_line)
246                     {
247                         for (int b = 0; b < 4; b++)
248                         {
249                             uint8 r = *(q + b);
250                             *(p +  0) = (*(p +  0) << 1) | ((r >> 0) & 1);
251                             *(p +  1) = (*(p +  1) << 1) | ((r >> 1) & 1);
252                             *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1);
253                             *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1);
254                             *(p +  0) = (*(p +  0) << 1) | ((r >> 4) & 1);
255                             *(p +  1) = (*(p +  1) << 1) | ((r >> 5) & 1);
256                             *(p + 16) = (*(p + 16) << 1) | ((r >> 6) & 1);
257                             *(p + 17) = (*(p + 17) << 1) | ((r >> 7) & 1);
258                         }
259                         p += 2;
260                     }
261                     p += 32 - 16;
262                 }
263             }
264             break;
265         case 8:
266             for (i = 0; i < count; i += inc, base += char_line_bytes, 
267                  inc = char_line_bytes, char_count = num_chars)
268             {
269                 uint8 *line = base + (num_chars - char_count) * 8;
270                 for (uint32 j = 0; j < char_count && p - buffer < count; 
271                      j++, line += 8)
272                 {
273                     uint8 *q = line;
274                     for (int l = 0; l < 8; l++, q += bytes_per_line)
275                     {
276                         for (int b = 0; b < 8; b++)
277                         {
278                             uint8 r = *(q + b);
279                             *(p +  0) = (*(p +  0) << 1) | ((r >> 0) & 1);
280                             *(p +  1) = (*(p +  1) << 1) | ((r >> 1) & 1);
281                             *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1);
282                             *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1);
283                             *(p + 32) = (*(p + 32) << 1) | ((r >> 4) & 1);
284                             *(p + 33) = (*(p + 33) << 1) | ((r >> 5) & 1);
285                             *(p + 48) = (*(p + 48) << 1) | ((r >> 6) & 1);
286                             *(p + 49) = (*(p + 49) << 1) | ((r >> 7) & 1);
287                         }
288                         p += 2;
289                     }
290                     p += 64 - 16;
291                 }
292             }
293             break;
294         }
295     }
296
297 #ifdef DEBUGGER
298     if (Settings.TraceDMA)
299     {
300         sprintf (String, "DMA[%d]: %s Mode: %d 0x%02X%04X->0x21%02X Bytes: %d (%s) V-Line:%ld",
301                 Channel, d->TransferDirection ? "read" : "write",
302                 d->TransferMode, d->ABank, d->AAddress,
303                 d->BAddress, d->TransferBytes,
304                 d->AAddressFixed ? "fixed" :
305                 (d->AAddressDecrement ? "dec" : "inc"),
306                 CPU.V_Counter);
307         if (d->BAddress == 0x18 || d->BAddress == 0x19)
308             sprintf (String, "%s VRAM: %04X (%d,%d) %s", String,
309                      PPU.VMA.Address,
310                      PPU.VMA.Increment, PPU.VMA.FullGraphicCount,
311                      PPU.VMA.High ? "word" : "byte");
312         else
313         if (d->BAddress == 0x22)
314             sprintf (String, "%s CGRAM: %02X (%x)", String, PPU.CGADD,
315                      PPU.CGFLIP);
316         else
317         if (d->BAddress == 0x04)
318             sprintf (String, "%s OBJADDR: %04X", String, PPU.OAMAddr);
319         S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String);
320     }
321 #endif
322
323     if (!d->TransferDirection)
324     {
325 #ifdef VAR_CYCLES
326         CPU.Cycles += 8 * count;
327 #else
328         CPU.Cycles += count + (count >> 2);
329 #endif
330         uint8 *base = GetBasePointer ((d->ABank << 16) + d->AAddress);
331         uint16 p = d->AAddress;
332
333         if (!base)
334             base = Memory.ROM;
335
336         if (in_sa1_dma)
337         {
338             base = &Memory.ROM [CMemory::MAX_ROM_SIZE - 0x10000];
339             p = 0;
340         }
341
342         if (in_sdd1_dma)
343         {
344             base = in_sdd1_dma;
345             p = 0;
346         }
347
348         if (inc > 0)
349             d->AAddress += count;
350         else
351         if (inc < 0)
352             d->AAddress -= count;
353
354         if (d->TransferMode == 0 || d->TransferMode == 2)
355         {
356             switch (d->BAddress)
357             {
358             case 0x04:
359                 do
360                 {
361                     Work = *(base + p);
362                     REGISTER_2104(Work);
363                     p += inc;
364                     CHECK_SOUND();
365                 } while (--count > 0);
366                 break;
367             case 0x18:
368                 IPPU.FirstVRAMRead = TRUE;
369                 if (!PPU.VMA.FullGraphicCount)
370                 {
371                     do
372                     {
373                         Work = *(base + p);
374                         REGISTER_2118_linear(Work);
375                         p += inc;
376                         CHECK_SOUND();
377                     } while (--count > 0);
378                 }
379                 else
380                 {
381                     do
382                     {
383                         Work = *(base + p);
384                         REGISTER_2118_tile(Work);
385                         p += inc;
386                         CHECK_SOUND();
387                     } while (--count > 0);
388                 }
389                 break;
390             case 0x19:
391                 IPPU.FirstVRAMRead = TRUE;
392                 if (!PPU.VMA.FullGraphicCount)
393                 {
394                     do
395                     {
396                         Work = *(base + p);
397                         REGISTER_2119_linear(Work);
398                         p += inc;
399                         CHECK_SOUND();
400                     } while (--count > 0);
401                 }
402                 else
403                 {
404                     do
405                     {
406                         Work = *(base + p);
407                         REGISTER_2119_tile(Work);
408                         p += inc;
409                         CHECK_SOUND();
410                     } while (--count > 0);
411                 }
412                 break;
413             case 0x22:
414                 do
415                 {
416                     Work = *(base + p);
417                     REGISTER_2122(Work);
418                     p += inc;
419                     CHECK_SOUND();
420                 } while (--count > 0);
421                 break;
422             case 0x80:
423                 do
424                 {
425                     Work = *(base + p);
426                     REGISTER_2180(Work);
427                     p += inc;
428                     CHECK_SOUND();
429                 } while (--count > 0);
430                 break;
431             default:
432                 do
433                 {
434                     Work = *(base + p);
435                     S9xSetPPU (Work, 0x2100 + d->BAddress);
436                     p += inc;
437                     CHECK_SOUND();
438                 } while (--count > 0);
439                 break;
440             }
441         }
442         else
443         if (d->TransferMode == 1 || d->TransferMode == 5)
444         {
445             if (d->BAddress == 0x18)
446             {
447                 // Write to V-RAM
448                 IPPU.FirstVRAMRead = TRUE;
449                 if (!PPU.VMA.FullGraphicCount)
450                 {
451                     while (count > 1)
452                     {
453                         Work = *(base + p);
454                         REGISTER_2118_linear(Work);
455                         p += inc;
456
457                         Work = *(base + p);
458                         REGISTER_2119_linear(Work);
459                         p += inc;
460                         CHECK_SOUND();
461                         count -= 2;
462                     }
463                     if (count == 1)
464                     {
465                         Work = *(base + p);
466                         REGISTER_2118_linear(Work);
467                         p += inc;
468                     }
469                 }
470                 else
471                 {
472                     while (count > 1)
473                     {
474                         Work = *(base + p);
475                         REGISTER_2118_tile(Work);
476                         p += inc;
477
478                         Work = *(base + p);
479                         REGISTER_2119_tile(Work);
480                         p += inc;
481                         CHECK_SOUND();
482                         count -= 2;
483                     }
484                     if (count == 1)
485                     {
486                         Work = *(base + p);
487                         REGISTER_2118_tile(Work);
488                         p += inc;
489                     }
490                 }
491             }
492             else
493             {
494                 // DMA mode 1 general case
495                 while (count > 1)
496                 {
497                     Work = *(base + p);
498                     S9xSetPPU (Work, 0x2100 + d->BAddress);
499                     p += inc;
500
501                     Work = *(base + p);
502                     S9xSetPPU (Work, 0x2101 + d->BAddress);
503                     p += inc;
504                     CHECK_SOUND();
505                     count -= 2;
506                 }
507                 if (count == 1)
508                 {
509                     Work = *(base + p);
510                     S9xSetPPU (Work, 0x2100 + d->BAddress);
511                     p += inc;
512                 }
513             }
514         }
515         else
516         if (d->TransferMode == 3)
517         {
518             do
519             {
520                 Work = *(base + p);
521                 S9xSetPPU (Work, 0x2100 + d->BAddress);
522                 p += inc;
523                 if (count <= 1)
524                     break;
525
526                 Work = *(base + p);
527                 S9xSetPPU (Work, 0x2100 + d->BAddress);
528                 p += inc;
529                 if (count <= 2)
530                     break;
531
532                 Work = *(base + p);
533                 S9xSetPPU (Work, 0x2101 + d->BAddress);
534                 p += inc;
535                 if (count <= 3)
536                     break;
537
538                 Work = *(base + p);
539                 S9xSetPPU (Work, 0x2101 + d->BAddress);
540                 p += inc;
541                 CHECK_SOUND();
542                 count -= 4;
543             } while (count > 0);
544         }
545         else
546         if (d->TransferMode == 4)
547         {
548             do
549             {
550                 Work = *(base + p);
551                 S9xSetPPU (Work, 0x2100 + d->BAddress);
552                 p += inc;
553                 if (count <= 1)
554                     break;
555
556                 Work = *(base + p);
557                 S9xSetPPU (Work, 0x2101 + d->BAddress);
558                 p += inc;
559                 if (count <= 2)
560                     break;
561
562                 Work = *(base + p);
563                 S9xSetPPU (Work, 0x2102 + d->BAddress);
564                 p += inc;
565                 if (count <= 3)
566                     break;
567
568                 Work = *(base + p);
569                 S9xSetPPU (Work, 0x2103 + d->BAddress);
570                 p += inc;
571                 CHECK_SOUND();
572                 count -= 4;
573             } while (count > 0);
574         }
575         else
576         {
577 #ifdef DEBUGGER
578 //          if (Settings.TraceDMA)
579             {
580                 sprintf (String, "Unknown DMA transfer mode: %d on channel %d\n",
581                          d->TransferMode, Channel);
582                 S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String);
583             }
584 #endif
585         }
586     }
587     else
588     {
589         do
590         {
591             switch (d->TransferMode)
592             {
593             case 0:
594             case 2:
595 #ifndef VAR_CYCLES
596                 CPU.Cycles += 1;
597 #endif
598                 Work = S9xGetPPU (0x2100 + d->BAddress);
599                 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
600                 d->AAddress += inc;
601                 --count;
602                 break;
603
604             case 1:
605             case 5:
606 #ifndef VAR_CYCLES
607                 CPU.Cycles += 3;
608 #endif
609                 Work = S9xGetPPU (0x2100 + d->BAddress);
610                 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
611                 d->AAddress += inc;
612                 if (!--count)
613                     break;
614
615                 Work = S9xGetPPU (0x2101 + d->BAddress);
616                 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
617                 d->AAddress += inc;
618                 count--;
619                 break;
620                 
621             case 3:
622 #ifndef VAR_CYCLES
623                 CPU.Cycles += 6;
624 #endif
625                 Work = S9xGetPPU (0x2100 + d->BAddress);
626                 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
627                 d->AAddress += inc;
628                 if (!--count)
629                     break;
630                     
631                 Work = S9xGetPPU (0x2100 + d->BAddress);
632                 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
633                 d->AAddress += inc;
634                 if (!--count)
635                     break;
636                     
637                 Work = S9xGetPPU (0x2101 + d->BAddress);
638                 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
639                 d->AAddress += inc;
640                 if (!--count)
641                     break;
642                     
643                 Work = S9xGetPPU (0x2101 + d->BAddress);
644                 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
645                 d->AAddress += inc;
646                 count--;
647                 break;
648
649             case 4:
650 #ifndef VAR_CYCLES
651                 CPU.Cycles += 6;
652 #endif
653                 Work = S9xGetPPU (0x2100 + d->BAddress);
654                 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
655                 d->AAddress += inc;
656                 if (!--count)
657                     break;
658                     
659                 Work = S9xGetPPU (0x2101 + d->BAddress);
660                 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
661                 d->AAddress += inc;
662                 if (!--count)
663                     break;
664
665                 Work = S9xGetPPU (0x2102 + d->BAddress);
666                 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
667                 d->AAddress += inc;
668                 if (!--count)
669                     break;
670                     
671                 Work = S9xGetPPU (0x2103 + d->BAddress);
672                 S9xSetByte (Work, (d->ABank << 16) + d->AAddress);
673                 d->AAddress += inc;
674                 count--;
675                 break;
676
677             default:
678 #ifdef DEBUGGER
679                 if (1) //Settings.TraceDMA)
680                 {
681                     sprintf (String, "Unknown DMA transfer mode: %d on channel %d\n",
682                              d->TransferMode, Channel);
683                     S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String);
684                 }
685 #endif
686                 count = 0;
687                 break;
688             }
689             CHECK_SOUND();
690         } while (count);
691     }
692     
693 #ifdef SPC700_C
694 #ifdef SPC700_SHUTDOWN          
695     CPU.APU_APUExecuting = Settings.APUEnabled;
696 #endif
697         APU_EXECUTE(1); // execute but only in normal mode
698 #endif
699     while (CPU.Cycles > CPU.NextEvent)
700         S9xDoHBlankProcessing ();
701
702     // Super Punch-Out requires that the A-BUS address be updated after the
703     // DMA transfer.
704     Memory.FillRAM[0x4302 + (Channel << 4)] = (uint8) d->AAddress;
705     Memory.FillRAM[0x4303 + (Channel << 4)] = d->AAddress >> 8;
706
707     // Secret of the Mana requires that the DMA bytes transfer count be set to
708     // zero when DMA has completed.
709     Memory.FillRAM [0x4305 + (Channel << 4)] = 0;
710     Memory.FillRAM [0x4306 + (Channel << 4)] = 0;
711
712     DMA[Channel].IndirectAddress = 0;
713     d->TransferBytes = 0;
714     
715     CPU.InDMA = FALSE;
716 }
717
718 void S9xStartHDMA ()
719 {
720     if (Settings.DisableHDMA)
721         IPPU.HDMA = 0;
722     else
723         missing.hdma_this_frame = IPPU.HDMA = Memory.FillRAM [0x420c];
724
725     IPPU.HDMAStarted = TRUE;
726
727     for (uint8 i = 0; i < 8; i++)
728     {
729         if (IPPU.HDMA & (1 << i))
730         {
731             DMA [i].LineCount = 0;
732             DMA [i].FirstLine = TRUE;
733             DMA [i].Address = DMA [i].AAddress;
734         }
735         HDMAMemPointers [i] = NULL;
736     }
737 }
738
739 #ifdef DEBUGGER
740 void S9xTraceSoundDSP (const char *s, int i1 = 0, int i2 = 0, int i3 = 0,
741                        int i4 = 0, int i5 = 0, int i6 = 0, int i7 = 0);
742 #endif
743
744
745 uint8 S9xDoHDMA (uint8 byte)
746 {
747     struct SDMA *p = &DMA [0];
748     
749     int d = 0;
750
751     for (uint8 mask = 1; mask; mask <<= 1, p++, d++)
752     {
753         if (byte & mask)
754         {
755             if (!p->LineCount)
756             {
757                 uint8 line = S9xGetByte ((p->ABank << 16) + p->Address);
758                 if (line == 0x80)
759                 {
760                     p->Repeat = TRUE;
761                     p->LineCount = 128;
762                 }
763                 else
764                 {
765                     p->Repeat = !(line & 0x80);
766                     p->LineCount = line & 0x7f;
767                 }
768                 
769                 // Disable H-DMA'ing into V-RAM (register 2118) for Hook
770                 if (!p->LineCount || p->BAddress == 0x18)
771                 {
772                     byte &= ~mask;
773                     p->IndirectAddress += HDMAMemPointers [d] - HDMABasePointers [d];
774                     Memory.FillRAM [0x4305 + (d << 4)] = (uint8) p->IndirectAddress;
775                     Memory.FillRAM [0x4306 + (d << 4)] = p->IndirectAddress >> 8;
776                     continue;
777                 }
778
779                 p->Address++;
780                 p->FirstLine = 1;
781                 if (p->HDMAIndirectAddressing)
782                 {
783                     p->IndirectBank = Memory.FillRAM [0x4307 + ((p - DMA) << 4)];
784                     p->IndirectAddress = S9xGetWord ((p->ABank << 16) + p->Address);
785                     p->Address += 2;
786                 }
787                 else
788                 {
789                     p->IndirectBank = p->ABank;
790                     p->IndirectAddress = p->Address;
791                 }
792                 HDMABasePointers [d] = HDMAMemPointers [d] = 
793                                     S9xGetMemPointer ((p->IndirectBank << 16) + p->IndirectAddress);
794             }
795             if (!HDMAMemPointers [d])
796             {
797                 if (!(HDMABasePointers [d] = HDMAMemPointers [d] = 
798                         S9xGetMemPointer ((p->IndirectBank << 16) + p->IndirectAddress)))
799                 {
800                     byte &= ~mask;
801                     continue;
802                 }
803                 // Uncommenting the following line breaks Punchout - it starts
804                 // H-DMA during the frame.
805                 //p->FirstLine = TRUE;
806             }
807             if (p->Repeat && !p->FirstLine)
808             {
809                 p->LineCount--;
810                 continue;
811             }
812
813 #ifdef DEBUGGER
814             if (Settings.TraceSoundDSP && p->FirstLine && 
815                 p->BAddress >= 0x40 && p->BAddress <= 0x43)
816                 S9xTraceSoundDSP ("Spooling data!!!\n");
817
818             if (Settings.TraceHDMA && p->FirstLine)
819             {
820                 sprintf (String, "H-DMA[%d] (%d) 0x%02X%04X->0x21%02X %s, Count: %3d, Rep: %s, V-LINE: %3ld %02X%04X",
821                          p-DMA, p->TransferMode, p->IndirectBank,
822                          p->IndirectAddress,
823                          p->BAddress,
824                          p->HDMAIndirectAddressing ? "ind" : "abs",
825                          p->LineCount,
826                          p->Repeat ? "yes" : "no ", CPU.V_Counter,
827                          p->ABank, p->Address);
828                 S9xMessage (S9X_TRACE, S9X_HDMA_TRACE, String);
829             }
830 #endif
831             switch (p->TransferMode)
832             {
833             case 0:
834 #ifndef VAR_CYCLES
835                 CPU.Cycles += 1;
836 #else
837                 CPU.Cycles += 8;
838 #endif
839                 S9xSetPPU (*HDMAMemPointers [d]++, 0x2100 + p->BAddress);
840                 break;
841             case 1:
842             case 5:
843 #ifndef VAR_CYCLES
844                 CPU.Cycles += 3;
845 #else
846                 CPU.Cycles += 16;
847 #endif
848                 S9xSetPPU (*(HDMAMemPointers [d] + 0), 0x2100 + p->BAddress);
849                 S9xSetPPU (*(HDMAMemPointers [d] + 1), 0x2101 + p->BAddress);
850                 HDMAMemPointers [d] += 2;
851                 break;
852             case 2:
853             case 6:
854 #ifndef VAR_CYCLES
855                 CPU.Cycles += 3;
856 #else
857                 CPU.Cycles += 16;
858 #endif
859                 S9xSetPPU (*(HDMAMemPointers [d] + 0), 0x2100 + p->BAddress);
860                 S9xSetPPU (*(HDMAMemPointers [d] + 1), 0x2100 + p->BAddress);
861                 HDMAMemPointers [d] += 2;
862                 break;
863             case 3:
864             case 7:
865 #ifndef VAR_CYCLES
866                 CPU.Cycles += 6;
867 #else
868                 CPU.Cycles += 32;
869 #endif
870                 S9xSetPPU (*(HDMAMemPointers [d] + 0), 0x2100 + p->BAddress);
871                 S9xSetPPU (*(HDMAMemPointers [d] + 1), 0x2100 + p->BAddress);
872                 S9xSetPPU (*(HDMAMemPointers [d] + 2), 0x2101 + p->BAddress);
873                 S9xSetPPU (*(HDMAMemPointers [d] + 3), 0x2101 + p->BAddress);
874                 HDMAMemPointers [d] += 4;
875                 break;
876             case 4:
877 #ifndef VAR_CYCLES
878                 CPU.Cycles += 6;
879 #else
880                 CPU.Cycles += 32;
881 #endif
882                 S9xSetPPU (*(HDMAMemPointers [d] + 0), 0x2100 + p->BAddress);
883                 S9xSetPPU (*(HDMAMemPointers [d] + 1), 0x2101 + p->BAddress);
884                 S9xSetPPU (*(HDMAMemPointers [d] + 2), 0x2102 + p->BAddress);
885                 S9xSetPPU (*(HDMAMemPointers [d] + 3), 0x2103 + p->BAddress);
886                 HDMAMemPointers [d] += 4;
887                 break;
888             }
889             if (!p->HDMAIndirectAddressing)
890                 p->Address += HDMA_ModeByteCounts [p->TransferMode];
891             p->FirstLine = FALSE;
892             p->LineCount--;
893         }
894     }
895     return (byte);
896 }
897
898 void S9xResetDMA ()
899 {
900     int d;
901     for (d = 0; d < 8; d++)
902     {
903         DMA [d].TransferDirection = FALSE;
904         DMA [d].HDMAIndirectAddressing = FALSE;
905         DMA [d].AAddressFixed = TRUE;
906         DMA [d].AAddressDecrement = FALSE;
907         DMA [d].TransferMode = 0xff;
908         DMA [d].ABank = 0xff;
909         DMA [d].AAddress = 0xffff;
910         DMA [d].Address = 0xffff;
911         DMA [d].BAddress = 0xff;
912         DMA [d].TransferBytes = 0xffff;
913     }
914     for (int c = 0x4300; c < 0x4380; c += 0x10)
915     {
916         for (d = c; d < c + 12; d++)
917             Memory.FillRAM [d] = 0xff;
918
919         Memory.FillRAM [c + 0xf] = 0xff;
920     }
921 }