src/gba/gba-memory.c (view raw)
1#include "gba-memory.h"
2
3#include "macros.h"
4
5#include "gba-gpio.h"
6#include "gba-io.h"
7#include "gba-serialize.h"
8#include "hle-bios.h"
9#include "util/memory.h"
10
11static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t region);
12static void GBAMemoryServiceDMA(struct GBA* gba, int number, struct GBADMA* info);
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_32[16] = { 0, 0, 5, 0, 0, 0, 0, 0, 7, 7, 9, 9, 13, 13, 9 };
16static const char GBA_BASE_WAITSTATES_SEQ[16] = { 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4 };
17static const char GBA_BASE_WAITSTATES_SEQ_32[16] = { 0, 0, 5, 0, 0, 0, 0, 0, 5, 5, 9, 9, 17, 17, 9 };
18static const char GBA_ROM_WAITSTATES[] = { 4, 3, 2, 8 };
19static const char GBA_ROM_WAITSTATES_SEQ[] = { 2, 1, 4, 1, 8, 1 };
20static const int DMA_OFFSET[] = { 1, -1, 0, 1 };
21
22void GBAMemoryInit(struct GBA* gba) {
23 struct ARMCore* cpu = gba->cpu;
24 cpu->memory.load32 = GBALoad32;
25 cpu->memory.load16 = GBALoad16;
26 cpu->memory.loadU16 = GBALoadU16;
27 cpu->memory.load8 = GBALoad8;
28 cpu->memory.loadU8 = GBALoadU8;
29 cpu->memory.loadMultiple = GBALoadMultiple;
30 cpu->memory.store32 = GBAStore32;
31 cpu->memory.store16 = GBAStore16;
32 cpu->memory.store8 = GBAStore8;
33 cpu->memory.storeMultiple = GBAStoreMultiple;
34
35 gba->memory.bios = (uint32_t*) hleBios;
36 gba->memory.fullBios = 0;
37 gba->memory.wram = 0;
38 gba->memory.iwram = 0;
39 gba->memory.rom = 0;
40 gba->memory.gpio.p = gba;
41
42 int i;
43 for (i = 0; i < 16; ++i) {
44 gba->memory.waitstatesNonseq16[i] = GBA_BASE_WAITSTATES[i];
45 gba->memory.waitstatesSeq16[i] = GBA_BASE_WAITSTATES_SEQ[i];
46 gba->memory.waitstatesPrefetchNonseq16[i] = GBA_BASE_WAITSTATES[i];
47 gba->memory.waitstatesPrefetchSeq16[i] = GBA_BASE_WAITSTATES_SEQ[i];
48 gba->memory.waitstatesNonseq32[i] = GBA_BASE_WAITSTATES_32[i];
49 gba->memory.waitstatesSeq32[i] = GBA_BASE_WAITSTATES_SEQ_32[i];
50 gba->memory.waitstatesPrefetchNonseq32[i] = GBA_BASE_WAITSTATES_32[i];
51 gba->memory.waitstatesPrefetchSeq32[i] = GBA_BASE_WAITSTATES_SEQ_32[i];
52 }
53 for (; i < 256; ++i) {
54 gba->memory.waitstatesNonseq16[i] = 0;
55 gba->memory.waitstatesSeq16[i] = 0;
56 gba->memory.waitstatesNonseq32[i] = 0;
57 gba->memory.waitstatesSeq32[i] = 0;
58 }
59
60 gba->memory.activeRegion = -1;
61 cpu->memory.activeRegion = 0;
62 cpu->memory.activeMask = 0;
63 cpu->memory.setActiveRegion = GBASetActiveRegion;
64 cpu->memory.activeSeqCycles32 = 0;
65 cpu->memory.activeSeqCycles16 = 0;
66 cpu->memory.activeNonseqCycles32 = 0;
67 cpu->memory.activeNonseqCycles16 = 0;
68 cpu->memory.activeUncachedCycles32 = 0;
69 cpu->memory.activeUncachedCycles16 = 0;
70 gba->memory.biosPrefetch = 0;
71}
72
73void GBAMemoryDeinit(struct GBA* gba) {
74 mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM);
75 mappedMemoryFree(gba->memory.iwram, SIZE_WORKING_IRAM);
76 if (gba->memory.rom) {
77 mappedMemoryFree(gba->memory.rom, gba->memory.romSize);
78 }
79 GBASavedataDeinit(&gba->memory.savedata);
80}
81
82void GBAMemoryReset(struct GBA* gba) {
83 if (gba->memory.wram) {
84 mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM);
85 }
86 gba->memory.wram = anonymousMemoryMap(SIZE_WORKING_RAM);
87
88 if (gba->memory.iwram) {
89 mappedMemoryFree(gba->memory.iwram, SIZE_WORKING_IRAM);
90 }
91 gba->memory.iwram = anonymousMemoryMap(SIZE_WORKING_IRAM);
92
93 memset(gba->memory.io, 0, sizeof(gba->memory.io));
94 memset(gba->memory.dma, 0, sizeof(gba->memory.dma));
95 int i;
96 for (i = 0; i < 4; ++i) {
97 gba->memory.dma[i].count = 0x10000;
98 gba->memory.dma[i].nextEvent = INT_MAX;
99 }
100 gba->memory.activeDMA = -1;
101 gba->memory.nextDMA = INT_MAX;
102 gba->memory.eventDiff = 0;
103
104 if (!gba->memory.wram || !gba->memory.iwram) {
105 GBAMemoryDeinit(gba);
106 GBALog(gba, GBA_LOG_FATAL, "Could not map memory");
107 }
108}
109
110static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
111 struct GBA* gba = (struct GBA*) cpu->master;
112 struct GBAMemory* memory = &gba->memory;
113
114 if (address == gba->busyLoop && memory->activeRegion != REGION_BIOS) {
115 GBAHalt(gba);
116 }
117
118 int newRegion = address >> BASE_OFFSET;
119 if (newRegion == memory->activeRegion) {
120 return;
121 }
122 if (memory->activeRegion == REGION_BIOS) {
123 memory->biosPrefetch = cpu->prefetch;
124 }
125 memory->activeRegion = newRegion;
126 switch (address & ~OFFSET_MASK) {
127 case BASE_BIOS:
128 cpu->memory.activeRegion = memory->bios;
129 cpu->memory.activeMask = SIZE_BIOS - 1;
130 break;
131 case BASE_WORKING_RAM:
132 cpu->memory.activeRegion = memory->wram;
133 cpu->memory.activeMask = SIZE_WORKING_RAM - 1;
134 break;
135 case BASE_WORKING_IRAM:
136 cpu->memory.activeRegion = memory->iwram;
137 cpu->memory.activeMask = SIZE_WORKING_IRAM - 1;
138 break;
139 case BASE_VRAM:
140 cpu->memory.activeRegion = (uint32_t*) gba->video.renderer->vram;
141 cpu->memory.activeMask = 0x0000FFFF;
142 break;
143 case BASE_CART0:
144 case BASE_CART0_EX:
145 case BASE_CART1:
146 case BASE_CART1_EX:
147 case BASE_CART2:
148 case BASE_CART2_EX:
149 cpu->memory.activeRegion = memory->rom;
150 cpu->memory.activeMask = SIZE_CART0 - 1;
151 break;
152 default:
153 cpu->memory.activeRegion = 0;
154 cpu->memory.activeMask = 0;
155 GBALog(gba, GBA_LOG_FATAL, "Jumped to invalid address");
156 break;
157 }
158 cpu->memory.activeSeqCycles32 = memory->waitstatesPrefetchSeq32[memory->activeRegion];
159 cpu->memory.activeSeqCycles16 = memory->waitstatesPrefetchSeq16[memory->activeRegion];
160 cpu->memory.activeNonseqCycles32 = memory->waitstatesPrefetchNonseq32[memory->activeRegion];
161 cpu->memory.activeNonseqCycles16 = memory->waitstatesPrefetchNonseq16[memory->activeRegion];
162 cpu->memory.activeUncachedCycles32 = memory->waitstatesNonseq32[memory->activeRegion];
163 cpu->memory.activeUncachedCycles16 = memory->waitstatesNonseq16[memory->activeRegion];
164}
165
166#define LOAD_BIOS \
167 if (memory->activeRegion == REGION_BIOS) { \
168 if (address < SIZE_BIOS) { \
169 LOAD_32(value, address, memory->bios); \
170 } else { \
171 value = 0; \
172 } \
173 } else { \
174 value = memory->biosPrefetch; \
175 }
176
177#define LOAD_WORKING_RAM \
178 LOAD_32(value, address & (SIZE_WORKING_RAM - 1), memory->wram); \
179 wait += waitstatesRegion[REGION_WORKING_RAM];
180
181#define LOAD_WORKING_IRAM LOAD_32(value, address & (SIZE_WORKING_IRAM - 1), memory->iwram);
182#define LOAD_IO value = GBAIORead(gba, (address & (SIZE_IO - 1)) & ~2) | (GBAIORead(gba, (address & (SIZE_IO - 1)) | 2) << 16);
183
184#define LOAD_PALETTE_RAM \
185 LOAD_32(value, address & (SIZE_PALETTE_RAM - 1), gba->video.palette); \
186 ++wait;
187
188#define LOAD_VRAM \
189 LOAD_32(value, address & 0x0001FFFF, gba->video.renderer->vram); \
190 ++wait;
191
192#define LOAD_OAM LOAD_32(value, address & (SIZE_OAM - 1), gba->video.oam.raw);
193
194#define LOAD_CART \
195 wait += waitstatesRegion[address >> BASE_OFFSET]; \
196 if ((address & (SIZE_CART0 - 1)) < memory->romSize) { \
197 LOAD_32(value, address & (SIZE_CART0 - 1), memory->rom); \
198 } else { \
199 value = (address >> 1) & 0xFFFF; \
200 }
201
202#define LOAD_SRAM \
203 GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Load32: 0x%08X", address); \
204 value = 0xDEADBEEF;
205
206#define LOAD_BAD \
207 GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load32: 0x%08X", address); \
208 value = cpu->prefetch; \
209 if (cpu->executionMode == MODE_THUMB) { \
210 value |= value << 16; \
211 }
212
213int32_t GBALoad32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
214 struct GBA* gba = (struct GBA*) cpu->master;
215 struct GBAMemory* memory = &gba->memory;
216 uint32_t value = 0;
217 int wait = 0;
218 char* waitstatesRegion = memory->waitstatesNonseq32;
219
220 switch (address >> BASE_OFFSET) {
221 case REGION_BIOS:
222 LOAD_BIOS;
223 break;
224 case REGION_WORKING_RAM:
225 LOAD_WORKING_RAM;
226 break;
227 case REGION_WORKING_IRAM:
228 LOAD_WORKING_IRAM;
229 break;
230 case REGION_IO:
231 LOAD_IO;
232 break;
233 case REGION_PALETTE_RAM:
234 LOAD_PALETTE_RAM;
235 break;
236 case REGION_VRAM:
237 LOAD_VRAM;
238 break;
239 case REGION_OAM:
240 LOAD_OAM;
241 break;
242 case REGION_CART0:
243 case REGION_CART0_EX:
244 case REGION_CART1:
245 case REGION_CART1_EX:
246 case REGION_CART2:
247 case REGION_CART2_EX:
248 LOAD_CART;
249 break;
250 case REGION_CART_SRAM:
251 case REGION_CART_SRAM_MIRROR:
252 LOAD_SRAM;
253 break;
254 default:
255 LOAD_BAD;
256 break;
257 }
258
259 if (cycleCounter) {
260 *cycleCounter += 2 + wait;
261 }
262 // Unaligned 32-bit loads are "rotated" so they make some semblance of sense
263 int rotate = (address & 3) << 3;
264 return (value >> rotate) | (value << (32 - rotate));
265}
266
267uint16_t GBALoadU16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
268 return GBALoad16(cpu, address, cycleCounter);
269}
270
271int16_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
272 struct GBA* gba = (struct GBA*) cpu->master;
273 struct GBAMemory* memory = &gba->memory;
274 uint16_t value = 0;
275 int wait = 0;
276
277 switch (address >> BASE_OFFSET) {
278 case REGION_BIOS:
279 if (memory->activeRegion == REGION_BIOS) {
280 if (address < SIZE_BIOS) {
281 LOAD_16(value, address, memory->bios);
282 } else {
283 value = 0;
284 }
285 } else {
286 value = memory->biosPrefetch;
287 }
288 break;
289 case REGION_WORKING_RAM:
290 LOAD_16(value, address & (SIZE_WORKING_RAM - 1), memory->wram);
291 wait = memory->waitstatesNonseq16[REGION_WORKING_RAM];
292 break;
293 case REGION_WORKING_IRAM:
294 LOAD_16(value, address & (SIZE_WORKING_IRAM - 1), memory->iwram);
295 break;
296 case REGION_IO:
297 value = GBAIORead(gba, address & (SIZE_IO - 1));
298 break;
299 case REGION_PALETTE_RAM:
300 LOAD_16(value, address & (SIZE_PALETTE_RAM - 1), gba->video.palette);
301 break;
302 case REGION_VRAM:
303 LOAD_16(value, address & 0x0001FFFF, gba->video.renderer->vram);
304 break;
305 case REGION_OAM:
306 LOAD_16(value, address & (SIZE_OAM - 1), gba->video.oam.raw);
307 break;
308 case REGION_CART0:
309 case REGION_CART0_EX:
310 case REGION_CART1:
311 case REGION_CART1_EX:
312 case REGION_CART2:
313 wait = memory->waitstatesNonseq16[address >> BASE_OFFSET];
314 if ((address & (SIZE_CART0 - 1)) < memory->romSize) {
315 LOAD_16(value, address & (SIZE_CART0 - 1), memory->rom);
316 }
317 break;
318 case REGION_CART2_EX:
319 wait = memory->waitstatesNonseq16[address >> BASE_OFFSET];
320 if (memory->savedata.type == SAVEDATA_EEPROM) {
321 value = GBASavedataReadEEPROM(&memory->savedata);
322 } else if ((address & (SIZE_CART0 - 1)) < memory->romSize) {
323 LOAD_16(value, address & (SIZE_CART0 - 1), memory->rom);
324 }
325 break;
326 case REGION_CART_SRAM:
327 case REGION_CART_SRAM_MIRROR:
328 GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Load16: 0x%08X", address);
329 break;
330 default:
331 GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load16: 0x%08X", address);
332 value = cpu->prefetch;
333 break;
334 }
335
336 if (cycleCounter) {
337 *cycleCounter += 2 + wait;
338 }
339 // Unaligned 16-bit loads are "unpredictable", but the GBA rotates them, so we have to, too.
340 int rotate = (address & 1) << 3;
341 return (value >> rotate) | (value << (16 - rotate));
342}
343
344uint8_t GBALoadU8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
345 return GBALoad8(cpu, address, cycleCounter);
346}
347
348int8_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
349 struct GBA* gba = (struct GBA*) cpu->master;
350 struct GBAMemory* memory = &gba->memory;
351 int8_t value = 0;
352 int wait = 0;
353
354 switch (address >> BASE_OFFSET) {
355 case REGION_BIOS:
356 if (memory->activeRegion == REGION_BIOS) {
357 if (address < SIZE_BIOS) {
358 value = ((int8_t*) memory->bios)[address];
359 } else {
360 value = 0;
361 }
362 } else {
363 value = memory->biosPrefetch;
364 }
365 break;
366 case REGION_WORKING_RAM:
367 value = ((int8_t*) memory->wram)[address & (SIZE_WORKING_RAM - 1)];
368 wait = memory->waitstatesNonseq16[REGION_WORKING_RAM];
369 break;
370 case REGION_WORKING_IRAM:
371 value = ((int8_t*) memory->iwram)[address & (SIZE_WORKING_IRAM - 1)];
372 break;
373 case REGION_IO:
374 value = (GBAIORead(gba, address & 0xFFFE) >> ((address & 0x0001) << 3)) & 0xFF;
375 break;
376 case REGION_PALETTE_RAM:
377 value = ((int8_t*) gba->video.palette)[address & (SIZE_PALETTE_RAM - 1)];
378 break;
379 case REGION_VRAM:
380 value = ((int8_t*) gba->video.renderer->vram)[address & 0x0001FFFF];
381 break;
382 case REGION_OAM:
383 GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Load8: 0x%08X", address);
384 break;
385 case REGION_CART0:
386 case REGION_CART0_EX:
387 case REGION_CART1:
388 case REGION_CART1_EX:
389 case REGION_CART2:
390 case REGION_CART2_EX:
391 wait = memory->waitstatesNonseq16[address >> BASE_OFFSET];
392 if ((address & (SIZE_CART0 - 1)) < memory->romSize) {
393 value = ((int8_t*) memory->rom)[address & (SIZE_CART0 - 1)];
394 }
395 break;
396 case REGION_CART_SRAM:
397 case REGION_CART_SRAM_MIRROR:
398 wait = memory->waitstatesNonseq16[address >> BASE_OFFSET];
399 if (memory->savedata.type == SAVEDATA_NONE) {
400 GBALog(gba, GBA_LOG_INFO, "Detected SRAM savegame");
401 GBASavedataInitSRAM(&memory->savedata);
402 }
403 if (memory->savedata.type == SAVEDATA_SRAM) {
404 value = memory->savedata.data[address & (SIZE_CART_SRAM - 1)];
405 } else if (memory->savedata.type == SAVEDATA_FLASH512 || memory->savedata.type == SAVEDATA_FLASH1M) {
406 value = GBASavedataReadFlash(&memory->savedata, address);
407 }
408 break;
409 default:
410 GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load8: 0x%08x", address);
411 value = cpu->prefetch & 0xFF;
412 break;
413 }
414
415 if (cycleCounter) {
416 *cycleCounter += 2 + wait;
417 }
418 return value;
419}
420
421#define STORE_WORKING_RAM \
422 STORE_32(value, address & (SIZE_WORKING_RAM - 1), memory->wram); \
423 wait += waitstatesRegion[REGION_WORKING_RAM];
424
425#define STORE_WORKING_IRAM \
426 STORE_32(value, address & (SIZE_WORKING_IRAM - 1), memory->iwram);
427
428#define STORE_IO \
429 GBAIOWrite32(gba, address & (SIZE_IO - 1), value);
430
431#define STORE_PALETTE_RAM \
432 STORE_32(value, address & (SIZE_PALETTE_RAM - 1), gba->video.palette); \
433 gba->video.renderer->writePalette(gba->video.renderer, (address & (SIZE_PALETTE_RAM - 1)) + 2, value >> 16); \
434 ++wait; \
435 gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 1), value);
436
437#define STORE_VRAM \
438 if ((address & OFFSET_MASK) < SIZE_VRAM) { \
439 STORE_32(value, address & 0x0001FFFF, gba->video.renderer->vram); \
440 } else if ((address & OFFSET_MASK) < 0x00020000) { \
441 STORE_32(value, address & 0x00017FFF, gba->video.renderer->vram); \
442 } \
443 ++wait;
444
445#define STORE_OAM \
446 STORE_32(value, address & (SIZE_OAM - 1), gba->video.oam.raw); \
447 gba->video.renderer->writeOAM(gba->video.renderer, (address & (SIZE_OAM - 4)) >> 1); \
448 gba->video.renderer->writeOAM(gba->video.renderer, ((address & (SIZE_OAM - 4)) >> 1) + 1);
449
450#define STORE_CART \
451 GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store32: 0x%08X", address);
452
453#define STORE_SRAM \
454 GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store32: 0x%08X", address);
455
456#define STORE_BAD \
457 GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Store32: 0x%08X", address);
458
459void GBAStore32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) {
460 struct GBA* gba = (struct GBA*) cpu->master;
461 struct GBAMemory* memory = &gba->memory;
462 int wait = 0;
463 char* waitstatesRegion = memory->waitstatesNonseq32;
464
465 switch (address >> BASE_OFFSET) {
466 case REGION_WORKING_RAM:
467 STORE_WORKING_RAM;
468 break;
469 case REGION_WORKING_IRAM:
470 STORE_WORKING_IRAM
471 break;
472 case REGION_IO:
473 STORE_IO;
474 break;
475 case REGION_PALETTE_RAM:
476 STORE_PALETTE_RAM;
477 break;
478 case REGION_VRAM:
479 STORE_VRAM;
480 break;
481 case REGION_OAM:
482 STORE_OAM;
483 break;
484 case REGION_CART0:
485 case REGION_CART0_EX:
486 case REGION_CART1:
487 case REGION_CART1_EX:
488 case REGION_CART2:
489 case REGION_CART2_EX:
490 STORE_CART;
491 break;
492 case REGION_CART_SRAM:
493 case REGION_CART_SRAM_MIRROR:
494 STORE_SRAM;
495 break;
496 default:
497 STORE_BAD;
498 break;
499 }
500
501 if (cycleCounter) {
502 *cycleCounter += 1 + wait;
503 }
504}
505
506void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter) {
507 struct GBA* gba = (struct GBA*) cpu->master;
508 struct GBAMemory* memory = &gba->memory;
509 int wait = 0;
510
511 switch (address >> BASE_OFFSET) {
512 case REGION_WORKING_RAM:
513 STORE_16(value, address & (SIZE_WORKING_RAM - 1), memory->wram);
514 wait = memory->waitstatesNonseq16[REGION_WORKING_RAM];
515 break;
516 case REGION_WORKING_IRAM:
517 STORE_16(value, address & (SIZE_WORKING_IRAM - 1), memory->iwram);
518 break;
519 case REGION_IO:
520 GBAIOWrite(gba, address & (SIZE_IO - 1), value);
521 break;
522 case REGION_PALETTE_RAM:
523 STORE_16(value, address & (SIZE_PALETTE_RAM - 1), gba->video.palette);
524 gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 1), value);
525 break;
526 case REGION_VRAM:
527 if ((address & OFFSET_MASK) < SIZE_VRAM) {
528 STORE_16(value, address & 0x0001FFFF, gba->video.renderer->vram);
529 } else if ((address & OFFSET_MASK) < 0x00020000) {
530 STORE_16(value, address & 0x00017FFF, gba->video.renderer->vram);
531 }
532 break;
533 case REGION_OAM:
534 STORE_16(value, address & (SIZE_OAM - 1), gba->video.oam.raw);
535 gba->video.renderer->writeOAM(gba->video.renderer, (address & (SIZE_OAM - 1)) >> 1);
536 break;
537 case REGION_CART0:
538 if (IS_GPIO_REGISTER(address & 0xFFFFFF)) {
539 uint32_t reg = address & 0xFFFFFF;
540 GBAGPIOWrite(&memory->gpio, reg, value);
541 } else {
542 GBALog(gba, GBA_LOG_GAME_ERROR, "Bad cartridge Store16: 0x%08X", address);
543 }
544 break;
545 case REGION_CART2_EX:
546 if (memory->savedata.type == SAVEDATA_NONE) {
547 GBALog(gba, GBA_LOG_INFO, "Detected EEPROM savegame");
548 GBASavedataInitEEPROM(&memory->savedata);
549 }
550 GBASavedataWriteEEPROM(&memory->savedata, value, 1);
551 break;
552 case REGION_CART_SRAM:
553 case REGION_CART_SRAM_MIRROR:
554 GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store16: 0x%08X", address);
555 break;
556 default:
557 GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Store16: 0x%08X", address);
558 break;
559 }
560
561 if (cycleCounter) {
562 *cycleCounter += 1 + wait;
563 }
564}
565
566void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter) {
567 struct GBA* gba = (struct GBA*) cpu->master;
568 struct GBAMemory* memory = &gba->memory;
569 int wait = 0;
570
571 switch (address >> BASE_OFFSET) {
572 case REGION_WORKING_RAM:
573 ((int8_t*) memory->wram)[address & (SIZE_WORKING_RAM - 1)] = value;
574 wait = memory->waitstatesNonseq16[REGION_WORKING_RAM];
575 break;
576 case REGION_WORKING_IRAM:
577 ((int8_t*) memory->iwram)[address & (SIZE_WORKING_IRAM - 1)] = value;
578 break;
579 case REGION_IO:
580 GBAIOWrite8(gba, address & (SIZE_IO - 1), value);
581 break;
582 case REGION_PALETTE_RAM:
583 GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store8: 0x%08X", address);
584 break;
585 case REGION_VRAM:
586 if (address >= 0x06018000) {
587 // TODO: check BG mode
588 GBALog(gba, GBA_LOG_GAME_ERROR, "Cannot Store8 to OBJ: 0x%08X", address);
589 break;
590 }
591 ((int8_t*) gba->video.renderer->vram)[address & 0x1FFFE] = value;
592 ((int8_t*) gba->video.renderer->vram)[(address & 0x1FFFE) | 1] = value;
593 break;
594 case REGION_OAM:
595 GBALog(gba, GBA_LOG_GAME_ERROR, "Cannot Store8 to OAM: 0x%08X", address);
596 break;
597 case REGION_CART0:
598 GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store8: 0x%08X", address);
599 break;
600 case REGION_CART_SRAM:
601 case REGION_CART_SRAM_MIRROR:
602 if (memory->savedata.type == SAVEDATA_NONE) {
603 if (address == SAVEDATA_FLASH_BASE) {
604 GBALog(gba, GBA_LOG_INFO, "Detected Flash savegame");
605 GBASavedataInitFlash(&memory->savedata);
606 } else {
607 GBALog(gba, GBA_LOG_INFO, "Detected SRAM savegame");
608 GBASavedataInitSRAM(&memory->savedata);
609 }
610 }
611 if (memory->savedata.type == SAVEDATA_FLASH512 || memory->savedata.type == SAVEDATA_FLASH1M) {
612 GBASavedataWriteFlash(&memory->savedata, address, value);
613 } else if (memory->savedata.type == SAVEDATA_SRAM) {
614 memory->savedata.data[address & (SIZE_CART_SRAM - 1)] = value;
615 }
616 wait = memory->waitstatesNonseq16[REGION_CART_SRAM];
617 break;
618 default:
619 GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Store8: 0x%08X", address);
620 break;
621 }
622
623 if (cycleCounter) {
624 *cycleCounter += 1 + wait;
625 }
626}
627
628#define LDM_LOOP_BEGIN \
629 for (i = 0; i < 16; ++i) { \
630 if (~mask & (1 << i)) { \
631 continue; \
632 }
633
634#define LDM_LOOP_END \
635 waitstatesRegion = memory->waitstatesSeq32; \
636 cpu->gprs[i] = value; \
637 ++wait; \
638 address += 4; \
639 }
640
641uint32_t GBALoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
642 struct GBA* gba = (struct GBA*) cpu->master;
643 struct GBAMemory* memory = &gba->memory;
644 uint32_t value;
645 int wait = 0;
646 char* waitstatesRegion = memory->waitstatesNonseq32;
647
648 int i;
649 int offset = 4;
650 int popcount = 0;
651 if (direction & LSM_D) {
652 offset = -4;
653 popcount = __builtin_popcount(mask);
654 address -= (popcount << 2) - 4;
655 }
656
657 if (direction & LSM_B) {
658 address += offset;
659 }
660
661 address &= 0xFFFFFFFC;
662
663 switch (address >> BASE_OFFSET) {
664 case REGION_WORKING_RAM:
665 LDM_LOOP_BEGIN;
666 LOAD_WORKING_RAM;
667 LDM_LOOP_END;
668 break;
669 case REGION_WORKING_IRAM:
670 LDM_LOOP_BEGIN;
671 LOAD_WORKING_IRAM;
672 LDM_LOOP_END;
673 break;
674 case REGION_IO:
675 LDM_LOOP_BEGIN;
676 LOAD_IO;
677 LDM_LOOP_END;
678 break;
679 case REGION_PALETTE_RAM:
680 LDM_LOOP_BEGIN;
681 LOAD_PALETTE_RAM;
682 LDM_LOOP_END;
683 break;
684 case REGION_VRAM:
685 LDM_LOOP_BEGIN;
686 LOAD_VRAM;
687 LDM_LOOP_END;
688 break;
689 case REGION_OAM:
690 LDM_LOOP_BEGIN;
691 LOAD_OAM;
692 LDM_LOOP_END;
693 break;
694 case REGION_CART0:
695 case REGION_CART0_EX:
696 case REGION_CART1:
697 case REGION_CART1_EX:
698 case REGION_CART2:
699 case REGION_CART2_EX:
700 LDM_LOOP_BEGIN;
701 LOAD_CART;
702 LDM_LOOP_END;
703 break;
704 case REGION_CART_SRAM:
705 case REGION_CART_SRAM_MIRROR:
706 LDM_LOOP_BEGIN;
707 LOAD_SRAM;
708 LDM_LOOP_END;
709 break;
710 default:
711 LDM_LOOP_BEGIN;
712 LOAD_BAD;
713 LDM_LOOP_END;
714 break;
715 }
716
717 if (cycleCounter) {
718 *cycleCounter += wait;
719 }
720
721 if (direction & LSM_B) {
722 address -= offset;
723 }
724
725 if (direction & LSM_D) {
726 address -= (popcount << 2) + 4;
727 }
728
729 return address;
730}
731
732#define STM_LOOP_BEGIN \
733 for (i = 0; i < 16; ++i) { \
734 if (~mask & (1 << i)) { \
735 continue; \
736 } \
737 value = cpu->gprs[i];
738
739#define STM_LOOP_END \
740 waitstatesRegion = memory->waitstatesSeq32; \
741 ++wait; \
742 address += 4; \
743 }
744
745uint32_t GBAStoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
746 struct GBA* gba = (struct GBA*) cpu->master;
747 struct GBAMemory* memory = &gba->memory;
748 uint32_t value;
749 int wait = 0;
750 char* waitstatesRegion = memory->waitstatesNonseq32;
751
752 int i;
753 int offset = 4;
754 int popcount = 0;
755 if (direction & LSM_D) {
756 offset = -4;
757 popcount = __builtin_popcount(mask);
758 address -= (popcount << 2) - 4;
759 }
760
761 if (direction & LSM_B) {
762 address += offset;
763 }
764
765 address &= 0xFFFFFFFC;
766
767 switch (address >> BASE_OFFSET) {
768 case REGION_WORKING_RAM:
769 STM_LOOP_BEGIN;
770 STORE_WORKING_RAM;
771 STM_LOOP_END;
772 break;
773 case REGION_WORKING_IRAM:
774 STM_LOOP_BEGIN;
775 STORE_WORKING_IRAM;
776 STM_LOOP_END;
777 break;
778 case REGION_IO:
779 STM_LOOP_BEGIN;
780 STORE_IO;
781 STM_LOOP_END;
782 break;
783 case REGION_PALETTE_RAM:
784 STM_LOOP_BEGIN;
785 STORE_PALETTE_RAM;
786 STM_LOOP_END;
787 break;
788 case REGION_VRAM:
789 STM_LOOP_BEGIN;
790 STORE_VRAM;
791 STM_LOOP_END;
792 break;
793 case REGION_OAM:
794 STM_LOOP_BEGIN;
795 STORE_OAM;
796 STM_LOOP_END;
797 break;
798 case REGION_CART0:
799 case REGION_CART0_EX:
800 case REGION_CART1:
801 case REGION_CART1_EX:
802 case REGION_CART2:
803 case REGION_CART2_EX:
804 STM_LOOP_BEGIN;
805 STORE_CART;
806 STM_LOOP_END;
807 break;
808 case REGION_CART_SRAM:
809 case REGION_CART_SRAM_MIRROR:
810 STM_LOOP_BEGIN;
811 STORE_SRAM;
812 STM_LOOP_END;
813 break;
814 default:
815 STM_LOOP_BEGIN;
816 STORE_BAD;
817 STM_LOOP_END;
818 break;
819 }
820
821 if (cycleCounter) {
822 *cycleCounter += wait;
823 }
824
825 if (direction & LSM_B) {
826 address -= offset;
827 }
828
829 if (direction & LSM_D) {
830 address -= (popcount << 2) + 4;
831 }
832
833 return address;
834}
835
836void GBAAdjustWaitstates(struct GBA* gba, uint16_t parameters) {
837 struct GBAMemory* memory = &gba->memory;
838 struct ARMCore* cpu = gba->cpu;
839 int sram = parameters & 0x0003;
840 int ws0 = (parameters & 0x000C) >> 2;
841 int ws0seq = (parameters & 0x0010) >> 4;
842 int ws1 = (parameters & 0x0060) >> 5;
843 int ws1seq = (parameters & 0x0080) >> 7;
844 int ws2 = (parameters & 0x0300) >> 8;
845 int ws2seq = (parameters & 0x0400) >> 10;
846 int prefetch = parameters & 0x4000;
847
848 memory->waitstatesNonseq16[REGION_CART_SRAM] = memory->waitstatesNonseq16[REGION_CART_SRAM_MIRROR] = GBA_ROM_WAITSTATES[sram];
849 memory->waitstatesSeq16[REGION_CART_SRAM] = memory->waitstatesSeq16[REGION_CART_SRAM_MIRROR] = GBA_ROM_WAITSTATES[sram];
850 memory->waitstatesNonseq32[REGION_CART_SRAM] = memory->waitstatesNonseq32[REGION_CART_SRAM_MIRROR] = 2 * GBA_ROM_WAITSTATES[sram] + 1;
851 memory->waitstatesSeq32[REGION_CART_SRAM] = memory->waitstatesSeq32[REGION_CART_SRAM_MIRROR] = 2 * GBA_ROM_WAITSTATES[sram] + 1;
852
853 memory->waitstatesNonseq16[REGION_CART0] = memory->waitstatesNonseq16[REGION_CART0_EX] = GBA_ROM_WAITSTATES[ws0];
854 memory->waitstatesNonseq16[REGION_CART1] = memory->waitstatesNonseq16[REGION_CART1_EX] = GBA_ROM_WAITSTATES[ws1];
855 memory->waitstatesNonseq16[REGION_CART2] = memory->waitstatesNonseq16[REGION_CART2_EX] = GBA_ROM_WAITSTATES[ws2];
856
857 memory->waitstatesSeq16[REGION_CART0] = memory->waitstatesSeq16[REGION_CART0_EX] = GBA_ROM_WAITSTATES_SEQ[ws0seq];
858 memory->waitstatesSeq16[REGION_CART1] = memory->waitstatesSeq16[REGION_CART1_EX] = GBA_ROM_WAITSTATES_SEQ[ws1seq + 2];
859 memory->waitstatesSeq16[REGION_CART2] = memory->waitstatesSeq16[REGION_CART2_EX] = GBA_ROM_WAITSTATES_SEQ[ws2seq + 4];
860
861 memory->waitstatesNonseq32[REGION_CART0] = memory->waitstatesNonseq32[REGION_CART0_EX] = memory->waitstatesSeq16[REGION_CART0] + 1 + memory->waitstatesSeq16[REGION_CART0];
862 memory->waitstatesNonseq32[REGION_CART1] = memory->waitstatesNonseq32[REGION_CART1_EX] = memory->waitstatesSeq16[REGION_CART1] + 1 + memory->waitstatesSeq16[REGION_CART1];
863 memory->waitstatesNonseq32[REGION_CART2] = memory->waitstatesNonseq32[REGION_CART2_EX] = memory->waitstatesSeq16[REGION_CART2] + 1 + memory->waitstatesSeq16[REGION_CART2];
864
865 memory->waitstatesSeq32[REGION_CART0] = memory->waitstatesSeq32[REGION_CART0_EX] = 2 * memory->waitstatesSeq16[REGION_CART0] + 1;
866 memory->waitstatesSeq32[REGION_CART1] = memory->waitstatesSeq32[REGION_CART1_EX] = 2 * memory->waitstatesSeq16[REGION_CART1] + 1;
867 memory->waitstatesSeq32[REGION_CART2] = memory->waitstatesSeq32[REGION_CART2_EX] = 2 * memory->waitstatesSeq16[REGION_CART2] + 1;
868
869 if (!prefetch) {
870 memory->waitstatesPrefetchSeq16[REGION_CART0] = memory->waitstatesPrefetchSeq16[REGION_CART0_EX] = memory->waitstatesSeq16[REGION_CART0];
871 memory->waitstatesPrefetchSeq16[REGION_CART1] = memory->waitstatesPrefetchSeq16[REGION_CART1_EX] = memory->waitstatesSeq16[REGION_CART1];
872 memory->waitstatesPrefetchSeq16[REGION_CART2] = memory->waitstatesPrefetchSeq16[REGION_CART2_EX] = memory->waitstatesSeq16[REGION_CART2];
873
874 memory->waitstatesPrefetchSeq32[REGION_CART0] = memory->waitstatesPrefetchSeq32[REGION_CART0_EX] = memory->waitstatesSeq32[REGION_CART0];
875 memory->waitstatesPrefetchSeq32[REGION_CART1] = memory->waitstatesPrefetchSeq32[REGION_CART1_EX] = memory->waitstatesSeq32[REGION_CART1];
876 memory->waitstatesPrefetchSeq32[REGION_CART2] = memory->waitstatesPrefetchSeq32[REGION_CART2_EX] = memory->waitstatesSeq32[REGION_CART2];
877
878 memory->waitstatesPrefetchNonseq16[REGION_CART0] = memory->waitstatesPrefetchNonseq16[REGION_CART0_EX] = memory->waitstatesNonseq16[REGION_CART0];
879 memory->waitstatesPrefetchNonseq16[REGION_CART1] = memory->waitstatesPrefetchNonseq16[REGION_CART1_EX] = memory->waitstatesNonseq16[REGION_CART1];
880 memory->waitstatesPrefetchNonseq16[REGION_CART2] = memory->waitstatesPrefetchNonseq16[REGION_CART2_EX] = memory->waitstatesNonseq16[REGION_CART2];
881
882 memory->waitstatesPrefetchNonseq32[REGION_CART0] = memory->waitstatesPrefetchNonseq32[REGION_CART0_EX] = memory->waitstatesNonseq32[REGION_CART0];
883 memory->waitstatesPrefetchNonseq32[REGION_CART1] = memory->waitstatesPrefetchNonseq32[REGION_CART1_EX] = memory->waitstatesNonseq32[REGION_CART1];
884 memory->waitstatesPrefetchNonseq32[REGION_CART2] = memory->waitstatesPrefetchNonseq32[REGION_CART2_EX] = memory->waitstatesNonseq32[REGION_CART2];
885 } else {
886 memory->waitstatesPrefetchSeq16[REGION_CART0] = memory->waitstatesPrefetchSeq16[REGION_CART0_EX] = 0;
887 memory->waitstatesPrefetchSeq16[REGION_CART1] = memory->waitstatesPrefetchSeq16[REGION_CART1_EX] = 0;
888 memory->waitstatesPrefetchSeq16[REGION_CART2] = memory->waitstatesPrefetchSeq16[REGION_CART2_EX] = 0;
889
890 memory->waitstatesPrefetchSeq32[REGION_CART0] = memory->waitstatesPrefetchSeq32[REGION_CART0_EX] = 0;
891 memory->waitstatesPrefetchSeq32[REGION_CART1] = memory->waitstatesPrefetchSeq32[REGION_CART1_EX] = 0;
892 memory->waitstatesPrefetchSeq32[REGION_CART2] = memory->waitstatesPrefetchSeq32[REGION_CART2_EX] = 0;
893
894 memory->waitstatesPrefetchNonseq16[REGION_CART0] = memory->waitstatesPrefetchNonseq16[REGION_CART0_EX] = 0;
895 memory->waitstatesPrefetchNonseq16[REGION_CART1] = memory->waitstatesPrefetchNonseq16[REGION_CART1_EX] = 0;
896 memory->waitstatesPrefetchNonseq16[REGION_CART2] = memory->waitstatesPrefetchNonseq16[REGION_CART2_EX] = 0;
897
898 memory->waitstatesPrefetchNonseq32[REGION_CART0] = memory->waitstatesPrefetchNonseq32[REGION_CART0_EX] = 0;
899 memory->waitstatesPrefetchNonseq32[REGION_CART1] = memory->waitstatesPrefetchNonseq32[REGION_CART1_EX] = 0;
900 memory->waitstatesPrefetchNonseq32[REGION_CART2] = memory->waitstatesPrefetchNonseq32[REGION_CART2_EX] = 0;
901 }
902
903 cpu->memory.activeSeqCycles32 = memory->waitstatesPrefetchSeq32[memory->activeRegion];
904 cpu->memory.activeSeqCycles16 = memory->waitstatesPrefetchSeq16[memory->activeRegion];
905
906 cpu->memory.activeNonseqCycles32 = memory->waitstatesPrefetchNonseq32[memory->activeRegion];
907 cpu->memory.activeNonseqCycles16 = memory->waitstatesPrefetchNonseq16[memory->activeRegion];
908
909 cpu->memory.activeUncachedCycles32 = memory->waitstatesNonseq32[memory->activeRegion];
910 cpu->memory.activeUncachedCycles16 = memory->waitstatesNonseq16[memory->activeRegion];
911}
912
913void GBAMemoryWriteDMASAD(struct GBA* gba, int dma, uint32_t address) {
914 struct GBAMemory* memory = &gba->memory;
915 memory->dma[dma].source = address & 0xFFFFFFFE;
916}
917
918void GBAMemoryWriteDMADAD(struct GBA* gba, int dma, uint32_t address) {
919 struct GBAMemory* memory = &gba->memory;
920 memory->dma[dma].dest = address & 0xFFFFFFFE;
921}
922
923void GBAMemoryWriteDMACNT_LO(struct GBA* gba, int dma, uint16_t count) {
924 struct GBAMemory* memory = &gba->memory;
925 memory->dma[dma].count = count ? count : (dma == 3 ? 0x10000 : 0x4000);
926}
927
928uint16_t GBAMemoryWriteDMACNT_HI(struct GBA* gba, int dma, uint16_t control) {
929 struct GBAMemory* memory = &gba->memory;
930 struct GBADMA* currentDma = &memory->dma[dma];
931 int wasEnabled = GBADMARegisterIsEnable(currentDma->reg);
932 currentDma->reg = control;
933
934 if (GBADMARegisterIsDRQ(currentDma->reg)) {
935 GBALog(gba, GBA_LOG_STUB, "DRQ not implemented");
936 }
937
938 if (!wasEnabled && GBADMARegisterIsEnable(currentDma->reg)) {
939 currentDma->nextSource = currentDma->source;
940 currentDma->nextDest = currentDma->dest;
941 currentDma->nextCount = currentDma->count;
942 GBAMemoryScheduleDMA(gba, dma, currentDma);
943 }
944 // If the DMA has already occurred, this value might have changed since the function started
945 return currentDma->reg;
946};
947
948void GBAMemoryScheduleDMA(struct GBA* gba, int number, struct GBADMA* info) {
949 struct ARMCore* cpu = gba->cpu;
950 switch (GBADMARegisterGetTiming(info->reg)) {
951 case DMA_TIMING_NOW:
952 info->nextEvent = cpu->cycles;
953 GBAMemoryUpdateDMAs(gba, 0);
954 break;
955 case DMA_TIMING_HBLANK:
956 // Handled implicitly
957 info->nextEvent = INT_MAX;
958 break;
959 case DMA_TIMING_VBLANK:
960 // Handled implicitly
961 info->nextEvent = INT_MAX;
962 break;
963 case DMA_TIMING_CUSTOM:
964 info->nextEvent = INT_MAX;
965 switch (number) {
966 case 0:
967 GBALog(gba, GBA_LOG_WARN, "Discarding invalid DMA0 scheduling");
968 break;
969 case 1:
970 case 2:
971 GBAAudioScheduleFifoDma(&gba->audio, number, info);
972 break;
973 case 3:
974 // GBAVideoScheduleVCaptureDma(dma, info);
975 break;
976 }
977 }
978}
979
980void GBAMemoryRunHblankDMAs(struct GBA* gba, int32_t cycles) {
981 struct GBAMemory* memory = &gba->memory;
982 struct GBADMA* dma;
983 int i;
984 for (i = 0; i < 4; ++i) {
985 dma = &memory->dma[i];
986 if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_HBLANK) {
987 dma->nextEvent = cycles;
988 }
989 }
990 GBAMemoryUpdateDMAs(gba, 0);
991}
992
993void GBAMemoryRunVblankDMAs(struct GBA* gba, int32_t cycles) {
994 struct GBAMemory* memory = &gba->memory;
995 struct GBADMA* dma;
996 int i;
997 for (i = 0; i < 4; ++i) {
998 dma = &memory->dma[i];
999 if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_VBLANK) {
1000 dma->nextEvent = cycles;
1001 }
1002 }
1003 GBAMemoryUpdateDMAs(gba, 0);
1004}
1005
1006int32_t GBAMemoryRunDMAs(struct GBA* gba, int32_t cycles) {
1007 struct GBAMemory* memory = &gba->memory;
1008 if (memory->nextDMA == INT_MAX) {
1009 return INT_MAX;
1010 }
1011 memory->nextDMA -= cycles;
1012 memory->eventDiff += cycles;
1013 if (memory->nextDMA <= 0) {
1014 struct GBADMA* dma = &memory->dma[memory->activeDMA];
1015 GBAMemoryServiceDMA(gba, memory->activeDMA, dma);
1016 GBAMemoryUpdateDMAs(gba, memory->eventDiff);
1017 memory->eventDiff = 0;
1018 }
1019 return memory->nextDMA;
1020}
1021
1022void GBAMemoryUpdateDMAs(struct GBA* gba, int32_t cycles) {
1023 int i;
1024 struct GBAMemory* memory = &gba->memory;
1025 struct ARMCore* cpu = gba->cpu;
1026 memory->activeDMA = -1;
1027 memory->nextDMA = INT_MAX;
1028 for (i = 3; i >= 0; --i) {
1029 struct GBADMA* dma = &memory->dma[i];
1030 if (dma->nextEvent != INT_MAX) {
1031 dma->nextEvent -= cycles;
1032 if (GBADMARegisterIsEnable(dma->reg)) {
1033 memory->activeDMA = i;
1034 memory->nextDMA = dma->nextEvent;
1035 }
1036 }
1037 }
1038 if (memory->nextDMA < cpu->nextEvent) {
1039 cpu->nextEvent = memory->nextDMA;
1040 }
1041}
1042
1043void GBAMemoryServiceDMA(struct GBA* gba, int number, struct GBADMA* info) {
1044 struct GBAMemory* memory = &gba->memory;
1045 struct ARMCore* cpu = gba->cpu;
1046 uint32_t width = GBADMARegisterGetWidth(info->reg) ? 4 : 2;
1047 int sourceOffset = DMA_OFFSET[GBADMARegisterGetSrcControl(info->reg)] * width;
1048 int destOffset = DMA_OFFSET[GBADMARegisterGetDestControl(info->reg)] * width;
1049 int32_t wordsRemaining = info->nextCount;
1050 uint32_t source = info->nextSource;
1051 uint32_t dest = info->nextDest;
1052 uint32_t sourceRegion = source >> BASE_OFFSET;
1053 uint32_t destRegion = dest >> BASE_OFFSET;
1054 int32_t cycles = 0;
1055
1056 if (source == info->source) {
1057 // TODO: support 4 cycles for ROM access
1058 cycles += 2;
1059 if (width == 4) {
1060 cycles += memory->waitstatesNonseq32[sourceRegion] + memory->waitstatesNonseq32[destRegion];
1061 source &= 0xFFFFFFFC;
1062 dest &= 0xFFFFFFFC;
1063 } else {
1064 cycles += memory->waitstatesNonseq16[sourceRegion] + memory->waitstatesNonseq16[destRegion];
1065 }
1066 } else {
1067 if (width == 4) {
1068 cycles += memory->waitstatesSeq32[sourceRegion] + memory->waitstatesSeq32[destRegion];
1069 } else {
1070 cycles += memory->waitstatesSeq16[sourceRegion] + memory->waitstatesSeq16[destRegion];
1071 }
1072 }
1073
1074 if (width == 4) {
1075 int32_t word;
1076 word = cpu->memory.load32(cpu, source, 0);
1077 cpu->memory.store32(cpu, dest, word, 0);
1078 source += sourceOffset;
1079 dest += destOffset;
1080 --wordsRemaining;
1081 } else {
1082 uint16_t word;
1083 if (sourceRegion == REGION_CART2_EX && memory->savedata.type == SAVEDATA_EEPROM) {
1084 word = GBASavedataReadEEPROM(&memory->savedata);
1085 cpu->memory.store16(cpu, dest, word, 0);
1086 source += sourceOffset;
1087 dest += destOffset;
1088 --wordsRemaining;
1089 } else if (destRegion == REGION_CART2_EX) {
1090 if (memory->savedata.type == SAVEDATA_NONE) {
1091 GBALog(gba, GBA_LOG_INFO, "Detected EEPROM savegame");
1092 GBASavedataInitEEPROM(&memory->savedata);
1093 }
1094 word = cpu->memory.load16(cpu, source, 0);
1095 GBASavedataWriteEEPROM(&memory->savedata, word, wordsRemaining);
1096 source += sourceOffset;
1097 dest += destOffset;
1098 --wordsRemaining;
1099 } else {
1100 word = cpu->memory.load16(cpu, source, 0);
1101 cpu->memory.store16(cpu, dest, word, 0);
1102 source += sourceOffset;
1103 dest += destOffset;
1104 --wordsRemaining;
1105 }
1106 }
1107
1108 if (!wordsRemaining) {
1109 if (!GBADMARegisterIsRepeat(info->reg)) {
1110 info->reg = GBADMARegisterClearEnable(info->reg);
1111 info->nextEvent = INT_MAX;
1112
1113 // Clear the enable bit in memory
1114 memory->io[(REG_DMA0CNT_HI + number * (REG_DMA1CNT_HI - REG_DMA0CNT_HI)) >> 1] &= 0x7FE0;
1115 } else {
1116 info->nextCount = info->count;
1117 if (GBADMARegisterGetDestControl(info->reg) == DMA_INCREMENT_RELOAD) {
1118 info->nextDest = info->dest;
1119 }
1120 GBAMemoryScheduleDMA(gba, number, info);
1121 }
1122 if (GBADMARegisterIsDoIRQ(info->reg)) {
1123 GBARaiseIRQ(gba, IRQ_DMA0 + number);
1124 }
1125 } else {
1126 info->nextDest = dest;
1127 info->nextCount = wordsRemaining;
1128 }
1129 info->nextSource = source;
1130
1131 if (info->nextEvent != INT_MAX) {
1132 info->nextEvent += cycles;
1133 }
1134 cpu->cycles += cycles;
1135}
1136
1137void GBAMemorySerialize(struct GBAMemory* memory, struct GBASerializedState* state) {
1138 memcpy(state->wram, memory->wram, SIZE_WORKING_RAM);
1139 memcpy(state->iwram, memory->iwram, SIZE_WORKING_IRAM);
1140}
1141
1142void GBAMemoryDeserialize(struct GBAMemory* memory, struct GBASerializedState* state) {
1143 memcpy(memory->wram, state->wram, SIZE_WORKING_RAM);
1144 memcpy(memory->iwram, state->iwram, SIZE_WORKING_IRAM);
1145}