GB MBC: Add MMM01

This commit is contained in:
Vicki Pfau 2018-07-28 01:04:36 -07:00
parent 162fd0b353
commit 575adcaf4c
6 changed files with 89 additions and 9 deletions

View File

@ -15,7 +15,7 @@ Features:
- Ability to select GB/GBC/SGB BIOS on console ports - Ability to select GB/GBC/SGB BIOS on console ports
- Optional automatic state saving/loading - Optional automatic state saving/loading
- Access to ur0 and uma0 partitions on the Vita - Access to ur0 and uma0 partitions on the Vita
- Partial support for MBC6, TAMA and HuC-1 GB mappers - Partial support for MBC6, MMM01, TAMA and HuC-1 GB mappers
Bugfixes: Bugfixes:
- GB Audio: Make audio unsigned with bias (fixes mgba.io/i/749) - GB Audio: Make audio unsigned with bias (fixes mgba.io/i/749)
- GB Serialize: Fix audio state loading - GB Serialize: Fix audio state loading

View File

@ -53,15 +53,12 @@ The following mappers are fully supported:
The following mappers are partially supported: The following mappers are partially supported:
- MBC6 - MBC6
- MMM01
- Pocket Cam - Pocket Cam
- TAMA5 - TAMA5
- HuC-1 - HuC-1
- HuC-3 - HuC-3
The following mappers are not currently supported:
- MMM01
### Planned features ### Planned features
- Networked multiplayer link cable support. - Networked multiplayer link cable support.

View File

@ -129,6 +129,11 @@ struct GBMBC7State {
GBMBC7Field eeprom; GBMBC7Field eeprom;
}; };
struct GBMMM01State {
bool locked;
int currentBank0;
};
struct GBPocketCamState { struct GBPocketCamState {
bool registersActive; bool registersActive;
uint8_t registers[0x36]; uint8_t registers[0x36];
@ -143,6 +148,7 @@ union GBMBCState {
struct GBMBC1State mbc1; struct GBMBC1State mbc1;
struct GBMBC6State mbc6; struct GBMBC6State mbc6;
struct GBMBC7State mbc7; struct GBMBC7State mbc7;
struct GBMMM01State mmm01;
struct GBPocketCamState pocketCam; struct GBPocketCamState pocketCam;
struct GBTAMA5State tama5; struct GBTAMA5State tama5;
}; };

View File

@ -373,6 +373,10 @@ struct GBSerializedState {
uint16_t sr; uint16_t sr;
uint32_t writable; uint32_t writable;
} mbc7; } mbc7;
struct {
uint8_t locked;
uint8_t bank0;
} mmm01;
struct { struct {
uint8_t reserved[16]; uint8_t reserved[16];
} padding; } padding;

View File

