Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
RishiRecon
GitHub Repository: RishiRecon/exploits
Path: blob/main/misc/emulator/xnes/snes9x/dma.cpp
28515 views
1
/***********************************************************************************
2
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3
4
(c) Copyright 1996 - 2002 Gary Henderson ([email protected]),
5
Jerremy Koot ([email protected])
6
7
(c) Copyright 2002 - 2004 Matthew Kendora
8
9
(c) Copyright 2002 - 2005 Peter Bortas ([email protected])
10
11
(c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
12
13
(c) Copyright 2001 - 2006 John Weidman ([email protected])
14
15
(c) Copyright 2002 - 2006 funkyass ([email protected]),
16
Kris Bleakley ([email protected])
17
18
(c) Copyright 2002 - 2010 Brad Jorsch ([email protected]),
19
Nach ([email protected]),
20
21
(c) Copyright 2002 - 2011 zones ([email protected])
22
23
(c) Copyright 2006 - 2007 nitsuja
24
25
(c) Copyright 2009 - 2011 BearOso,
26
OV2
27
28
29
BS-X C emulator code
30
(c) Copyright 2005 - 2006 Dreamer Nom,
31
zones
32
33
C4 x86 assembler and some C emulation code
34
(c) Copyright 2000 - 2003 _Demo_ ([email protected]),
35
Nach,
36
zsKnight ([email protected])
37
38
C4 C++ code
39
(c) Copyright 2003 - 2006 Brad Jorsch,
40
Nach
41
42
DSP-1 emulator code
43
(c) Copyright 1998 - 2006 _Demo_,
44
Andreas Naive ([email protected]),
45
Gary Henderson,
46
Ivar ([email protected]),
47
John Weidman,
48
Kris Bleakley,
49
Matthew Kendora,
50
Nach,
51
neviksti ([email protected])
52
53
DSP-2 emulator code
54
(c) Copyright 2003 John Weidman,
55
Kris Bleakley,
56
Lord Nightmare ([email protected]),
57
Matthew Kendora,
58
neviksti
59
60
DSP-3 emulator code
61
(c) Copyright 2003 - 2006 John Weidman,
62
Kris Bleakley,
63
Lancer,
64
z80 gaiden
65
66
DSP-4 emulator code
67
(c) Copyright 2004 - 2006 Dreamer Nom,
68
John Weidman,
69
Kris Bleakley,
70
Nach,
71
z80 gaiden
72
73
OBC1 emulator code
74
(c) Copyright 2001 - 2004 zsKnight,
75
pagefault ([email protected]),
76
Kris Bleakley
77
Ported from x86 assembler to C by sanmaiwashi
78
79
SPC7110 and RTC C++ emulator code used in 1.39-1.51
80
(c) Copyright 2002 Matthew Kendora with research by
81
zsKnight,
82
John Weidman,
83
Dark Force
84
85
SPC7110 and RTC C++ emulator code used in 1.52+
86
(c) Copyright 2009 byuu,
87
neviksti
88
89
S-DD1 C emulator code
90
(c) Copyright 2003 Brad Jorsch with research by
91
Andreas Naive,
92
John Weidman
93
94
S-RTC C emulator code
95
(c) Copyright 2001 - 2006 byuu,
96
John Weidman
97
98
ST010 C++ emulator code
99
(c) Copyright 2003 Feather,
100
John Weidman,
101
Kris Bleakley,
102
Matthew Kendora
103
104
Super FX x86 assembler emulator code
105
(c) Copyright 1998 - 2003 _Demo_,
106
pagefault,
107
zsKnight
108
109
Super FX C emulator code
110
(c) Copyright 1997 - 1999 Ivar,
111
Gary Henderson,
112
John Weidman
113
114
Sound emulator code used in 1.5-1.51
115
(c) Copyright 1998 - 2003 Brad Martin
116
(c) Copyright 1998 - 2006 Charles Bilyue'
117
118
Sound emulator code used in 1.52+
119
(c) Copyright 2004 - 2007 Shay Green ([email protected])
120
121
SH assembler code partly based on x86 assembler code
122
(c) Copyright 2002 - 2004 Marcus Comstedt ([email protected])
123
124
2xSaI filter
125
(c) Copyright 1999 - 2001 Derek Liauw Kie Fa
126
127
HQ2x, HQ3x, HQ4x filters
128
(c) Copyright 2003 Maxim Stepin ([email protected])
129
130
NTSC filter
131
(c) Copyright 2006 - 2007 Shay Green
132
133
GTK+ GUI code
134
(c) Copyright 2004 - 2011 BearOso
135
136
Win32 GUI code
137
(c) Copyright 2003 - 2006 blip,
138
funkyass,
139
Matthew Kendora,
140
Nach,
141
nitsuja
142
(c) Copyright 2009 - 2011 OV2
143
144
Mac OS GUI code
145
(c) Copyright 1998 - 2001 John Stiles
146
(c) Copyright 2001 - 2011 zones
147
148
149
Specific ports contains the works of other authors. See headers in
150
individual files.
151
152
153
Snes9x homepage: http://www.snes9x.com/
154
155
Permission to use, copy, modify and/or distribute Snes9x in both binary
156
and source form, for non-commercial purposes, is hereby granted without
157
fee, providing that this license information and copyright notice appear
158
with all copies and any derived work.
159
160
This software is provided 'as-is', without any express or implied
161
warranty. In no event shall the authors be held liable for any damages
162
arising from the use of this software or it's derivatives.
163
164
Snes9x is freeware for PERSONAL USE only. Commercial users should
165
seek permission of the copyright holders first. Commercial use includes,
166
but is not limited to, charging money for Snes9x or software derived from
167
Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
168
using Snes9x as a promotion for your commercial product.
169
170
The copyright holders request that bug fixes and improvements to the code
171
should be forwarded to them so everyone can benefit from the modifications
172
in future versions.
173
174
Super NES and Super Nintendo Entertainment System are trademarks of
175
Nintendo Co., Limited and its subsidiary companies.
176
***********************************************************************************/
177
178
179
#include "snes9x.h"
180
#include "memmap.h"
181
#include "dma.h"
182
#include "apu/apu.h"
183
#include "sdd1emu.h"
184
#include "spc7110emu.h"
185
#ifdef DEBUGGER
186
#include "missing.h"
187
#endif
188
189
#define ADD_CYCLES(n) { CPU.PrevCycles = CPU.Cycles; CPU.Cycles += (n); S9xCheckInterrupts(); }
190
191
extern uint8 *HDMAMemPointers[8];
192
extern int HDMA_ModeByteCounts[8];
193
extern SPC7110 s7emu;
194
195
static uint8 sdd1_decode_buffer[0x10000];
196
197
static inline bool8 addCyclesInDMA (uint8);
198
static inline bool8 HDMAReadLineCount (int);
199
200
201
static inline bool8 addCyclesInDMA (uint8 dma_channel)
202
{
203
// Add 8 cycles per byte, sync APU, and do HC related events.
204
// If HDMA was done in S9xDoHEventProcessing(), check if it used the same channel as DMA.
205
ADD_CYCLES(SLOW_ONE_CYCLE);
206
while (CPU.Cycles >= CPU.NextEvent)
207
S9xDoHEventProcessing();
208
209
if (CPU.HDMARanInDMA & (1 << dma_channel))
210
{
211
CPU.HDMARanInDMA = 0;
212
#ifdef DEBUGGER
213
printf("HDMA and DMA use the same channel %d!\n", dma_channel);
214
#endif
215
// If HDMA triggers in the middle of DMA transfer and it uses the same channel,
216
// it kills the DMA transfer immediately. $43x2 and $43x5 stop updating.
217
return (FALSE);
218
}
219
220
CPU.HDMARanInDMA = 0;
221
return (TRUE);
222
}
223
224
bool8 S9xDoDMA (uint8 Channel)
225
{
226
CPU.InDMA = TRUE;
227
CPU.InDMAorHDMA = TRUE;
228
CPU.CurrentDMAorHDMAChannel = Channel;
229
230
SDMA *d = &DMA[Channel];
231
232
// Check invalid DMA first
233
if ((d->ABank == 0x7E || d->ABank == 0x7F) && d->BAddress == 0x80 && !d->ReverseTransfer)
234
{
235
// Attempting a DMA from WRAM to $2180 will not work, WRAM will not be written.
236
// Attempting a DMA from $2180 to WRAM will similarly not work,
237
// the value written is (initially) the OpenBus value.
238
// In either case, the address in $2181-3 is not incremented.
239
240
// Does an invalid DMA actually take time?
241
// I'd say yes, since 'invalid' is probably just the WRAM chip
242
// not being able to read and write itself at the same time
243
// And no, PPU.WRAM should not be updated.
244
245
int32 c = d->TransferBytes;
246
// Writing $0000 to $43x5 actually results in a transfer of $10000 bytes, not 0.
247
if (c == 0)
248
c = 0x10000;
249
250
// 8 cycles per channel
251
ADD_CYCLES(SLOW_ONE_CYCLE);
252
// 8 cycles per byte
253
while (c)
254
{
255
d->TransferBytes--;
256
d->AAddress++;
257
c--;
258
if (!addCyclesInDMA(Channel))
259
{
260
CPU.InDMA = FALSE;
261
CPU.InDMAorHDMA = FALSE;
262
CPU.CurrentDMAorHDMAChannel = -1;
263
return (FALSE);
264
}
265
}
266
267
#ifdef DEBUGGER
268
if (Settings.TraceDMA)
269
{
270
sprintf(String, "DMA[%d]: WRAM Bank:%02X->$2180", Channel, d->ABank);
271
S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String);
272
}
273
#endif
274
275
CPU.InDMA = FALSE;
276
CPU.InDMAorHDMA = FALSE;
277
CPU.CurrentDMAorHDMAChannel = -1;
278
return (TRUE);
279
}
280
281
// Prepare for accessing $2118-2119
282
switch (d->BAddress)
283
{
284
case 0x18:
285
case 0x19:
286
if (IPPU.RenderThisFrame)
287
FLUSH_REDRAW();
288
break;
289
}
290
291
int32 inc = d->AAddressFixed ? 0 : (!d->AAddressDecrement ? 1 : -1);
292
int32 count = d->TransferBytes;
293
// Writing $0000 to $43x5 actually results in a transfer of $10000 bytes, not 0.
294
if (count == 0)
295
count = 0x10000;
296
297
// Prepare for custom chip DMA
298
299
// S-DD1
300
301
uint8 *in_sdd1_dma = NULL;
302
303
if (Settings.SDD1)
304
{
305
if (d->AAddressFixed && Memory.FillRAM[0x4801] > 0)
306
{
307
// XXX: Should probably verify that we're DMAing from ROM?
308
// And somewhere we should make sure we're not running across a mapping boundary too.
309
// Hacky support for pre-decompressed S-DD1 data
310
inc = !d->AAddressDecrement ? 1 : -1;
311
312
uint8 *in_ptr = S9xGetBasePointer(((d->ABank << 16) | d->AAddress));
313
if (in_ptr)
314
{
315
in_ptr += d->AAddress;
316
SDD1_decompress(sdd1_decode_buffer, in_ptr, d->TransferBytes);
317
}
318
#ifdef DEBUGGER
319
else
320
{
321
sprintf(String, "S-DD1: DMA from non-block address $%02X:%04X", d->ABank, d->AAddress);
322
S9xMessage(S9X_WARNING, S9X_DMA_TRACE, String);
323
}
324
#endif
325
326
in_sdd1_dma = sdd1_decode_buffer;
327
}
328
329
Memory.FillRAM[0x4801] = 0;
330
}
331
332
// SPC7110
333
334
uint8 *spc7110_dma = NULL;
335
336
if (Settings.SPC7110)
337
{
338
if (d->AAddress == 0x4800 || d->ABank == 0x50)
339
{
340
spc7110_dma = new uint8[d->TransferBytes];
341
for (int i = 0; i < d->TransferBytes; i++)
342
spc7110_dma[i] = s7emu.decomp.read();
343
344
int32 icount = s7emu.r4809 | (s7emu.r480a << 8);
345
icount -= d->TransferBytes;
346
s7emu.r4809 = icount & 0x00ff;
347
s7emu.r480a = (icount & 0xff00) >> 8;
348
349
inc = 1;
350
d->AAddress -= count;
351
}
352
}
353
354
// SA-1
355
356
bool8 in_sa1_dma = FALSE;
357
358
if (Settings.SA1)
359
{
360
if (SA1.in_char_dma && d->BAddress == 0x18 && (d->ABank & 0xf0) == 0x40)
361
{
362
// Perform packed bitmap to PPU character format conversion on the data
363
// before transmitting it to V-RAM via-DMA.
364
int32 num_chars = 1 << ((Memory.FillRAM[0x2231] >> 2) & 7);
365
int32 depth = (Memory.FillRAM[0x2231] & 3) == 0 ? 8 : (Memory.FillRAM[0x2231] & 3) == 1 ? 4 : 2;
366
int32 bytes_per_char = 8 * depth;
367
int32 bytes_per_line = depth * num_chars;
368
int32 char_line_bytes = bytes_per_char * num_chars;
369
uint32 addr = (d->AAddress / char_line_bytes) * char_line_bytes;
370
371
uint8 *base = S9xGetBasePointer((d->ABank << 16) + addr);
372
if (!base)
373
{
374
sprintf(String, "SA-1: DMA from non-block address $%02X:%04X", d->ABank, addr);
375
S9xMessage(S9X_WARNING, S9X_DMA_TRACE, String);
376
base = Memory.ROM;
377
}
378
379
base += addr;
380
381
uint8 *buffer = &Memory.ROM[CMemory::MAX_ROM_SIZE - 0x10000];
382
uint8 *p = buffer;
383
uint32 inc_sa1 = char_line_bytes - (d->AAddress % char_line_bytes);
384
uint32 char_count = inc_sa1 / bytes_per_char;
385
386
in_sa1_dma = TRUE;
387
388
#if 0
389
printf("SA-1 DMA: %08x,", base);
390
printf("depth = %d, count = %d, bytes_per_char = %d, bytes_per_line = %d, num_chars = %d, char_line_bytes = %d\n",
391
depth, count, bytes_per_char, bytes_per_line, num_chars, char_line_bytes);
392
#endif
393
394
switch (depth)
395
{
396
case 2:
397
for (int32 i = 0; i < count; i += inc_sa1, base += char_line_bytes, inc_sa1 = char_line_bytes, char_count = num_chars)
398
{
399
uint8 *line = base + (num_chars - char_count) * 2;
400
for (uint32 j = 0; j < char_count && p - buffer < count; j++, line += 2)
401
{
402
uint8 *q = line;
403
for (int32 l = 0; l < 8; l++, q += bytes_per_line)
404
{
405
for (int32 b = 0; b < 2; b++)
406
{
407
uint8 r = *(q + b);
408
*(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1);
409
*(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1);
410
*(p + 0) = (*(p + 0) << 1) | ((r >> 2) & 1);
411
*(p + 1) = (*(p + 1) << 1) | ((r >> 3) & 1);
412
*(p + 0) = (*(p + 0) << 1) | ((r >> 4) & 1);
413
*(p + 1) = (*(p + 1) << 1) | ((r >> 5) & 1);
414
*(p + 0) = (*(p + 0) << 1) | ((r >> 6) & 1);
415
*(p + 1) = (*(p + 1) << 1) | ((r >> 7) & 1);
416
}
417
418
p += 2;
419
}
420
}
421
}
422
423
break;
424
425
case 4:
426
for (int32 i = 0; i < count; i += inc_sa1, base += char_line_bytes, inc_sa1 = char_line_bytes, char_count = num_chars)
427
{
428
uint8 *line = base + (num_chars - char_count) * 4;
429
for (uint32 j = 0; j < char_count && p - buffer < count; j++, line += 4)
430
{
431
uint8 *q = line;
432
for (int32 l = 0; l < 8; l++, q += bytes_per_line)
433
{
434
for (int32 b = 0; b < 4; b++)
435
{
436
uint8 r = *(q + b);
437
*(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1);
438
*(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1);
439
*(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1);
440
*(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1);
441
*(p + 0) = (*(p + 0) << 1) | ((r >> 4) & 1);
442
*(p + 1) = (*(p + 1) << 1) | ((r >> 5) & 1);
443
*(p + 16) = (*(p + 16) << 1) | ((r >> 6) & 1);
444
*(p + 17) = (*(p + 17) << 1) | ((r >> 7) & 1);
445
}
446
447
p += 2;
448
}
449
450
p += 32 - 16;
451
}
452
}
453
454
break;
455
456
case 8:
457
for (int32 i = 0; i < count; i += inc_sa1, base += char_line_bytes, inc_sa1 = char_line_bytes, char_count = num_chars)
458
{
459
uint8 *line = base + (num_chars - char_count) * 8;
460
for (uint32 j = 0; j < char_count && p - buffer < count; j++, line += 8)
461
{
462
uint8 *q = line;
463
for (int32 l = 0; l < 8; l++, q += bytes_per_line)
464
{
465
for (int32 b = 0; b < 8; b++)
466
{
467
uint8 r = *(q + b);
468
*(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1);
469
*(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1);
470
*(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1);
471
*(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1);
472
*(p + 32) = (*(p + 32) << 1) | ((r >> 4) & 1);
473
*(p + 33) = (*(p + 33) << 1) | ((r >> 5) & 1);
474
*(p + 48) = (*(p + 48) << 1) | ((r >> 6) & 1);
475
*(p + 49) = (*(p + 49) << 1) | ((r >> 7) & 1);
476
}
477
478
p += 2;
479
}
480
481
p += 64 - 16;
482
}
483
}
484
485
break;
486
}
487
}
488
}
489
490
#ifdef DEBUGGER
491
if (Settings.TraceDMA)
492
{
493
sprintf(String, "DMA[%d]: %s Mode:%d 0x%02X%04X->0x21%02X Bytes:%d (%s) V:%03d",
494
Channel, d->ReverseTransfer ? "PPU->CPU" : "CPU->PPU", d->TransferMode, d->ABank, d->AAddress, d->BAddress,
495
d->TransferBytes, d->AAddressFixed ? "fixed" : (d->AAddressDecrement ? "dec" : "inc"), CPU.V_Counter);
496
497
if (d->BAddress == 0x18 || d->BAddress == 0x19 || d->BAddress == 0x39 || d->BAddress == 0x3a)
498
sprintf(String, "%s VRAM: %04X (%d,%d) %s", String,
499
PPU.VMA.Address, PPU.VMA.Increment, PPU.VMA.FullGraphicCount, PPU.VMA.High ? "word" : "byte");
500
else
501
if (d->BAddress == 0x22 || d->BAddress == 0x3b)
502
sprintf(String, "%s CGRAM: %02X (%x)", String, PPU.CGADD, PPU.CGFLIP);
503
else
504
if (d->BAddress == 0x04 || d->BAddress == 0x38)
505
sprintf(String, "%s OBJADDR: %04X", String, PPU.OAMAddr);
506
507
S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String);
508
}
509
#endif
510
511
// Do Transfer
512
513
uint8 Work;
514
515
// 8 cycles per channel
516
ADD_CYCLES(SLOW_ONE_CYCLE);
517
518
if (!d->ReverseTransfer)
519
{
520
// CPU -> PPU
521
int32 b = 0;
522
uint16 p = d->AAddress;
523
uint8 *base = S9xGetBasePointer((d->ABank << 16) + d->AAddress);
524
bool8 inWRAM_DMA;
525
526
int32 rem = count;
527
// Transfer per block if d->AAdressFixed is FALSE
528
count = d->AAddressFixed ? rem : (d->AAddressDecrement ? ((p & MEMMAP_MASK) + 1) : (MEMMAP_BLOCK_SIZE - (p & MEMMAP_MASK)));
529
530
// Settings for custom chip DMA
531
if (in_sa1_dma)
532
{
533
base = &Memory.ROM[CMemory::MAX_ROM_SIZE - 0x10000];
534
p = 0;
535
count = rem;
536
}
537
else
538
if (in_sdd1_dma)
539
{
540
base = in_sdd1_dma;
541
p = 0;
542
count = rem;
543
}
544
else
545
if (spc7110_dma)
546
{
547
base = spc7110_dma;
548
p = 0;
549
count = rem;
550
}
551
552
inWRAM_DMA = ((!in_sa1_dma && !in_sdd1_dma && !spc7110_dma) &&
553
(d->ABank == 0x7e || d->ABank == 0x7f || (!(d->ABank & 0x40) && d->AAddress < 0x2000)));
554
555
// 8 cycles per byte
556
#define UPDATE_COUNTERS \
557
d->TransferBytes--; \
558
d->AAddress += inc; \
559
p += inc; \
560
if (!addCyclesInDMA(Channel)) \
561
{ \
562
CPU.InDMA = FALSE; \
563
CPU.InDMAorHDMA = FALSE; \
564
CPU.InWRAMDMAorHDMA = FALSE; \
565
CPU.CurrentDMAorHDMAChannel = -1; \
566
return (FALSE); \
567
}
568
569
while (1)
570
{
571
if (count > rem)
572
count = rem;
573
rem -= count;
574
575
CPU.InWRAMDMAorHDMA = inWRAM_DMA;
576
577
if (!base)
578
{
579
// DMA SLOW PATH
580
if (d->TransferMode == 0 || d->TransferMode == 2 || d->TransferMode == 6)
581
{
582
do
583
{
584
Work = S9xGetByte((d->ABank << 16) + p);
585
S9xSetPPU(Work, 0x2100 + d->BAddress);
586
UPDATE_COUNTERS;
587
} while (--count > 0);
588
}
589
else
590
if (d->TransferMode == 1 || d->TransferMode == 5)
591
{
592
// This is a variation on Duff's Device. It is legal C/C++.
593
switch (b)
594
{
595
default:
596
while (count > 1)
597
{
598
Work = S9xGetByte((d->ABank << 16) + p);
599
S9xSetPPU(Work, 0x2100 + d->BAddress);
600
UPDATE_COUNTERS;
601
count--;
602
603
case 1:
604
Work = S9xGetByte((d->ABank << 16) + p);
605
S9xSetPPU(Work, 0x2101 + d->BAddress);
606
UPDATE_COUNTERS;
607
count--;
608
}
609
}
610
611
if (count == 1)
612
{
613
Work = S9xGetByte((d->ABank << 16) + p);
614
S9xSetPPU(Work, 0x2100 + d->BAddress);
615
UPDATE_COUNTERS;
616
b = 1;
617
}
618
else
619
b = 0;
620
}
621
else
622
if (d->TransferMode == 3 || d->TransferMode == 7)
623
{
624
switch (b)
625
{
626
default:
627
do
628
{
629
Work = S9xGetByte((d->ABank << 16) + p);
630
S9xSetPPU(Work, 0x2100 + d->BAddress);
631
UPDATE_COUNTERS;
632
if (--count <= 0)
633
{
634
b = 1;
635
break;
636
}
637
638
case 1:
639
Work = S9xGetByte((d->ABank << 16) + p);
640
S9xSetPPU(Work, 0x2100 + d->BAddress);
641
UPDATE_COUNTERS;
642
if (--count <= 0)
643
{
644
b = 2;
645
break;
646
}
647
648
case 2:
649
Work = S9xGetByte((d->ABank << 16) + p);
650
S9xSetPPU(Work, 0x2101 + d->BAddress);
651
UPDATE_COUNTERS;
652
if (--count <= 0)
653
{
654
b = 3;
655
break;
656
}
657
658
case 3:
659
Work = S9xGetByte((d->ABank << 16) + p);
660
S9xSetPPU(Work, 0x2101 + d->BAddress);
661
UPDATE_COUNTERS;
662
if (--count <= 0)
663
{
664
b = 0;
665
break;
666
}
667
} while (1);
668
}
669
}
670
else
671
if (d->TransferMode == 4)
672
{
673
switch (b)
674
{
675
default:
676
do
677
{
678
Work = S9xGetByte((d->ABank << 16) + p);
679
S9xSetPPU(Work, 0x2100 + d->BAddress);
680
UPDATE_COUNTERS;
681
if (--count <= 0)
682
{
683
b = 1;
684
break;
685
}
686
687
case 1:
688
Work = S9xGetByte((d->ABank << 16) + p);
689
S9xSetPPU(Work, 0x2101 + d->BAddress);
690
UPDATE_COUNTERS;
691
if (--count <= 0)
692
{
693
b = 2;
694
break;
695
}
696
697
case 2:
698
Work = S9xGetByte((d->ABank << 16) + p);
699
S9xSetPPU(Work, 0x2102 + d->BAddress);
700
UPDATE_COUNTERS;
701
if (--count <= 0)
702
{
703
b = 3;
704
break;
705
}
706
707
case 3:
708
Work = S9xGetByte((d->ABank << 16) + p);
709
S9xSetPPU(Work, 0x2103 + d->BAddress);
710
UPDATE_COUNTERS;
711
if (--count <= 0)
712
{
713
b = 0;
714
break;
715
}
716
} while (1);
717
}
718
}
719
#ifdef DEBUGGER
720
else
721
{
722
sprintf(String, "Unknown DMA transfer mode: %d on channel %d\n", d->TransferMode, Channel);
723
S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String);
724
}
725
#endif
726
}
727
else
728
{
729
// DMA FAST PATH
730
if (d->TransferMode == 0 || d->TransferMode == 2 || d->TransferMode == 6)
731
{
732
switch (d->BAddress)
733
{
734
case 0x04: // OAMDATA
735
do
736
{
737
Work = *(base + p);
738
REGISTER_2104(Work);
739
UPDATE_COUNTERS;
740
} while (--count > 0);
741
742
break;
743
744
case 0x18: // VMDATAL
745
if (!PPU.VMA.FullGraphicCount)
746
{
747
do
748
{
749
Work = *(base + p);
750
REGISTER_2118_linear(Work);
751
UPDATE_COUNTERS;
752
} while (--count > 0);
753
}
754
else
755
{
756
do
757
{
758
Work = *(base + p);
759
REGISTER_2118_tile(Work);
760
UPDATE_COUNTERS;
761
} while (--count > 0);
762
}
763
764
break;
765
766
case 0x19: // VMDATAH
767
if (!PPU.VMA.FullGraphicCount)
768
{
769
do
770
{
771
Work = *(base + p);
772
REGISTER_2119_linear(Work);
773
UPDATE_COUNTERS;
774
} while (--count > 0);
775
}
776
else
777
{
778
do
779
{
780
Work = *(base + p);
781
REGISTER_2119_tile(Work);
782
UPDATE_COUNTERS;
783
} while (--count > 0);
784
}
785
786
break;
787
788
case 0x22: // CGDATA
789
do
790
{
791
Work = *(base + p);
792
REGISTER_2122(Work);
793
UPDATE_COUNTERS;
794
} while (--count > 0);
795
796
break;
797
798
case 0x80: // WMDATA
799
if (!CPU.InWRAMDMAorHDMA)
800
{
801
do
802
{
803
Work = *(base + p);
804
REGISTER_2180(Work);
805
UPDATE_COUNTERS;
806
} while (--count > 0);
807
}
808
else
809
{
810
do
811
{
812
UPDATE_COUNTERS;
813
} while (--count > 0);
814
}
815
816
break;
817
818
default:
819
do
820
{
821
Work = *(base + p);
822
S9xSetPPU(Work, 0x2100 + d->BAddress);
823
UPDATE_COUNTERS;
824
} while (--count > 0);
825
826
break;
827
}
828
}
829
else
830
if (d->TransferMode == 1 || d->TransferMode == 5)
831
{
832
if (d->BAddress == 0x18)
833
{
834
// VMDATAL
835
if (!PPU.VMA.FullGraphicCount)
836
{
837
switch (b)
838
{
839
default:
840
while (count > 1)
841
{
842
Work = *(base + p);
843
REGISTER_2118_linear(Work);
844
UPDATE_COUNTERS;
845
count--;
846
847
case 1:
848
Work = *(base + p);
849
REGISTER_2119_linear(Work);
850
UPDATE_COUNTERS;
851
count--;
852
}
853
}
854
855
if (count == 1)
856
{
857
Work = *(base + p);
858
REGISTER_2118_linear(Work);
859
UPDATE_COUNTERS;
860
b = 1;
861
}
862
else
863
b = 0;
864
}
865
else
866
{
867
switch (b)
868
{
869
default:
870
while (count > 1)
871
{
872
Work = *(base + p);
873
REGISTER_2118_tile(Work);
874
UPDATE_COUNTERS;
875
count--;
876
877
case 1:
878
Work = *(base + p);
879
REGISTER_2119_tile(Work);
880
UPDATE_COUNTERS;
881
count--;
882
}
883
}
884
885
if (count == 1)
886
{
887
Work = *(base + p);
888
REGISTER_2118_tile(Work);
889
UPDATE_COUNTERS;
890
b = 1;
891
}
892
else
893
b = 0;
894
}
895
}
896
else
897
{
898
// DMA mode 1 general case
899
switch (b)
900
{
901
default:
902
while (count > 1)
903
{
904
Work = *(base + p);
905
S9xSetPPU(Work, 0x2100 + d->BAddress);
906
UPDATE_COUNTERS;
907
count--;
908
909
case 1:
910
Work = *(base + p);
911
S9xSetPPU(Work, 0x2101 + d->BAddress);
912
UPDATE_COUNTERS;
913
count--;
914
}
915
}
916
917
if (count == 1)
918
{
919
Work = *(base + p);
920
S9xSetPPU(Work, 0x2100 + d->BAddress);
921
UPDATE_COUNTERS;
922
b = 1;
923
}
924
else
925
b = 0;
926
}
927
}
928
else
929
if (d->TransferMode == 3 || d->TransferMode == 7)
930
{
931
switch (b)
932
{
933
default:
934
do
935
{
936
Work = *(base + p);
937
S9xSetPPU(Work, 0x2100 + d->BAddress);
938
UPDATE_COUNTERS;
939
if (--count <= 0)
940
{
941
b = 1;
942
break;
943
}
944
945
case 1:
946
Work = *(base + p);
947
S9xSetPPU(Work, 0x2100 + d->BAddress);
948
UPDATE_COUNTERS;
949
if (--count <= 0)
950
{
951
b = 2;
952
break;
953
}
954
955
case 2:
956
Work = *(base + p);
957
S9xSetPPU(Work, 0x2101 + d->BAddress);
958
UPDATE_COUNTERS;
959
if (--count <= 0)
960
{
961
b = 3;
962
break;
963
}
964
965
case 3:
966
Work = *(base + p);
967
S9xSetPPU(Work, 0x2101 + d->BAddress);
968
UPDATE_COUNTERS;
969
if (--count <= 0)
970
{
971
b = 0;
972
break;
973
}
974
} while (1);
975
}
976
}
977
else
978
if (d->TransferMode == 4)
979
{
980
switch (b)
981
{
982
default:
983
do
984
{
985
Work = *(base + p);
986
S9xSetPPU(Work, 0x2100 + d->BAddress);
987
UPDATE_COUNTERS;
988
if (--count <= 0)
989
{
990
b = 1;
991
break;
992
}
993
994
case 1:
995
Work = *(base + p);
996
S9xSetPPU(Work, 0x2101 + d->BAddress);
997
UPDATE_COUNTERS;
998
if (--count <= 0)
999
{
1000
b = 2;
1001
break;
1002
}
1003
1004
case 2:
1005
Work = *(base + p);
1006
S9xSetPPU(Work, 0x2102 + d->BAddress);
1007
UPDATE_COUNTERS;
1008
if (--count <= 0)
1009
{
1010
b = 3;
1011
break;
1012
}
1013
1014
case 3:
1015
Work = *(base + p);
1016
S9xSetPPU(Work, 0x2103 + d->BAddress);
1017
UPDATE_COUNTERS;
1018
if (--count <= 0)
1019
{
1020
b = 0;
1021
break;
1022
}
1023
} while (1);
1024
}
1025
}
1026
#ifdef DEBUGGER
1027
else
1028
{
1029
sprintf(String, "Unknown DMA transfer mode: %d on channel %d\n", d->TransferMode, Channel);
1030
S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String);
1031
}
1032
#endif
1033
}
1034
1035
if (rem <= 0)
1036
break;
1037
1038
base = S9xGetBasePointer((d->ABank << 16) + d->AAddress);
1039
count = MEMMAP_BLOCK_SIZE;
1040
inWRAM_DMA = ((!in_sa1_dma && !in_sdd1_dma && !spc7110_dma) &&
1041
(d->ABank == 0x7e || d->ABank == 0x7f || (!(d->ABank & 0x40) && d->AAddress < 0x2000)));
1042
}
1043
1044
#undef UPDATE_COUNTERS
1045
}
1046
else
1047
{
1048
// PPU -> CPU
1049
1050
// 8 cycles per byte
1051
#define UPDATE_COUNTERS \
1052
d->TransferBytes--; \
1053
d->AAddress += inc; \
1054
if (!addCyclesInDMA(Channel)) \
1055
{ \
1056
CPU.InDMA = FALSE; \
1057
CPU.InDMAorHDMA = FALSE; \
1058
CPU.InWRAMDMAorHDMA = FALSE; \
1059
CPU.CurrentDMAorHDMAChannel = -1; \
1060
return (FALSE); \
1061
}
1062
1063
if (d->BAddress > 0x80 - 4 && d->BAddress <= 0x83 && !(d->ABank & 0x40))
1064
{
1065
// REVERSE-DMA REALLY-SLOW PATH
1066
do
1067
{
1068
switch (d->TransferMode)
1069
{
1070
case 0:
1071
case 2:
1072
case 6:
1073
CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
1074
Work = S9xGetPPU(0x2100 + d->BAddress);
1075
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1076
UPDATE_COUNTERS;
1077
count--;
1078
1079
break;
1080
1081
case 1:
1082
case 5:
1083
CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
1084
Work = S9xGetPPU(0x2100 + d->BAddress);
1085
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1086
UPDATE_COUNTERS;
1087
if (!--count)
1088
break;
1089
1090
CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
1091
Work = S9xGetPPU(0x2101 + d->BAddress);
1092
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1093
UPDATE_COUNTERS;
1094
count--;
1095
1096
break;
1097
1098
case 3:
1099
case 7:
1100
CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
1101
Work = S9xGetPPU(0x2100 + d->BAddress);
1102
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1103
UPDATE_COUNTERS;
1104
if (!--count)
1105
break;
1106
1107
CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
1108
Work = S9xGetPPU(0x2100 + d->BAddress);
1109
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1110
UPDATE_COUNTERS;
1111
if (!--count)
1112
break;
1113
1114
CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
1115
Work = S9xGetPPU(0x2101 + d->BAddress);
1116
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1117
UPDATE_COUNTERS;
1118
if (!--count)
1119
break;
1120
1121
CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
1122
Work = S9xGetPPU(0x2101 + d->BAddress);
1123
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1124
UPDATE_COUNTERS;
1125
count--;
1126
1127
break;
1128
1129
case 4:
1130
CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
1131
Work = S9xGetPPU(0x2100 + d->BAddress);
1132
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1133
UPDATE_COUNTERS;
1134
if (!--count)
1135
break;
1136
1137
CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
1138
Work = S9xGetPPU(0x2101 + d->BAddress);
1139
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1140
UPDATE_COUNTERS;
1141
if (!--count)
1142
break;
1143
1144
CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
1145
Work = S9xGetPPU(0x2102 + d->BAddress);
1146
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1147
UPDATE_COUNTERS;
1148
if (!--count)
1149
break;
1150
1151
CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
1152
Work = S9xGetPPU(0x2103 + d->BAddress);
1153
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1154
UPDATE_COUNTERS;
1155
count--;
1156
1157
break;
1158
1159
default:
1160
#ifdef DEBUGGER
1161
sprintf(String, "Unknown DMA transfer mode: %d on channel %d\n", d->TransferMode, Channel);
1162
S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String);
1163
#endif
1164
while (count)
1165
{
1166
UPDATE_COUNTERS;
1167
count--;
1168
}
1169
1170
break;
1171
}
1172
} while (count);
1173
}
1174
else
1175
{
1176
// REVERSE-DMA FASTER PATH
1177
CPU.InWRAMDMAorHDMA = (d->ABank == 0x7e || d->ABank == 0x7f);
1178
do
1179
{
1180
switch (d->TransferMode)
1181
{
1182
case 0:
1183
case 2:
1184
case 6:
1185
Work = S9xGetPPU(0x2100 + d->BAddress);
1186
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1187
UPDATE_COUNTERS;
1188
count--;
1189
1190
break;
1191
1192
case 1:
1193
case 5:
1194
Work = S9xGetPPU(0x2100 + d->BAddress);
1195
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1196
UPDATE_COUNTERS;
1197
if (!--count)
1198
break;
1199
1200
Work = S9xGetPPU(0x2101 + d->BAddress);
1201
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1202
UPDATE_COUNTERS;
1203
count--;
1204
1205
break;
1206
1207
case 3:
1208
case 7:
1209
Work = S9xGetPPU(0x2100 + d->BAddress);
1210
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1211
UPDATE_COUNTERS;
1212
if (!--count)
1213
break;
1214
1215
Work = S9xGetPPU(0x2100 + d->BAddress);
1216
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1217
UPDATE_COUNTERS;
1218
if (!--count)
1219
break;
1220
1221
Work = S9xGetPPU(0x2101 + d->BAddress);
1222
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1223
UPDATE_COUNTERS;
1224
if (!--count)
1225
break;
1226
1227
Work = S9xGetPPU(0x2101 + d->BAddress);
1228
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1229
UPDATE_COUNTERS;
1230
count--;
1231
1232
break;
1233
1234
case 4:
1235
Work = S9xGetPPU(0x2100 + d->BAddress);
1236
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1237
UPDATE_COUNTERS;
1238
if (!--count)
1239
break;
1240
1241
Work = S9xGetPPU(0x2101 + d->BAddress);
1242
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1243
UPDATE_COUNTERS;
1244
if (!--count)
1245
break;
1246
1247
Work = S9xGetPPU(0x2102 + d->BAddress);
1248
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1249
UPDATE_COUNTERS;
1250
if (!--count)
1251
break;
1252
1253
Work = S9xGetPPU(0x2103 + d->BAddress);
1254
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
1255
UPDATE_COUNTERS;
1256
count--;
1257
1258
break;
1259
1260
default:
1261
#ifdef DEBUGGER
1262
sprintf(String, "Unknown DMA transfer mode: %d on channel %d\n", d->TransferMode, Channel);
1263
S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String);
1264
#endif
1265
while (count)
1266
{
1267
UPDATE_COUNTERS;
1268
count--;
1269
}
1270
1271
break;
1272
}
1273
} while (count);
1274
}
1275
}
1276
1277
if (CPU.NMILine && (Timings.NMITriggerPos != 0xffff))
1278
{
1279
Timings.NMITriggerPos = CPU.Cycles + Timings.NMIDMADelay;
1280
if (Timings.NMITriggerPos >= Timings.H_Max)
1281
Timings.NMITriggerPos -= Timings.H_Max;
1282
}
1283
1284
// Release the memory used in SPC7110 DMA
1285
if (Settings.SPC7110)
1286
{
1287
if (spc7110_dma)
1288
delete [] spc7110_dma;
1289
}
1290
1291
#if 0
1292
// sanity check
1293
if (d->TransferBytes != 0)
1294
fprintf(stderr,"DMA[%d] TransferBytes not 0! $21%02x Reverse:%d %04x\n", Channel, d->BAddress, d->ReverseTransfer, d->TransferBytes);
1295
#endif
1296
1297
CPU.InDMA = FALSE;
1298
CPU.InDMAorHDMA = FALSE;
1299
CPU.InWRAMDMAorHDMA = FALSE;
1300
CPU.CurrentDMAorHDMAChannel = -1;
1301
1302
return (TRUE);
1303
}
1304
1305
static inline bool8 HDMAReadLineCount (int d)
1306
{
1307
// CPU.InDMA is set, so S9xGetXXX() / S9xSetXXX() incur no charges.
1308
1309
uint8 line;
1310
1311
line = S9xGetByte((DMA[d].ABank << 16) + DMA[d].Address);
1312
ADD_CYCLES(SLOW_ONE_CYCLE);
1313
1314
if (!line)
1315
{
1316
DMA[d].Repeat = FALSE;
1317
DMA[d].LineCount = 128;
1318
1319
if (DMA[d].HDMAIndirectAddressing)
1320
{
1321
if (PPU.HDMA & (0xfe << d))
1322
{
1323
DMA[d].Address++;
1324
ADD_CYCLES(SLOW_ONE_CYCLE << 1);
1325
}
1326
else
1327
ADD_CYCLES(SLOW_ONE_CYCLE);
1328
1329
DMA[d].IndirectAddress = S9xGetWord((DMA[d].ABank << 16) + DMA[d].Address);
1330
DMA[d].Address++;
1331
}
1332
1333
DMA[d].Address++;
1334
HDMAMemPointers[d] = NULL;
1335
1336
return (FALSE);
1337
}
1338
else
1339
if (line == 0x80)
1340
{
1341
DMA[d].Repeat = TRUE;
1342
DMA[d].LineCount = 128;
1343
}
1344
else
1345
{
1346
DMA[d].Repeat = !(line & 0x80);
1347
DMA[d].LineCount = line & 0x7f;
1348
}
1349
1350
DMA[d].Address++;
1351
DMA[d].DoTransfer = TRUE;
1352
1353
if (DMA[d].HDMAIndirectAddressing)
1354
{
1355
ADD_CYCLES(SLOW_ONE_CYCLE << 1);
1356
DMA[d].IndirectAddress = S9xGetWord((DMA[d].ABank << 16) + DMA[d].Address);
1357
DMA[d].Address += 2;
1358
HDMAMemPointers[d] = S9xGetMemPointer((DMA[d].IndirectBank << 16) + DMA[d].IndirectAddress);
1359
}
1360
else
1361
HDMAMemPointers[d] = S9xGetMemPointer((DMA[d].ABank << 16) + DMA[d].Address);
1362
1363
return (TRUE);
1364
}
1365
1366
void S9xStartHDMA (void)
1367
{
1368
PPU.HDMA = Memory.FillRAM[0x420c];
1369
1370
#ifdef DEBUGGER
1371
missing.hdma_this_frame = PPU.HDMA;
1372
#endif
1373
1374
PPU.HDMAEnded = 0;
1375
1376
int32 tmpch;
1377
1378
CPU.InHDMA = TRUE;
1379
CPU.InDMAorHDMA = TRUE;
1380
tmpch = CPU.CurrentDMAorHDMAChannel;
1381
1382
// XXX: Not quite right...
1383
if (PPU.HDMA != 0)
1384
ADD_CYCLES(Timings.DMACPUSync);
1385
1386
for (uint8 i = 0; i < 8; i++)
1387
{
1388
if (PPU.HDMA & (1 << i))
1389
{
1390
CPU.CurrentDMAorHDMAChannel = i;
1391
1392
DMA[i].Address = DMA[i].AAddress;
1393
1394
if (!HDMAReadLineCount(i))
1395
{
1396
PPU.HDMA &= ~(1 << i);
1397
PPU.HDMAEnded |= (1 << i);
1398
}
1399
}
1400
else
1401
DMA[i].DoTransfer = FALSE;
1402
}
1403
1404
CPU.InHDMA = FALSE;
1405
CPU.InDMAorHDMA = CPU.InDMA;
1406
CPU.HDMARanInDMA = CPU.InDMA ? PPU.HDMA : 0;
1407
CPU.CurrentDMAorHDMAChannel = tmpch;
1408
}
1409
1410
uint8 S9xDoHDMA (uint8 byte)
1411
{
1412
struct SDMA *p = &DMA[0];
1413
1414
uint32 ShiftedIBank;
1415
uint16 IAddr;
1416
bool8 temp;
1417
int32 tmpch;
1418
int d = 0;
1419
1420
CPU.InHDMA = TRUE;
1421
CPU.InDMAorHDMA = TRUE;
1422
CPU.HDMARanInDMA = CPU.InDMA ? byte : 0;
1423
temp = CPU.InWRAMDMAorHDMA;
1424
tmpch = CPU.CurrentDMAorHDMAChannel;
1425
1426
// XXX: Not quite right...
1427
ADD_CYCLES(Timings.DMACPUSync);
1428
1429
for (uint8 mask = 1; mask; mask <<= 1, p++, d++)
1430
{
1431
if (byte & mask)
1432
{
1433
CPU.InWRAMDMAorHDMA = FALSE;
1434
CPU.CurrentDMAorHDMAChannel = d;
1435
1436
if (p->HDMAIndirectAddressing)
1437
{
1438
ShiftedIBank = (p->IndirectBank << 16);
1439
IAddr = p->IndirectAddress;
1440
}
1441
else
1442
{
1443
ShiftedIBank = (p->ABank << 16);
1444
IAddr = p->Address;
1445
}
1446
1447
if (!HDMAMemPointers[d])
1448
HDMAMemPointers[d] = S9xGetMemPointer(ShiftedIBank + IAddr);
1449
1450
if (p->DoTransfer)
1451
{
1452
// XXX: Hack for Uniracers, because we don't understand
1453
// OAM Address Invalidation
1454
if (p->BAddress == 0x04)
1455
{
1456
if (SNESGameFixes.Uniracers)
1457
{
1458
PPU.OAMAddr = 0x10c;
1459
PPU.OAMFlip = 0;
1460
}
1461
}
1462
1463
#ifdef DEBUGGER
1464
if (Settings.TraceHDMA && p->DoTransfer)
1465
{
1466
sprintf(String, "H-DMA[%d] %s (%d) 0x%06X->0x21%02X %s, Count: %3d, Rep: %s, V-LINE: %3ld %02X%04X",
1467
p-DMA, p->ReverseTransfer? "read" : "write",
1468
p->TransferMode, ShiftedIBank+IAddr, p->BAddress,
1469
p->HDMAIndirectAddressing ? "ind" : "abs",
1470
p->LineCount,
1471
p->Repeat ? "yes" : "no ", (long) CPU.V_Counter,
1472
p->ABank, p->Address);
1473
S9xMessage(S9X_TRACE, S9X_HDMA_TRACE, String);
1474
}
1475
#endif
1476
1477
if (!p->ReverseTransfer)
1478
{
1479
if ((IAddr & MEMMAP_MASK) + HDMA_ModeByteCounts[p->TransferMode] >= MEMMAP_BLOCK_SIZE)
1480
{
1481
// HDMA REALLY-SLOW PATH
1482
HDMAMemPointers[d] = NULL;
1483
1484
#define DOBYTE(Addr, RegOff) \
1485
CPU.InWRAMDMAorHDMA = (ShiftedIBank == 0x7e0000 || ShiftedIBank == 0x7f0000 || \
1486
(!(ShiftedIBank & 0x400000) && ((uint16) (Addr)) < 0x2000)); \
1487
S9xSetPPU(S9xGetByte(ShiftedIBank + ((uint16) (Addr))), 0x2100 + p->BAddress + (RegOff));
1488
1489
switch (p->TransferMode)
1490
{
1491
case 0:
1492
DOBYTE(IAddr, 0);
1493
ADD_CYCLES(SLOW_ONE_CYCLE);
1494
break;
1495
1496
case 5:
1497
DOBYTE(IAddr + 0, 0);
1498
ADD_CYCLES(SLOW_ONE_CYCLE);
1499
DOBYTE(IAddr + 1, 1);
1500
ADD_CYCLES(SLOW_ONE_CYCLE);
1501
DOBYTE(IAddr + 2, 0);
1502
ADD_CYCLES(SLOW_ONE_CYCLE);
1503
DOBYTE(IAddr + 3, 1);
1504
ADD_CYCLES(SLOW_ONE_CYCLE);
1505
break;
1506
1507
case 1:
1508
DOBYTE(IAddr + 0, 0);
1509
ADD_CYCLES(SLOW_ONE_CYCLE);
1510
DOBYTE(IAddr + 1, 1);
1511
ADD_CYCLES(SLOW_ONE_CYCLE);
1512
break;
1513
1514
case 2:
1515
case 6:
1516
DOBYTE(IAddr + 0, 0);
1517
ADD_CYCLES(SLOW_ONE_CYCLE);
1518
DOBYTE(IAddr + 1, 0);
1519
ADD_CYCLES(SLOW_ONE_CYCLE);
1520
break;
1521
1522
case 3:
1523
case 7:
1524
DOBYTE(IAddr + 0, 0);
1525
ADD_CYCLES(SLOW_ONE_CYCLE);
1526
DOBYTE(IAddr + 1, 0);
1527
ADD_CYCLES(SLOW_ONE_CYCLE);
1528
DOBYTE(IAddr + 2, 1);
1529
ADD_CYCLES(SLOW_ONE_CYCLE);
1530
DOBYTE(IAddr + 3, 1);
1531
ADD_CYCLES(SLOW_ONE_CYCLE);
1532
break;
1533
1534
case 4:
1535
DOBYTE(IAddr + 0, 0);
1536
ADD_CYCLES(SLOW_ONE_CYCLE);
1537
DOBYTE(IAddr + 1, 1);
1538
ADD_CYCLES(SLOW_ONE_CYCLE);
1539
DOBYTE(IAddr + 2, 2);
1540
ADD_CYCLES(SLOW_ONE_CYCLE);
1541
DOBYTE(IAddr + 3, 3);
1542
ADD_CYCLES(SLOW_ONE_CYCLE);
1543
break;
1544
}
1545
1546
#undef DOBYTE
1547
}
1548
else
1549
{
1550
CPU.InWRAMDMAorHDMA = (ShiftedIBank == 0x7e0000 || ShiftedIBank == 0x7f0000 ||
1551
(!(ShiftedIBank & 0x400000) && IAddr < 0x2000));
1552
1553
if (!HDMAMemPointers[d])
1554
{
1555
// HDMA SLOW PATH
1556
uint32 Addr = ShiftedIBank + IAddr;
1557
1558
switch (p->TransferMode)
1559
{
1560
case 0:
1561
S9xSetPPU(S9xGetByte(Addr), 0x2100 + p->BAddress);
1562
ADD_CYCLES(SLOW_ONE_CYCLE);
1563
break;
1564
1565
case 5:
1566
S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress);
1567
ADD_CYCLES(SLOW_ONE_CYCLE);
1568
S9xSetPPU(S9xGetByte(Addr + 1), 0x2101 + p->BAddress);
1569
ADD_CYCLES(SLOW_ONE_CYCLE);
1570
Addr += 2;
1571
/* fall through */
1572
case 1:
1573
S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress);
1574
ADD_CYCLES(SLOW_ONE_CYCLE);
1575
S9xSetPPU(S9xGetByte(Addr + 1), 0x2101 + p->BAddress);
1576
ADD_CYCLES(SLOW_ONE_CYCLE);
1577
break;
1578
1579
case 2:
1580
case 6:
1581
S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress);
1582
ADD_CYCLES(SLOW_ONE_CYCLE);
1583
S9xSetPPU(S9xGetByte(Addr + 1), 0x2100 + p->BAddress);
1584
ADD_CYCLES(SLOW_ONE_CYCLE);
1585
break;
1586
1587
case 3:
1588
case 7:
1589
S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress);
1590
ADD_CYCLES(SLOW_ONE_CYCLE);
1591
S9xSetPPU(S9xGetByte(Addr + 1), 0x2100 + p->BAddress);
1592
ADD_CYCLES(SLOW_ONE_CYCLE);
1593
S9xSetPPU(S9xGetByte(Addr + 2), 0x2101 + p->BAddress);
1594
ADD_CYCLES(SLOW_ONE_CYCLE);
1595
S9xSetPPU(S9xGetByte(Addr + 3), 0x2101 + p->BAddress);
1596
ADD_CYCLES(SLOW_ONE_CYCLE);
1597
break;
1598
1599
case 4:
1600
S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress);
1601
ADD_CYCLES(SLOW_ONE_CYCLE);
1602
S9xSetPPU(S9xGetByte(Addr + 1), 0x2101 + p->BAddress);
1603
ADD_CYCLES(SLOW_ONE_CYCLE);
1604
S9xSetPPU(S9xGetByte(Addr + 2), 0x2102 + p->BAddress);
1605
ADD_CYCLES(SLOW_ONE_CYCLE);
1606
S9xSetPPU(S9xGetByte(Addr + 3), 0x2103 + p->BAddress);
1607
ADD_CYCLES(SLOW_ONE_CYCLE);
1608
break;
1609
}
1610
}
1611
else
1612
{
1613
// HDMA FAST PATH
1614
switch (p->TransferMode)
1615
{
1616
case 0:
1617
S9xSetPPU(*HDMAMemPointers[d]++, 0x2100 + p->BAddress);
1618
ADD_CYCLES(SLOW_ONE_CYCLE);
1619
break;
1620
1621
case 5:
1622
S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress);
1623
ADD_CYCLES(SLOW_ONE_CYCLE);
1624
S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2101 + p->BAddress);
1625
ADD_CYCLES(SLOW_ONE_CYCLE);
1626
HDMAMemPointers[d] += 2;
1627
/* fall through */
1628
case 1:
1629
S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress);
1630
ADD_CYCLES(SLOW_ONE_CYCLE);
1631
S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2101 + p->BAddress);
1632
ADD_CYCLES(SLOW_ONE_CYCLE);
1633
HDMAMemPointers[d] += 2;
1634
break;
1635
1636
case 2:
1637
case 6:
1638
S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress);
1639
ADD_CYCLES(SLOW_ONE_CYCLE);
1640
S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2100 + p->BAddress);
1641
ADD_CYCLES(SLOW_ONE_CYCLE);
1642
HDMAMemPointers[d] += 2;
1643
break;
1644
1645
case 3:
1646
case 7:
1647
S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress);
1648
ADD_CYCLES(SLOW_ONE_CYCLE);
1649
S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2100 + p->BAddress);
1650
ADD_CYCLES(SLOW_ONE_CYCLE);
1651
S9xSetPPU(*(HDMAMemPointers[d] + 2), 0x2101 + p->BAddress);
1652
ADD_CYCLES(SLOW_ONE_CYCLE);
1653
S9xSetPPU(*(HDMAMemPointers[d] + 3), 0x2101 + p->BAddress);
1654
ADD_CYCLES(SLOW_ONE_CYCLE);
1655
HDMAMemPointers[d] += 4;
1656
break;
1657
1658
case 4:
1659
S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress);
1660
ADD_CYCLES(SLOW_ONE_CYCLE);
1661
S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2101 + p->BAddress);
1662
ADD_CYCLES(SLOW_ONE_CYCLE);
1663
S9xSetPPU(*(HDMAMemPointers[d] + 2), 0x2102 + p->BAddress);
1664
ADD_CYCLES(SLOW_ONE_CYCLE);
1665
S9xSetPPU(*(HDMAMemPointers[d] + 3), 0x2103 + p->BAddress);
1666
ADD_CYCLES(SLOW_ONE_CYCLE);
1667
HDMAMemPointers[d] += 4;
1668
break;
1669
}
1670
}
1671
}
1672
}
1673
else
1674
{
1675
// REVERSE HDMA REALLY-SLOW PATH
1676
// anomie says: Since this is apparently never used
1677
// (otherwise we would have noticed before now), let's not bother with faster paths.
1678
HDMAMemPointers[d] = NULL;
1679
1680
#define DOBYTE(Addr, RegOff) \
1681
CPU.InWRAMDMAorHDMA = (ShiftedIBank == 0x7e0000 || ShiftedIBank == 0x7f0000 || \
1682
(!(ShiftedIBank & 0x400000) && ((uint16) (Addr)) < 0x2000)); \
1683
S9xSetByte(S9xGetPPU(0x2100 + p->BAddress + (RegOff)), ShiftedIBank + ((uint16) (Addr)));
1684
1685
switch (p->TransferMode)
1686
{
1687
case 0:
1688
DOBYTE(IAddr, 0);
1689
ADD_CYCLES(SLOW_ONE_CYCLE);
1690
break;
1691
1692
case 5:
1693
DOBYTE(IAddr + 0, 0);
1694
ADD_CYCLES(SLOW_ONE_CYCLE);
1695
DOBYTE(IAddr + 1, 1);
1696
ADD_CYCLES(SLOW_ONE_CYCLE);
1697
DOBYTE(IAddr + 2, 0);
1698
ADD_CYCLES(SLOW_ONE_CYCLE);
1699
DOBYTE(IAddr + 3, 1);
1700
ADD_CYCLES(SLOW_ONE_CYCLE);
1701
break;
1702
1703
case 1:
1704
DOBYTE(IAddr + 0, 0);
1705
ADD_CYCLES(SLOW_ONE_CYCLE);
1706
DOBYTE(IAddr + 1, 1);
1707
ADD_CYCLES(SLOW_ONE_CYCLE);
1708
break;
1709
1710
case 2:
1711
case 6:
1712
DOBYTE(IAddr + 0, 0);
1713
ADD_CYCLES(SLOW_ONE_CYCLE);
1714
DOBYTE(IAddr + 1, 0);
1715
ADD_CYCLES(SLOW_ONE_CYCLE);
1716
break;
1717
1718
case 3:
1719
case 7:
1720
DOBYTE(IAddr + 0, 0);
1721
ADD_CYCLES(SLOW_ONE_CYCLE);
1722
DOBYTE(IAddr + 1, 0);
1723
ADD_CYCLES(SLOW_ONE_CYCLE);
1724
DOBYTE(IAddr + 2, 1);
1725
ADD_CYCLES(SLOW_ONE_CYCLE);
1726
DOBYTE(IAddr + 3, 1);
1727
ADD_CYCLES(SLOW_ONE_CYCLE);
1728
break;
1729
1730
case 4:
1731
DOBYTE(IAddr + 0, 0);
1732
ADD_CYCLES(SLOW_ONE_CYCLE);
1733
DOBYTE(IAddr + 1, 1);
1734
ADD_CYCLES(SLOW_ONE_CYCLE);
1735
DOBYTE(IAddr + 2, 2);
1736
ADD_CYCLES(SLOW_ONE_CYCLE);
1737
DOBYTE(IAddr + 3, 3);
1738
ADD_CYCLES(SLOW_ONE_CYCLE);
1739
break;
1740
}
1741
1742
#undef DOBYTE
1743
}
1744
1745
if (p->HDMAIndirectAddressing)
1746
p->IndirectAddress += HDMA_ModeByteCounts[p->TransferMode];
1747
else
1748
p->Address += HDMA_ModeByteCounts[p->TransferMode];
1749
}
1750
1751
p->DoTransfer = !p->Repeat;
1752
1753
if (!--p->LineCount)
1754
{
1755
if (!HDMAReadLineCount(d))
1756
{
1757
byte &= ~mask;
1758
PPU.HDMAEnded |= mask;
1759
p->DoTransfer = FALSE;
1760
continue;
1761
}
1762
}
1763
else
1764
ADD_CYCLES(SLOW_ONE_CYCLE);
1765
}
1766
}
1767
1768
CPU.InHDMA = FALSE;
1769
CPU.InDMAorHDMA = CPU.InDMA;
1770
CPU.InWRAMDMAorHDMA = temp;
1771
CPU.CurrentDMAorHDMAChannel = tmpch;
1772
1773
return (byte);
1774
}
1775
1776
void S9xResetDMA (void)
1777
{
1778
for (int d = 0; d < 8; d++)
1779
{
1780
DMA[d].ReverseTransfer = TRUE;
1781
DMA[d].HDMAIndirectAddressing = TRUE;
1782
DMA[d].AAddressFixed = TRUE;
1783
DMA[d].AAddressDecrement = TRUE;
1784
DMA[d].TransferMode = 7;
1785
DMA[d].BAddress = 0xff;
1786
DMA[d].AAddress = 0xffff;
1787
DMA[d].ABank = 0xff;
1788
DMA[d].DMACount_Or_HDMAIndirectAddress = 0xffff;
1789
DMA[d].IndirectBank = 0xff;
1790
DMA[d].Address = 0xffff;
1791
DMA[d].Repeat = FALSE;
1792
DMA[d].LineCount = 0x7f;
1793
DMA[d].UnknownByte = 0xff;
1794
DMA[d].DoTransfer = FALSE;
1795
DMA[d].UnusedBit43x0 = 1;
1796
}
1797
}
1798
1799