all repos — mgba @ 573920cae492e56e19db412fecf29890ba53c421

mGBA Game Boy Advance Emulator

src/gb/mbc.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 "mbc.h"
  7
  8#include "gb/gb.h"
  9#include "gb/memory.h"
 10#include "util/vfs.h"
 11
 12mLOG_DEFINE_CATEGORY(GB_MBC, "GB MBC");
 13
 14static void _GBMBCNone(struct GB* gb, uint16_t address, uint8_t value) {
 15	UNUSED(gb);
 16	UNUSED(address);
 17	UNUSED(value);
 18
 19	mLOG(GB_MBC, GAME_ERROR, "Wrote to invalid MBC");
 20}
 21
 22static void _GBMBC1(struct GB*, uint16_t address, uint8_t value);
 23static void _GBMBC2(struct GB*, uint16_t address, uint8_t value);
 24static void _GBMBC3(struct GB*, uint16_t address, uint8_t value);
 25static void _GBMBC5(struct GB*, uint16_t address, uint8_t value);
 26static void _GBMBC6(struct GB*, uint16_t address, uint8_t value);
 27static void _GBMBC7(struct GB*, uint16_t address, uint8_t value);
 28static void _GBHuC3(struct GB*, uint16_t address, uint8_t value);
 29
 30void GBMBCSwitchBank(struct GBMemory* memory, int bank) {
 31	size_t bankStart = bank * GB_SIZE_CART_BANK0;
 32	if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
 33		mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
 34		bankStart &= (memory->romSize - 1);
 35		bank = bankStart / GB_SIZE_CART_BANK0;
 36	}
 37	memory->romBank = &memory->rom[bankStart];
 38	memory->currentBank = bank;
 39}
 40
 41void GBMBCSwitchSramBank(struct GB* gb, int bank) {
 42	size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
 43	GBResizeSram(gb, (bank + 1) * GB_SIZE_EXTERNAL_RAM);
 44	gb->memory.sramBank = &gb->memory.sram[bankStart];
 45	gb->memory.sramCurrentBank = bank;
 46}
 47
 48void GBMBCInit(struct GB* gb) {
 49	const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
 50	switch (cart->ramSize) {
 51	case 0:
 52		gb->sramSize = 0;
 53		break;
 54	case 1:
 55		gb->sramSize = 0x800;
 56		break;
 57	default:
 58	case 2:
 59		gb->sramSize = 0x2000;
 60		break;
 61	case 3:
 62		gb->sramSize = 0x8000;
 63		break;
 64	}
 65
 66	if (gb->memory.mbcType == GB_MBC_AUTODETECT) {
 67		const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
 68		switch (cart->type) {
 69		case 0:
 70		case 8:
 71		case 9:
 72			gb->memory.mbcType = GB_MBC_NONE;
 73			break;
 74		case 1:
 75		case 2:
 76		case 3:
 77			gb->memory.mbcType = GB_MBC1;
 78			break;
 79		case 5:
 80		case 6:
 81			gb->memory.mbcType = GB_MBC2;
 82			break;
 83		case 0x0F:
 84		case 0x10:
 85			gb->memory.mbcType = GB_MBC3_RTC;
 86			break;
 87		case 0x11:
 88		case 0x12:
 89		case 0x13:
 90			gb->memory.mbcType = GB_MBC3;
 91			break;
 92		default:
 93			mLOG(GB_MBC, WARN, "Unknown MBC type: %02X", cart->type);
 94			// Fall through
 95		case 0x19:
 96		case 0x1A:
 97		case 0x1B:
 98			gb->memory.mbcType = GB_MBC5;
 99			break;
100		case 0x1C:
101		case 0x1D:
102		case 0x1E:
103			gb->memory.mbcType = GB_MBC5_RUMBLE;
104			break;
105		case 0x20:
106			gb->memory.mbcType = GB_MBC6;
107			break;
108		case 0x22:
109			gb->memory.mbcType = GB_MBC7;
110			break;
111		case 0xFE:
112			gb->memory.mbcType = GB_HuC3;
113			break;
114		}
115	}
116	switch (gb->memory.mbcType) {
117	case GB_MBC_NONE:
118		gb->memory.mbc = _GBMBCNone;
119		break;
120	case GB_MBC1:
121		gb->memory.mbc = _GBMBC1;
122		break;
123	case GB_MBC2:
124		gb->memory.mbc = _GBMBC2;
125		gb->sramSize = 0x200;
126		break;
127	case GB_MBC3:
128		gb->memory.mbc = _GBMBC3;
129		break;
130	default:
131		mLOG(GB_MBC, WARN, "Unknown MBC type: %02X", cart->type);
132		// Fall through
133	case GB_MBC5:
134		gb->memory.mbc = _GBMBC5;
135		break;
136	case GB_MBC6:
137		mLOG(GB_MBC, WARN, "unimplemented MBC: MBC6");
138		gb->memory.mbc = _GBMBC6;
139		break;
140	case GB_MBC7:
141		gb->memory.mbc = _GBMBC7;
142		break;
143	case GB_MMM01:
144		mLOG(GB_MBC, WARN, "unimplemented MBC: MMM01");
145		gb->memory.mbc = _GBMBC1;
146		break;
147	case GB_HuC1:
148		mLOG(GB_MBC, WARN, "unimplemented MBC: HuC-1");
149		gb->memory.mbc = _GBMBC1;
150		break;
151	case GB_HuC3:
152		gb->memory.mbc = _GBHuC3;
153		break;
154	case GB_MBC3_RTC:
155		memset(gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));
156		gb->memory.mbc = _GBMBC3;
157		break;
158	case GB_MBC5_RUMBLE:
159		gb->memory.mbc = _GBMBC5;
160		break;
161	}
162
163	GBResizeSram(gb, gb->sramSize);
164
165	if (gb->memory.mbcType == GB_MBC3_RTC) {
166		GBMBCRTCRead(gb);
167	}
168}
169
170static void _latchRtc(struct mRTCSource* rtc, uint8_t* rtcRegs, time_t* rtcLastLatch) {
171	time_t t;
172	if (rtc) {
173		if (rtc->sample) {
174			rtc->sample(rtc);
175		}
176		t = rtc->unixTime(rtc);
177	} else {
178		t = time(0);
179	}
180	time_t currentLatch = t;
181	t -= *rtcLastLatch;
182	*rtcLastLatch = currentLatch;
183
184	int64_t diff;
185	diff = rtcRegs[0] + t % 60;
186	if (diff < 0) {
187		diff += 60;
188		t -= 60;
189	}
190	rtcRegs[0] = diff % 60;
191	t /= 60;
192	t += diff / 60;
193
194	diff = rtcRegs[1] + t % 60;
195	if (diff < 0) {
196		diff += 60;
197		t -= 60;
198	}
199	rtcRegs[1] = diff % 60;
200	t /= 60;
201	t += diff / 60;
202
203	diff = rtcRegs[2] + t % 24;
204	if (diff < 0) {
205		diff += 24;
206		t -= 24;
207	}
208	rtcRegs[2] = diff % 24;
209	t /= 24;
210	t += diff / 24;
211
212	diff = rtcRegs[3] + ((rtcRegs[4] & 1) << 8) + (t & 0x1FF);
213	rtcRegs[3] = diff;
214	rtcRegs[4] &= 0xFE;
215	rtcRegs[4] |= (diff >> 8) & 1;
216	if (diff & 0x200) {
217		rtcRegs[4] |= 0x80;
218	}
219}
220
221void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) {
222	struct GBMemory* memory = &gb->memory;
223	int bank = value & 0x1F;
224	switch (address >> 13) {
225	case 0x0:
226		switch (value) {
227		case 0:
228			memory->sramAccess = false;
229			break;
230		case 0xA:
231			memory->sramAccess = true;
232			GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
233			break;
234		default:
235			// TODO
236			mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
237			break;
238		}
239		break;
240	case 0x1:
241		if (!bank) {
242			++bank;
243		}
244		GBMBCSwitchBank(memory, bank | (memory->currentBank & 0x60));
245		break;
246	case 0x2:
247		bank &= 3;
248		if (!memory->mbcState.mbc1.mode) {
249			GBMBCSwitchBank(memory, (bank << 5) | (memory->currentBank & 0x1F));
250		} else {
251			GBMBCSwitchSramBank(gb, bank);
252		}
253		break;
254	case 0x3:
255		memory->mbcState.mbc1.mode = value & 1;
256		if (memory->mbcState.mbc1.mode) {
257			GBMBCSwitchBank(memory, memory->currentBank & 0x1F);
258		} else {
259			GBMBCSwitchSramBank(gb, 0);
260		}
261		break;
262	default:
263		// TODO
264		mLOG(GB_MBC, STUB, "MBC1 unknown address: %04X:%02X", address, value);
265		break;
266	}
267}
268
269void _GBMBC2(struct GB* gb, uint16_t address, uint8_t value) {
270	struct GBMemory* memory = &gb->memory;
271	int bank = value & 0xF;
272	switch (address >> 13) {
273	case 0x0:
274		switch (value) {
275		case 0:
276			memory->sramAccess = false;
277			break;
278		case 0xA:
279			memory->sramAccess = true;
280			GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
281			break;
282		default:
283			// TODO
284			mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
285			break;
286		}
287		break;
288	case 0x1:
289		if (!bank) {
290			++bank;
291		}
292		GBMBCSwitchBank(memory, bank);
293		break;
294	default:
295		// TODO
296		mLOG(GB_MBC, STUB, "MBC2 unknown address: %04X:%02X", address, value);
297		break;
298	}}
299
300void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) {
301	struct GBMemory* memory = &gb->memory;
302	int bank = value & 0x7F;
303	switch (address >> 13) {
304	case 0x0:
305		switch (value) {
306		case 0:
307			memory->sramAccess = false;
308			break;
309		case 0xA:
310			memory->sramAccess = true;
311			GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
312			break;
313		default:
314			// TODO
315			mLOG(GB_MBC, STUB, "MBC3 unknown value %02X", value);
316			break;
317		}
318		break;
319	case 0x1:
320		if (!bank) {
321			++bank;
322		}
323		GBMBCSwitchBank(memory, bank);
324		break;
325	case 0x2:
326		if (value < 4) {
327			GBMBCSwitchSramBank(gb, value);
328			memory->rtcAccess = false;
329		} else if (value >= 8 && value <= 0xC) {
330			memory->activeRtcReg = value - 8;
331			memory->rtcAccess = true;
332		}
333		break;
334	case 0x3:
335		if (memory->rtcLatched && value == 0) {
336			memory->rtcLatched = false;
337		} else if (!memory->rtcLatched && value == 1) {
338			_latchRtc(gb->memory.rtc, gb->memory.rtcRegs, &gb->memory.rtcLastLatch);
339			memory->rtcLatched = true;
340		}
341		break;
342	}
343}
344
345void _GBMBC5(struct GB* gb, uint16_t address, uint8_t value) {
346	struct GBMemory* memory = &gb->memory;
347	int bank;
348	switch (address >> 12) {
349	case 0x0:
350	case 0x1:
351		switch (value) {
352		case 0:
353			memory->sramAccess = false;
354			break;
355		case 0xA:
356			memory->sramAccess = true;
357			GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
358			break;
359		default:
360			// TODO
361			mLOG(GB_MBC, STUB, "MBC5 unknown value %02X", value);
362			break;
363		}
364		break;
365	case 0x2:
366		bank = (memory->currentBank & 0x100) | value;
367		GBMBCSwitchBank(memory, bank);
368		break;
369	case 0x3:
370		bank = (memory->currentBank & 0xFF) | ((value & 1) << 8);
371		GBMBCSwitchBank(memory, bank);
372		break;
373	case 0x4:
374	case 0x5:
375		if (memory->mbcType == GB_MBC5_RUMBLE && memory->rumble) {
376			memory->rumble->setRumble(memory->rumble, (value >> 3) & 1);
377			value &= ~8;
378		}
379		GBMBCSwitchSramBank(gb, value & 0xF);
380		break;
381	default:
382		// TODO
383		mLOG(GB_MBC, STUB, "MBC5 unknown address: %04X:%02X", address, value);
384		break;
385	}
386}
387
388void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
389	// TODO
390	mLOG(GB_MBC, STUB, "MBC6 unimplemented");
391	UNUSED(gb);
392	UNUSED(address);
393	UNUSED(value);
394}
395
396void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {
397	struct GBMemory* memory = &gb->memory;
398	int bank = value & 0x7F;
399	switch (address >> 13) {
400	case 0x1:
401		GBMBCSwitchBank(memory, bank);
402		break;
403	case 0x2:
404		if (value < 0x10) {
405			GBMBCSwitchSramBank(gb, value);
406		}
407		break;
408	default:
409		// TODO
410		mLOG(GB_MBC, STUB, "MBC7 unknown address: %04X:%02X", address, value);
411		break;
412	}
413}
414
415uint8_t GBMBC7Read(struct GBMemory* memory, uint16_t address) {
416	struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
417	switch (address & 0xF0) {
418	case 0x00:
419	case 0x10:
420	case 0x60:
421	case 0x70:
422		return 0;
423	case 0x20:
424		if (memory->rotation && memory->rotation->readTiltX) {
425			int32_t x = -memory->rotation->readTiltX(memory->rotation);
426			x >>= 21;
427			x += 2047;
428			return x;
429		}
430		return 0xFF;
431	case 0x30:
432		if (memory->rotation && memory->rotation->readTiltX) {
433			int32_t x = -memory->rotation->readTiltX(memory->rotation);
434			x >>= 21;
435			x += 2047;
436			return x >> 8;
437		}
438		return 7;
439	case 0x40:
440		if (memory->rotation && memory->rotation->readTiltY) {
441			int32_t y = -memory->rotation->readTiltY(memory->rotation);
442			y >>= 21;
443			y += 2047;
444			return y;
445		}
446		return 0xFF;
447	case 0x50:
448		if (memory->rotation && memory->rotation->readTiltY) {
449			int32_t y = -memory->rotation->readTiltY(memory->rotation);
450			y >>= 21;
451			y += 2047;
452			return y >> 8;
453		}
454		return 7;
455	case 0x80:
456		return (mbc7->sr >> 16) & 1;
457	default:
458		return 0xFF;
459	}
460}
461
462void GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) {
463	if ((address & 0xF0) != 0x80) {
464		return;
465	}
466	struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
467	GBMBC7Field old = memory->mbcState.mbc7.field;
468	mbc7->field = GBMBC7FieldClearIO(value);
469	if (!GBMBC7FieldIsCS(old) && GBMBC7FieldIsCS(value)) {
470		if (mbc7->state == GBMBC7_STATE_WRITE) {
471			if (mbc7->writable) {
472				memory->sramBank[mbc7->address * 2] = mbc7->sr >> 8;
473				memory->sramBank[mbc7->address * 2 + 1] = mbc7->sr;
474			}
475			mbc7->sr = 0x1FFFF;
476			mbc7->state = GBMBC7_STATE_NULL;
477		} else {
478			mbc7->state = GBMBC7_STATE_IDLE;
479		}
480	}
481	if (!GBMBC7FieldIsSK(old) && GBMBC7FieldIsSK(value)) {
482		if (mbc7->state > GBMBC7_STATE_IDLE && mbc7->state != GBMBC7_STATE_READ) {
483			mbc7->sr <<= 1;
484			mbc7->sr |= GBMBC7FieldGetIO(value);
485			++mbc7->srBits;
486		}
487		switch (mbc7->state) {
488		case GBMBC7_STATE_IDLE:
489			if (GBMBC7FieldIsIO(value)) {
490				mbc7->state = GBMBC7_STATE_READ_COMMAND;
491				mbc7->srBits = 0;
492				mbc7->sr = 0;
493			}
494			break;
495		case GBMBC7_STATE_READ_COMMAND:
496			if (mbc7->srBits == 2) {
497				mbc7->state = GBMBC7_STATE_READ_ADDRESS;
498				mbc7->srBits = 0;
499				mbc7->command = mbc7->sr;
500			}
501			break;
502		case GBMBC7_STATE_READ_ADDRESS:
503			if (mbc7->srBits == 8) {
504				mbc7->state = GBMBC7_STATE_COMMAND_0 + mbc7->command;
505				mbc7->srBits = 0;
506				mbc7->address = mbc7->sr;
507				if (mbc7->state == GBMBC7_STATE_COMMAND_0) {
508					switch (mbc7->address >> 6) {
509					case 0:
510						mbc7->writable = false;
511						mbc7->state = GBMBC7_STATE_NULL;
512						break;
513					case 3:
514						mbc7->writable = true;
515						mbc7->state = GBMBC7_STATE_NULL;
516						break;
517					}
518				}
519			}
520			break;
521		case GBMBC7_STATE_COMMAND_0:
522			if (mbc7->srBits == 16) {
523				switch (mbc7->address >> 6) {
524				case 0:
525					mbc7->writable = false;
526					mbc7->state = GBMBC7_STATE_NULL;
527					break;
528				case 1:
529					mbc7->state = GBMBC7_STATE_WRITE;
530					if (mbc7->writable) {
531						int i;
532						for (i = 0; i < 256; ++i) {
533							memory->sramBank[i * 2] = mbc7->sr >> 8;
534							memory->sramBank[i * 2 + 1] = mbc7->sr;
535						}
536					}
537					break;
538				case 2:
539					mbc7->state = GBMBC7_STATE_WRITE;
540					if (mbc7->writable) {
541						int i;
542						for (i = 0; i < 256; ++i) {
543							memory->sramBank[i * 2] = 0xFF;
544							memory->sramBank[i * 2 + 1] = 0xFF;
545						}
546					}
547					break;
548				case 3:
549					mbc7->writable = true;
550					mbc7->state = GBMBC7_STATE_NULL;
551					break;
552				}
553			}
554			break;
555		case GBMBC7_STATE_COMMAND_SR_WRITE:
556			if (mbc7->srBits == 16) {
557				mbc7->srBits = 0;
558				mbc7->state = GBMBC7_STATE_WRITE;
559			}
560			break;
561		case GBMBC7_STATE_COMMAND_SR_READ:
562			if (mbc7->srBits == 1) {
563				mbc7->sr = memory->sramBank[mbc7->address * 2] << 8;
564				mbc7->sr |= memory->sramBank[mbc7->address * 2 + 1];
565				mbc7->srBits = 0;
566				mbc7->state = GBMBC7_STATE_READ;
567			}
568			break;
569		case GBMBC7_STATE_COMMAND_SR_FILL:
570			if (mbc7->srBits == 16) {
571				mbc7->sr = 0xFFFF;
572				mbc7->srBits = 0;
573				mbc7->state = GBMBC7_STATE_WRITE;
574			}
575			break;
576		default:
577			break;
578		}
579	} else if (GBMBC7FieldIsSK(old) && !GBMBC7FieldIsSK(value)) {
580		if (mbc7->state == GBMBC7_STATE_READ) {
581			mbc7->sr <<= 1;
582			++mbc7->srBits;
583			if (mbc7->srBits == 16) {
584				mbc7->srBits = 0;
585				mbc7->state = GBMBC7_STATE_NULL;
586			}
587		}
588	}
589}
590
591void _GBHuC3(struct GB* gb, uint16_t address, uint8_t value) {
592	struct GBMemory* memory = &gb->memory;
593	int bank = value & 0x3F;
594	if (address & 0x1FFF) {
595		mLOG(GB_MBC, STUB, "HuC-3 unknown value %04X:%02X", address, value);
596	}
597
598	switch (address >> 13) {
599	case 0x0:
600		switch (value) {
601		case 0xA:
602			memory->sramAccess = true;
603			GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
604			break;
605		default:
606			memory->sramAccess = false;
607			break;
608		}
609		break;
610	case 0x1:
611		GBMBCSwitchBank(memory, bank);
612		break;
613	case 0x2:
614		GBMBCSwitchSramBank(gb, bank);
615		break;
616	default:
617		// TODO
618		mLOG(GB_MBC, STUB, "HuC-3 unknown address: %04X:%02X", address, value);
619		break;
620	}
621}
622
623void GBMBCRTCRead(struct GB* gb) {
624	struct GBMBCRTCSaveBuffer rtcBuffer;
625	struct VFile* vf = gb->sramVf;
626	ssize_t end = vf->seek(vf, -sizeof(rtcBuffer), SEEK_END);
627	switch (end & 0x1FFF) {
628	case 0:
629		break;
630	case 0x1FFC:
631		vf->seek(vf, -sizeof(rtcBuffer) - 4, SEEK_END);
632		break;
633	default:
634		return;
635	}
636	vf->read(vf, &rtcBuffer, sizeof(rtcBuffer));
637
638	LOAD_32LE(gb->memory.rtcRegs[0], 0, &rtcBuffer.latchedSec);
639	LOAD_32LE(gb->memory.rtcRegs[1], 0, &rtcBuffer.latchedMin);
640	LOAD_32LE(gb->memory.rtcRegs[2], 0, &rtcBuffer.latchedHour);
641	LOAD_32LE(gb->memory.rtcRegs[3], 0, &rtcBuffer.latchedDays);
642	LOAD_32LE(gb->memory.rtcRegs[4], 0, &rtcBuffer.latchedDaysHi);
643	LOAD_64LE(gb->memory.rtcLastLatch, 0, &rtcBuffer.unixTime);
644}
645
646void GBMBCRTCWrite(struct GB* gb) {
647	uint8_t rtcRegs[5];
648	memcpy(rtcRegs, gb->memory.rtcRegs, sizeof(rtcRegs));
649	time_t rtcLastLatch = gb->memory.rtcLastLatch;
650	_latchRtc(gb->memory.rtc, rtcRegs, &rtcLastLatch);
651
652	struct GBMBCRTCSaveBuffer rtcBuffer;
653	STORE_32LE(rtcRegs[0], 0, &rtcBuffer.sec);
654	STORE_32LE(rtcRegs[1], 0, &rtcBuffer.min);
655	STORE_32LE(rtcRegs[2], 0, &rtcBuffer.hour);
656	STORE_32LE(rtcRegs[3], 0, &rtcBuffer.days);
657	STORE_32LE(rtcRegs[4], 0, &rtcBuffer.daysHi);
658	STORE_32LE(gb->memory.rtcRegs[0], 0, &rtcBuffer.latchedSec);
659	STORE_32LE(gb->memory.rtcRegs[1], 0, &rtcBuffer.latchedMin);
660	STORE_32LE(gb->memory.rtcRegs[2], 0, &rtcBuffer.latchedHour);
661	STORE_32LE(gb->memory.rtcRegs[3], 0, &rtcBuffer.latchedDays);
662	STORE_32LE(gb->memory.rtcRegs[4], 0, &rtcBuffer.latchedDaysHi);
663	STORE_64LE(rtcLastLatch, 0, &rtcBuffer.unixTime);
664
665	struct VFile* vf = gb->sramVf;
666	vf->seek(vf, gb->sramSize, SEEK_SET);
667	vf->write(vf, &rtcBuffer, sizeof(rtcBuffer));
668}