@ -9,8 +9,11 @@
#include <mgba/internal/lr35902/lr35902.h> #include <mgba/internal/lr35902/lr35902.h>
#include <mgba/internal/gb/gb.h> #include <mgba/internal/gb/gb.h>
#include <mgba/internal/gb/memory.h> #include <mgba/internal/gb/memory.h>
#include <mgba-util/crc32.h>
#include <mgba-util/vfs.h> #include <mgba-util/vfs.h>
const uint32_t GB_LOGO_HASH = 0x46195417;
mLOG_DEFINE_CATEGORY(GB_MBC, "GB MBC", "gb.mbc"); mLOG_DEFINE_CATEGORY(GB_MBC, "GB MBC", "gb.mbc");
static void _GBMBCNone(struct GB* gb, uint16_t address, uint8_t value) { static void _GBMBCNone(struct GB* gb, uint16_t address, uint8_t value) {
@ -27,6 +30,7 @@ static void _GBMBC3(struct GB*, uint16_t address, uint8_t value);
static void _GBMBC5(struct GB*, uint16_t address, uint8_t value); static void _GBMBC5(struct GB*, uint16_t address, uint8_t value);
static void _GBMBC6(struct GB*, uint16_t address, uint8_t value); static void _GBMBC6(struct GB*, uint16_t address, uint8_t value);
static void _GBMBC7(struct GB*, uint16_t address, uint8_t value); static void _GBMBC7(struct GB*, uint16_t address, uint8_t value);
static void _GBMMM01(struct GB*, uint16_t address, uint8_t value);
static void _GBHuC1(struct GB*, uint16_t address, uint8_t value); static void _GBHuC1(struct GB*, uint16_t address, uint8_t value);
static void _GBHuC3(struct GB*, uint16_t address, uint8_t value); static void _GBHuC3(struct GB*, uint16_t address, uint8_t value);
static void _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value); static void _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value);
@ -135,6 +139,12 @@ void GBMBCSwitchSramHalfBank(struct GB* gb, int half, int bank) {
void GBMBCInit(struct GB* gb) { void GBMBCInit(struct GB* gb) {
const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
if (gb->memory.rom) { if (gb->memory.rom) {
if (gb->memory.romSize >= 0x8000) {
const struct GBCartridge* cartFooter = (const struct GBCartridge*) &gb->memory.rom[gb->memory.romSize - 0x7F00];
if (doCrc32(cartFooter->logo, sizeof(cartFooter->logo)) == GB_LOGO_HASH) {
cart = cartFooter;
}
}
switch (cart->ramSize) { switch (cart->ramSize) {
case 0: case 0:
gb->sramSize = 0; gb->sramSize = 0;
@ -178,6 +188,11 @@ void GBMBCInit(struct GB* gb) {
case 6: case 6:
gb->memory.mbcType = GB_MBC2; gb->memory.mbcType = GB_MBC2;
break; break;
case 0x0B:
case 0x0C:
case 0x0D:
gb->memory.mbcType = GB_MMM01;
break;
case 0x0F: case 0x0F:
case 0x10: case 0x10:
gb->memory.mbcType = GB_MBC3_RTC; gb->memory.mbcType = GB_MBC3_RTC;
@ -256,8 +271,7 @@ void GBMBCInit(struct GB* gb) {
gb->sramSize = 0x100; gb->sramSize = 0x100;
break; break;
case GB_MMM01: case GB_MMM01:
mLOG(GB_MBC, WARN, "unimplemented MBC: MMM01"); gb->memory.mbcWrite = _GBMMM01;
gb->memory.mbcWrite = _GBMBC1;
break; break;
case GB_HuC1: case GB_HuC1:
gb->memory.mbcWrite = _GBHuC1; gb->memory.mbcWrite = _GBHuC1;
@ -821,6 +835,49 @@ static void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t valu
mbc7->eeprom = value; mbc7->eeprom = value;
} }
void _GBMMM01(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
if (!memory->mbcState.mmm01.locked) {
switch (address >> 13) {
case 0x0:
memory->mbcState.mmm01.locked = true;
GBMBCSwitchBank0(gb, memory->mbcState.mmm01.currentBank0);
break;
case 0x1:
memory->mbcState.mmm01.currentBank0 = value & 0x3F;
break;
default:
// TODO
mLOG(GB_MBC, STUB, "MMM01 unknown address: %04X:%02X", address, value);
break;
}
return;
}
switch (address >> 13) {
case 0x0:
switch (value) {
case 0xA:
memory->sramAccess = true;
GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
break;
default:
memory->sramAccess = false;
break;
}
break;
case 0x1:
GBMBCSwitchBank(gb, value + memory->mbcState.mmm01.currentBank0);
break;
case 0x2:
GBMBCSwitchSramBank(gb, value);
break;
default:
// TODO
mLOG(GB_MBC, STUB, "MMM01 unknown address: %04X:%02X", address, value);
break;
}
}
void _GBHuC1(struct GB* gb, uint16_t address, uint8_t value) { void _GBHuC1(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory; struct GBMemory* memory = &gb->memory;
int bank = value & 0x3F; int bank = value & 0x3F;

View File

@ -176,6 +176,8 @@ void GBMemoryReset(struct GB* gb) {
gb->memory.hdmaEvent.priority = 0x41; gb->memory.hdmaEvent.priority = 0x41;
memset(&gb->memory.hram, 0, sizeof(gb->memory.hram)); memset(&gb->memory.hram, 0, sizeof(gb->memory.hram));
GBMBCInit(gb);
switch (gb->memory.mbcType) { switch (gb->memory.mbcType) {
case GB_MBC1: case GB_MBC1:
gb->memory.mbcState.mbc1.mode = 0; gb->memory.mbcState.mbc1.mode = 0;
@ -187,11 +189,12 @@ void GBMemoryReset(struct GB* gb) {
GBMBCSwitchSramHalfBank(gb, 0, 0); GBMBCSwitchSramHalfBank(gb, 0, 0);
GBMBCSwitchSramHalfBank(gb, 0, 1); GBMBCSwitchSramHalfBank(gb, 0, 1);
break; break;
case GB_MMM01:
GBMBCSwitchBank0(gb, gb->memory.romSize / GB_SIZE_CART_BANK0 - 2);
GBMBCSwitchBank(gb, gb->memory.romSize / GB_SIZE_CART_BANK0 - 1);
default: default:
memset(&gb->memory.mbcState, 0, sizeof(gb->memory.mbcState)); memset(&gb->memory.mbcState, 0, sizeof(gb->memory.mbcState));
} }
GBMBCInit(gb);
gb->memory.sramBank = gb->memory.sram; gb->memory.sramBank = gb->memory.sram;
if (!gb->memory.wram) { if (!gb->memory.wram) {
@ -688,6 +691,10 @@ void GBMemorySerialize(const struct GB* gb, struct GBSerializedState* state) {
STORE_16LE(memory->mbcState.mbc7.sr, 0, &state->memory.mbc7.sr); STORE_16LE(memory->mbcState.mbc7.sr, 0, &state->memory.mbc7.sr);
STORE_32LE(memory->mbcState.mbc7.writable, 0, &state->memory.mbc7.writable); STORE_32LE(memory->mbcState.mbc7.writable, 0, &state->memory.mbc7.writable);
break; break;
case GB_MMM01:
state->memory.mmm01.locked = memory->mbcState.mmm01.locked;
state->memory.mmm01.bank0 = memory->mbcState.mmm01.currentBank0;
break;
default: default:
break; break;
} }
@ -755,6 +762,15 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
LOAD_16LE(memory->mbcState.mbc7.sr, 0, &state->memory.mbc7.sr); LOAD_16LE(memory->mbcState.mbc7.sr, 0, &state->memory.mbc7.sr);
LOAD_32LE(memory->mbcState.mbc7.writable, 0, &state->memory.mbc7.writable); LOAD_32LE(memory->mbcState.mbc7.writable, 0, &state->memory.mbc7.writable);
break; break;
case GB_MMM01:
memory->mbcState.mmm01.locked = state->memory.mmm01.locked;
memory->mbcState.mmm01.currentBank0 = state->memory.mmm01.bank0;
if (memory->mbcState.mmm01.locked) {
GBMBCSwitchBank0(gb, memory->mbcState.mmm01.currentBank0);
} else {
GBMBCSwitchBank0(gb, gb->memory.romSize / GB_SIZE_CART_BANK0 - 2);
}
break;
default: default:
break; break;
} }