all repos — mgba @ 05ef05317c2cb639e41648ddc74256b7977972eb

mGBA Game Boy Advance Emulator

src/gb/memory.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 "memory.h"
  7
  8#include "core/interface.h"
  9#include "gb/gb.h"
 10#include "gb/io.h"
 11
 12#include "util/memory.h"
 13
 14#include <time.h>
 15
 16mLOG_DEFINE_CATEGORY(GB_MBC, "GB MBC");
 17mLOG_DEFINE_CATEGORY(GB_MEM, "GB Memory");
 18
 19static void _GBMBCNone(struct GBMemory* memory, uint16_t address, uint8_t value) {
 20	UNUSED(memory);
 21	UNUSED(address);
 22	UNUSED(value);
 23
 24	mLOG(GB_MBC, GAME_ERROR, "Wrote to invalid MBC");
 25}
 26
 27static void _GBMBC1(struct GBMemory*, uint16_t address, uint8_t value);
 28static void _GBMBC2(struct GBMemory*, uint16_t address, uint8_t value);
 29static void _GBMBC3(struct GBMemory*, uint16_t address, uint8_t value);
 30static void _GBMBC5(struct GBMemory*, uint16_t address, uint8_t value);
 31static void _GBMBC6(struct GBMemory*, uint16_t address, uint8_t value);
 32static void _GBMBC7(struct GBMemory*, uint16_t address, uint8_t value);
 33static uint8_t _GBMBC7Read(struct GBMemory*, uint16_t address);
 34static void _GBMBC7Write(struct GBMemory*, uint16_t address, uint8_t value);
 35
 36static uint8_t GBFastLoad8(struct LR35902Core* cpu, uint16_t address) {
 37	if (UNLIKELY(address > cpu->memory.activeRegionEnd)) {
 38		cpu->memory.setActiveRegion(cpu, address);
 39		return cpu->memory.cpuLoad8(cpu, address);
 40	}
 41	return cpu->memory.activeRegion[address & cpu->memory.activeMask];
 42}
 43
 44static void GBSetActiveRegion(struct LR35902Core* cpu, uint16_t address) {
 45	struct GB* gb = (struct GB*) cpu->master;
 46	struct GBMemory* memory = &gb->memory;
 47	switch (address >> 12) {
 48	case GB_REGION_CART_BANK0:
 49	case GB_REGION_CART_BANK0 + 1:
 50	case GB_REGION_CART_BANK0 + 2:
 51	case GB_REGION_CART_BANK0 + 3:
 52		cpu->memory.cpuLoad8 = GBFastLoad8;
 53		cpu->memory.activeRegion = memory->rom;
 54		cpu->memory.activeRegionEnd = GB_BASE_CART_BANK1;
 55		cpu->memory.activeMask = GB_SIZE_CART_BANK0 - 1;
 56		break;
 57	case GB_REGION_CART_BANK1:
 58	case GB_REGION_CART_BANK1 + 1:
 59	case GB_REGION_CART_BANK1 + 2:
 60	case GB_REGION_CART_BANK1 + 3:
 61		cpu->memory.cpuLoad8 = GBFastLoad8;
 62		cpu->memory.activeRegion = memory->romBank;
 63		cpu->memory.activeRegionEnd = GB_BASE_VRAM;
 64		cpu->memory.activeMask = GB_SIZE_CART_BANK0 - 1;
 65		break;
 66	default:
 67		cpu->memory.cpuLoad8 = GBLoad8;
 68		break;
 69	}
 70}
 71
 72static void _GBMemoryDMAService(struct GB* gb);
 73static void _GBMemoryHDMAService(struct GB* gb);
 74
 75void GBMemoryInit(struct GB* gb) {
 76	struct LR35902Core* cpu = gb->cpu;
 77	cpu->memory.cpuLoad8 = GBLoad8;
 78	cpu->memory.load8 = GBLoad8;
 79	cpu->memory.store8 = GBStore8;
 80	cpu->memory.setActiveRegion = GBSetActiveRegion;
 81
 82	gb->memory.wram = 0;
 83	gb->memory.wramBank = 0;
 84	gb->memory.rom = 0;
 85	gb->memory.romBank = 0;
 86	gb->memory.romSize = 0;
 87	gb->memory.sram = 0;
 88	gb->memory.mbcType = GB_MBC_NONE;
 89	gb->memory.mbc = 0;
 90
 91	gb->memory.rtc = NULL;
 92
 93	GBIOInit(gb);
 94}
 95
 96void GBMemoryDeinit(struct GB* gb) {
 97	mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
 98	if (gb->memory.rom) {
 99		mappedMemoryFree(gb->memory.rom, gb->memory.romSize);
100	}
101}
102
103void GBMemoryReset(struct GB* gb) {
104	if (gb->memory.wram) {
105		mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM);
106	}
107	gb->memory.wram = anonymousMemoryMap(GB_SIZE_WORKING_RAM);
108	GBMemorySwitchWramBank(&gb->memory, 1);
109	gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0];
110	gb->memory.currentBank = 1;
111	gb->memory.sramCurrentBank = 0;
112	gb->memory.sramBank = gb->memory.sram;
113
114	gb->memory.ime = false;
115	gb->memory.ie = 0;
116
117	gb->memory.dmaNext = INT_MAX;
118	gb->memory.dmaRemaining = 0;
119	gb->memory.dmaSource = 0;
120	gb->memory.dmaDest = 0;
121	gb->memory.hdmaNext = INT_MAX;
122	gb->memory.hdmaRemaining = 0;
123	gb->memory.hdmaSource = 0;
124	gb->memory.hdmaDest = 0;
125	gb->memory.isHdma = false;
126
127	gb->memory.sramAccess = false;
128	gb->memory.rtcAccess = false;
129	gb->memory.activeRtcReg = 0;
130	gb->memory.rtcLatched = 0;
131	memset(&gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));
132
133	memset(&gb->memory.hram, 0, sizeof(gb->memory.hram));
134
135	const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
136	switch (cart->type) {
137	case 0:
138	case 8:
139	case 9:
140		gb->memory.mbc = _GBMBCNone;
141		gb->memory.mbcType = GB_MBC_NONE;
142		break;
143	case 1:
144	case 2:
145	case 3:
146		gb->memory.mbc = _GBMBC1;
147		gb->memory.mbcType = GB_MBC1;
148		break;
149	case 5:
150	case 6:
151		gb->memory.mbc = _GBMBC2;
152		gb->memory.mbcType = GB_MBC2;
153		break;
154	case 0x0F:
155	case 0x10:
156	case 0x11:
157	case 0x12:
158	case 0x13:
159		gb->memory.mbc = _GBMBC3;
160		gb->memory.mbcType = GB_MBC3;
161		break;
162	default:
163		mLOG(GB_MBC, WARN, "Unknown MBC type: %02X", cart->type);
164	case 0x19:
165	case 0x1A:
166	case 0x1B:
167		gb->memory.mbc = _GBMBC5;
168		gb->memory.mbcType = GB_MBC5;
169		break;
170	case 0x1C:
171	case 0x1D:
172	case 0x1E:
173		gb->memory.mbc = _GBMBC5;
174		gb->memory.mbcType = GB_MBC5_RUMBLE;
175		break;
176	case 0x20:
177		gb->memory.mbc = _GBMBC6;
178		gb->memory.mbcType = GB_MBC6;
179		break;
180	case 0x22:
181		gb->memory.mbc = _GBMBC7;
182		gb->memory.mbcType = GB_MBC7;
183		memset(&gb->memory.mbcState.mbc7, 0, sizeof(gb->memory.mbcState.mbc7));
184		break;
185	}
186
187	if (!gb->memory.wram) {
188		GBMemoryDeinit(gb);
189	}
190}
191
192void GBMemorySwitchWramBank(struct GBMemory* memory, int bank) {
193	bank &= 7;
194	if (!bank) {
195		bank = 1;
196	}
197	memory->wramBank = &memory->wram[GB_SIZE_WORKING_RAM_BANK0 * bank];
198	memory->wramCurrentBank = bank;
199}
200
201uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
202	struct GB* gb = (struct GB*) cpu->master;
203	struct GBMemory* memory = &gb->memory;
204	switch (address >> 12) {
205	case GB_REGION_CART_BANK0:
206	case GB_REGION_CART_BANK0 + 1:
207	case GB_REGION_CART_BANK0 + 2:
208	case GB_REGION_CART_BANK0 + 3:
209		return memory->rom[address & (GB_SIZE_CART_BANK0 - 1)];
210	case GB_REGION_CART_BANK1:
211	case GB_REGION_CART_BANK1 + 1:
212	case GB_REGION_CART_BANK1 + 2:
213	case GB_REGION_CART_BANK1 + 3:
214		return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
215	case GB_REGION_VRAM:
216	case GB_REGION_VRAM + 1:
217		return gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)];
218	case GB_REGION_EXTERNAL_RAM:
219	case GB_REGION_EXTERNAL_RAM + 1:
220		if (memory->rtcAccess) {
221			return gb->memory.rtcRegs[memory->activeRtcReg];
222		} else if (memory->sramAccess) {
223			return gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
224		} else if (memory->mbcType == GB_MBC7) {
225			return _GBMBC7Read(memory, address);
226		}
227		return 0xFF;
228	case GB_REGION_WORKING_RAM_BANK0:
229	case GB_REGION_WORKING_RAM_BANK0 + 2:
230		return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
231	case GB_REGION_WORKING_RAM_BANK1:
232		return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
233	default:
234		if (address < GB_BASE_OAM) {
235			return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
236		}
237		if (address < GB_BASE_UNUSABLE) {
238			if (gb->video.mode < 2) {
239				return gb->video.oam.raw[address & 0xFF];
240			}
241			return 0xFF;
242		}
243		if (address < GB_BASE_IO) {
244			mLOG(GB_MEM, GAME_ERROR, "Attempt to read from unusable memory: %04X", address);
245			return 0xFF;
246		}
247		if (address < GB_BASE_HRAM) {
248			return GBIORead(gb, address & (GB_SIZE_IO - 1));
249		}
250		if (address < GB_BASE_IE) {
251			return memory->hram[address & GB_SIZE_HRAM];
252		}
253		return GBIORead(gb, REG_IE);
254	}
255}
256
257void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
258	struct GB* gb = (struct GB*) cpu->master;
259	struct GBMemory* memory = &gb->memory;
260	switch (address >> 12) {
261	case GB_REGION_CART_BANK0:
262	case GB_REGION_CART_BANK0 + 1:
263	case GB_REGION_CART_BANK0 + 2:
264	case GB_REGION_CART_BANK0 + 3:
265	case GB_REGION_CART_BANK1:
266	case GB_REGION_CART_BANK1 + 1:
267	case GB_REGION_CART_BANK1 + 2:
268	case GB_REGION_CART_BANK1 + 3:
269		memory->mbc(memory, address, value);
270		cpu->memory.setActiveRegion(cpu, cpu->pc);
271		return;
272	case GB_REGION_VRAM:
273	case GB_REGION_VRAM + 1:
274		// TODO: Block access in wrong modes
275		gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)] = value;
276		return;
277	case GB_REGION_EXTERNAL_RAM:
278	case GB_REGION_EXTERNAL_RAM + 1:
279		if (memory->rtcAccess) {
280			gb->memory.rtcRegs[memory->activeRtcReg] = value;
281		} else if (memory->sramAccess) {
282			gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
283		} else if (gb->memory.mbcType == GB_MBC7) {
284			_GBMBC7Write(&gb->memory, address, value);
285		}
286		return;
287	case GB_REGION_WORKING_RAM_BANK0:
288	case GB_REGION_WORKING_RAM_BANK0 + 2:
289		memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
290		return;
291	case GB_REGION_WORKING_RAM_BANK1:
292		memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
293		return;
294	default:
295		if (address < GB_BASE_OAM) {
296			memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
297		} else if (address < GB_BASE_UNUSABLE) {
298			if (gb->video.mode < 2) {
299				gb->video.oam.raw[address & 0xFF] = value;
300			}
301		} else if (address < GB_BASE_IO) {
302			mLOG(GB_MEM, GAME_ERROR, "Attempt to write to unusable memory: %04X:%02X", address, value);
303		} else if (address < GB_BASE_HRAM) {
304			GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
305		} else if (address < GB_BASE_IE) {
306			memory->hram[address & GB_SIZE_HRAM] = value;
307		} else {
308			GBIOWrite(gb, REG_IE, value);
309		}
310	}
311}
312
313int32_t GBMemoryProcessEvents(struct GB* gb, int32_t cycles) {
314	int nextEvent = INT_MAX;
315	if (gb->memory.dmaRemaining) {
316		gb->memory.dmaNext -= cycles;
317		if (gb->memory.dmaNext <= 0) {
318			_GBMemoryDMAService(gb);
319		}
320		nextEvent = gb->memory.dmaNext;
321	}
322	if (gb->memory.hdmaRemaining) {
323		gb->memory.hdmaNext -= cycles;
324		if (gb->memory.hdmaNext <= 0) {
325			_GBMemoryHDMAService(gb);
326		}
327		if (gb->memory.hdmaNext < nextEvent) {
328			nextEvent = gb->memory.hdmaNext;
329		}
330	}
331	return nextEvent;
332}
333
334void GBMemoryDMA(struct GB* gb, uint16_t base) {
335	if (base > 0xF100) {
336		return;
337	}
338	gb->cpu->memory.store8 = GBDMAStore8;
339	gb->cpu->memory.load8 = GBDMALoad8;
340	gb->cpu->memory.cpuLoad8 = GBDMALoad8;
341	gb->memory.dmaNext = gb->cpu->cycles + 8;
342	if (gb->memory.dmaNext < gb->cpu->nextEvent) {
343		gb->cpu->nextEvent = gb->memory.dmaNext;
344	}
345	gb->memory.dmaSource = base;
346	gb->memory.dmaDest = 0;
347	gb->memory.dmaRemaining = 0xA0;
348}
349
350void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) {
351	gb->memory.hdmaSource = gb->memory.io[REG_HDMA1] << 8;
352	gb->memory.hdmaSource |= gb->memory.io[REG_HDMA2];
353	gb->memory.hdmaDest = gb->memory.io[REG_HDMA3] << 8;
354	gb->memory.hdmaDest |= gb->memory.io[REG_HDMA4];
355	gb->memory.hdmaSource &= 0xFFF0;
356	if (gb->memory.hdmaSource >= 0x8000 && gb->memory.hdmaSource < 0xA000) {
357		mLOG(GB_MEM, GAME_ERROR, "Invalid HDMA source: %04X", gb->memory.hdmaSource);
358		return;
359	}
360	gb->memory.hdmaDest &= 0x1FF0;
361	gb->memory.hdmaDest |= 0x8000;
362	bool wasHdma = gb->memory.isHdma;
363	gb->memory.isHdma = value & 0x80;
364	if (!wasHdma && !gb->memory.isHdma) {
365		gb->memory.hdmaRemaining = ((value & 0x7F) + 1) * 0x10;
366		gb->memory.hdmaNext = gb->cpu->cycles;
367		gb->cpu->nextEvent = gb->cpu->cycles;
368	}
369}
370
371void _GBMemoryDMAService(struct GB* gb) {
372	uint8_t b = GBLoad8(gb->cpu, gb->memory.dmaSource);
373	// TODO: Can DMA write OAM during modes 2-3?
374	gb->video.oam.raw[gb->memory.dmaDest] = b;
375	++gb->memory.dmaSource;
376	++gb->memory.dmaDest;
377	--gb->memory.dmaRemaining;
378	if (gb->memory.dmaRemaining) {
379		gb->memory.dmaNext += 4;
380	} else {
381		gb->memory.dmaNext = INT_MAX;
382		gb->cpu->memory.store8 = GBStore8;
383		gb->cpu->memory.load8 = GBLoad8;
384	}
385}
386
387void _GBMemoryHDMAService(struct GB* gb) {
388	uint8_t b = gb->cpu->memory.load8(gb->cpu, gb->memory.hdmaSource);
389	gb->cpu->memory.store8(gb->cpu, gb->memory.hdmaDest, b);
390	++gb->memory.hdmaSource;
391	++gb->memory.hdmaDest;
392	--gb->memory.hdmaRemaining;
393	gb->cpu->cycles += 2;
394	if (gb->memory.hdmaRemaining) {
395		gb->memory.hdmaNext += 2;
396	} else {
397		gb->memory.io[REG_HDMA1] = gb->memory.hdmaSource >> 8;
398		gb->memory.io[REG_HDMA2] = gb->memory.hdmaSource;
399		gb->memory.io[REG_HDMA3] = gb->memory.hdmaDest >> 8;
400		gb->memory.io[REG_HDMA4] = gb->memory.hdmaDest;
401		if (gb->memory.isHdma) {
402			--gb->memory.io[REG_HDMA5];
403			if (gb->memory.io[REG_HDMA5] == 0xFF) {
404				gb->memory.isHdma = false;
405			}
406		} else {
407			gb->memory.io[REG_HDMA5] |= 0x80;
408		}
409	}
410}
411
412uint8_t GBDMALoad8(struct LR35902Core* cpu, uint16_t address) {
413	struct GB* gb = (struct GB*) cpu->master;
414	struct GBMemory* memory = &gb->memory;
415	if (address < 0xFF80 || address == 0xFFFF) {
416		return 0xFF;
417	}
418	return memory->hram[address & GB_SIZE_HRAM];
419}
420
421void GBDMAStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
422	struct GB* gb = (struct GB*) cpu->master;
423	struct GBMemory* memory = &gb->memory;
424	if (address < 0xFF80 || address == 0xFFFF) {
425		return;
426	}
427	memory->hram[address & GB_SIZE_HRAM] = value;
428}
429
430uint8_t GBView8(struct LR35902Core* cpu, uint16_t address);
431
432void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old);
433
434static void _switchBank(struct GBMemory* memory, int bank) {
435	size_t bankStart = bank * GB_SIZE_CART_BANK0;
436	if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) {
437		mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
438		bankStart &= (GB_SIZE_CART_BANK0 - 1);
439		bank /= GB_SIZE_CART_BANK0;
440	}
441	memory->romBank = &memory->rom[bankStart];
442	memory->currentBank = bank;
443}
444
445static void _switchSramBank(struct GBMemory* memory, int bank) {
446	size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
447	memory->sramBank = &memory->sram[bankStart];
448	memory->sramCurrentBank = bank;
449}
450
451static void _latchRtc(struct GBMemory* memory) {
452	time_t t;
453	struct mRTCSource* rtc = memory->rtc;
454	if (rtc) {
455		if (rtc->sample) {
456			rtc->sample(rtc);
457		}
458		t = rtc->unixTime(rtc);
459	} else {
460		t = time(0);
461	}
462	struct tm date;
463	localtime_r(&t, &date);
464	memory->rtcRegs[0] = date.tm_sec;
465	memory->rtcRegs[1] = date.tm_min;
466	memory->rtcRegs[2] = date.tm_hour;
467	memory->rtcRegs[3] = date.tm_yday; // TODO: Persist day counter
468	memory->rtcRegs[4] &= 0xF0;
469	memory->rtcRegs[4] |= date.tm_yday >> 8;
470}
471
472void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
473	int bank = value & 0x1F;
474	switch (address >> 13) {
475	case 0x0:
476		switch (value) {
477		case 0:
478			memory->sramAccess = false;
479			break;
480		case 0xA:
481			memory->sramAccess = true;
482			_switchSramBank(memory, memory->sramCurrentBank);
483			break;
484		default:
485			// TODO
486			mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
487			break;
488		}
489		break;
490	case 0x1:
491		if (!bank) {
492			++bank;
493		}
494		_switchBank(memory, bank | (memory->currentBank & 0x60));
495		break;
496	default:
497		// TODO
498		mLOG(GB_MBC, STUB, "MBC1 unknown address: %04X:%02X", address, value);
499		break;
500	}
501}
502
503void _GBMBC2(struct GBMemory* memory, uint16_t address, uint8_t value) {
504	mLOG(GB_MBC, STUB, "MBC2 unimplemented");
505}
506
507void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
508	int bank = value & 0x7F;
509	switch (address >> 13) {
510	case 0x0:
511		switch (value) {
512		case 0:
513			memory->sramAccess = false;
514			break;
515		case 0xA:
516			memory->sramAccess = true;
517			_switchSramBank(memory, memory->sramCurrentBank);
518			break;
519		default:
520			// TODO
521			mLOG(GB_MBC, STUB, "MBC3 unknown value %02X", value);
522			break;
523		}
524		break;
525	case 0x1:
526		if (!bank) {
527			++bank;
528		}
529		_switchBank(memory, bank);
530		break;
531	case 0x2:
532		if (value < 4) {
533			_switchSramBank(memory, value);
534			memory->rtcAccess = false;
535		} else if (value >= 8 && value <= 0xC) {
536			memory->activeRtcReg = value - 8;
537			memory->rtcAccess = true;
538		}
539		break;
540	case 0x3:
541		if (memory->rtcLatched && value == 0) {
542			memory->rtcLatched = value;
543		} else if (!memory->rtcLatched && value == 1) {
544			_latchRtc(memory);
545		}
546		break;
547	}
548}
549
550void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
551	int bank;
552	switch (address >> 12) {
553	case 0x0:
554	case 0x1:
555		switch (value) {
556		case 0:
557			memory->sramAccess = false;
558			break;
559		case 0xA:
560			memory->sramAccess = true;
561			_switchSramBank(memory, memory->sramCurrentBank);
562			break;
563		default:
564			// TODO
565			mLOG(GB_MBC, STUB, "MBC5 unknown value %02X", value);
566			break;
567		}
568		break;
569	case 0x2:
570		bank = (memory->currentBank & 0x100) | value;
571		_switchBank(memory, bank);
572		break;
573	case 0x3:
574		bank = (memory->currentBank & 0xFF) | ((value & 1) << 8);
575		_switchBank(memory, bank);
576		break;
577	case 0x4:
578	case 0x5:
579		if (memory->mbcType == GB_MBC5_RUMBLE) {
580			memory->rumble->setRumble(memory->rumble, (value >> 3) & 1);
581			value &= ~8;
582		}
583		_switchSramBank(memory, value & 0xF);
584		break;
585	default:
586		// TODO
587		mLOG(GB_MBC, STUB, "MBC5 unknown address: %04X:%02X", address, value);
588		break;
589	}
590}
591
592void _GBMBC6(struct GBMemory* memory, uint16_t address, uint8_t value) {
593	// TODO
594	mLOG(GB_MBC, STUB, "MBC6 unimplemented");
595}
596
597void _GBMBC7(struct GBMemory* memory, uint16_t address, uint8_t value) {
598	int bank = value & 0x7F;
599	switch (address >> 13) {
600	case 0x1:
601		_switchBank(memory, bank);
602		break;
603	case 0x2:
604		if (value < 0x10) {
605			_switchSramBank(memory, value);
606		}
607		break;
608	default:
609		// TODO
610		mLOG(GB_MBC, STUB, "MBC7 unknown address: %04X:%02X", address, value);
611		break;
612	}
613}
614
615uint8_t _GBMBC7Read(struct GBMemory* memory, uint16_t address) {
616	struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
617	switch (address & 0xF0) {
618	case 0x00:
619	case 0x10:
620	case 0x60:
621	case 0x70:
622		return 0;
623	case 0x20:
624		if (memory->rotation && memory->rotation->readTiltX) {
625			int32_t x = -memory->rotation->readTiltX(memory->rotation);
626			x >>= 21;
627			x += 2047;
628			return x;
629		}
630		return 0xFF;
631	case 0x30:
632		if (memory->rotation && memory->rotation->readTiltX) {
633			int32_t x = -memory->rotation->readTiltX(memory->rotation);
634			x >>= 21;
635			x += 2047;
636			return x >> 8;
637		}
638		return 7;
639	case 0x40:
640		if (memory->rotation && memory->rotation->readTiltY) {
641			int32_t y = -memory->rotation->readTiltY(memory->rotation);
642			y >>= 21;
643			y += 2047;
644			return y;
645		}
646		return 0xFF;
647	case 0x50:
648		if (memory->rotation && memory->rotation->readTiltY) {
649			int32_t y = -memory->rotation->readTiltY(memory->rotation);
650			y >>= 21;
651			y += 2047;
652			return y >> 8;
653		}
654		return 7;
655	case 0x80:
656		return (mbc7->sr >> 16) & 1;
657	default:
658		return 0xFF;
659	}
660}
661
662void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) {
663	if ((address & 0xF0) != 0x80) {
664		return;
665	}
666	struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
667	GBMBC7Field old = memory->mbcState.mbc7.field;
668	mbc7->field = GBMBC7FieldClearIO(value);
669	if (!GBMBC7FieldIsCS(old) && GBMBC7FieldIsCS(value)) {
670		if (mbc7->state == GBMBC7_STATE_WRITE) {
671			if (mbc7->writable) {
672				memory->sramBank[mbc7->address * 2] = mbc7->sr >> 8;
673				memory->sramBank[mbc7->address * 2 + 1] = mbc7->sr;
674			}
675			mbc7->sr = 0x1FFFF;
676			mbc7->state = GBMBC7_STATE_NULL;
677		} else {
678			mbc7->state = GBMBC7_STATE_IDLE;
679		}
680	}
681	if (!GBMBC7FieldIsSK(old) && GBMBC7FieldIsSK(value)) {
682		if (mbc7->state > GBMBC7_STATE_IDLE && mbc7->state != GBMBC7_STATE_READ) {
683			mbc7->sr <<= 1;
684			mbc7->sr |= GBMBC7FieldGetIO(value);
685			++mbc7->srBits;
686		}
687		switch (mbc7->state) {
688		case GBMBC7_STATE_IDLE:
689			if (GBMBC7FieldIsIO(value)) {
690				mbc7->state = GBMBC7_STATE_READ_COMMAND;
691				mbc7->srBits = 0;
692				mbc7->sr = 0;
693			}
694			break;
695		case GBMBC7_STATE_READ_COMMAND:
696			if (mbc7->srBits == 2) {
697				mbc7->state = GBMBC7_STATE_READ_ADDRESS;
698				mbc7->srBits = 0;
699				mbc7->command = mbc7->sr;
700			}
701			break;
702		case GBMBC7_STATE_READ_ADDRESS:
703			if (mbc7->srBits == 8) {
704				mbc7->state = GBMBC7_STATE_COMMAND_0 + mbc7->command;
705				mbc7->srBits = 0;
706				mbc7->address = mbc7->sr;
707				if (mbc7->state == GBMBC7_STATE_COMMAND_0) {
708					switch (mbc7->address >> 6) {
709					case 0:
710						mbc7->writable = false;
711						mbc7->state = GBMBC7_STATE_NULL;
712						break;
713					case 3:
714						mbc7->writable = true;
715						mbc7->state = GBMBC7_STATE_NULL;
716						break;
717					}
718				}
719			}
720			break;
721		case GBMBC7_STATE_COMMAND_0:
722			if (mbc7->srBits == 16) {
723				switch (mbc7->address >> 6) {
724				case 0:
725					mbc7->writable = false;
726					mbc7->state = GBMBC7_STATE_NULL;
727					break;
728				case 1:
729					mbc7->state = GBMBC7_STATE_WRITE;
730					if (mbc7->writable) {
731						int i;
732						for (i = 0; i < 256; ++i) {
733							memory->sramBank[i * 2] = mbc7->sr >> 8;
734							memory->sramBank[i * 2 + 1] = mbc7->sr;
735						}
736					}
737					break;
738				case 2:
739					mbc7->state = GBMBC7_STATE_WRITE;
740					if (mbc7->writable) {
741						int i;
742						for (i = 0; i < 256; ++i) {
743							memory->sramBank[i * 2] = 0xFF;
744							memory->sramBank[i * 2 + 1] = 0xFF;
745						}
746					}
747					break;
748				case 3:
749					mbc7->writable = true;
750					mbc7->state = GBMBC7_STATE_NULL;
751					break;
752				}
753			}
754			break;
755		case GBMBC7_STATE_COMMAND_SR_WRITE:
756			if (mbc7->srBits == 16) {
757				mbc7->srBits = 0;
758				mbc7->state = GBMBC7_STATE_WRITE;
759			}
760			break;
761		case GBMBC7_STATE_COMMAND_SR_READ:
762			if (mbc7->srBits == 1) {
763				mbc7->sr = memory->sramBank[mbc7->address * 2] << 8;
764				mbc7->sr |= memory->sramBank[mbc7->address * 2 + 1];
765				mbc7->srBits = 0;
766				mbc7->state = GBMBC7_STATE_READ;
767			}
768			break;
769		case GBMBC7_STATE_COMMAND_SR_FILL:
770			if (mbc7->srBits == 16) {
771				mbc7->sr = 0xFFFF;
772				mbc7->srBits = 0;
773				mbc7->state = GBMBC7_STATE_WRITE;
774			}
775			break;
776		default:
777			break;
778		}
779	} else if (GBMBC7FieldIsSK(old) && !GBMBC7FieldIsSK(value)) {
780		if (mbc7->state == GBMBC7_STATE_READ) {
781			mbc7->sr <<= 1;
782			++mbc7->srBits;
783			if (mbc7->srBits == 16) {
784				mbc7->srBits = 0;
785				mbc7->state = GBMBC7_STATE_NULL;
786			}
787		}
788	}
789}