Skip to content

Commit 70dfc70

Browse files
Add new DMA code path
- Refactor existing DMA logic to a loop-based basic, removes repetitions, improves timing logic - Moves DMA into its own source file
1 parent d6d5d95 commit 70dfc70

File tree

4 files changed

+198
-4
lines changed

4 files changed

+198
-4
lines changed

src/core/gba/gba.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ int dummyAddress = 0;
7171
uint32_t cpuDmaLatchData[4];
7272
uint32_t cpuDmaBusValue = 0;
7373

74-
const uint32_t cpuDmaSrcMask[4] = { 0x07ffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff };
75-
const uint32_t cpuDmaDstMask[4] = { 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x0fffffff };
74+
uint32_t cpuDmaSrcMask[4] = { 0x07ffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff };
75+
uint32_t cpuDmaDstMask[4] = { 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x0fffffff };
7676

7777
bool cpuBreakLoop = false;
7878
int cpuNextEvent = 0;
@@ -2641,6 +2641,7 @@ void CPUCompareVCOUNT()
26412641
}
26422642
}
26432643

2644+
#ifndef USE_GBA_DMA_LOOP
26442645
void doDMA(int ch, uint32_t& s, uint32_t& d, uint32_t si, uint32_t di, uint32_t c, int transfer32, bool isFIFO)
26452646
{
26462647
int sm = s >> 24;
@@ -2994,6 +2995,7 @@ void CPUCheckDMA(int reason, int dmamask)
29942995
}
29952996
}
29962997
}
2998+
#endif // !USE_GBA_DMA_LOOP
29972999

29983000
void CPUUpdateRegister(uint32_t address, uint16_t value)
29993001
{
@@ -4081,7 +4083,7 @@ void CPULoop(int ticks)
40814083
cpuNextEvent = CPUUpdateTicks();
40824084
if (cpuNextEvent > ticks)
40834085
cpuNextEvent = ticks;
4084-
4086+
40854087
for (;;) {
40864088
if (!holdState && !SWITicks) {
40874089
if (armState) {
@@ -4456,7 +4458,7 @@ void CPULoop(int ticks)
44564458
if (systemPauseOnFrame()) {
44574459
ticks = 0;
44584460
}
4459-
4461+
44604462
has_frames = true;
44614463
cpuBreakLoop = true;
44624464
}

src/core/gba/gbaDma.cpp

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#include "core/base/port.h"
2+
#include "gbaGlobals.h"
3+
#include "gbaInline.h"
4+
5+
extern uint32_t dma0Source;
6+
extern uint32_t dma1Source;
7+
extern uint32_t dma2Source;
8+
extern uint32_t dma3Source;
9+
10+
extern uint32_t dma0Dest;
11+
extern uint32_t dma1Dest;
12+
extern uint32_t dma2Dest;
13+
extern uint32_t dma3Dest;
14+
15+
extern uint32_t cpuDmaLatchData[];
16+
17+
extern int cpuDmaTicksToUpdate;
18+
extern int cpuDmaCount;
19+
20+
extern uint32_t cpuDmaSrcMask[4];
21+
extern uint32_t cpuDmaDstMask[4];
22+
23+
struct DMAChannel {
24+
uint16_t &cnt_h;
25+
uint16_t &cnt_l;
26+
uint32_t &src;
27+
uint32_t &dest;
28+
uint32_t &latch;
29+
uint32_t count;
30+
bool sound;
31+
};
32+
33+
DMAChannel dmaCh[4] = {
34+
{ DM0CNT_H, DM0CNT_L, dma0Source, dma0Dest, cpuDmaLatchData[0], 0, false },
35+
{ DM1CNT_H, DM1CNT_L, dma1Source, dma1Dest, cpuDmaLatchData[1], 0, false },
36+
{ DM2CNT_H, DM2CNT_L, dma2Source, dma2Dest, cpuDmaLatchData[2], 0, false },
37+
{ DM3CNT_H, DM3CNT_L, dma3Source, dma3Dest, cpuDmaLatchData[3], 0, false },
38+
};
39+
40+
static inline void dma_update_addr(uint32_t &addr, int addr_ctrl, int wsize) {
41+
if (((addr >> 24) >= REGION_ROM0) && ((addr >> 24) < REGION_SRAM)) {
42+
addr += wsize;
43+
} else {
44+
switch (addr_ctrl) {
45+
case 0:
46+
case 3:
47+
addr += wsize;
48+
break;
49+
case 1:
50+
addr -= wsize;
51+
break;
52+
}
53+
}
54+
}
55+
56+
static inline void dma_transfer_word_loop(DMAChannel *dmac,
57+
int &srcWait, int &destWait)
58+
{
59+
bool first = true;
60+
61+
int sm = (int)((dmac->src >> 24) & 0xFF);
62+
int dm = (int)((dmac->dest >> 24) & 0xFF);
63+
64+
do {
65+
bool srcInBios = (sm < REGION_EWRAM);
66+
67+
uint32_t value = CPUReadMemory(dmac->src);
68+
if (srcInBios) value = dmac->latch;
69+
else dmac->latch = value;
70+
CPUWriteMemory(dmac->dest, value);
71+
cpuDmaBusValue = value;
72+
73+
srcWait += first ? memoryWait32[sm & 15] : memoryWaitSeq32[sm & 15];
74+
destWait += first ? memoryWait32[dm & 15] : memoryWaitSeq32[dm & 15];
75+
76+
dma_update_addr(dmac->src, (dmac->cnt_h >> 7 & 3), (2 << ((dmac->cnt_h >> 10) & 1)));
77+
if (!dmac->sound)
78+
dma_update_addr(dmac->dest, (dmac->cnt_h >> 5 & 3), (2 << ((dmac->cnt_h >> 10) & 1)));
79+
80+
first = false;
81+
} while (--dmac->count > 0);
82+
}
83+
84+
static inline void dma_transfer_halfword_loop(DMAChannel *dmac,
85+
int &srcWait, int &destWait)
86+
{
87+
bool first = true;
88+
89+
int sm = (int)((dmac->src >> 24) & 0xFF);
90+
int dm = (int)((dmac->dest >> 24) & 0xFF);
91+
92+
do {
93+
bool srcInBios = (sm < REGION_EWRAM);
94+
95+
uint32_t value = CPUReadHalfWord(dmac->src);
96+
if (srcInBios) value = dmac->latch;
97+
else dmac->latch = value * 0x00010001;
98+
CPUWriteHalfWord(dmac->dest, Downcast16(value));
99+
cpuDmaBusValue = value * 0x00010001;
100+
101+
srcWait += first ? memoryWait[sm & 15] : memoryWaitSeq[sm & 15];
102+
destWait += first ? memoryWait[dm & 15] : memoryWaitSeq[dm & 15];
103+
104+
dma_update_addr(dmac->src, (dmac->cnt_h >> 7 & 3), (2 << ((dmac->cnt_h >> 10) & 1)));
105+
if (!dmac->sound) // this dont exist in 16-bit transfer but whatever
106+
dma_update_addr(dmac->dest, (dmac->cnt_h >> 5 & 3), (2 << ((dmac->cnt_h >> 10) & 1)));
107+
108+
first = false;
109+
} while (--dmac->count > 0);
110+
}
111+
112+
void CPUCheckDMA(int reason, int dmamask) {
113+
for (int i = 0; i < 4; i++) {
114+
DMAChannel *dmac = &dmaCh[i];
115+
116+
bool enable = dmac->cnt_h & 0x8000;
117+
uint8_t startTiming = (dmac->cnt_h >> 12) & 3;
118+
119+
if (!(enable && (dmamask & (1 << i)))) {
120+
continue;
121+
}
122+
if (startTiming != reason) {
123+
continue;
124+
}
125+
126+
bool transfer32 = (dmac->cnt_h & 0x400);
127+
128+
if (reason == 3 && (i == 1 || i == 2)) dmac->sound = true;
129+
130+
if (dmac->sound) dmac->count = 4;
131+
else dmac->count = dmac->cnt_l;
132+
if (dmac->count == 0) {
133+
if (i < 3) dmac->count = 0x4000;
134+
else dmac->count = 0x10000;
135+
}
136+
137+
dmac->src &= cpuDmaSrcMask[i];
138+
dmac->dest &= cpuDmaDstMask[i];
139+
if (transfer32) {
140+
dmac->src &= ~3;
141+
dmac->dest &= ~3;
142+
} else {
143+
dmac->src &= ~1;
144+
dmac->dest &= ~1;
145+
}
146+
147+
cpuDmaRunning = true;
148+
cpuDmaPC = reg[15].I;
149+
cpuDmaCount = dmac->count;
150+
151+
int sw = 0;
152+
int dw = 0;
153+
154+
if (transfer32 || dmac->sound) {
155+
dma_transfer_word_loop( dmac, sw, dw);
156+
} else {
157+
dma_transfer_halfword_loop(dmac, sw, dw);
158+
}
159+
160+
dmac->sound = false;
161+
cpuDmaCount = 0;
162+
163+
cpuDmaTicksToUpdate += 4 + sw + dw;
164+
cpuDmaRunning = false;
165+
166+
if (dmac->cnt_h & 0x4000) {
167+
IF |= (0x0100 << i);
168+
UPDATE_REG(IO_REG_IF, IF);
169+
cpuNextEvent = cpuTotalTicks;
170+
}
171+
172+
if (((dmac->cnt_h >> 5) & 3) == 3) {
173+
dmac->dest = READ32LE(&g_ioMem[IO_REG_DMA0SAD + (12 * i)]);
174+
dmac->dest &= cpuDmaDstMask[i];
175+
if (transfer32) dmac->dest &= ~3;
176+
else dmac->dest &= ~1;
177+
}
178+
179+
if (!(dmac->cnt_h & 0x200) || (reason == 0)) {
180+
dmac->cnt_h &= ~0x8000;
181+
UPDATE_REG(IO_REG_DMA0CTL + (12 * i), dmac->cnt_h);
182+
}
183+
}
184+
}

src/libretro/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ FRONTEND_SUPPORTS_RGB565=1
1010
FRONTEND_SUPPORTS_BGR1555=0
1111
endif
1212

13+
# NEW CODE PATHS
14+
USE_GBA_DMA_LOOP=1
1315
AFFINE_BG_UNIFIED=1
1416

1517
NO_LINK=1

src/libretro/Makefile.common

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ SOURCES_CXX += \
6565
$(CORE_DIR)/core/gba/internal/gbaEreader.cpp \
6666
$(CORE_DIR)/core/gba/internal/gbaSram.cpp \
6767

68+
ifeq ($(USE_GBA_DMA_LOOP), 1)
69+
VBA_DEFINES += -DUSE_GBA_DMA_LOOP
70+
SOURCES_CXX += \
71+
$(CORE_DIR)/core/gba/gbaDma.cpp
72+
endif
73+
6874
SOURCES_CXX += \
6975
$(CORE_DIR)/core/gb/gb.cpp \
7076
$(CORE_DIR)/core/gb/gbCartData.cpp \

0 commit comments

Comments
 (0)