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