mirror of https://github.com/mgba-emu/mgba.git
GB MBC: Add MMM01
This commit is contained in:
parent
162fd0b353
commit
575adcaf4c
2
CHANGES
2
CHANGES
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
61
src/gb/mbc.c
61
src/gb/mbc.c
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue