all repos — mgba @ 2000c8e2dfc050a817a96449cadd5f5f09b3e58a

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