all repos — mgba @ cbad932f45ca2cda872c3e5c1b6c2963c15662f9

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		return gb->video.vram[address & (GB_SIZE_VRAM - 1)];
138	case GB_REGION_EXTERNAL_RAM:
139	case GB_REGION_EXTERNAL_RAM + 1:
140		// TODO
141		return 0;
142	case GB_REGION_WORKING_RAM_BANK0:
143	case GB_REGION_WORKING_RAM_BANK0 + 2:
144		return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
145	case GB_REGION_WORKING_RAM_BANK1:
146		return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
147	default:
148		if (address < GB_BASE_OAM) {
149			return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
150		}
151		if (address < GB_BASE_IO) {
152			// TODO
153			return 0;
154		}
155		if (address < GB_BASE_HRAM) {
156			return GBIORead(gb, address & (GB_SIZE_IO - 1));
157		}
158		if (address < GB_BASE_IE) {
159			return memory->hram[address & GB_SIZE_HRAM];
160		}
161		return GBIORead(gb, REG_IE);
162	}
163}
164
165void GBStore16(struct LR35902Core* cpu, uint16_t address, int16_t value) {
166	// TODO
167}
168
169void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
170	struct GB* gb = (struct GB*) cpu->master;
171	struct GBMemory* memory = &gb->memory;
172	switch (address >> 12) {
173	case GB_REGION_CART_BANK0:
174	case GB_REGION_CART_BANK0 + 1:
175	case GB_REGION_CART_BANK0 + 2:
176	case GB_REGION_CART_BANK0 + 3:
177	case GB_REGION_CART_BANK1:
178	case GB_REGION_CART_BANK1 + 1:
179	case GB_REGION_CART_BANK1 + 2:
180	case GB_REGION_CART_BANK1 + 3:
181		memory->mbc(memory, address, value);
182		return;
183	case GB_REGION_VRAM:
184	case GB_REGION_VRAM + 1:
185		// TODO: Block access in wrong modes
186		gb->video.vram[address & (GB_SIZE_VRAM - 1)] = value;
187		gb->video.renderer->writeVRAM(gb->video.renderer, address & (GB_SIZE_VRAM - 1));
188		return;
189	case GB_REGION_EXTERNAL_RAM:
190	case GB_REGION_EXTERNAL_RAM + 1:
191		// TODO
192		return;
193	case GB_REGION_WORKING_RAM_BANK0:
194	case GB_REGION_WORKING_RAM_BANK0 + 2:
195		memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
196		return;
197	case GB_REGION_WORKING_RAM_BANK1:
198		memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
199		return;
200	default:
201		if (address < GB_BASE_OAM) {
202			memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
203		} else if (address < GB_BASE_IO) {
204			// TODO
205		} else if (address < GB_BASE_HRAM) {
206			GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
207		} else if (address < GB_BASE_IE) {
208			memory->hram[address & GB_SIZE_HRAM] = value;
209		} else {
210			GBIOWrite(gb, REG_IE, value);
211		}
212	}
213}
214
215uint16_t GBView16(struct LR35902Core* cpu, uint16_t address);
216uint8_t GBView8(struct LR35902Core* cpu, uint16_t address);
217
218void GBPatch16(struct LR35902Core* cpu, uint16_t address, int16_t value, int16_t* old);
219void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old);
220
221static void _switchBank(struct GBMemory* memory, int bank) {
222	size_t bankStart = bank * GB_SIZE_CART_BANK0;
223	if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
224		// TODO: Log
225		return;
226	}
227	memory->romBank = &memory->rom[bankStart];
228	memory->currentBank = bank;
229}
230
231void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
232	int bank = value & 0x1F;
233	switch (address >> 13) {
234	case 0x0:
235		// TODO
236		break;
237	case 0x1:
238		if (!bank) {
239			++bank;
240		}
241		_switchBank(memory, bank | (memory->currentBank & 0x60));
242		break;
243	}
244}
245
246void _GBMBC2(struct GBMemory* memory, uint16_t address, uint8_t value) {
247	// TODO
248}
249
250void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
251	int bank = value & 0x7F;
252	switch (address >> 13) {
253	case 0x0:
254		// TODO
255		break;
256	case 0x1:
257		if (!bank) {
258			++bank;
259		}
260		_switchBank(memory, bank);
261		break;
262	}
263}
264
265void _GBMBC4(struct GBMemory* memory, uint16_t address, uint8_t value) {
266	// TODO
267}
268
269void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
270	int bank = value & 0x7F;
271	switch (address >> 13) {
272	case 0x0:
273		// TODO
274		break;
275	case 0x1:
276		_switchBank(memory, bank);
277		break;
278	}
279}