all repos — mgba @ c0b965a41ed22373b76cc6bd8d23e0ff3bdf9c99

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	gb->memory.currentBank = 1;
 66
 67	const struct GBCartridge* cart = &gb->memory.rom[0x100];
 68	switch (cart->type) {
 69	case 0:
 70	case 8:
 71	case 9:
 72		gb->memory.mbc = _GBMBCNone;
 73		gb->memory.mbcType = GB_MBC_NONE;
 74		break;
 75	case 1:
 76	case 2:
 77	case 3:
 78		gb->memory.mbc = _GBMBC1;
 79		gb->memory.mbcType = GB_MBC1;
 80		break;
 81	case 5:
 82	case 6:
 83		gb->memory.mbc = _GBMBC2;
 84		gb->memory.mbcType = GB_MBC2;
 85		break;
 86	case 0x0F:
 87	case 0x10:
 88	case 0x11:
 89	case 0x12:
 90	case 0x13:
 91		gb->memory.mbc = _GBMBC3;
 92		gb->memory.mbcType = GB_MBC3;
 93		break;
 94	case 0x15:
 95	case 0x16:
 96	case 0x17:
 97		gb->memory.mbc = _GBMBC4;
 98		gb->memory.mbcType = GB_MBC4;
 99		break;
100	default:
101		// TODO: Log
102	case 0x19:
103	case 0x1A:
104	case 0x1B:
105	case 0x1C:
106	case 0x1D:
107	case 0x1E:
108		gb->memory.mbc = _GBMBC5;
109		gb->memory.mbcType = GB_MBC5;
110		break;
111	}
112
113	if (!gb->memory.wram) {
114		GBMemoryDeinit(gb);
115	}
116}
117
118uint16_t GBLoad16(struct LR35902Core* cpu, uint16_t address) {
119	// TODO
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 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: Block access in wrong modes
187		gb->video.vram[address & (GB_SIZE_VRAM - 1)] = value;
188		gb->video.renderer->writeVRAM(gb->video.renderer, address & (GB_SIZE_VRAM - 1));
189		return;
190	case GB_REGION_EXTERNAL_RAM:
191	case GB_REGION_EXTERNAL_RAM + 1:
192		// TODO
193		return;
194	case GB_REGION_WORKING_RAM_BANK0:
195	case GB_REGION_WORKING_RAM_BANK0 + 2:
196		memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
197		return;
198	case GB_REGION_WORKING_RAM_BANK1:
199		memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
200		return;
201	default:
202		if (address < GB_BASE_OAM) {
203			memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
204		} else if (address < GB_BASE_IO) {
205			// TODO
206		} else if (address < GB_BASE_HRAM) {
207			GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
208		} else if (address < GB_BASE_IE) {
209			memory->hram[address & GB_SIZE_HRAM] = value;
210		} else {
211			GBIOWrite(gb, REG_IE, value);
212		}
213	}
214}
215
216uint16_t GBView16(struct LR35902Core* cpu, uint16_t address);
217uint8_t GBView8(struct LR35902Core* cpu, uint16_t address);
218
219void GBPatch16(struct LR35902Core* cpu, uint16_t address, int16_t value, int16_t* old);
220void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old);
221
222static void _switchBank(struct GBMemory* memory, int bank) {
223	size_t bankStart = bank * GB_SIZE_CART_BANK0;
224	if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
225		// TODO: Log
226		return;
227	}
228	memory->romBank = &memory->rom[bankStart];
229	memory->currentBank = bank;
230}
231
232void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
233	int bank = value & 0x1F;
234	switch (address >> 13) {
235	case 0x0:
236		// TODO
237		break;
238	case 0x1:
239		if (!bank) {
240			++bank;
241		}
242		_switchBank(memory, bank | (memory->currentBank & 0x60));
243		break;
244	}
245}
246
247void _GBMBC2(struct GBMemory* memory, uint16_t address, uint8_t value) {
248	// TODO
249}
250
251void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
252	int bank = value & 0x7F;
253	switch (address >> 13) {
254	case 0x0:
255		// TODO
256		break;
257	case 0x1:
258		if (!bank) {
259			++bank;
260		}
261		_switchBank(memory, bank);
262		break;
263	}
264}
265
266void _GBMBC4(struct GBMemory* memory, uint16_t address, uint8_t value) {
267	// TODO
268}
269
270void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
271	int bank = value & 0x7F;
272	switch (address >> 13) {
273	case 0x0:
274		// TODO
275		break;
276	case 0x1:
277		_switchBank(memory, bank);
278		break;
279	}
280}