src/gba/gba-memory.c (view raw)
1#include "gba-memory.h"
2
3#include "gba-io.h"
4#include "hle-bios.h"
5
6#include <limits.h>
7#include <string.h>
8#include <sys/mman.h>
9
10static const char* GBA_CANNOT_MMAP = "Could not map memory";
11
12static void GBASetActiveRegion(struct ARMMemory* memory, uint32_t region);
13
14static const char GBA_BASE_WAITSTATES[16] = { 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4 };
15static const char GBA_BASE_WAITSTATES_SEQ[16] = { 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4 };
16static const char GBA_ROM_WAITSTATES[] = { 4, 3, 2, 8 };
17static const char GBA_ROM_WAITSTATES_SEQ[] = { 2, 1, 4, 1, 8, 1 };
18static const int DMA_OFFSET[] = { 1, -1, 0, 1 };
19
20void GBAMemoryInit(struct GBAMemory* memory) {
21 memory->d.load32 = GBALoad32;
22 memory->d.load16 = GBALoad16;
23 memory->d.loadU16 = GBALoadU16;
24 memory->d.load8 = GBALoad8;
25 memory->d.loadU8 = GBALoadU8;
26 memory->d.store32 = GBAStore32;
27 memory->d.store16 = GBAStore16;
28 memory->d.store8 = GBAStore8;
29
30 memory->bios = (uint32_t*) hleBios;
31 memory->wram = mmap(0, SIZE_WORKING_RAM, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
32 memory->iwram = mmap(0, SIZE_WORKING_IRAM, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
33 memory->rom = 0;
34 memset(memory->io, 0, sizeof(memory->io));
35 memset(memory->dma, 0, sizeof(memory->dma));
36
37 if (!memory->wram || !memory->iwram) {
38 GBAMemoryDeinit(memory);
39 memory->p->errno = GBA_OUT_OF_MEMORY;
40 memory->p->errstr = GBA_CANNOT_MMAP;
41 }
42
43 GBASavedataInit(&memory->savedata, "test.sav");
44
45 int i;
46 for (i = 0; i < 16; ++i) {
47 memory->waitstates16[i] = GBA_BASE_WAITSTATES[i];
48 memory->waitstatesSeq16[i] = GBA_BASE_WAITSTATES_SEQ[i];
49 memory->waitstates32[i] = GBA_BASE_WAITSTATES[i] + GBA_BASE_WAITSTATES_SEQ[i] + 1;
50 memory->waitstatesSeq32[i] = GBA_BASE_WAITSTATES_SEQ[i] + GBA_BASE_WAITSTATES_SEQ[i] + 1;
51 }
52 for (; i < 256; ++i) {
53 memory->waitstates16[i] = 0;
54 memory->waitstatesSeq16[i] = 0;
55 memory->waitstates32[i] = 0;
56 memory->waitstatesSeq32[i] = 0;
57 }
58
59 memory->activeRegion = 0;
60 memory->d.activeRegion = 0;
61 memory->d.activeMask = 0;
62 memory->d.setActiveRegion = GBASetActiveRegion;
63 memory->d.activePrefetchCycles32 = 0;
64 memory->d.activePrefetchCycles16 = 0;
65}
66
67void GBAMemoryDeinit(struct GBAMemory* memory) {
68 munmap(memory->wram, SIZE_WORKING_RAM);
69 munmap(memory->iwram, SIZE_WORKING_IRAM);
70 GBASavedataDeinit(&memory->savedata);
71}
72
73static void GBASetActiveRegion(struct ARMMemory* memory, uint32_t address) {
74 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
75
76 memory->activePrefetchCycles32 = gbaMemory->waitstates32[address >> BASE_OFFSET];
77 memory->activePrefetchCycles16 = gbaMemory->waitstates16[address >> BASE_OFFSET];
78 gbaMemory->activeRegion = address >> BASE_OFFSET;
79 switch (address & ~OFFSET_MASK) {
80 case BASE_BIOS:
81 memory->activeRegion = gbaMemory->bios;
82 memory->activeMask = SIZE_BIOS - 1;
83 break;
84 case BASE_WORKING_RAM:
85 memory->activeRegion = gbaMemory->wram;
86 memory->activeMask = SIZE_WORKING_RAM - 1;
87 break;
88 case BASE_WORKING_IRAM:
89 memory->activeRegion = gbaMemory->iwram;
90 memory->activeMask = SIZE_WORKING_IRAM - 1;
91 break;
92 case BASE_CART0:
93 case BASE_CART0_EX:
94 case BASE_CART1:
95 case BASE_CART1_EX:
96 case BASE_CART2:
97 case BASE_CART2_EX:
98 memory->activeRegion = gbaMemory->rom;
99 memory->activeMask = SIZE_CART0 - 1;
100 break;
101 default:
102 memory->activeRegion = 0;
103 memory->activeMask = 0;
104 break;
105 }
106}
107
108int32_t GBALoad32(struct ARMMemory* memory, uint32_t address) {
109 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
110
111 switch (address & ~OFFSET_MASK) {
112 case BASE_BIOS:
113 break;
114 case BASE_WORKING_RAM:
115 return gbaMemory->wram[(address & (SIZE_WORKING_RAM - 1)) >> 2];
116 case BASE_WORKING_IRAM:
117 return gbaMemory->iwram[(address & (SIZE_WORKING_IRAM - 1)) >> 2];
118 case BASE_IO:
119 return GBAIORead(gbaMemory->p, address & (SIZE_IO - 1)) | (GBAIORead(gbaMemory->p, (address & (SIZE_IO - 1)) | 2) << 16);
120 case BASE_PALETTE_RAM:
121 return ((int32_t*) gbaMemory->p->video.palette)[(address & (SIZE_PALETTE_RAM - 1)) >> 2];
122 case BASE_VRAM:
123 return ((int32_t*) gbaMemory->p->video.vram)[(address & 0x0001FFFF) >> 2];
124 case BASE_OAM:
125 break;
126 case BASE_CART0:
127 case BASE_CART0_EX:
128 case BASE_CART1:
129 case BASE_CART1_EX:
130 case BASE_CART2:
131 case BASE_CART2_EX:
132 if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) {
133 return gbaMemory->rom[(address & (SIZE_CART0 - 1)) >> 2];
134 }
135 case BASE_CART_SRAM:
136 break;
137 default:
138 break;
139 }
140
141 return 0;
142}
143
144int16_t GBALoad16(struct ARMMemory* memory, uint32_t address) {
145 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
146
147 switch (address & ~OFFSET_MASK) {
148 case BASE_BIOS:
149 break;
150 case BASE_WORKING_RAM:
151 return ((int16_t*) gbaMemory->wram)[(address & (SIZE_WORKING_RAM - 1)) >> 1];
152 case BASE_WORKING_IRAM:
153 return ((int16_t*) gbaMemory->iwram)[(address & (SIZE_WORKING_IRAM - 1)) >> 1];
154 case BASE_IO:
155 return GBAIORead(gbaMemory->p, address & (SIZE_IO - 1));
156 case BASE_PALETTE_RAM:
157 return gbaMemory->p->video.palette[(address & (SIZE_PALETTE_RAM - 1)) >> 1];
158 case BASE_VRAM:
159 return gbaMemory->p->video.vram[(address & 0x0001FFFF) >> 1];
160 case BASE_OAM:
161 break;
162 case BASE_CART0:
163 case BASE_CART0_EX:
164 case BASE_CART1:
165 case BASE_CART1_EX:
166 case BASE_CART2:
167 case BASE_CART2_EX:
168 if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) {
169 return ((int16_t*) gbaMemory->rom)[(address & (SIZE_CART0 - 1)) >> 1];
170 }
171 case BASE_CART_SRAM:
172 break;
173 default:
174 break;
175 }
176
177 return 0;
178}
179
180uint16_t GBALoadU16(struct ARMMemory* memory, uint32_t address) {
181 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
182
183 switch (address & ~OFFSET_MASK) {
184 case BASE_BIOS:
185 break;
186 case BASE_WORKING_RAM:
187 return ((uint16_t*) gbaMemory->wram)[(address & (SIZE_WORKING_RAM - 1)) >> 1];
188 case BASE_WORKING_IRAM:
189 return ((uint16_t*) gbaMemory->iwram)[(address & (SIZE_WORKING_IRAM - 1)) >> 1];
190 case BASE_IO:
191 return GBAIORead(gbaMemory->p, address & (SIZE_IO - 1));
192 case BASE_PALETTE_RAM:
193 return gbaMemory->p->video.palette[(address & (SIZE_PALETTE_RAM - 1)) >> 1];
194 case BASE_VRAM:
195 return gbaMemory->p->video.vram[(address & 0x0001FFFF) >> 1];
196 case BASE_OAM:
197 break;
198 case BASE_CART0:
199 case BASE_CART0_EX:
200 case BASE_CART1:
201 case BASE_CART1_EX:
202 case BASE_CART2:
203 case BASE_CART2_EX:
204 if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) {
205 return ((uint16_t*) gbaMemory->rom)[(address & (SIZE_CART0 - 1)) >> 1];
206 }
207 case BASE_CART_SRAM:
208 break;
209 default:
210 break;
211 }
212
213 return 0;
214}
215
216int8_t GBALoad8(struct ARMMemory* memory, uint32_t address) {
217 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
218
219 switch (address & ~OFFSET_MASK) {
220 case BASE_BIOS:
221 break;
222 case BASE_WORKING_RAM:
223 return ((int8_t*) gbaMemory->wram)[address & (SIZE_WORKING_RAM - 1)];
224 case BASE_WORKING_IRAM:
225 return ((int8_t*) gbaMemory->iwram)[address & (SIZE_WORKING_IRAM - 1)];
226 case BASE_IO:
227 break;
228 case BASE_PALETTE_RAM:
229 break;
230 case BASE_VRAM:
231 break;
232 case BASE_OAM:
233 break;
234 case BASE_CART0:
235 case BASE_CART0_EX:
236 case BASE_CART1:
237 case BASE_CART1_EX:
238 case BASE_CART2:
239 case BASE_CART2_EX:
240 if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) {
241 return ((int8_t*) gbaMemory->rom)[address & (SIZE_CART0 - 1)];
242 }
243 case BASE_CART_SRAM:
244 if (gbaMemory->savedata.type == SAVEDATA_NONE) {
245 GBASavedataInitSRAM(&gbaMemory->savedata);
246 }
247 return gbaMemory->savedata.data[address & (SIZE_CART_SRAM - 1)];
248 default:
249 break;
250 }
251
252 return 0;
253}
254
255uint8_t GBALoadU8(struct ARMMemory* memory, uint32_t address) {
256 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
257
258 switch (address & ~OFFSET_MASK) {
259 case BASE_BIOS:
260 break;
261 case BASE_WORKING_RAM:
262 return ((uint8_t*) gbaMemory->wram)[address & (SIZE_WORKING_RAM - 1)];
263 break;
264 case BASE_WORKING_IRAM:
265 return ((uint8_t*) gbaMemory->iwram)[address & (SIZE_WORKING_IRAM - 1)];
266 break;
267 case BASE_IO:
268 return (GBAIORead(gbaMemory->p, address & 0xFFFE) >> ((address & 0x0001) << 3)) & 0xFF;
269 case BASE_PALETTE_RAM:
270 break;
271 case BASE_VRAM:
272 break;
273 case BASE_OAM:
274 break;
275 case BASE_CART0:
276 case BASE_CART0_EX:
277 case BASE_CART1:
278 case BASE_CART1_EX:
279 case BASE_CART2:
280 case BASE_CART2_EX:
281 if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) {
282 return ((uint8_t*) gbaMemory->rom)[address & (SIZE_CART0 - 1)];
283 }
284 case BASE_CART_SRAM:
285 if (gbaMemory->savedata.type == SAVEDATA_NONE) {
286 GBASavedataInitSRAM(&gbaMemory->savedata);
287 }
288 return gbaMemory->savedata.data[address & (SIZE_CART_SRAM - 1)];
289 default:
290 break;
291 }
292
293 return 0;
294}
295
296void GBAStore32(struct ARMMemory* memory, uint32_t address, int32_t value) {
297 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
298
299 switch (address & ~OFFSET_MASK) {
300 case BASE_WORKING_RAM:
301 gbaMemory->wram[(address & (SIZE_WORKING_RAM - 1)) >> 2] = value;
302 break;
303 case BASE_WORKING_IRAM:
304 gbaMemory->iwram[(address & (SIZE_WORKING_IRAM - 1)) >> 2] = value;
305 break;
306 case BASE_IO:
307 GBAIOWrite32(gbaMemory->p, address & (SIZE_IO - 1), value);
308 break;
309 case BASE_PALETTE_RAM:
310 ((int32_t*) gbaMemory->p->video.palette)[(address & (SIZE_PALETTE_RAM - 1)) >> 2] = value;
311 break;
312 case BASE_VRAM:
313 if ((address & OFFSET_MASK) < SIZE_VRAM - 2) {
314 ((int32_t*) gbaMemory->p->video.vram)[(address & 0x0001FFFF) >> 2] = value;
315 }
316 break;
317 case BASE_OAM:
318 ((int32_t*) gbaMemory->p->video.oam.raw)[(address & (SIZE_OAM - 1)) >> 2] = value;
319 break;
320 case BASE_CART0:
321 break;
322 case BASE_CART_SRAM:
323 break;
324 default:
325 break;
326 }
327}
328
329void GBAStore16(struct ARMMemory* memory, uint32_t address, int16_t value) {
330 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
331
332 switch (address & ~OFFSET_MASK) {
333 case BASE_WORKING_RAM:
334 ((int16_t*) gbaMemory->wram)[(address & (SIZE_WORKING_RAM - 1)) >> 1] = value;
335 break;
336 case BASE_WORKING_IRAM:
337 ((int16_t*) gbaMemory->iwram)[(address & (SIZE_WORKING_IRAM - 1)) >> 1] = value;
338 break;
339 case BASE_IO:
340 GBAIOWrite(gbaMemory->p, address & (SIZE_IO - 1), value);
341 break;
342 case BASE_PALETTE_RAM:
343 gbaMemory->p->video.palette[(address & (SIZE_PALETTE_RAM - 1)) >> 1] = value;
344 break;
345 case BASE_VRAM:
346 if ((address & OFFSET_MASK) < SIZE_VRAM) {
347 gbaMemory->p->video.vram[(address & 0x0001FFFF) >> 1] = value;
348 }
349 break;
350 case BASE_OAM:
351 gbaMemory->p->video.oam.raw[(address & (SIZE_OAM - 1)) >> 1] = value;
352 break;
353 case BASE_CART0:
354 break;
355 case BASE_CART2_EX:
356 if (gbaMemory->savedata.type == SAVEDATA_NONE) {
357 GBASavedataInitEEPROM(&gbaMemory->savedata);
358 }
359 GBASavedataWriteEEPROM(&gbaMemory->savedata, value);
360 break;
361 case BASE_CART_SRAM:
362 break;
363 default:
364 break;
365 }
366}
367
368void GBAStore8(struct ARMMemory* memory, uint32_t address, int8_t value) {
369 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
370
371 switch (address & ~OFFSET_MASK) {
372 case BASE_WORKING_RAM:
373 ((int8_t*) gbaMemory->wram)[address & (SIZE_WORKING_RAM - 1)] = value;
374 break;
375 case BASE_WORKING_IRAM:
376 ((int8_t*) gbaMemory->iwram)[address & (SIZE_WORKING_IRAM - 1)] = value;
377 break;
378 case BASE_IO:
379 break;
380 case BASE_PALETTE_RAM:
381 break;
382 case BASE_VRAM:
383 break;
384 case BASE_OAM:
385 break;
386 case BASE_CART0:
387 break;
388 case BASE_CART_SRAM:
389 if (gbaMemory->savedata.type == SAVEDATA_NONE) {
390 if (address == SAVEDATA_FLASH_BASE) {
391 GBASavedataInitFlash(&gbaMemory->savedata);
392 } else {
393 GBASavedataInitSRAM(&gbaMemory->savedata);
394 }
395 }
396 if (gbaMemory->savedata.type == SAVEDATA_FLASH512 || gbaMemory->savedata.type == SAVEDATA_FLASH1M) {
397 GBASavedataWriteFlash(&gbaMemory->savedata, value);
398 } else if (gbaMemory->savedata.type == SAVEDATA_SRAM) {
399 gbaMemory->savedata.data[address & (SIZE_CART_SRAM - 1)] = value;
400 }
401 break;
402 default:
403 break;
404 }
405}
406
407void GBAAdjustWaitstates(struct GBAMemory* memory, uint16_t parameters) {
408 int sram = parameters & 0x0003;
409 int ws0 = (parameters & 0x000C) >> 2;
410 int ws0seq = (parameters & 0x0010) >> 4;
411 int ws1 = (parameters & 0x0060) >> 5;
412 int ws1seq = (parameters & 0x0080) >> 7;
413 int ws2 = (parameters & 0x0300) >> 8;
414 int ws2seq = (parameters & 0x0400) >> 10;
415 int prefetch = parameters & 0x4000;
416
417 memory->waitstates16[REGION_CART_SRAM] = GBA_ROM_WAITSTATES[sram];
418 memory->waitstatesSeq16[REGION_CART_SRAM] = GBA_ROM_WAITSTATES[sram];
419 memory->waitstates32[REGION_CART_SRAM] = 2 * GBA_ROM_WAITSTATES[sram] + 1;
420 memory->waitstatesSeq32[REGION_CART_SRAM] = 2 * GBA_ROM_WAITSTATES[sram] + 1;
421
422 memory->waitstates16[REGION_CART0] = memory->waitstates16[REGION_CART0_EX] = GBA_ROM_WAITSTATES[ws0];
423 memory->waitstates16[REGION_CART1] = memory->waitstates16[REGION_CART1_EX] = GBA_ROM_WAITSTATES[ws1];
424 memory->waitstates16[REGION_CART2] = memory->waitstates16[REGION_CART2_EX] = GBA_ROM_WAITSTATES[ws2];
425
426 memory->waitstatesSeq16[REGION_CART0] = memory->waitstatesSeq16[REGION_CART0_EX] = GBA_ROM_WAITSTATES_SEQ[ws0seq];
427 memory->waitstatesSeq16[REGION_CART1] = memory->waitstatesSeq16[REGION_CART1_EX] = GBA_ROM_WAITSTATES_SEQ[ws1seq + 2];
428 memory->waitstatesSeq16[REGION_CART2] = memory->waitstatesSeq16[REGION_CART2_EX] = GBA_ROM_WAITSTATES_SEQ[ws2seq + 4];
429
430 memory->waitstates32[REGION_CART0] = memory->waitstates32[REGION_CART0_EX] = memory->waitstates16[REGION_CART0] + 1 + memory->waitstatesSeq16[REGION_CART0];
431 memory->waitstates32[REGION_CART1] = memory->waitstates32[REGION_CART1_EX] = memory->waitstates16[REGION_CART1] + 1 + memory->waitstatesSeq16[REGION_CART1];
432 memory->waitstates32[REGION_CART2] = memory->waitstates32[REGION_CART2_EX] = memory->waitstates16[REGION_CART2] + 1 + memory->waitstatesSeq16[REGION_CART2];
433
434 memory->waitstatesSeq32[REGION_CART0] = memory->waitstatesSeq32[REGION_CART0 + 1] = 2 * memory->waitstatesSeq16[REGION_CART0] + 1;
435 memory->waitstatesSeq32[REGION_CART1] = memory->waitstatesSeq32[REGION_CART1 + 1] = 2 * memory->waitstatesSeq16[REGION_CART1] + 1;
436 memory->waitstatesSeq32[REGION_CART2] = memory->waitstatesSeq32[REGION_CART2 + 1] = 2 * memory->waitstatesSeq16[REGION_CART2] + 1;
437
438 memory->d.activePrefetchCycles32 = memory->waitstates32[memory->activeRegion];
439 memory->d.activePrefetchCycles16 = memory->waitstates16[memory->activeRegion];
440}
441
442int32_t GBAMemoryProcessEvents(struct GBAMemory* memory, int32_t cycles) {
443 struct GBADMA* dma;
444 int32_t test = INT_MAX;
445
446 dma = &memory->dma[0];
447 dma->nextIRQ -= cycles;
448 if (dma->enable && dma->doIrq && dma->nextIRQ) {
449 if (dma->nextIRQ <= 0) {
450 dma->nextIRQ = INT_MAX;
451 GBARaiseIRQ(memory->p, IRQ_DMA0);
452 } else if (dma->nextIRQ < test) {
453 test = dma->nextIRQ;
454 }
455 }
456
457 dma = &memory->dma[1];
458 dma->nextIRQ -= cycles;
459 if (dma->enable && dma->doIrq && dma->nextIRQ) {
460 if (dma->nextIRQ <= 0) {
461 dma->nextIRQ = INT_MAX;
462 GBARaiseIRQ(memory->p, IRQ_DMA1);
463 } else if (dma->nextIRQ < test) {
464 test = dma->nextIRQ;
465 }
466 }
467
468 dma = &memory->dma[2];
469 dma->nextIRQ -= cycles;
470 if (dma->enable && dma->doIrq && dma->nextIRQ) {
471 if (dma->nextIRQ <= 0) {
472 dma->nextIRQ = INT_MAX;
473 GBARaiseIRQ(memory->p, IRQ_DMA2);
474 } else if (dma->nextIRQ < test) {
475 test = dma->nextIRQ;
476 }
477 }
478
479 dma = &memory->dma[3];
480 dma->nextIRQ -= cycles;
481 if (dma->enable && dma->doIrq && dma->nextIRQ) {
482 if (dma->nextIRQ <= 0) {
483 dma->nextIRQ = INT_MAX;
484 GBARaiseIRQ(memory->p, IRQ_DMA3);
485 } else if (dma->nextIRQ < test) {
486 test = dma->nextIRQ;
487 }
488 }
489
490 return test;
491}
492
493void GBAMemoryWriteDMASAD(struct GBAMemory* memory, int dma, uint32_t address) {
494 memory->dma[dma].source = address & 0xFFFFFFFE;
495}
496
497void GBAMemoryWriteDMADAD(struct GBAMemory* memory, int dma, uint32_t address) {
498 memory->dma[dma].dest = address & 0xFFFFFFFE;
499}
500
501void GBAMemoryWriteDMACNT_LO(struct GBAMemory* memory, int dma, uint16_t count) {
502 memory->dma[dma].count = count ? count : (dma == 3 ? 0x10000 : 0x4000);
503}
504
505uint16_t GBAMemoryWriteDMACNT_HI(struct GBAMemory* memory, int dma, uint16_t control) {
506 struct GBADMA* currentDma = &memory->dma[dma];
507 int wasEnabled = currentDma->enable;
508 currentDma->packed = control;
509 currentDma->nextIRQ = 0;
510
511 if (currentDma->drq) {
512 GBALog(GBA_LOG_STUB, "DRQ not implemented");
513 }
514
515 if (!wasEnabled && currentDma->enable) {
516 currentDma->nextSource = currentDma->source;
517 currentDma->nextDest = currentDma->dest;
518 currentDma->nextCount = currentDma->count;
519 GBAMemoryScheduleDMA(memory, dma, currentDma);
520 }
521 // If the DMA has already occurred, this value might have changed since the function started
522 return currentDma->packed;
523};
524
525void GBAMemoryScheduleDMA(struct GBAMemory* memory, int number, struct GBADMA* info) {
526 switch (info->timing) {
527 case DMA_TIMING_NOW:
528 GBAMemoryServiceDMA(memory, number, info);
529 break;
530 case DMA_TIMING_HBLANK:
531 // Handled implicitly
532 break;
533 case DMA_TIMING_VBLANK:
534 // Handled implicitly
535 break;
536 case DMA_TIMING_CUSTOM:
537 switch (number) {
538 case 0:
539 GBALog(GBA_LOG_WARN, "Discarding invalid DMA0 scheduling");
540 break;
541 case 1:
542 case 2:
543 //this.cpu.irq.audio.scheduleFIFODma(number, info);
544 break;
545 case 3:
546 //this.cpu.irq.video.scheduleVCaptureDma(dma, info);
547 break;
548 }
549 }
550}
551
552void GBAMemoryRunHblankDMAs(struct GBAMemory* memory) {
553 struct GBADMA* dma;
554 int i;
555 for (i = 0; i < 4; ++i) {
556 dma = &memory->dma[i];
557 if (dma->enable && dma->timing == DMA_TIMING_HBLANK) {
558 GBAMemoryServiceDMA(memory, i, dma);
559 }
560 }
561}
562
563void GBAMemoryRunVblankDMAs(struct GBAMemory* memory) {
564 struct GBADMA* dma;
565 int i;
566 for (i = 0; i < 4; ++i) {
567 dma = &memory->dma[i];
568 if (dma->enable && dma->timing == DMA_TIMING_VBLANK) {
569 GBAMemoryServiceDMA(memory, i, dma);
570 }
571 }
572}
573
574void GBAMemoryServiceDMA(struct GBAMemory* memory, int number, struct GBADMA* info) {
575 if (!info->enable) {
576 // There was a DMA scheduled that got canceled
577 return;
578 }
579
580 uint32_t width = info->width ? 4 : 2;
581 int sourceOffset = DMA_OFFSET[info->srcControl] * width;
582 int destOffset = DMA_OFFSET[info->dstControl] * width;
583 int32_t wordsRemaining = info->nextCount;
584 uint32_t source = info->nextSource;
585 uint32_t dest = info->nextDest;
586 uint32_t sourceRegion = source >> BASE_OFFSET;
587 uint32_t destRegion = dest >> BASE_OFFSET;
588
589 if (width == 4) {
590 int32_t word;
591 source &= 0xFFFFFFFC;
592 dest &= 0xFFFFFFFC;
593 while (wordsRemaining--) {
594 word = GBALoad32(&memory->d, source);
595 GBAStore32(&memory->d, dest, word);
596 source += sourceOffset;
597 dest += destOffset;
598 }
599 } else {
600 uint16_t word;
601 if (source >> BASE_OFFSET == BASE_CART2_EX && memory->savedata.type == SAVEDATA_EEPROM) {
602 while (wordsRemaining--) {
603 word = GBASavedataReadEEPROM(&memory->savedata);
604 GBAStore16(&memory->d, dest, word);
605 source += sourceOffset;
606 dest += destOffset;
607 }
608 } else if (dest >> BASE_OFFSET == BASE_CART2_EX && memory->savedata.type == SAVEDATA_EEPROM) {
609 while (wordsRemaining--) {
610 word = GBALoadU16(&memory->d, source);
611 GBASavedataWriteEEPROM(&memory->savedata, word);
612 source += sourceOffset;
613 dest += destOffset;
614 }
615 } else {
616 while (wordsRemaining--) {
617 word = GBALoadU16(&memory->d, source);
618 GBAStore16(&memory->d, dest, word);
619 source += sourceOffset;
620 dest += destOffset;
621 }
622 }
623 }
624
625 if (info->doIrq) {
626 info->nextIRQ = memory->p->cpu.cycles + 2;
627 info->nextIRQ += (width == 4 ? memory->waitstates32[sourceRegion] + memory->waitstates32[destRegion]
628 : memory->waitstates16[sourceRegion] + memory->waitstates16[destRegion]);
629 info->nextIRQ += (info->count - 1) * (width == 4 ? memory->waitstatesSeq32[sourceRegion] + memory->waitstatesSeq32[destRegion]
630 : memory->waitstatesSeq16[sourceRegion] + memory->waitstatesSeq16[destRegion]);
631 }
632
633 info->nextSource = source;
634 info->nextDest = dest;
635 info->nextCount = wordsRemaining;
636
637 if (!info->repeat) {
638 info->enable = 0;
639
640 // Clear the enable bit in memory
641 memory->io[(REG_DMA0CNT_HI + number * (REG_DMA1CNT_HI - REG_DMA0CNT_HI)) >> 1] &= 0x7FE0;
642 } else {
643 info->nextCount = info->count;
644 if (info->dstControl == DMA_INCREMENT_RELOAD) {
645 info->nextDest = info->dest;
646 }
647 GBAMemoryScheduleDMA(memory, number, info);
648 }
649}