all repos — mgba @ d9764e8cea482fead7e1a3376d1007c884ee252b

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