From 7b543df00225ce9c356f357e5f4c4c2de76ab61e Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 24 Jun 2017 17:45:20 -0700 Subject: [PATCH] GB MBC: New MBC7 implementation --- CHANGES | 1 + include/mgba/internal/gb/memory.h | 29 ++-- src/gb/mbc.c | 231 ++++++++++++++++-------------- src/gb/video.c | 3 - 4 files changed, 137 insertions(+), 127 deletions(-) diff --git a/CHANGES b/CHANGES index 2be7f0846..6c721fe05 100644 --- a/CHANGES +++ b/CHANGES @@ -140,6 +140,7 @@ Misc: - GB: Trust ROM header for number of SRAM banks (fixes mgba.io/i/726) - Core: Config values can now be hexadecimal - GB: Reset with initial state of DIV register + - GB MBC: New MBC7 implementation 0.5.2: (2016-12-31) Bugfixes: diff --git a/include/mgba/internal/gb/memory.h b/include/mgba/internal/gb/memory.h index 2d169635a..d28338cff 100644 --- a/include/mgba/internal/gb/memory.h +++ b/include/mgba/internal/gb/memory.h @@ -67,21 +67,23 @@ typedef void (*GBMemoryBankControllerWrite)(struct GB*, uint16_t address, uint8_ typedef uint8_t (*GBMemoryBankControllerRead)(struct GBMemory*, uint16_t address); DECL_BITFIELD(GBMBC7Field, uint8_t); -DECL_BIT(GBMBC7Field, SK, 6); DECL_BIT(GBMBC7Field, CS, 7); -DECL_BIT(GBMBC7Field, IO, 1); +DECL_BIT(GBMBC7Field, CLK, 6); +DECL_BIT(GBMBC7Field, DI, 1); +DECL_BIT(GBMBC7Field, DO, 0); enum GBMBC7MachineState { - GBMBC7_STATE_NULL = -1, GBMBC7_STATE_IDLE = 0, GBMBC7_STATE_READ_COMMAND = 1, - GBMBC7_STATE_READ_ADDRESS = 2, - GBMBC7_STATE_COMMAND_0 = 3, - GBMBC7_STATE_COMMAND_SR_WRITE = 4, - GBMBC7_STATE_COMMAND_SR_READ = 5, - GBMBC7_STATE_COMMAND_SR_FILL = 6, - GBMBC7_STATE_READ = 7, - GBMBC7_STATE_WRITE = 8, + GBMBC7_STATE_DO = 2, + + GBMBC7_STATE_EEPROM_EWDS = 0x10, + GBMBC7_STATE_EEPROM_WRAL = 0x11, + GBMBC7_STATE_EEPROM_ERAL = 0x12, + GBMBC7_STATE_EEPROM_EWEN = 0x13, + GBMBC7_STATE_EEPROM_WRITE = 0x14, + GBMBC7_STATE_EEPROM_READ = 0x18, + GBMBC7_STATE_EEPROM_ERASE = 0x1C, }; struct GBMBC1State { @@ -91,12 +93,13 @@ struct GBMBC1State { struct GBMBC7State { enum GBMBC7MachineState state; - uint32_t sr; + uint16_t sr; uint8_t address; bool writable; int srBits; - int command; - GBMBC7Field field; + uint8_t access; + uint8_t latch; + GBMBC7Field eeprom; }; struct GBPocketCamState { diff --git a/src/gb/mbc.c b/src/gb/mbc.c index a26edeac6..87fae1510 100644 --- a/src/gb/mbc.c +++ b/src/gb/mbc.c @@ -198,7 +198,7 @@ void GBMBCInit(struct GB* gb) { case GB_MBC7: gb->memory.mbcWrite = _GBMBC7; gb->memory.mbcRead = _GBMBC7Read; - gb->sramSize = GB_SIZE_EXTERNAL_RAM; + gb->sramSize = 0x100; break; case GB_MMM01: mLOG(GB_MBC, WARN, "unimplemented MBC: MMM01"); @@ -472,12 +472,25 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) { void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) { int bank = value & 0x7F; switch (address >> 13) { + case 0x0: + switch (value) { + default: + case 0: + gb->memory.mbcState.mbc7.access = 0; + break; + case 0xA: + gb->memory.mbcState.mbc7.access |= 1; + break; + } + break; case 0x1: GBMBCSwitchBank(gb, bank); break; case 0x2: - if (value < 0x10) { - GBMBCSwitchSramBank(gb, value); + if (value == 0x40) { + gb->memory.mbcState.mbc7.access |= 2; + } else { + gb->memory.mbcState.mbc7.access &= ~2; } break; default: @@ -489,17 +502,15 @@ void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) { uint8_t _GBMBC7Read(struct GBMemory* memory, uint16_t address) { struct GBMBC7State* mbc7 = &memory->mbcState.mbc7; + if (mbc7->access != 3) { + return 0xFF; + } switch (address & 0xF0) { - case 0x00: - case 0x10: - case 0x60: - case 0x70: - return 0; case 0x20: if (memory->rotation && memory->rotation->readTiltX) { int32_t x = -memory->rotation->readTiltX(memory->rotation); x >>= 21; - x += 2047; + x += 0x81D0; return x; } return 0xFF; @@ -507,7 +518,7 @@ uint8_t _GBMBC7Read(struct GBMemory* memory, uint16_t address) { if (memory->rotation && memory->rotation->readTiltX) { int32_t x = -memory->rotation->readTiltX(memory->rotation); x >>= 21; - x += 2047; + x += 0x81D0; return x >> 8; } return 7; @@ -515,7 +526,7 @@ uint8_t _GBMBC7Read(struct GBMemory* memory, uint16_t address) { if (memory->rotation && memory->rotation->readTiltY) { int32_t y = -memory->rotation->readTiltY(memory->rotation); y >>= 21; - y += 2047; + y += 0x81D0; return y; } return 0xFF; @@ -523,144 +534,142 @@ uint8_t _GBMBC7Read(struct GBMemory* memory, uint16_t address) { if (memory->rotation && memory->rotation->readTiltY) { int32_t y = -memory->rotation->readTiltY(memory->rotation); y >>= 21; - y += 2047; + y += 0x81D0; return y >> 8; } return 7; + case 0x60: + return 0; case 0x80: - return (mbc7->sr >> 16) & 1; + return mbc7->eeprom; default: return 0xFF; } } void GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) { - if ((address & 0xF0) != 0x80) { + struct GBMBC7State* mbc7 = &memory->mbcState.mbc7; + if (mbc7->access != 3) { return; } - struct GBMBC7State* mbc7 = &memory->mbcState.mbc7; - GBMBC7Field old = memory->mbcState.mbc7.field; - mbc7->field = GBMBC7FieldClearIO(value); - if (!GBMBC7FieldIsCS(old) && GBMBC7FieldIsCS(value)) { - if (mbc7->state == GBMBC7_STATE_WRITE) { - if (mbc7->writable) { - memory->sramBank[mbc7->address * 2] = mbc7->sr >> 8; - memory->sramBank[mbc7->address * 2 + 1] = mbc7->sr; - } - mbc7->sr = 0x1FFFF; - mbc7->state = GBMBC7_STATE_NULL; - } else { - mbc7->state = GBMBC7_STATE_IDLE; + switch (address & 0xF0) { + case 0x00: + mbc7->latch = (value & 0x55) == 0x55; + return; + case 0x10: + mbc7->latch |= (value & 0xAA); + if (mbc7->latch == 0xFF && memory->rotation && memory->rotation->sample) { + memory->rotation->sample(memory->rotation); } + mbc7->latch = 0; + return; + default: + mLOG(GB_MBC, STUB, "MBC7 unknown register: %04X:%02X", address, value); + return; + case 0x80: + break; } - if (!GBMBC7FieldIsSK(old) && GBMBC7FieldIsSK(value)) { - if (mbc7->state > GBMBC7_STATE_IDLE && mbc7->state != GBMBC7_STATE_READ) { + GBMBC7Field old = memory->mbcState.mbc7.eeprom; + value = GBMBC7FieldFillDO(value); // Hi-Z + if (!GBMBC7FieldIsCS(old) && GBMBC7FieldIsCS(value)) { + mbc7->state = GBMBC7_STATE_IDLE; + } + if (!GBMBC7FieldIsCLK(old) && GBMBC7FieldIsCLK(value)) { + if (mbc7->state == GBMBC7_STATE_READ_COMMAND || mbc7->state == GBMBC7_STATE_EEPROM_WRITE || mbc7->state == GBMBC7_STATE_EEPROM_WRAL) { mbc7->sr <<= 1; - mbc7->sr |= GBMBC7FieldGetIO(value); + mbc7->sr |= GBMBC7FieldGetDI(value); ++mbc7->srBits; } switch (mbc7->state) { case GBMBC7_STATE_IDLE: - if (GBMBC7FieldIsIO(value)) { + if (GBMBC7FieldIsDI(value)) { mbc7->state = GBMBC7_STATE_READ_COMMAND; mbc7->srBits = 0; mbc7->sr = 0; } break; case GBMBC7_STATE_READ_COMMAND: - if (mbc7->srBits == 2) { - mbc7->state = GBMBC7_STATE_READ_ADDRESS; - mbc7->srBits = 0; - mbc7->command = mbc7->sr; - } - break; - case GBMBC7_STATE_READ_ADDRESS: - if (mbc7->srBits == 8) { - mbc7->state = GBMBC7_STATE_COMMAND_0 + mbc7->command; - mbc7->srBits = 0; - mbc7->address = mbc7->sr; - if (mbc7->state == GBMBC7_STATE_COMMAND_0) { - switch (mbc7->address >> 6) { - case 0: - mbc7->writable = false; - mbc7->state = GBMBC7_STATE_NULL; - break; - case 3: - mbc7->writable = true; - mbc7->state = GBMBC7_STATE_NULL; - break; - } + if (mbc7->srBits == 10) { + mbc7->state = 0x10 | (mbc7->sr >> 6); + if (mbc7->state & 0xC) { + mbc7->state &= ~0x3; } - } - break; - case GBMBC7_STATE_COMMAND_0: - if (mbc7->srBits == 16) { - switch (mbc7->address >> 6) { - case 0: - mbc7->writable = false; - mbc7->state = GBMBC7_STATE_NULL; - break; - case 1: - mbc7->state = GBMBC7_STATE_WRITE; - if (mbc7->writable) { - int i; - for (i = 0; i < 256; ++i) { - memory->sramBank[i * 2] = mbc7->sr >> 8; - memory->sramBank[i * 2 + 1] = mbc7->sr; - } - } - break; - case 2: - mbc7->state = GBMBC7_STATE_WRITE; - if (mbc7->writable) { - int i; - for (i = 0; i < 256; ++i) { - memory->sramBank[i * 2] = 0xFF; - memory->sramBank[i * 2 + 1] = 0xFF; - } - } - break; - case 3: - mbc7->writable = true; - mbc7->state = GBMBC7_STATE_NULL; - break; - } - } - break; - case GBMBC7_STATE_COMMAND_SR_WRITE: - if (mbc7->srBits == 16) { mbc7->srBits = 0; - mbc7->state = GBMBC7_STATE_WRITE; + mbc7->address = mbc7->sr & 0x7F; } break; - case GBMBC7_STATE_COMMAND_SR_READ: - if (mbc7->srBits == 1) { - mbc7->sr = memory->sramBank[mbc7->address * 2] << 8; - mbc7->sr |= memory->sramBank[mbc7->address * 2 + 1]; - mbc7->srBits = 0; - mbc7->state = GBMBC7_STATE_READ; - } - break; - case GBMBC7_STATE_COMMAND_SR_FILL: - if (mbc7->srBits == 16) { - mbc7->sr = 0xFFFF; - mbc7->srBits = 0; - mbc7->state = GBMBC7_STATE_WRITE; + case GBMBC7_STATE_DO: + value = GBMBC7FieldSetDO(value, mbc7->sr >> 15); + mbc7->sr <<= 1; + --mbc7->srBits; + if (!mbc7->srBits) { + mbc7->state = GBMBC7_STATE_IDLE; } break; default: break; } - } else if (GBMBC7FieldIsSK(old) && !GBMBC7FieldIsSK(value)) { - if (mbc7->state == GBMBC7_STATE_READ) { - mbc7->sr <<= 1; - ++mbc7->srBits; + switch (mbc7->state) { + case GBMBC7_STATE_EEPROM_EWEN: + mbc7->writable = true; + mbc7->state = GBMBC7_STATE_IDLE; + break; + case GBMBC7_STATE_EEPROM_EWDS: + mbc7->writable = false; + mbc7->state = GBMBC7_STATE_IDLE; + break; + case GBMBC7_STATE_EEPROM_WRITE: if (mbc7->srBits == 16) { - mbc7->srBits = 0; - mbc7->state = GBMBC7_STATE_NULL; + if (mbc7->writable) { + memory->sram[mbc7->address * 2] = mbc7->sr >> 8; + memory->sram[mbc7->address * 2 + 1] = mbc7->sr; + } + mbc7->state = GBMBC7_STATE_IDLE; } + break; + case GBMBC7_STATE_EEPROM_ERASE: + if (mbc7->writable) { + memory->sram[mbc7->address * 2] = 0xFF; + memory->sram[mbc7->address * 2 + 1] = 0xFF; + } + mbc7->state = GBMBC7_STATE_IDLE; + break; + case GBMBC7_STATE_EEPROM_READ: + mbc7->srBits = 16; + mbc7->sr = memory->sram[mbc7->address * 2] << 8; + mbc7->sr |= memory->sram[mbc7->address * 2 + 1]; + mbc7->state = GBMBC7_STATE_DO; + value = GBMBC7FieldClearDO(value); + break; + case GBMBC7_STATE_EEPROM_WRAL: + if (mbc7->srBits == 16) { + if (mbc7->writable) { + int i; + for (i = 0; i < 128; ++i) { + memory->sram[i * 2] = mbc7->sr >> 8; + memory->sram[i * 2 + 1] = mbc7->sr; + } + } + mbc7->state = GBMBC7_STATE_IDLE; + } + break; + case GBMBC7_STATE_EEPROM_ERAL: + if (mbc7->writable) { + int i; + for (i = 0; i < 128; ++i) { + memory->sram[i * 2] = 0xFF; + memory->sram[i * 2 + 1] = 0xFF; + } + } + mbc7->state = GBMBC7_STATE_IDLE; + break; + default: + break; } + } else if (GBMBC7FieldIsCS(value) && GBMBC7FieldIsCLK(old) && !GBMBC7FieldIsCLK(value)) { + value = GBMBC7FieldSetDO(value, GBMBC7FieldGetDO(old)); } + mbc7->eeprom = value; } void _GBHuC3(struct GB* gb, uint16_t address, uint8_t value) { diff --git a/src/gb/video.c b/src/gb/video.c index 9741de2f7..b495a96b1 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -185,9 +185,6 @@ void _endMode1(struct mTiming* timing, void* context, uint32_t cyclesLate) { next = GB_VIDEO_MODE_2_LENGTH + (video->p->memory.io[REG_SCX] & 7); video->mode = 2; video->modeEvent.callback = _endMode2; - if (video->p->memory.mbcType == GB_MBC7 && video->p->memory.rotation && video->p->memory.rotation->sample) { - video->p->memory.rotation->sample(video->p->memory.rotation); - } } else if (video->ly == GB_VIDEO_VERTICAL_TOTAL_PIXELS) { video->p->memory.io[REG_LY] = 0; next = GB_VIDEO_HORIZONTAL_LENGTH - 8;