all repos — mgba @ 31f45e3e1d2c2231020ec71e36dfa2ebcb923766

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