all repos — mgba @ 187e099f255a46854bb0b23d8cb062e524ef09a0

mGBA Game Boy Advance Emulator

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}