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