all repos — mgba @ a0af67842add0d49b3339d5f1b3b91945ee0a47c

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/formatting.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 + (gb->sramSize & 0xFF));
 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		gb->sramSize += 0x48;
133		break;
134	default:
135		mLOG(GB_MBC, WARN, "Unknown MBC type: %02X", cart->type);
136		// Fall through
137	case GB_MBC5:
138		gb->memory.mbc = _GBMBC5;
139		break;
140	case GB_MBC6:
141		mLOG(GB_MBC, WARN, "unimplemented MBC: MBC6");
142		gb->memory.mbc = _GBMBC6;
143		break;
144	case GB_MBC7:
145		gb->memory.mbc = _GBMBC7;
146		break;
147	case GB_MMM01:
148		mLOG(GB_MBC, WARN, "unimplemented MBC: MMM01");
149		gb->memory.mbc = _GBMBC1;
150		break;
151	case GB_HuC1:
152		mLOG(GB_MBC, WARN, "unimplemented MBC: HuC-1");
153		gb->memory.mbc = _GBMBC1;
154		break;
155	case GB_HuC3:
156		gb->memory.mbc = _GBHuC3;
157		break;
158	case GB_MBC3_RTC:
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
169static void _latchRtc(struct GBMemory* memory) {
170	time_t t;
171	struct mRTCSource* rtc = memory->rtc;
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	struct tm date;
181	localtime_r(&t, &date);
182	memory->rtcRegs[0] = date.tm_sec;
183	memory->rtcRegs[1] = date.tm_min;
184	memory->rtcRegs[2] = date.tm_hour;
185	memory->rtcRegs[3] = date.tm_yday; // TODO: Persist day counter
186	memory->rtcRegs[4] &= 0xF0;
187	memory->rtcRegs[4] |= date.tm_yday >> 8;
188}
189
190void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) {
191	struct GBMemory* memory = &gb->memory;
192	int bank = value & 0x1F;
193	switch (address >> 13) {
194	case 0x0:
195		switch (value) {
196		case 0:
197			memory->sramAccess = false;
198			break;
199		case 0xA:
200			memory->sramAccess = true;
201			GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
202			break;
203		default:
204			// TODO
205			mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
206			break;
207		}
208		break;
209	case 0x1:
210		if (!bank) {
211			++bank;
212		}
213		GBMBCSwitchBank(memory, bank | (memory->currentBank & 0x60));
214		break;
215	case 0x2:
216		bank &= 3;
217		if (!memory->mbcState.mbc1.mode) {
218			GBMBCSwitchBank(memory, (bank << 5) | (memory->currentBank & 0x1F));
219		} else {
220			GBMBCSwitchSramBank(gb, bank);
221		}
222		break;
223	case 0x3:
224		memory->mbcState.mbc1.mode = value & 1;
225		if (memory->mbcState.mbc1.mode) {
226			GBMBCSwitchBank(memory, memory->currentBank & 0x1F);
227		} else {
228			GBMBCSwitchSramBank(gb, 0);
229		}
230		break;
231	default:
232		// TODO
233		mLOG(GB_MBC, STUB, "MBC1 unknown address: %04X:%02X", address, value);
234		break;
235	}
236}
237
238void _GBMBC2(struct GB* gb, uint16_t address, uint8_t value) {
239	struct GBMemory* memory = &gb->memory;
240	int bank = value & 0xF;
241	switch (address >> 13) {
242	case 0x0:
243		switch (value) {
244		case 0:
245			memory->sramAccess = false;
246			break;
247		case 0xA:
248			memory->sramAccess = true;
249			GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
250			break;
251		default:
252			// TODO
253			mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
254			break;
255		}
256		break;
257	case 0x1:
258		if (!bank) {
259			++bank;
260		}
261		GBMBCSwitchBank(memory, bank);
262		break;
263	default:
264		// TODO
265		mLOG(GB_MBC, STUB, "MBC2 unknown address: %04X:%02X", address, value);
266		break;
267	}}
268
269void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) {
270	struct GBMemory* memory = &gb->memory;
271	int bank = value & 0x7F;
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, "MBC3 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	case 0x2:
295		if (value < 4) {
296			GBMBCSwitchSramBank(gb, value);
297			memory->rtcAccess = false;
298		} else if (value >= 8 && value <= 0xC) {
299			memory->activeRtcReg = value - 8;
300			memory->rtcAccess = true;
301		}
302		break;
303	case 0x3:
304		if (memory->rtcLatched && value == 0) {
305			memory->rtcLatched = false;
306		} else if (!memory->rtcLatched && value == 1) {
307			_latchRtc(memory);
308			memory->rtcLatched = true;
309		}
310		break;
311	}
312}
313
314void _GBMBC5(struct GB* gb, uint16_t address, uint8_t value) {
315	struct GBMemory* memory = &gb->memory;
316	int bank;
317	switch (address >> 12) {
318	case 0x0:
319	case 0x1:
320		switch (value) {
321		case 0:
322			memory->sramAccess = false;
323			break;
324		case 0xA:
325			memory->sramAccess = true;
326			GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
327			break;
328		default:
329			// TODO
330			mLOG(GB_MBC, STUB, "MBC5 unknown value %02X", value);
331			break;
332		}
333		break;
334	case 0x2:
335		bank = (memory->currentBank & 0x100) | value;
336		GBMBCSwitchBank(memory, bank);
337		break;
338	case 0x3:
339		bank = (memory->currentBank & 0xFF) | ((value & 1) << 8);
340		GBMBCSwitchBank(memory, bank);
341		break;
342	case 0x4:
343	case 0x5:
344		if (memory->mbcType == GB_MBC5_RUMBLE && memory->rumble) {
345			memory->rumble->setRumble(memory->rumble, (value >> 3) & 1);
346			value &= ~8;
347		}
348		GBMBCSwitchSramBank(gb, value & 0xF);
349		break;
350	default:
351		// TODO
352		mLOG(GB_MBC, STUB, "MBC5 unknown address: %04X:%02X", address, value);
353		break;
354	}
355}
356
357void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
358	// TODO
359	mLOG(GB_MBC, STUB, "MBC6 unimplemented");
360	UNUSED(gb);
361	UNUSED(address);
362	UNUSED(value);
363}
364
365void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {
366	struct GBMemory* memory = &gb->memory;
367	int bank = value & 0x7F;
368	switch (address >> 13) {
369	case 0x1:
370		GBMBCSwitchBank(memory, bank);
371		break;
372	case 0x2:
373		if (value < 0x10) {
374			GBMBCSwitchSramBank(gb, value);
375		}
376		break;
377	default:
378		// TODO
379		mLOG(GB_MBC, STUB, "MBC7 unknown address: %04X:%02X", address, value);
380		break;
381	}
382}
383
384uint8_t GBMBC7Read(struct GBMemory* memory, uint16_t address) {
385	struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
386	switch (address & 0xF0) {
387	case 0x00:
388	case 0x10:
389	case 0x60:
390	case 0x70:
391		return 0;
392	case 0x20:
393		if (memory->rotation && memory->rotation->readTiltX) {
394			int32_t x = -memory->rotation->readTiltX(memory->rotation);
395			x >>= 21;
396			x += 2047;
397			return x;
398		}
399		return 0xFF;
400	case 0x30:
401		if (memory->rotation && memory->rotation->readTiltX) {
402			int32_t x = -memory->rotation->readTiltX(memory->rotation);
403			x >>= 21;
404			x += 2047;
405			return x >> 8;
406		}
407		return 7;
408	case 0x40:
409		if (memory->rotation && memory->rotation->readTiltY) {
410			int32_t y = -memory->rotation->readTiltY(memory->rotation);
411			y >>= 21;
412			y += 2047;
413			return y;
414		}
415		return 0xFF;
416	case 0x50:
417		if (memory->rotation && memory->rotation->readTiltY) {
418			int32_t y = -memory->rotation->readTiltY(memory->rotation);
419			y >>= 21;
420			y += 2047;
421			return y >> 8;
422		}
423		return 7;
424	case 0x80:
425		return (mbc7->sr >> 16) & 1;
426	default:
427		return 0xFF;
428	}
429}
430
431void GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) {
432	if ((address & 0xF0) != 0x80) {
433		return;
434	}
435	struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
436	GBMBC7Field old = memory->mbcState.mbc7.field;
437	mbc7->field = GBMBC7FieldClearIO(value);
438	if (!GBMBC7FieldIsCS(old) && GBMBC7FieldIsCS(value)) {
439		if (mbc7->state == GBMBC7_STATE_WRITE) {
440			if (mbc7->writable) {
441				memory->sramBank[mbc7->address * 2] = mbc7->sr >> 8;
442				memory->sramBank[mbc7->address * 2 + 1] = mbc7->sr;
443			}
444			mbc7->sr = 0x1FFFF;
445			mbc7->state = GBMBC7_STATE_NULL;
446		} else {
447			mbc7->state = GBMBC7_STATE_IDLE;
448		}
449	}
450	if (!GBMBC7FieldIsSK(old) && GBMBC7FieldIsSK(value)) {
451		if (mbc7->state > GBMBC7_STATE_IDLE && mbc7->state != GBMBC7_STATE_READ) {
452			mbc7->sr <<= 1;
453			mbc7->sr |= GBMBC7FieldGetIO(value);
454			++mbc7->srBits;
455		}
456		switch (mbc7->state) {
457		case GBMBC7_STATE_IDLE:
458			if (GBMBC7FieldIsIO(value)) {
459				mbc7->state = GBMBC7_STATE_READ_COMMAND;
460				mbc7->srBits = 0;
461				mbc7->sr = 0;
462			}
463			break;
464		case GBMBC7_STATE_READ_COMMAND:
465			if (mbc7->srBits == 2) {
466				mbc7->state = GBMBC7_STATE_READ_ADDRESS;
467				mbc7->srBits = 0;
468				mbc7->command = mbc7->sr;
469			}
470			break;
471		case GBMBC7_STATE_READ_ADDRESS:
472			if (mbc7->srBits == 8) {
473				mbc7->state = GBMBC7_STATE_COMMAND_0 + mbc7->command;
474				mbc7->srBits = 0;
475				mbc7->address = mbc7->sr;
476				if (mbc7->state == GBMBC7_STATE_COMMAND_0) {
477					switch (mbc7->address >> 6) {
478					case 0:
479						mbc7->writable = false;
480						mbc7->state = GBMBC7_STATE_NULL;
481						break;
482					case 3:
483						mbc7->writable = true;
484						mbc7->state = GBMBC7_STATE_NULL;
485						break;
486					}
487				}
488			}
489			break;
490		case GBMBC7_STATE_COMMAND_0:
491			if (mbc7->srBits == 16) {
492				switch (mbc7->address >> 6) {
493				case 0:
494					mbc7->writable = false;
495					mbc7->state = GBMBC7_STATE_NULL;
496					break;
497				case 1:
498					mbc7->state = GBMBC7_STATE_WRITE;
499					if (mbc7->writable) {
500						int i;
501						for (i = 0; i < 256; ++i) {
502							memory->sramBank[i * 2] = mbc7->sr >> 8;
503							memory->sramBank[i * 2 + 1] = mbc7->sr;
504						}
505					}
506					break;
507				case 2:
508					mbc7->state = GBMBC7_STATE_WRITE;
509					if (mbc7->writable) {
510						int i;
511						for (i = 0; i < 256; ++i) {
512							memory->sramBank[i * 2] = 0xFF;
513							memory->sramBank[i * 2 + 1] = 0xFF;
514						}
515					}
516					break;
517				case 3:
518					mbc7->writable = true;
519					mbc7->state = GBMBC7_STATE_NULL;
520					break;
521				}
522			}
523			break;
524		case GBMBC7_STATE_COMMAND_SR_WRITE:
525			if (mbc7->srBits == 16) {
526				mbc7->srBits = 0;
527				mbc7->state = GBMBC7_STATE_WRITE;
528			}
529			break;
530		case GBMBC7_STATE_COMMAND_SR_READ:
531			if (mbc7->srBits == 1) {
532				mbc7->sr = memory->sramBank[mbc7->address * 2] << 8;
533				mbc7->sr |= memory->sramBank[mbc7->address * 2 + 1];
534				mbc7->srBits = 0;
535				mbc7->state = GBMBC7_STATE_READ;
536			}
537			break;
538		case GBMBC7_STATE_COMMAND_SR_FILL:
539			if (mbc7->srBits == 16) {
540				mbc7->sr = 0xFFFF;
541				mbc7->srBits = 0;
542				mbc7->state = GBMBC7_STATE_WRITE;
543			}
544			break;
545		default:
546			break;
547		}
548	} else if (GBMBC7FieldIsSK(old) && !GBMBC7FieldIsSK(value)) {
549		if (mbc7->state == GBMBC7_STATE_READ) {
550			mbc7->sr <<= 1;
551			++mbc7->srBits;
552			if (mbc7->srBits == 16) {
553				mbc7->srBits = 0;
554				mbc7->state = GBMBC7_STATE_NULL;
555			}
556		}
557	}
558}
559
560void _GBHuC3(struct GB* gb, uint16_t address, uint8_t value) {
561	struct GBMemory* memory = &gb->memory;
562	int bank = value & 0x3F;
563	if (address & 0x1FFF) {
564		mLOG(GB_MBC, STUB, "HuC-3 unknown value %04X:%02X", address, value);
565	}
566
567	switch (address >> 13) {
568	case 0x0:
569		switch (value) {
570		case 0xA:
571			memory->sramAccess = true;
572			GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
573			break;
574		default:
575			memory->sramAccess = false;
576			break;
577		}
578		break;
579	case 0x1:
580		GBMBCSwitchBank(memory, bank);
581		break;
582	case 0x2:
583		GBMBCSwitchSramBank(gb, bank);
584		break;
585	default:
586		// TODO
587		mLOG(GB_MBC, STUB, "HuC-3 unknown address: %04X:%02X", address, value);
588		break;
589	}
590}