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