all repos — mgba @ 5cd84799bec7ad1593b859ecf5ab8f383da581fa

mGBA Game Boy Advance Emulator

src/gb/memory.c (view raw)

  1/* Copyright (c) 2013-2016 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "memory.h"
  7
  8#include "gb/gb.h"
  9#include "gb/io.h"
 10
 11#include "util/memory.h"
 12
 13static void _GBMBCNone(struct GBMemory* memory, uint16_t address, uint8_t value) {
 14	// TODO: Log game error
 15	UNUSED(memory);
 16	UNUSED(address);
 17	UNUSED(value);
 18}
 19
 20static void _GBMBC1(struct GBMemory*, uint16_t address, uint8_t value);
 21static void _GBMBC2(struct GBMemory*, uint16_t address, uint8_t value);
 22static void _GBMBC3(struct GBMemory*, uint16_t address, uint8_t value);
 23static void _GBMBC4(struct GBMemory*, uint16_t address, uint8_t value);
 24static void _GBMBC5(struct GBMemory*, uint16_t address, uint8_t value);
 25
 26static void GBSetActiveRegion(struct LR35902Core* cpu, uint16_t address) {
 27	// TODO
 28}
 29
 30static void _GBMemoryDMAService(struct GB* gb);
 31
 32
 33void GBMemoryInit(struct GB* gb) {
 34	struct LR35902Core* cpu = gb->cpu;
 35	cpu->memory.load8 = GBLoad8;
 36	cpu->memory.store8 = GBStore8;
 37	cpu->memory.setActiveRegion = GBSetActiveRegion;
 38
 39	gb->memory.wram = 0;
 40	gb->memory.wramBank = 0;
 41	gb->memory.rom = 0;
 42	gb->memory.romBank = 0;
 43	gb->memory.romSize = 0;
 44	gb->memory.mbcType = GB_MBC_NONE;
 45	gb->memory.mbc = 0;
 46
 47	gb->memory.dmaNext = INT_MAX;
 48	gb->memory.dmaRemaining = 0;
 49
 50	memset(gb->memory.hram, 0, sizeof(gb->memory.hram));
 51
 52	GBIOInit(gb);
 53}
 54
 55void GBMemoryDeinit(struct GB* gb) {
 56	mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
 57	if (gb->memory.rom) {
 58		mappedMemoryFree(gb->memory.rom, gb->memory.romSize);
 59	}
 60}
 61
 62void GBMemoryReset(struct GB* gb) {
 63	if (gb->memory.wram) {
 64		mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
 65	}
 66	gb->memory.wram = anonymousMemoryMap(GB_SIZE_WORKING_RAM);
 67	gb->memory.wramBank = &gb->memory.wram[GB_SIZE_WORKING_RAM_BANK0];
 68	gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0];
 69	gb->memory.currentBank = 1;
 70
 71	const struct GBCartridge* cart = &gb->memory.rom[0x100];
 72	switch (cart->type) {
 73	case 0:
 74	case 8:
 75	case 9:
 76		gb->memory.mbc = _GBMBCNone;
 77		gb->memory.mbcType = GB_MBC_NONE;
 78		break;
 79	case 1:
 80	case 2:
 81	case 3:
 82		gb->memory.mbc = _GBMBC1;
 83		gb->memory.mbcType = GB_MBC1;
 84		break;
 85	case 5:
 86	case 6:
 87		gb->memory.mbc = _GBMBC2;
 88		gb->memory.mbcType = GB_MBC2;
 89		break;
 90	case 0x0F:
 91	case 0x10:
 92	case 0x11:
 93	case 0x12:
 94	case 0x13:
 95		gb->memory.mbc = _GBMBC3;
 96		gb->memory.mbcType = GB_MBC3;
 97		break;
 98	case 0x15:
 99	case 0x16:
100	case 0x17:
101		gb->memory.mbc = _GBMBC4;
102		gb->memory.mbcType = GB_MBC4;
103		break;
104	default:
105		// TODO: Log
106	case 0x19:
107	case 0x1A:
108	case 0x1B:
109	case 0x1C:
110	case 0x1D:
111	case 0x1E:
112		gb->memory.mbc = _GBMBC5;
113		gb->memory.mbcType = GB_MBC5;
114		break;
115	}
116
117	if (!gb->memory.wram) {
118		GBMemoryDeinit(gb);
119	}
120}
121
122uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
123	struct GB* gb = (struct GB*) cpu->master;
124	struct GBMemory* memory = &gb->memory;
125	switch (address >> 12) {
126	case GB_REGION_CART_BANK0:
127	case GB_REGION_CART_BANK0 + 1:
128	case GB_REGION_CART_BANK0 + 2:
129	case GB_REGION_CART_BANK0 + 3:
130		return memory->rom[address & (GB_SIZE_CART_BANK0 - 1)];
131	case GB_REGION_CART_BANK1:
132	case GB_REGION_CART_BANK1 + 1:
133	case GB_REGION_CART_BANK1 + 2:
134	case GB_REGION_CART_BANK1 + 3:
135		return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
136	case GB_REGION_VRAM:
137	case GB_REGION_VRAM + 1:
138		return gb->video.vram[address & (GB_SIZE_VRAM - 1)];
139	case GB_REGION_EXTERNAL_RAM:
140	case GB_REGION_EXTERNAL_RAM + 1:
141		// TODO
142		return 0;
143	case GB_REGION_WORKING_RAM_BANK0:
144	case GB_REGION_WORKING_RAM_BANK0 + 2:
145		return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
146	case GB_REGION_WORKING_RAM_BANK1:
147		return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
148	default:
149		if (address < GB_BASE_OAM) {
150			return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
151		}
152		if (address < GB_BASE_IO) {
153			// TODO
154			return 0;
155		}
156		if (address < GB_BASE_HRAM) {
157			return GBIORead(gb, address & (GB_SIZE_IO - 1));
158		}
159		if (address < GB_BASE_IE) {
160			return memory->hram[address & GB_SIZE_HRAM];
161		}
162		return GBIORead(gb, REG_IE);
163	}
164}
165
166void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
167	struct GB* gb = (struct GB*) cpu->master;
168	struct GBMemory* memory = &gb->memory;
169	switch (address >> 12) {
170	case GB_REGION_CART_BANK0:
171	case GB_REGION_CART_BANK0 + 1:
172	case GB_REGION_CART_BANK0 + 2:
173	case GB_REGION_CART_BANK0 + 3:
174	case GB_REGION_CART_BANK1:
175	case GB_REGION_CART_BANK1 + 1:
176	case GB_REGION_CART_BANK1 + 2:
177	case GB_REGION_CART_BANK1 + 3:
178		memory->mbc(memory, address, value);
179		return;
180	case GB_REGION_VRAM:
181	case GB_REGION_VRAM + 1:
182		// TODO: Block access in wrong modes
183		gb->video.vram[address & (GB_SIZE_VRAM - 1)] = value;
184		gb->video.renderer->writeVRAM(gb->video.renderer, address & (GB_SIZE_VRAM - 1));
185		return;
186	case GB_REGION_EXTERNAL_RAM:
187	case GB_REGION_EXTERNAL_RAM + 1:
188		// TODO
189		return;
190	case GB_REGION_WORKING_RAM_BANK0:
191	case GB_REGION_WORKING_RAM_BANK0 + 2:
192		memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
193		return;
194	case GB_REGION_WORKING_RAM_BANK1:
195		memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
196		return;
197	default:
198		if (address < GB_BASE_OAM) {
199			memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
200		} else if (address < GB_BASE_IO) {
201			// TODO
202		} else if (address < GB_BASE_HRAM) {
203			GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
204		} else if (address < GB_BASE_IE) {
205			memory->hram[address & GB_SIZE_HRAM] = value;
206		} else {
207			GBIOWrite(gb, REG_IE, value);
208		}
209	}
210}
211
212int32_t GBMemoryProcessEvents(struct GB* gb, int32_t cycles) {
213	if (!gb->memory.dmaRemaining) {
214		return INT_MAX;
215	}
216	gb->memory.dmaNext -= cycles;
217	if (gb->memory.dmaNext <= 0) {
218		_GBMemoryDMAService(gb);
219	}
220	return gb->memory.dmaNext;
221}
222
223void GBMemoryDMA(struct GB* gb, uint16_t base) {
224	if (base > 0xF100) {
225		return;
226	}
227	gb->cpu->memory.store8 = GBDMAStore8;
228	gb->cpu->memory.load8 = GBDMALoad8;
229	gb->memory.dmaNext = gb->cpu->cycles + 4;
230	if (gb->memory.dmaNext < gb->cpu->nextEvent) {
231		gb->cpu->nextEvent = gb->memory.dmaNext;
232	}
233	gb->memory.dmaSource = base;
234	gb->memory.dmaDest = GB_BASE_OAM;
235	gb->memory.dmaRemaining = 0xA0;
236}
237
238void _GBMemoryDMAService(struct GB* gb) {
239	uint8_t b = GBLoad8(gb->cpu, gb->memory.dmaSource);
240	GBStore8(gb->cpu, gb->memory.dmaDest, b);
241	++gb->memory.dmaSource;
242	++gb->memory.dmaDest;
243	--gb->memory.dmaRemaining;
244	if (gb->memory.dmaRemaining) {
245		gb->memory.dmaNext += 4;
246	} else {
247		gb->memory.dmaNext = INT_MAX;
248		gb->cpu->memory.store8 = GBStore8;
249		gb->cpu->memory.load8 = GBLoad8;
250	}
251}
252
253uint8_t GBDMALoad8(struct LR35902Core* cpu, uint16_t address) {
254	struct GB* gb = (struct GB*) cpu->master;
255	struct GBMemory* memory = &gb->memory;
256	if (address < 0xFF80 || address == 0xFFFF) {
257		return 0xFF;
258	}
259	return memory->hram[address & GB_SIZE_HRAM];
260}
261
262void GBDMAStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
263	struct GB* gb = (struct GB*) cpu->master;
264	struct GBMemory* memory = &gb->memory;
265	if (address < 0xFF80 || address == 0xFFFF) {
266		return;
267	}
268	memory->hram[address & GB_SIZE_HRAM] = value;
269}
270
271uint8_t GBView8(struct LR35902Core* cpu, uint16_t address);
272
273void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old);
274
275static void _switchBank(struct GBMemory* memory, int bank) {
276	size_t bankStart = bank * GB_SIZE_CART_BANK0;
277	if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
278		// TODO: Log
279		return;
280	}
281	memory->romBank = &memory->rom[bankStart];
282	memory->currentBank = bank;
283}
284
285void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
286	int bank = value & 0x1F;
287	switch (address >> 13) {
288	case 0x0:
289		// TODO
290		break;
291	case 0x1:
292		if (!bank) {
293			++bank;
294		}
295		_switchBank(memory, bank | (memory->currentBank & 0x60));
296		break;
297	}
298}
299
300void _GBMBC2(struct GBMemory* memory, uint16_t address, uint8_t value) {
301	// TODO
302}
303
304void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
305	int bank = value & 0x7F;
306	switch (address >> 13) {
307	case 0x0:
308		// TODO
309		break;
310	case 0x1:
311		if (!bank) {
312			++bank;
313		}
314		_switchBank(memory, bank);
315		break;
316	}
317}
318
319void _GBMBC4(struct GBMemory* memory, uint16_t address, uint8_t value) {
320	// TODO
321}
322
323void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
324	int bank = value & 0x7F;
325	switch (address >> 13) {
326	case 0x0:
327		// TODO
328		break;
329	case 0x1:
330		_switchBank(memory, bank);
331		break;
332	}
333}