all repos — mgba @ 7e5eada69baa4d29c56c6e45654306efae11a4ab

mGBA Game Boy Advance Emulator

src/gba/gba-memory.c (view raw)

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