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 value = ((int8_t*) gbaMemory->p->video.renderer->palette)[address & (SIZE_PALETTE_RAM - 1)];
255 break;
256 case BASE_VRAM:
257 break;
258 case BASE_OAM:
259 break;
260 case BASE_CART0:
261 case BASE_CART0_EX:
262 case BASE_CART1:
263 case BASE_CART1_EX:
264 case BASE_CART2:
265 case BASE_CART2_EX:
266 wait = gbaMemory->waitstates16[address >> BASE_OFFSET];
267 if ((address & (SIZE_CART0 - 1)) < gbaMemory->romSize) {
268 value = ((int8_t*) gbaMemory->rom)[address & (SIZE_CART0 - 1)];
269 }
270 break;
271 case BASE_CART_SRAM:
272 wait = gbaMemory->waitstates16[address >> BASE_OFFSET];
273 if (gbaMemory->savedata.type == SAVEDATA_NONE) {
274 GBASavedataInit(&gbaMemory->savedata, gbaMemory->p->savefile);
275 GBASavedataInitSRAM(&gbaMemory->savedata);
276 } else if (gbaMemory->savedata.type == SAVEDATA_SRAM) {
277 value = gbaMemory->savedata.data[address & (SIZE_CART_SRAM - 1)];
278 } else if (gbaMemory->savedata.type == SAVEDATA_FLASH512 || gbaMemory->savedata.type == SAVEDATA_FLASH1M) {
279 value = GBASavedataReadFlash(&gbaMemory->savedata, address);
280 }
281 default:
282 break;
283 }
284
285 if (cycleCounter) {
286 *cycleCounter += 2 + wait;
287 }
288 return value;
289}
290
291void GBAStore32(struct ARMMemory* memory, uint32_t address, int32_t value, int* cycleCounter) {
292 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
293 int wait = 0;
294
295 switch (address & ~OFFSET_MASK) {
296 case BASE_WORKING_RAM:
297 gbaMemory->wram[(address & (SIZE_WORKING_RAM - 1)) >> 2] = value;
298 wait = gbaMemory->waitstates32[REGION_WORKING_RAM];
299 break;
300 case BASE_WORKING_IRAM:
301 gbaMemory->iwram[(address & (SIZE_WORKING_IRAM - 1)) >> 2] = value;
302 break;
303 case BASE_IO:
304 GBAIOWrite32(gbaMemory->p, address & (SIZE_IO - 1), value);
305 break;
306 case BASE_PALETTE_RAM:
307 ((int32_t*) gbaMemory->p->video.palette)[(address & (SIZE_PALETTE_RAM - 1)) >> 2] = value;
308 gbaMemory->p->video.renderer->writePalette(gbaMemory->p->video.renderer, (address & (SIZE_PALETTE_RAM - 1)) + 2, value >> 16);
309 gbaMemory->p->video.renderer->writePalette(gbaMemory->p->video.renderer, address & (SIZE_PALETTE_RAM - 1), value);
310 break;
311 case BASE_VRAM:
312 if ((address & OFFSET_MASK) < SIZE_VRAM - 2) {
313 ((int32_t*) gbaMemory->p->video.renderer->vram)[(address & 0x0001FFFF) >> 2] = value;
314 }
315 break;
316 case BASE_OAM:
317 ((int32_t*) gbaMemory->p->video.oam.raw)[(address & (SIZE_OAM - 1)) >> 2] = value;
318 gbaMemory->p->video.renderer->writeOAM(gbaMemory->p->video.renderer, (address & (SIZE_OAM - 4)) >> 1);
319 gbaMemory->p->video.renderer->writeOAM(gbaMemory->p->video.renderer, ((address & (SIZE_OAM - 4)) >> 1) + 1);
320 break;
321 case BASE_CART0:
322 break;
323 case BASE_CART_SRAM:
324 break;
325 default:
326 break;
327 }
328
329 if (cycleCounter) {
330 *cycleCounter += 1 + wait;
331 }
332}
333
334void GBAStore16(struct ARMMemory* memory, uint32_t address, int16_t value, int* cycleCounter) {
335 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
336 int wait = 0;
337
338 switch (address & ~OFFSET_MASK) {
339 case BASE_WORKING_RAM:
340 ((int16_t*) gbaMemory->wram)[(address & (SIZE_WORKING_RAM - 1)) >> 1] = value;
341 wait = gbaMemory->waitstates16[REGION_WORKING_RAM];
342 break;
343 case BASE_WORKING_IRAM:
344 ((int16_t*) gbaMemory->iwram)[(address & (SIZE_WORKING_IRAM - 1)) >> 1] = value;
345 break;
346 case BASE_IO:
347 GBAIOWrite(gbaMemory->p, address & (SIZE_IO - 1), value);
348 break;
349 case BASE_PALETTE_RAM:
350 gbaMemory->p->video.palette[(address & (SIZE_PALETTE_RAM - 1)) >> 1] = value;
351 gbaMemory->p->video.renderer->writePalette(gbaMemory->p->video.renderer, address & (SIZE_PALETTE_RAM - 1), value);
352 break;
353 case BASE_VRAM:
354 if ((address & OFFSET_MASK) < SIZE_VRAM) {
355 gbaMemory->p->video.renderer->vram[(address & 0x0001FFFF) >> 1] = value;
356 }
357 break;
358 case BASE_OAM:
359 gbaMemory->p->video.oam.raw[(address & (SIZE_OAM - 1)) >> 1] = value;
360 gbaMemory->p->video.renderer->writeOAM(gbaMemory->p->video.renderer, (address & (SIZE_OAM - 1)) >> 1);
361 break;
362 case BASE_CART0:
363 break;
364 case BASE_CART2_EX:
365 if (gbaMemory->savedata.type == SAVEDATA_NONE) {
366 GBASavedataInit(&gbaMemory->savedata, gbaMemory->p->savefile);
367 GBASavedataInitEEPROM(&gbaMemory->savedata);
368 }
369 GBASavedataWriteEEPROM(&gbaMemory->savedata, value, 1);
370 break;
371 case BASE_CART_SRAM:
372 break;
373 default:
374 break;
375 }
376
377 if (cycleCounter) {
378 *cycleCounter += 1 + wait;
379 }
380}
381
382void GBAStore8(struct ARMMemory* memory, uint32_t address, int8_t value, int* cycleCounter) {
383 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
384 int wait = 0;
385
386 switch (address & ~OFFSET_MASK) {
387 case BASE_WORKING_RAM:
388 ((int8_t*) gbaMemory->wram)[address & (SIZE_WORKING_RAM - 1)] = value;
389 wait = gbaMemory->waitstates16[REGION_WORKING_RAM];
390 break;
391 case BASE_WORKING_IRAM:
392 ((int8_t*) gbaMemory->iwram)[address & (SIZE_WORKING_IRAM - 1)] = value;
393 break;
394 case BASE_IO:
395 GBAIOWrite8(gbaMemory->p, address & (SIZE_IO - 1), value);
396 break;
397 case BASE_PALETTE_RAM:
398 break;
399 case BASE_VRAM:
400 break;
401 case BASE_OAM:
402 break;
403 case BASE_CART0:
404 break;
405 case BASE_CART_SRAM:
406 if (gbaMemory->savedata.type == SAVEDATA_NONE) {
407 GBASavedataInit(&gbaMemory->savedata, gbaMemory->p->savefile);
408 if (address == SAVEDATA_FLASH_BASE) {
409 GBASavedataInitFlash(&gbaMemory->savedata);
410 } else {
411 GBASavedataInitSRAM(&gbaMemory->savedata);
412 }
413 }
414 if (gbaMemory->savedata.type == SAVEDATA_FLASH512 || gbaMemory->savedata.type == SAVEDATA_FLASH1M) {
415 GBASavedataWriteFlash(&gbaMemory->savedata, address, value);
416 } else if (gbaMemory->savedata.type == SAVEDATA_SRAM) {
417 gbaMemory->savedata.data[address & (SIZE_CART_SRAM - 1)] = value;
418 }
419 wait = gbaMemory->waitstates16[REGION_CART_SRAM];
420 break;
421 default:
422 break;
423 }
424
425 if (cycleCounter) {
426 *cycleCounter += 1 + wait;
427 }
428}
429
430static int GBAWaitMultiple(struct ARMMemory* memory, uint32_t startAddress, int count) {
431 struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
432 int wait = 1 + gbaMemory->waitstates32[startAddress >> BASE_OFFSET];
433 wait += (1 + gbaMemory->waitstatesSeq32[startAddress >> BASE_OFFSET]) * (count - 1);
434 return wait;
435}
436
437void GBAAdjustWaitstates(struct GBAMemory* memory, uint16_t parameters) {
438 int sram = parameters & 0x0003;
439 int ws0 = (parameters & 0x000C) >> 2;
440 int ws0seq = (parameters & 0x0010) >> 4;
441 int ws1 = (parameters & 0x0060) >> 5;
442 int ws1seq = (parameters & 0x0080) >> 7;
443 int ws2 = (parameters & 0x0300) >> 8;
444 int ws2seq = (parameters & 0x0400) >> 10;
445 int prefetch = parameters & 0x4000;
446
447 memory->waitstates16[REGION_CART_SRAM] = GBA_ROM_WAITSTATES[sram];
448 memory->waitstatesSeq16[REGION_CART_SRAM] = GBA_ROM_WAITSTATES[sram];
449 memory->waitstates32[REGION_CART_SRAM] = 2 * GBA_ROM_WAITSTATES[sram] + 1;
450 memory->waitstatesSeq32[REGION_CART_SRAM] = 2 * GBA_ROM_WAITSTATES[sram] + 1;
451
452 memory->waitstates16[REGION_CART0] = memory->waitstates16[REGION_CART0_EX] = GBA_ROM_WAITSTATES[ws0];
453 memory->waitstates16[REGION_CART1] = memory->waitstates16[REGION_CART1_EX] = GBA_ROM_WAITSTATES[ws1];
454 memory->waitstates16[REGION_CART2] = memory->waitstates16[REGION_CART2_EX] = GBA_ROM_WAITSTATES[ws2];
455
456 memory->waitstatesSeq16[REGION_CART0] = memory->waitstatesSeq16[REGION_CART0_EX] = GBA_ROM_WAITSTATES_SEQ[ws0seq];
457 memory->waitstatesSeq16[REGION_CART1] = memory->waitstatesSeq16[REGION_CART1_EX] = GBA_ROM_WAITSTATES_SEQ[ws1seq + 2];
458 memory->waitstatesSeq16[REGION_CART2] = memory->waitstatesSeq16[REGION_CART2_EX] = GBA_ROM_WAITSTATES_SEQ[ws2seq + 4];
459
460 memory->waitstates32[REGION_CART0] = memory->waitstates32[REGION_CART0_EX] = memory->waitstates16[REGION_CART0] + 1 + memory->waitstatesSeq16[REGION_CART0];
461 memory->waitstates32[REGION_CART1] = memory->waitstates32[REGION_CART1_EX] = memory->waitstates16[REGION_CART1] + 1 + memory->waitstatesSeq16[REGION_CART1];
462 memory->waitstates32[REGION_CART2] = memory->waitstates32[REGION_CART2_EX] = memory->waitstates16[REGION_CART2] + 1 + memory->waitstatesSeq16[REGION_CART2];
463
464 memory->waitstatesSeq32[REGION_CART0] = memory->waitstatesSeq32[REGION_CART0_EX] = 2 * memory->waitstatesSeq16[REGION_CART0] + 1;
465 memory->waitstatesSeq32[REGION_CART1] = memory->waitstatesSeq32[REGION_CART1_EX] = 2 * memory->waitstatesSeq16[REGION_CART1] + 1;
466 memory->waitstatesSeq32[REGION_CART2] = memory->waitstatesSeq32[REGION_CART2_EX] = 2 * memory->waitstatesSeq16[REGION_CART2] + 1;
467
468 if (!prefetch) {
469 memory->waitstatesPrefetch16[REGION_CART0] = memory->waitstatesPrefetch16[REGION_CART0_EX] = memory->waitstatesSeq16[REGION_CART0];
470 memory->waitstatesPrefetch16[REGION_CART1] = memory->waitstatesPrefetch16[REGION_CART1_EX] = memory->waitstatesSeq16[REGION_CART1];
471 memory->waitstatesPrefetch16[REGION_CART2] = memory->waitstatesPrefetch16[REGION_CART2_EX] = memory->waitstatesSeq16[REGION_CART2];
472
473 memory->waitstatesPrefetch32[REGION_CART0] = memory->waitstatesPrefetch32[REGION_CART0_EX] = memory->waitstatesSeq32[REGION_CART0];
474 memory->waitstatesPrefetch32[REGION_CART1] = memory->waitstatesPrefetch32[REGION_CART1_EX] = memory->waitstatesSeq32[REGION_CART1];
475 memory->waitstatesPrefetch32[REGION_CART2] = memory->waitstatesPrefetch32[REGION_CART2_EX] = memory->waitstatesSeq32[REGION_CART2];
476 } else {
477 memory->waitstatesPrefetch16[REGION_CART0] = memory->waitstatesPrefetch16[REGION_CART0_EX] = 0;
478 memory->waitstatesPrefetch16[REGION_CART1] = memory->waitstatesPrefetch16[REGION_CART1_EX] = 0;
479 memory->waitstatesPrefetch16[REGION_CART2] = memory->waitstatesPrefetch16[REGION_CART2_EX] = 0;
480
481 memory->waitstatesPrefetch32[REGION_CART0] = memory->waitstatesPrefetch32[REGION_CART0_EX] = 0;
482 memory->waitstatesPrefetch32[REGION_CART1] = memory->waitstatesPrefetch32[REGION_CART1_EX] = 0;
483 memory->waitstatesPrefetch32[REGION_CART2] = memory->waitstatesPrefetch32[REGION_CART2_EX] = 0;
484 }
485
486 memory->d.activePrefetchCycles32 = memory->waitstatesPrefetch32[memory->activeRegion];
487 memory->d.activePrefetchCycles16 = memory->waitstatesPrefetch16[memory->activeRegion];
488 memory->d.activeNonseqCycles32 = memory->waitstates32[memory->activeRegion];
489 memory->d.activeNonseqCycles16 = memory->waitstates16[memory->activeRegion];
490}
491
492int32_t GBAMemoryProcessEvents(struct GBAMemory* memory, int32_t cycles) {
493 struct GBADMA* dma;
494 int32_t test = INT_MAX;
495
496 dma = &memory->dma[0];
497 dma->nextIRQ -= cycles;
498 if (dma->enable && dma->doIrq && dma->nextIRQ) {
499 if (dma->nextIRQ <= 0) {
500 dma->nextIRQ = INT_MAX;
501 GBARaiseIRQ(memory->p, IRQ_DMA0);
502 } else if (dma->nextIRQ < test) {
503 test = dma->nextIRQ;
504 }
505 }
506
507 dma = &memory->dma[1];
508 dma->nextIRQ -= cycles;
509 if (dma->enable && dma->doIrq && dma->nextIRQ) {
510 if (dma->nextIRQ <= 0) {
511 dma->nextIRQ = INT_MAX;
512 GBARaiseIRQ(memory->p, IRQ_DMA1);
513 } else if (dma->nextIRQ < test) {
514 test = dma->nextIRQ;
515 }
516 }
517
518 dma = &memory->dma[2];
519 dma->nextIRQ -= cycles;
520 if (dma->enable && dma->doIrq && dma->nextIRQ) {
521 if (dma->nextIRQ <= 0) {
522 dma->nextIRQ = INT_MAX;
523 GBARaiseIRQ(memory->p, IRQ_DMA2);
524 } else if (dma->nextIRQ < test) {
525 test = dma->nextIRQ;
526 }
527 }
528
529 dma = &memory->dma[3];
530 dma->nextIRQ -= cycles;
531 if (dma->enable && dma->doIrq && dma->nextIRQ) {
532 if (dma->nextIRQ <= 0) {
533 dma->nextIRQ = INT_MAX;
534 GBARaiseIRQ(memory->p, IRQ_DMA3);
535 } else if (dma->nextIRQ < test) {
536 test = dma->nextIRQ;
537 }
538 }
539
540 return test;
541}
542
543void GBAMemoryWriteDMASAD(struct GBAMemory* memory, int dma, uint32_t address) {
544 memory->dma[dma].source = address & 0xFFFFFFFE;
545}
546
547void GBAMemoryWriteDMADAD(struct GBAMemory* memory, int dma, uint32_t address) {
548 memory->dma[dma].dest = address & 0xFFFFFFFE;
549}
550
551void GBAMemoryWriteDMACNT_LO(struct GBAMemory* memory, int dma, uint16_t count) {
552 memory->dma[dma].count = count ? count : (dma == 3 ? 0x10000 : 0x4000);
553}
554
555uint16_t GBAMemoryWriteDMACNT_HI(struct GBAMemory* memory, int dma, uint16_t control) {
556 struct GBADMA* currentDma = &memory->dma[dma];
557 int wasEnabled = currentDma->enable;
558 currentDma->packed = control;
559 currentDma->nextIRQ = 0;
560
561 if (currentDma->drq) {
562 GBALog(memory->p, GBA_LOG_STUB, "DRQ not implemented");
563 }
564
565 if (!wasEnabled && currentDma->enable) {
566 currentDma->nextSource = currentDma->source;
567 currentDma->nextDest = currentDma->dest;
568 currentDma->nextCount = currentDma->count;
569 GBAMemoryScheduleDMA(memory, dma, currentDma);
570 }
571 // If the DMA has already occurred, this value might have changed since the function started
572 return currentDma->packed;
573};
574
575void GBAMemoryScheduleDMA(struct GBAMemory* memory, int number, struct GBADMA* info) {
576 switch (info->timing) {
577 case DMA_TIMING_NOW:
578 GBAMemoryServiceDMA(memory, number, info);
579 break;
580 case DMA_TIMING_HBLANK:
581 // Handled implicitly
582 break;
583 case DMA_TIMING_VBLANK:
584 // Handled implicitly
585 break;
586 case DMA_TIMING_CUSTOM:
587 switch (number) {
588 case 0:
589 GBALog(memory->p, GBA_LOG_WARN, "Discarding invalid DMA0 scheduling");
590 break;
591 case 1:
592 case 2:
593 //this.cpu.irq.audio.scheduleFIFODma(number, info);
594 break;
595 case 3:
596 //this.cpu.irq.video.scheduleVCaptureDma(dma, info);
597 break;
598 }
599 }
600}
601
602void GBAMemoryRunHblankDMAs(struct GBAMemory* memory) {
603 struct GBADMA* dma;
604 int i;
605 for (i = 0; i < 4; ++i) {
606 dma = &memory->dma[i];
607 if (dma->enable && dma->timing == DMA_TIMING_HBLANK) {
608 GBAMemoryServiceDMA(memory, i, dma);
609 }
610 }
611}
612
613void GBAMemoryRunVblankDMAs(struct GBAMemory* memory) {
614 struct GBADMA* dma;
615 int i;
616 for (i = 0; i < 4; ++i) {
617 dma = &memory->dma[i];
618 if (dma->enable && dma->timing == DMA_TIMING_VBLANK) {
619 GBAMemoryServiceDMA(memory, i, dma);
620 }
621 }
622}
623
624void GBAMemoryServiceDMA(struct GBAMemory* memory, int number, struct GBADMA* info) {
625 if (!info->enable) {
626 // There was a DMA scheduled that got canceled
627 return;
628 }
629
630 uint32_t width = info->width ? 4 : 2;
631 int sourceOffset = DMA_OFFSET[info->srcControl] * width;
632 int destOffset = DMA_OFFSET[info->dstControl] * width;
633 int32_t wordsRemaining = info->nextCount;
634 uint32_t source = info->nextSource;
635 uint32_t dest = info->nextDest;
636 uint32_t sourceRegion = source >> BASE_OFFSET;
637 uint32_t destRegion = dest >> BASE_OFFSET;
638
639 if (width == 4) {
640 int32_t word;
641 source &= 0xFFFFFFFC;
642 dest &= 0xFFFFFFFC;
643 while (wordsRemaining--) {
644 word = GBALoad32(&memory->d, source, 0);
645 GBAStore32(&memory->d, dest, word, 0);
646 source += sourceOffset;
647 dest += destOffset;
648 }
649 } else {
650 uint16_t word;
651 if (sourceRegion == REGION_CART2_EX && memory->savedata.type == SAVEDATA_EEPROM) {
652 while (wordsRemaining--) {
653 word = GBASavedataReadEEPROM(&memory->savedata);
654 GBAStore16(&memory->d, dest, word, 0);
655 source += sourceOffset;
656 dest += destOffset;
657 }
658 } else if (destRegion == REGION_CART2_EX) {
659 if (memory->savedata.type != SAVEDATA_EEPROM) {
660 GBASavedataInitEEPROM(&memory->savedata);
661 }
662 while (wordsRemaining) {
663 word = GBALoadU16(&memory->d, source, 0);
664 GBASavedataWriteEEPROM(&memory->savedata, word, wordsRemaining);
665 source += sourceOffset;
666 dest += destOffset;
667 --wordsRemaining;
668 }
669 } else {
670 while (wordsRemaining--) {
671 word = GBALoadU16(&memory->d, source, 0);
672 GBAStore16(&memory->d, dest, word, 0);
673 source += sourceOffset;
674 dest += destOffset;
675 }
676 }
677 }
678
679 if (info->doIrq) {
680 info->nextIRQ = memory->p->cpu.cycles + 2;
681 info->nextIRQ += (width == 4 ? memory->waitstates32[sourceRegion] + memory->waitstates32[destRegion]
682 : memory->waitstates16[sourceRegion] + memory->waitstates16[destRegion]);
683 info->nextIRQ += (info->count - 1) * (width == 4 ? memory->waitstatesSeq32[sourceRegion] + memory->waitstatesSeq32[destRegion]
684 : memory->waitstatesSeq16[sourceRegion] + memory->waitstatesSeq16[destRegion]);
685 }
686
687 info->nextSource = source;
688 info->nextDest = dest;
689 info->nextCount = wordsRemaining;
690
691 if (!info->repeat) {
692 info->enable = 0;
693
694 // Clear the enable bit in memory
695 memory->io[(REG_DMA0CNT_HI + number * (REG_DMA1CNT_HI - REG_DMA0CNT_HI)) >> 1] &= 0x7FE0;
696 } else {
697 info->nextCount = info->count;
698 if (info->dstControl == DMA_INCREMENT_RELOAD) {
699 info->nextDest = info->dest;
700 }
701 GBAMemoryScheduleDMA(memory, number, info);
702 }
703}