all repos — mgba @ d3a204086d670377e2aa6b685218ac09024b15ba

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