all repos — mgba @ 3158db06c2c68a5b53a5b0d2ea8fe9375ec74522

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
 30void GBMemoryInit(struct GB* gb) {
 31	struct LR35902Core* cpu = gb->cpu;
 32	cpu->memory.load16 = GBLoad16;
 33	cpu->memory.load8 = GBLoad8;
 34	cpu->memory.store16 = GBStore16;
 35	cpu->memory.store8 = GBStore8;
 36	cpu->memory.setActiveRegion = GBSetActiveRegion;
 37
 38	gb->memory.wram = 0;
 39	gb->memory.wramBank = 0;
 40	gb->memory.rom = 0;
 41	gb->memory.romBank = 0;
 42	gb->memory.romSize = 0;
 43	gb->memory.mbcType = GB_MBC_NONE;
 44	gb->memory.mbc = 0;
 45
 46	memset(gb->memory.hram, 0, sizeof(gb->memory.hram));
 47
 48	GBIOInit(gb);
 49}
 50
 51void GBMemoryDeinit(struct GB* gb) {
 52	mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
 53	if (gb->memory.rom) {
 54		mappedMemoryFree(gb->memory.rom, gb->memory.romSize);
 55	}
 56}
 57
 58void GBMemoryReset(struct GB* gb) {
 59	if (gb->memory.wram) {
 60		mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
 61	}
 62	gb->memory.wram = anonymousMemoryMap(GB_SIZE_WORKING_RAM);
 63	gb->memory.wramBank = &gb->memory.wram[GB_SIZE_WORKING_RAM_BANK0];
 64	gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0];
 65
 66	const struct GBCartridge* cart = &gb->memory.rom[0x100];
 67	switch (cart->type) {
 68	case 0:
 69	case 8:
 70	case 9:
 71		gb->memory.mbc = _GBMBCNone;
 72		gb->memory.mbcType = GB_MBC_NONE;
 73		break;
 74	case 1:
 75	case 2:
 76	case 3:
 77		gb->memory.mbc = _GBMBC1;
 78		gb->memory.mbcType = GB_MBC1;
 79		break;
 80	case 5:
 81	case 6:
 82		gb->memory.mbc = _GBMBC2;
 83		gb->memory.mbcType = GB_MBC2;
 84		break;
 85	case 0x0F:
 86	case 0x10:
 87	case 0x11:
 88	case 0x12:
 89	case 0x13:
 90		gb->memory.mbc = _GBMBC3;
 91		gb->memory.mbcType = GB_MBC3;
 92		break;
 93	case 0x15:
 94	case 0x16:
 95	case 0x17:
 96		gb->memory.mbc = _GBMBC4;
 97		gb->memory.mbcType = GB_MBC4;
 98		break;
 99	default:
100		// TODO: Log
101	case 0x19:
102	case 0x1A:
103	case 0x1B:
104	case 0x1C:
105	case 0x1D:
106	case 0x1E:
107		gb->memory.mbc = _GBMBC5;
108		gb->memory.mbcType = GB_MBC5;
109		break;
110	}
111
112	if (!gb->memory.wram) {
113		GBMemoryDeinit(gb);
114	}
115}
116
117uint16_t GBLoad16(struct LR35902Core* cpu, uint16_t address) {
118	// TODO
119}
120
121uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
122	struct GB* gb = (struct GB*) cpu->master;
123	struct GBMemory* memory = &gb->memory;
124	switch (address >> 12) {
125	case GB_REGION_CART_BANK0:
126	case GB_REGION_CART_BANK0 + 1:
127	case GB_REGION_CART_BANK0 + 2:
128	case GB_REGION_CART_BANK0 + 3:
129		return memory->rom[address & (GB_SIZE_CART_BANK0 - 1)];
130	case GB_REGION_CART_BANK1:
131	case GB_REGION_CART_BANK1 + 1:
132	case GB_REGION_CART_BANK1 + 2:
133	case GB_REGION_CART_BANK1 + 3:
134		return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
135	case GB_REGION_VRAM:
136	case GB_REGION_VRAM + 1:
137		// TODO
138		return 0;
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 GBStore16(struct LR35902Core* cpu, uint16_t address, int16_t value) {
167	// TODO
168}
169
170void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
171	struct GB* gb = (struct GB*) cpu->master;
172	struct GBMemory* memory = &gb->memory;
173	switch (address >> 12) {
174	case GB_REGION_CART_BANK0:
175	case GB_REGION_CART_BANK0 + 1:
176	case GB_REGION_CART_BANK0 + 2:
177	case GB_REGION_CART_BANK0 + 3:
178	case GB_REGION_CART_BANK1:
179	case GB_REGION_CART_BANK1 + 1:
180	case GB_REGION_CART_BANK1 + 2:
181	case GB_REGION_CART_BANK1 + 3:
182		memory->mbc(memory, address, value);
183		return;
184	case GB_REGION_VRAM:
185	case GB_REGION_VRAM + 1:
186		// TODO
187		return;
188	case GB_REGION_EXTERNAL_RAM:
189	case GB_REGION_EXTERNAL_RAM + 1:
190		// TODO
191		return;
192	case GB_REGION_WORKING_RAM_BANK0:
193	case GB_REGION_WORKING_RAM_BANK0 + 2:
194		memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
195		return;
196	case GB_REGION_WORKING_RAM_BANK1:
197		memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
198		return;
199	default:
200		if (address < GB_BASE_OAM) {
201			memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
202		} else if (address < GB_BASE_IO) {
203			// TODO
204		} else if (address < GB_BASE_HRAM) {
205			GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
206		} else if (address < GB_BASE_IE) {
207			memory->hram[address & GB_SIZE_HRAM] = value;
208		} else {
209			GBIOWrite(gb, REG_IE, value);
210		}
211	}
212}
213
214uint16_t GBView16(struct LR35902Core* cpu, uint16_t address);
215uint8_t GBView8(struct LR35902Core* cpu, uint16_t address);
216
217void GBPatch16(struct LR35902Core* cpu, uint16_t address, int16_t value, int16_t* old);
218void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old);
219
220static void _switchBank(struct GBMemory* memory, int bank) {
221	size_t bankStart = bank * GB_SIZE_CART_BANK0;
222	if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
223		// TODO: Log
224		return;
225	}
226	memory->romBank = &memory->rom[bankStart];
227	memory->currentBank = bank;
228}
229
230void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
231	int bank = value & 0x1F;
232	switch (address >> 13) {
233	case 0x0:
234		// TODO
235		break;
236	case 0x1:
237		if (!bank) {
238			++bank;
239		}
240		_switchBank(memory, bank | (memory->currentBank & 0x60));
241		break;
242	}
243}
244
245void _GBMBC2(struct GBMemory* memory, uint16_t address, uint8_t value) {
246	// TODO
247}
248
249void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
250	int bank = value & 0x7F;
251	switch (address >> 13) {
252	case 0x0:
253		// TODO
254		break;
255	case 0x1:
256		if (!bank) {
257			++bank;
258		}
259		_switchBank(memory, bank);
260		break;
261	}
262}
263
264void _GBMBC4(struct GBMemory* memory, uint16_t address, uint8_t value) {
265	// TODO
266}
267
268void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
269	int bank = value & 0x7F;
270	switch (address >> 13) {
271	case 0x0:
272		// TODO
273		break;
274	case 0x1:
275		_switchBank(memory, bank);
276		break;
277	}
278}