GB MBC: More detailed TAMA5 implementation, working saves
Vicki Pfau vi@endrift.com
Mon, 24 Jul 2017 13:48:59 -0700
2 files changed,
66 insertions(+),
26 deletions(-)
M
include/mgba/internal/gb/memory.h
→
include/mgba/internal/gb/memory.h
@@ -87,8 +87,16 @@ GBMBC7_STATE_EEPROM_ERASE = 0x1C,
}; enum GBTAMA5Register { - GBTAMA5_BANK = 0x0, - GBTAMA5_MAX + GBTAMA5_BANK_LO = 0x0, + GBTAMA5_BANK_HI = 0x1, + GBTAMA5_WRITE_LO = 0x4, + GBTAMA5_WRITE_HI = 0x5, + GBTAMA5_CS = 0x6, + GBTAMA5_ADDR_LO = 0x7, + GBTAMA5_MAX = 0x8, + GBTAMA5_ACTIVE = 0xA, + GBTAMA5_READ_LO = 0xC, + GBTAMA5_READ_HI = 0xD, }; struct GBMBC1State {@@ -112,9 +120,7 @@ bool registersActive;
}; struct GBTAMA5State { - bool unlocked; uint8_t reg; - uint8_t value; uint8_t registers[GBTAMA5_MAX]; };
M
src/gb/mbc.c
→
src/gb/mbc.c
@@ -224,6 +224,7 @@ mLOG(GB_MBC, WARN, "unimplemented MBC: TAMA5");
memset(gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs)); gb->memory.mbcWrite = _GBTAMA5; gb->memory.mbcRead = _GBTAMA5Read; + gb->sramSize = 0x20; break; case GB_MBC3_RTC: memset(gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));@@ -772,31 +773,39 @@ struct GBTAMA5State* tama5 = &memory->mbcState.tama5;
switch (address >> 13) { case 0x5: if (address & 1) { - if (tama5->unlocked) { - tama5->reg = value; - } else if (value == 0xA) { - tama5->unlocked = true; - } + tama5->reg = value; } else { - uint8_t reg = tama5->reg >> 1; - if (reg < GBTAMA5_MAX) { - uint8_t mask = 0xF << (4 * (tama5->reg & 1)); - value <<= (4 * (tama5->reg & 1)); - value |= tama5->registers[reg] & ~mask; - tama5->registers[reg] = value; - if (tama5->reg & 1) { - switch (reg) { - case GBTAMA5_BANK: - GBMBCSwitchBank(gb, value & 0x1F); - // Fall through + value &= 0xF; + if (tama5->reg < GBTAMA5_MAX) { + tama5->registers[tama5->reg] = value; + uint8_t address = ((tama5->registers[GBTAMA5_CS] << 4) & 0x10) | tama5->registers[GBTAMA5_ADDR_LO]; + uint8_t out = (tama5->registers[GBTAMA5_WRITE_HI] << 4) | tama5->registers[GBTAMA5_WRITE_LO]; + switch (tama5->reg) { + case GBTAMA5_BANK_LO: + case GBTAMA5_BANK_HI: + GBMBCSwitchBank(gb, tama5->registers[GBTAMA5_BANK_LO] | (tama5->registers[GBTAMA5_BANK_HI] << 4)); + break; + case GBTAMA5_WRITE_LO: + case GBTAMA5_WRITE_HI: + case GBTAMA5_CS: + break; + case GBTAMA5_ADDR_LO: + switch (tama5->registers[GBTAMA5_CS] >> 1) { + case 0x0: // RAM write + memory->sram[address] = out; + break; + case 0x1: // RAM read + break; default: - mLOG(GB_MBC, STUB, "TAMA5 unknown register: %02X:%02X", reg, value); - break; + mLOG(GB_MBC, STUB, "TAMA5 unknown address: %X-%02X:%02X", tama5->registers[GBTAMA5_CS] >> 1, address, out); } - tama5->unlocked = false; + break; + default: + mLOG(GB_MBC, STUB, "TAMA5 unknown write: %02X:%X", tama5->reg, value); + break; } } else { - mLOG(GB_MBC, STUB, "TAMA5 unknown register: %02X", reg); + mLOG(GB_MBC, STUB, "TAMA5 unknown write: %02X", tama5->reg); } } break;@@ -807,11 +816,36 @@ }
uint8_t _GBTAMA5Read(struct GBMemory* memory, uint16_t address) { struct GBTAMA5State* tama5 = &memory->mbcState.tama5; - mLOG(GB_MBC, STUB, "TAMA5 unknown address: %04X", address); + if ((address & 0x1FFF) > 1) { + mLOG(GB_MBC, STUB, "TAMA5 unknown address: %04X", address); + } if (address & 1) { return 0xFF; } else { - return 0xF0 | tama5->unlocked; + uint8_t value = 0xF0; + uint8_t address = ((tama5->registers[GBTAMA5_CS] << 4) & 0x10) | tama5->registers[GBTAMA5_ADDR_LO]; + switch (tama5->reg) { + case GBTAMA5_ACTIVE: + return 0xF1; + case GBTAMA5_READ_LO: + case GBTAMA5_READ_HI: + switch (tama5->registers[GBTAMA5_CS] >> 1) { + case 1: + value = memory->sram[address]; + break; + default: + mLOG(GB_MBC, STUB, "TAMA5 unknown read: %02X", tama5->reg); + break; + } + if (tama5->reg == GBTAMA5_READ_HI) { + value >>= 4; + } + value |= 0xF0; + return value; + default: + mLOG(GB_MBC, STUB, "TAMA5 unknown read: %02X", tama5->reg); + return 0xF1; + } } }