all repos — mgba @ 4dd4d9b25c3ff353cd76d8bd8458d6462e49ad06

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