all repos — mgba @ ab44084236a244751d4ecd8e6403d58fb7c38de2

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 "core/interface.h"
  9#include "gb/gb.h"
 10#include "gb/io.h"
 11
 12#include "util/memory.h"
 13
 14#include <time.h>
 15
 16mLOG_DEFINE_CATEGORY(GB_MBC, "GB MBC");
 17mLOG_DEFINE_CATEGORY(GB_MEM, "GB Memory");
 18
 19static void _GBMBCNone(struct GBMemory* memory, uint16_t address, uint8_t value) {
 20	UNUSED(memory);
 21	UNUSED(address);
 22	UNUSED(value);
 23
 24	mLOG(GB_MBC, GAME_ERROR, "Wrote to invalid MBC");
 25}
 26
 27static void _GBMBC1(struct GBMemory*, uint16_t address, uint8_t value);
 28static void _GBMBC2(struct GBMemory*, uint16_t address, uint8_t value);
 29static void _GBMBC3(struct GBMemory*, uint16_t address, uint8_t value);
 30static void _GBMBC5(struct GBMemory*, uint16_t address, uint8_t value);
 31static void _GBMBC6(struct GBMemory*, uint16_t address, uint8_t value);
 32static void _GBMBC7(struct GBMemory*, uint16_t address, uint8_t value);
 33
 34static void GBSetActiveRegion(struct LR35902Core* cpu, uint16_t address) {
 35	// TODO
 36}
 37
 38static void _GBMemoryDMAService(struct GB* gb);
 39static void _GBMemoryHDMAService(struct GB* gb);
 40
 41void GBMemoryInit(struct GB* gb) {
 42	struct LR35902Core* cpu = gb->cpu;
 43	cpu->memory.cpuLoad8 = GBLoad8;
 44	cpu->memory.load8 = GBLoad8;
 45	cpu->memory.store8 = GBStore8;
 46	cpu->memory.setActiveRegion = GBSetActiveRegion;
 47
 48	gb->memory.wram = 0;
 49	gb->memory.wramBank = 0;
 50	gb->memory.rom = 0;
 51	gb->memory.romBank = 0;
 52	gb->memory.romSize = 0;
 53	gb->memory.sram = 0;
 54	gb->memory.mbcType = GB_MBC_NONE;
 55	gb->memory.mbc = 0;
 56
 57	gb->memory.dmaNext = INT_MAX;
 58	gb->memory.dmaRemaining = 0;
 59	gb->memory.hdmaNext = INT_MAX;
 60	gb->memory.hdmaRemaining = 0;
 61
 62	memset(gb->memory.hram, 0, sizeof(gb->memory.hram));
 63
 64	gb->memory.sramAccess = false;
 65	gb->memory.rtcAccess = false;
 66	gb->memory.rtcLatched = 0;
 67	gb->memory.rtc = NULL;
 68
 69	GBIOInit(gb);
 70}
 71
 72void GBMemoryDeinit(struct GB* gb) {
 73	mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
 74	if (gb->memory.rom) {
 75		mappedMemoryFree(gb->memory.rom, gb->memory.romSize);
 76	}
 77}
 78
 79void GBMemoryReset(struct GB* gb) {
 80	if (gb->memory.wram) {
 81		mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
 82	}
 83	gb->memory.wram = anonymousMemoryMap(GB_SIZE_WORKING_RAM);
 84	GBMemorySwitchWramBank(&gb->memory, 1);
 85	gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0];
 86	gb->memory.currentBank = 1;
 87	gb->memory.sramCurrentBank = 0;
 88	gb->memory.sramBank = gb->memory.sram;
 89
 90	memset(&gb->video.oam, 0, sizeof(gb->video.oam));
 91
 92	const struct GBCartridge* cart = &gb->memory.rom[0x100];
 93	switch (cart->type) {
 94	case 0:
 95	case 8:
 96	case 9:
 97		gb->memory.mbc = _GBMBCNone;
 98		gb->memory.mbcType = GB_MBC_NONE;
 99		break;
100	case 1:
101	case 2:
102	case 3:
103		gb->memory.mbc = _GBMBC1;
104		gb->memory.mbcType = GB_MBC1;
105		break;
106	case 5:
107	case 6:
108		gb->memory.mbc = _GBMBC2;
109		gb->memory.mbcType = GB_MBC2;
110		break;
111	case 0x0F:
112	case 0x10:
113	case 0x11:
114	case 0x12:
115	case 0x13:
116		gb->memory.mbc = _GBMBC3;
117		gb->memory.mbcType = GB_MBC3;
118		break;
119	default:
120		mLOG(GB_MBC, WARN, "Unknown MBC type: %02X", cart->type);
121	case 0x19:
122	case 0x1A:
123	case 0x1B:
124	case 0x1C:
125	case 0x1D:
126	case 0x1E:
127		gb->memory.mbc = _GBMBC5;
128		gb->memory.mbcType = GB_MBC5;
129		break;
130	case 0x20:
131		gb->memory.mbc = _GBMBC6;
132		gb->memory.mbcType = GB_MBC6;
133		break;
134	case 0x22:
135		gb->memory.mbc = _GBMBC7;
136		gb->memory.mbcType = GB_MBC7;
137		break;
138	}
139
140	if (!gb->memory.wram) {
141		GBMemoryDeinit(gb);
142	}
143}
144
145void GBMemorySwitchWramBank(struct GBMemory* memory, int bank) {
146	bank &= 7;
147	if (!bank) {
148		bank = 1;
149	}
150	memory->wramBank = &memory->wram[GB_SIZE_WORKING_RAM_BANK0 * bank];
151	memory->wramCurrentBank = bank;
152}
153
154uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
155	struct GB* gb = (struct GB*) cpu->master;
156	struct GBMemory* memory = &gb->memory;
157	switch (address >> 12) {
158	case GB_REGION_CART_BANK0:
159	case GB_REGION_CART_BANK0 + 1:
160	case GB_REGION_CART_BANK0 + 2:
161	case GB_REGION_CART_BANK0 + 3:
162		return memory->rom[address & (GB_SIZE_CART_BANK0 - 1)];
163	case GB_REGION_CART_BANK1:
164	case GB_REGION_CART_BANK1 + 1:
165	case GB_REGION_CART_BANK1 + 2:
166	case GB_REGION_CART_BANK1 + 3:
167		return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
168	case GB_REGION_VRAM:
169	case GB_REGION_VRAM + 1:
170		return gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)];
171	case GB_REGION_EXTERNAL_RAM:
172	case GB_REGION_EXTERNAL_RAM + 1:
173		if (memory->rtcAccess) {
174			return gb->memory.rtcRegs[memory->activeRtcReg];
175		} else if (memory->sramAccess) {
176			return gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
177		}
178		return 0xFF;
179	case GB_REGION_WORKING_RAM_BANK0:
180	case GB_REGION_WORKING_RAM_BANK0 + 2:
181		return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
182	case GB_REGION_WORKING_RAM_BANK1:
183		return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
184	default:
185		if (address < GB_BASE_OAM) {
186			return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
187		}
188		if (address < GB_BASE_UNUSABLE) {
189			if (gb->video.mode < 2) {
190				return gb->video.oam.raw[address & 0xFF];
191			}
192			return 0xFF;
193		}
194		if (address < GB_BASE_IO) {
195			mLOG(GB_MEM, GAME_ERROR, "Attempt to read from unusable memory: %04X", address);
196			return 0xFF;
197		}
198		if (address < GB_BASE_HRAM) {
199			return GBIORead(gb, address & (GB_SIZE_IO - 1));
200		}
201		if (address < GB_BASE_IE) {
202			return memory->hram[address & GB_SIZE_HRAM];
203		}
204		return GBIORead(gb, REG_IE);
205	}
206}
207
208void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
209	struct GB* gb = (struct GB*) cpu->master;
210	struct GBMemory* memory = &gb->memory;
211	switch (address >> 12) {
212	case GB_REGION_CART_BANK0:
213	case GB_REGION_CART_BANK0 + 1:
214	case GB_REGION_CART_BANK0 + 2:
215	case GB_REGION_CART_BANK0 + 3:
216	case GB_REGION_CART_BANK1:
217	case GB_REGION_CART_BANK1 + 1:
218	case GB_REGION_CART_BANK1 + 2:
219	case GB_REGION_CART_BANK1 + 3:
220		memory->mbc(memory, address, value);
221		return;
222	case GB_REGION_VRAM:
223	case GB_REGION_VRAM + 1:
224		// TODO: Block access in wrong modes
225		gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)] = value;
226		return;
227	case GB_REGION_EXTERNAL_RAM:
228	case GB_REGION_EXTERNAL_RAM + 1:
229		if (memory->rtcAccess) {
230			gb->memory.rtcRegs[memory->activeRtcReg] = value;
231		} else if (memory->sramAccess) {
232			gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
233		}
234		return;
235	case GB_REGION_WORKING_RAM_BANK0:
236	case GB_REGION_WORKING_RAM_BANK0 + 2:
237		memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
238		return;
239	case GB_REGION_WORKING_RAM_BANK1:
240		memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
241		return;
242	default:
243		if (address < GB_BASE_OAM) {
244			memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
245		} else if (address < GB_BASE_UNUSABLE) {
246			if (gb->video.mode < 2) {
247				gb->video.oam.raw[address & 0xFF] = value;
248			}
249		} else if (address < GB_BASE_IO) {
250			mLOG(GB_MEM, GAME_ERROR, "Attempt to write to unusable memory: %04X:%02X", address, value);
251		} else if (address < GB_BASE_HRAM) {
252			GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
253		} else if (address < GB_BASE_IE) {
254			memory->hram[address & GB_SIZE_HRAM] = value;
255		} else {
256			GBIOWrite(gb, REG_IE, value);
257		}
258	}
259}
260
261int32_t GBMemoryProcessEvents(struct GB* gb, int32_t cycles) {
262	int nextEvent = INT_MAX;
263	if (gb->memory.dmaRemaining) {
264		gb->memory.dmaNext -= cycles;
265		if (gb->memory.dmaNext <= 0) {
266			_GBMemoryDMAService(gb);
267		}
268		nextEvent = gb->memory.dmaNext;
269	}
270	if (gb->memory.hdmaRemaining) {
271		gb->memory.hdmaNext -= cycles;
272		if (gb->memory.hdmaNext <= 0) {
273			_GBMemoryHDMAService(gb);
274		}
275		if (gb->memory.hdmaNext < nextEvent) {
276			nextEvent = gb->memory.hdmaNext;
277		}
278	}
279	return nextEvent;
280}
281
282void GBMemoryDMA(struct GB* gb, uint16_t base) {
283	if (base > 0xF100) {
284		return;
285	}
286	gb->cpu->memory.store8 = GBDMAStore8;
287	gb->cpu->memory.load8 = GBDMALoad8;
288	gb->memory.dmaNext = gb->cpu->cycles + 8;
289	if (gb->memory.dmaNext < gb->cpu->nextEvent) {
290		gb->cpu->nextEvent = gb->memory.dmaNext;
291	}
292	gb->memory.dmaSource = base;
293	gb->memory.dmaDest = 0;
294	gb->memory.dmaRemaining = 0xA0;
295}
296
297void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) {
298	gb->memory.hdmaSource = gb->memory.io[REG_HDMA1] << 8;
299	gb->memory.hdmaSource |= gb->memory.io[REG_HDMA2];
300	gb->memory.hdmaDest = gb->memory.io[REG_HDMA3] << 8;
301	gb->memory.hdmaDest |= gb->memory.io[REG_HDMA4];
302	gb->memory.hdmaSource &= 0xFFF0;
303	if (gb->memory.hdmaSource >= 0x8000 && gb->memory.hdmaSource < 0xA000) {
304		mLOG(GB_MEM, GAME_ERROR, "Invalid HDMA source: %04X", gb->memory.hdmaSource);
305		return;
306	}
307	gb->memory.hdmaDest &= 0x1FF0;
308	gb->memory.hdmaDest |= 0x8000;
309	gb->memory.isHdma = value & 0x80;
310	if (!gb->memory.isHdma) {
311		gb->memory.hdmaRemaining = ((value & 0x7F) + 1) * 0x10;
312		gb->memory.hdmaNext = gb->cpu->cycles;
313		gb->cpu->nextEvent = gb->cpu->cycles;
314	}
315}
316
317void _GBMemoryDMAService(struct GB* gb) {
318	uint8_t b = GBLoad8(gb->cpu, gb->memory.dmaSource);
319	// TODO: Can DMA write OAM during modes 2-3?
320	gb->video.oam.raw[gb->memory.dmaDest] = b;
321	++gb->memory.dmaSource;
322	++gb->memory.dmaDest;
323	--gb->memory.dmaRemaining;
324	if (gb->memory.dmaRemaining) {
325		gb->memory.dmaNext += 4;
326	} else {
327		gb->memory.dmaNext = INT_MAX;
328		gb->cpu->memory.store8 = GBStore8;
329		gb->cpu->memory.load8 = GBLoad8;
330	}
331}
332
333void _GBMemoryHDMAService(struct GB* gb) {
334	uint8_t b = gb->cpu->memory.load8(gb->cpu, gb->memory.hdmaSource);
335	gb->cpu->memory.store8(gb->cpu, gb->memory.hdmaDest, b);
336	++gb->memory.hdmaSource;
337	++gb->memory.hdmaDest;
338	--gb->memory.hdmaRemaining;
339	gb->cpu->cycles += 2;
340	if (gb->memory.hdmaRemaining) {
341		gb->memory.hdmaNext += 2;
342	} else {
343		if (gb->memory.isHdma) {
344			--gb->memory.io[REG_HDMA5];
345		} else {
346			gb->memory.io[REG_HDMA5] |= 0x80;
347		}
348	}
349}
350
351uint8_t GBDMALoad8(struct LR35902Core* cpu, uint16_t address) {
352	struct GB* gb = (struct GB*) cpu->master;
353	struct GBMemory* memory = &gb->memory;
354	if (address < 0xFF80 || address == 0xFFFF) {
355		return 0xFF;
356	}
357	return memory->hram[address & GB_SIZE_HRAM];
358}
359
360void GBDMAStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
361	struct GB* gb = (struct GB*) cpu->master;
362	struct GBMemory* memory = &gb->memory;
363	if (address < 0xFF80 || address == 0xFFFF) {
364		return;
365	}
366	memory->hram[address & GB_SIZE_HRAM] = value;
367}
368
369uint8_t GBView8(struct LR35902Core* cpu, uint16_t address);
370
371void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old);
372
373static void _switchBank(struct GBMemory* memory, int bank) {
374	size_t bankStart = bank * GB_SIZE_CART_BANK0;
375	if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
376		mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
377		bankStart &= (GB_SIZE_CART_BANK0 - 1);
378		bank /= GB_SIZE_CART_BANK0;
379	}
380	memory->romBank = &memory->rom[bankStart];
381	memory->currentBank = bank;
382}
383
384static void _switchSramBank(struct GBMemory* memory, int bank) {
385	size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
386	memory->sramBank = &memory->sram[bankStart];
387	memory->sramCurrentBank = bank;
388}
389
390static void _latchRtc(struct GBMemory* memory) {
391	time_t t;
392	struct mRTCSource* rtc = memory->rtc;
393	if (rtc) {
394		if (rtc->sample) {
395			rtc->sample(rtc);
396		}
397		t = rtc->unixTime(rtc);
398	} else {
399		t = time(0);
400	}
401	struct tm date;
402	localtime_r(&t, &date);
403	memory->rtcRegs[0] = date.tm_sec;
404	memory->rtcRegs[1] = date.tm_min;
405	memory->rtcRegs[2] = date.tm_hour;
406	memory->rtcRegs[3] = date.tm_yday; // TODO: Persist day counter
407	memory->rtcRegs[4] &= 0xF0;
408	memory->rtcRegs[4] |= date.tm_yday >> 8;
409}
410
411void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
412	int bank = value & 0x1F;
413	switch (address >> 13) {
414	case 0x0:
415		switch (value) {
416		case 0:
417			memory->sramAccess = false;
418			break;
419		case 0xA:
420			memory->sramAccess = true;
421			_switchSramBank(memory, memory->sramCurrentBank);
422			break;
423		default:
424			// TODO
425			mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
426			break;
427		}
428		break;
429	case 0x1:
430		if (!bank) {
431			++bank;
432		}
433		_switchBank(memory, bank | (memory->currentBank & 0x60));
434		break;
435	default:
436		// TODO
437		mLOG(GB_MBC, STUB, "MBC1 unknown address: %04X:%02X", address, value);
438		break;
439	}
440}
441
442void _GBMBC2(struct GBMemory* memory, uint16_t address, uint8_t value) {
443	mLOG(GB_MBC, STUB, "MBC2 unimplemented");
444}
445
446void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
447	int bank = value & 0x7F;
448	switch (address >> 13) {
449	case 0x0:
450		switch (value) {
451		case 0:
452			memory->sramAccess = false;
453			break;
454		case 0xA:
455			memory->sramAccess = true;
456			_switchSramBank(memory, memory->sramCurrentBank);
457			break;
458		default:
459			// TODO
460			mLOG(GB_MBC, STUB, "MBC3 unknown value %02X", value);
461			break;
462		}
463		break;
464	case 0x1:
465		if (!bank) {
466			++bank;
467		}
468		_switchBank(memory, bank);
469		break;
470	case 0x2:
471		if (value < 4) {
472			_switchSramBank(memory, value);
473			memory->rtcAccess = false;
474		} else if (value >= 8 && value <= 0xC) {
475			memory->activeRtcReg = value - 8;
476			memory->rtcAccess = true;
477		}
478		break;
479	case 0x3:
480		if (memory->rtcLatched && value == 0) {
481			memory->rtcLatched = value;
482		} else if (!memory->rtcLatched && value == 1) {
483			_latchRtc(memory);
484		}
485		break;
486	}
487}
488
489void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
490	int bank = value;
491	switch (address >> 13) {
492	case 0x0:
493		switch (value) {
494		case 0:
495			memory->sramAccess = false;
496			break;
497		case 0xA:
498			memory->sramAccess = true;
499			_switchSramBank(memory, memory->sramCurrentBank);
500			break;
501		default:
502			// TODO
503			mLOG(GB_MBC, STUB, "MBC5 unknown value %02X", value);
504			break;
505		}
506		break;
507	case 0x1:
508		_switchBank(memory, bank);
509		break;
510	case 0x2:
511		if (value < 0x10) {
512			_switchSramBank(memory, value);
513		}
514		break;
515	default:
516		// TODO
517		mLOG(GB_MBC, STUB, "MBC5 unknown address: %04X:%02X", address, value);
518		break;
519	}
520}
521
522void _GBMBC6(struct GBMemory* memory, uint16_t address, uint8_t value) {
523	// TODO
524	mLOG(GB_MBC, STUB, "MBC6 unimplemented");
525}
526
527void _GBMBC7(struct GBMemory* memory, uint16_t address, uint8_t value) {
528	// TODO
529	mLOG(GB_MBC, STUB, "MBC7 unimplemented");
530}