all repos — mgba @ 8750f78808736560c24cc662d5a570b81e64b6e0

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	if (gb->memory.sram) {
 61		mappedMemoryFree(gb->memory.sram, 0x8000);
 62	}
 63}
 64
 65void GBMemoryReset(struct GB* gb) {
 66	if (gb->memory.wram) {
 67		mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
 68	}
 69	gb->memory.wram = anonymousMemoryMap(GB_SIZE_WORKING_RAM);
 70	gb->memory.wramBank = &gb->memory.wram[GB_SIZE_WORKING_RAM_BANK0];
 71	gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0];
 72	gb->memory.currentBank = 1;
 73	gb->memory.sram = anonymousMemoryMap(0x8000); // TODO: Persist
 74	gb->memory.sramCurrentBank = 0;
 75
 76	memset(&gb->video.oam, 0, sizeof(gb->video.oam));
 77
 78	const struct GBCartridge* cart = &gb->memory.rom[0x100];
 79	switch (cart->type) {
 80	case 0:
 81	case 8:
 82	case 9:
 83		gb->memory.mbc = _GBMBCNone;
 84		gb->memory.mbcType = GB_MBC_NONE;
 85		break;
 86	case 1:
 87	case 2:
 88	case 3:
 89		gb->memory.mbc = _GBMBC1;
 90		gb->memory.mbcType = GB_MBC1;
 91		break;
 92	case 5:
 93	case 6:
 94		gb->memory.mbc = _GBMBC2;
 95		gb->memory.mbcType = GB_MBC2;
 96		break;
 97	case 0x0F:
 98	case 0x10:
 99	case 0x11:
100	case 0x12:
101	case 0x13:
102		gb->memory.mbc = _GBMBC3;
103		gb->memory.mbcType = GB_MBC3;
104		break;
105	case 0x15:
106	case 0x16:
107	case 0x17:
108		gb->memory.mbc = _GBMBC4;
109		gb->memory.mbcType = GB_MBC4;
110		break;
111	default:
112		// TODO: Log
113	case 0x19:
114	case 0x1A:
115	case 0x1B:
116	case 0x1C:
117	case 0x1D:
118	case 0x1E:
119		gb->memory.mbc = _GBMBC5;
120		gb->memory.mbcType = GB_MBC5;
121		break;
122	}
123
124	if (!gb->memory.wram) {
125		GBMemoryDeinit(gb);
126	}
127}
128
129uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
130	struct GB* gb = (struct GB*) cpu->master;
131	struct GBMemory* memory = &gb->memory;
132	switch (address >> 12) {
133	case GB_REGION_CART_BANK0:
134	case GB_REGION_CART_BANK0 + 1:
135	case GB_REGION_CART_BANK0 + 2:
136	case GB_REGION_CART_BANK0 + 3:
137		return memory->rom[address & (GB_SIZE_CART_BANK0 - 1)];
138	case GB_REGION_CART_BANK1:
139	case GB_REGION_CART_BANK1 + 1:
140	case GB_REGION_CART_BANK1 + 2:
141	case GB_REGION_CART_BANK1 + 3:
142		return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
143	case GB_REGION_VRAM:
144	case GB_REGION_VRAM + 1:
145		return gb->video.vram[address & (GB_SIZE_VRAM - 1)];
146	case GB_REGION_EXTERNAL_RAM:
147	case GB_REGION_EXTERNAL_RAM + 1:
148		if (memory->sramAccess) {
149			return gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
150		}
151		return 0xFF;
152	case GB_REGION_WORKING_RAM_BANK0:
153	case GB_REGION_WORKING_RAM_BANK0 + 2:
154		return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
155	case GB_REGION_WORKING_RAM_BANK1:
156		return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
157	default:
158		if (address < GB_BASE_OAM) {
159			return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
160		}
161		if (address < GB_BASE_UNUSABLE) {
162			if (gb->video.mode < 2) {
163				return gb->video.oam.raw[address & 0xFF];
164			}
165			return 0xFF;
166		}
167		if (address < GB_BASE_IO) {
168			return 0xFF;
169		}
170		if (address < GB_BASE_HRAM) {
171			return GBIORead(gb, address & (GB_SIZE_IO - 1));
172		}
173		if (address < GB_BASE_IE) {
174			return memory->hram[address & GB_SIZE_HRAM];
175		}
176		return GBIORead(gb, REG_IE);
177	}
178}
179
180void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
181	struct GB* gb = (struct GB*) cpu->master;
182	struct GBMemory* memory = &gb->memory;
183	switch (address >> 12) {
184	case GB_REGION_CART_BANK0:
185	case GB_REGION_CART_BANK0 + 1:
186	case GB_REGION_CART_BANK0 + 2:
187	case GB_REGION_CART_BANK0 + 3:
188	case GB_REGION_CART_BANK1:
189	case GB_REGION_CART_BANK1 + 1:
190	case GB_REGION_CART_BANK1 + 2:
191	case GB_REGION_CART_BANK1 + 3:
192		memory->mbc(memory, address, value);
193		return;
194	case GB_REGION_VRAM:
195	case GB_REGION_VRAM + 1:
196		// TODO: Block access in wrong modes
197		gb->video.vram[address & (GB_SIZE_VRAM - 1)] = value;
198		gb->video.renderer->writeVRAM(gb->video.renderer, address & (GB_SIZE_VRAM - 1));
199		return;
200	case GB_REGION_EXTERNAL_RAM:
201	case GB_REGION_EXTERNAL_RAM + 1:
202		if (memory->sramAccess) {
203			gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
204		}
205		return;
206	case GB_REGION_WORKING_RAM_BANK0:
207	case GB_REGION_WORKING_RAM_BANK0 + 2:
208		memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
209		return;
210	case GB_REGION_WORKING_RAM_BANK1:
211		memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
212		return;
213	default:
214		if (address < GB_BASE_OAM) {
215			memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
216		} else if (address < GB_BASE_UNUSABLE) {
217			if (gb->video.mode < 2) {
218				gb->video.oam.raw[address & 0xFF] = value;
219				gb->video.renderer->writeOAM(gb->video.renderer, address & 0xFF);
220			}
221		} else if (address < GB_BASE_IO) {
222			// TODO: Log
223		} else if (address < GB_BASE_HRAM) {
224			GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
225		} else if (address < GB_BASE_IE) {
226			memory->hram[address & GB_SIZE_HRAM] = value;
227		} else {
228			GBIOWrite(gb, REG_IE, value);
229		}
230	}
231}
232
233int32_t GBMemoryProcessEvents(struct GB* gb, int32_t cycles) {
234	if (!gb->memory.dmaRemaining) {
235		return INT_MAX;
236	}
237	gb->memory.dmaNext -= cycles;
238	if (gb->memory.dmaNext <= 0) {
239		_GBMemoryDMAService(gb);
240	}
241	return gb->memory.dmaNext;
242}
243
244void GBMemoryDMA(struct GB* gb, uint16_t base) {
245	if (base > 0xF100) {
246		return;
247	}
248	gb->cpu->memory.store8 = GBDMAStore8;
249	gb->cpu->memory.load8 = GBDMALoad8;
250	gb->memory.dmaNext = gb->cpu->cycles + 4;
251	if (gb->memory.dmaNext < gb->cpu->nextEvent) {
252		gb->cpu->nextEvent = gb->memory.dmaNext;
253	}
254	gb->memory.dmaSource = base;
255	gb->memory.dmaDest = GB_BASE_OAM;
256	gb->memory.dmaRemaining = 0xA0;
257}
258
259void _GBMemoryDMAService(struct GB* gb) {
260	uint8_t b = GBLoad8(gb->cpu, gb->memory.dmaSource);
261	GBStore8(gb->cpu, gb->memory.dmaDest, b);
262	++gb->memory.dmaSource;
263	++gb->memory.dmaDest;
264	--gb->memory.dmaRemaining;
265	if (gb->memory.dmaRemaining) {
266		gb->memory.dmaNext += 4;
267	} else {
268		gb->memory.dmaNext = INT_MAX;
269		gb->cpu->memory.store8 = GBStore8;
270		gb->cpu->memory.load8 = GBLoad8;
271	}
272}
273
274uint8_t GBDMALoad8(struct LR35902Core* cpu, uint16_t address) {
275	struct GB* gb = (struct GB*) cpu->master;
276	struct GBMemory* memory = &gb->memory;
277	if (address < 0xFF80 || address == 0xFFFF) {
278		return 0xFF;
279	}
280	return memory->hram[address & GB_SIZE_HRAM];
281}
282
283void GBDMAStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
284	struct GB* gb = (struct GB*) cpu->master;
285	struct GBMemory* memory = &gb->memory;
286	if (address < 0xFF80 || address == 0xFFFF) {
287		return;
288	}
289	memory->hram[address & GB_SIZE_HRAM] = value;
290}
291
292uint8_t GBView8(struct LR35902Core* cpu, uint16_t address);
293
294void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old);
295
296static void _switchBank(struct GBMemory* memory, int bank) {
297	size_t bankStart = bank * GB_SIZE_CART_BANK0;
298	if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
299		// TODO: Log
300		return;
301	}
302	memory->romBank = &memory->rom[bankStart];
303	memory->currentBank = bank;
304}
305
306static void _switchSramBank(struct GBMemory* memory, int bank) {
307	size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
308	memory->sramBank = &memory->sram[bankStart];
309	memory->sramCurrentBank = bank;
310}
311
312void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
313	int bank = value & 0x1F;
314	switch (address >> 13) {
315	case 0x0:
316		switch (value) {
317		case 0:
318			memory->sramAccess = false;
319			break;
320		case 0xA:
321			memory->sramAccess = true;
322			_switchSramBank(memory, memory->sramCurrentBank);
323			break;
324		default:
325			// TODO
326			break;
327		}
328		break;
329		break;
330	case 0x1:
331		if (!bank) {
332			++bank;
333		}
334		_switchBank(memory, bank | (memory->currentBank & 0x60));
335		break;
336	}
337}
338
339void _GBMBC2(struct GBMemory* memory, uint16_t address, uint8_t value) {
340	// TODO
341}
342
343void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
344	int bank = value & 0x7F;
345	switch (address >> 13) {
346	case 0x0:
347		switch (value) {
348		case 0:
349			memory->sramAccess = false;
350			break;
351		case 0xA:
352			memory->sramAccess = true;
353			_switchSramBank(memory, memory->sramCurrentBank);
354			break;
355		default:
356			// TODO
357			break;
358		}
359		break;
360	case 0x1:
361		if (!bank) {
362			++bank;
363		}
364		_switchBank(memory, bank);
365		break;
366	case 0x2:
367		if (value < 4) {
368			_switchSramBank(memory, value);
369		}
370		break;
371	}
372}
373
374void _GBMBC4(struct GBMemory* memory, uint16_t address, uint8_t value) {
375	// TODO
376}
377
378void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
379	int bank = value & 0x7F;
380	switch (address >> 13) {
381	case 0x0:
382		switch (value) {
383		case 0:
384			memory->sramAccess = false;
385			break;
386		case 0xA:
387			memory->sramAccess = true;
388			_switchSramBank(memory, memory->sramCurrentBank);
389			break;
390		default:
391			// TODO
392			break;
393		}
394		break;
395		break;
396	case 0x1:
397		_switchBank(memory, bank);
398		break;
399	}
400}