MMM01 support
This commit is contained in:
parent
a621803e82
commit
c78a003712
@ -1546,16 +1546,20 @@ static bool mbc(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg
|
||||
}
|
||||
else {
|
||||
static const char *const mapper_names[] = {
|
||||
[GB_MBC1] = "MBC1",
|
||||
[GB_MBC2] = "MBC2",
|
||||
[GB_MBC3] = "MBC3",
|
||||
[GB_MBC5] = "MBC5",
|
||||
[GB_MBC7] = "MBC7",
|
||||
[GB_HUC1] = "HUC-1",
|
||||
[GB_HUC3] = "HUC-3",
|
||||
[GB_MBC1] = "MBC1",
|
||||
[GB_MBC2] = "MBC2",
|
||||
[GB_MBC3] = "MBC3",
|
||||
[GB_MBC5] = "MBC5",
|
||||
[GB_MBC7] = "MBC7",
|
||||
[GB_MMM01] = "MMM01",
|
||||
[GB_HUC1] = "HUC-1",
|
||||
[GB_HUC3] = "HUC-3",
|
||||
};
|
||||
GB_log(gb, "%s\n", mapper_names[cartridge->mbc_type]);
|
||||
}
|
||||
if (cartridge->mbc_type == GB_MMM01 || cartridge->mbc_type == GB_MBC1) {
|
||||
GB_log(gb, "Current mapped ROM0 bank: %x\n", gb->mbc_rom0_bank);
|
||||
}
|
||||
GB_log(gb, "Current mapped ROM bank: %x\n", gb->mbc_rom_bank);
|
||||
if (cartridge->has_ram) {
|
||||
GB_log(gb, "Current mapped RAM bank: %x\n", gb->mbc_ram_bank);
|
||||
|
@ -1609,7 +1609,8 @@ void GB_reset(GB_gameboy_t *gb)
|
||||
gb->model = model;
|
||||
gb->version = GB_STRUCT_VERSION;
|
||||
|
||||
gb->mbc_rom_bank = 1;
|
||||
GB_reset_mbc(gb);
|
||||
|
||||
gb->last_rtc_second = time(NULL);
|
||||
gb->cgb_ram_bank = 1;
|
||||
gb->io_registers[GB_IO_JOYP] = 0xCF;
|
||||
|
49
Core/gb.h
49
Core/gb.h
@ -440,6 +440,7 @@ struct GB_gameboy_internal_s {
|
||||
/* MBC */
|
||||
GB_SECTION(mbc,
|
||||
uint16_t mbc_rom_bank;
|
||||
uint16_t mbc_rom0_bank; /* For multicart mappings . */
|
||||
uint8_t mbc_ram_bank;
|
||||
uint32_t mbc_ram_size;
|
||||
bool mbc_ram_enable;
|
||||
@ -466,21 +467,38 @@ struct GB_gameboy_internal_s {
|
||||
uint8_t ram_bank:4;
|
||||
} mbc5;
|
||||
|
||||
struct {
|
||||
uint8_t rom_bank;
|
||||
uint16_t x_latch;
|
||||
uint16_t y_latch;
|
||||
bool latch_ready:1;
|
||||
bool eeprom_do:1;
|
||||
bool eeprom_di:1;
|
||||
bool eeprom_clk:1;
|
||||
bool eeprom_cs:1;
|
||||
uint16_t eeprom_command:11;
|
||||
uint16_t read_bits;
|
||||
uint8_t bits_countdown:5;
|
||||
bool secondary_ram_enable:1;
|
||||
bool eeprom_write_enabled:1;
|
||||
} mbc7;
|
||||
struct {
|
||||
uint8_t rom_bank;
|
||||
uint16_t x_latch;
|
||||
uint16_t y_latch;
|
||||
bool latch_ready:1;
|
||||
bool eeprom_do:1;
|
||||
bool eeprom_di:1;
|
||||
bool eeprom_clk:1;
|
||||
bool eeprom_cs:1;
|
||||
uint16_t eeprom_command:11;
|
||||
uint16_t read_bits;
|
||||
uint8_t bits_countdown:5;
|
||||
bool secondary_ram_enable:1;
|
||||
bool eeprom_write_enabled:1;
|
||||
} mbc7;
|
||||
|
||||
struct {
|
||||
uint8_t rom_bank_low:5;
|
||||
uint8_t rom_bank_mid:2;
|
||||
bool mbc1_mode:1;
|
||||
|
||||
uint8_t rom_bank_mask:4;
|
||||
uint8_t rom_bank_high:2;
|
||||
uint8_t ram_bank_low:2;
|
||||
|
||||
uint8_t ram_bank_high:2;
|
||||
uint8_t ram_bank_mask:2;
|
||||
|
||||
bool locked:1;
|
||||
bool mbc1_mode_disable:1;
|
||||
bool multiplex_mode:1;
|
||||
} mmm01;
|
||||
|
||||
struct {
|
||||
uint8_t bank_low:6;
|
||||
@ -508,7 +526,6 @@ struct GB_gameboy_internal_s {
|
||||
uint8_t mode;
|
||||
} tpp1;
|
||||
};
|
||||
uint16_t mbc_rom0_bank; /* For some MBC1 wirings. */
|
||||
bool camera_registers_mapped;
|
||||
uint8_t camera_registers[0x36];
|
||||
uint8_t rumble_strength;
|
||||
|
73
Core/mbc.c
73
Core/mbc.c
@ -18,9 +18,9 @@ const GB_cartridge_t GB_cart_defs[256] = {
|
||||
{ GB_NO_MBC, GB_STANDARD_MBC, true , true , false, false}, // 09h ROM+RAM+BATTERY
|
||||
[0xB] =
|
||||
/* Todo: Not supported yet */
|
||||
{ GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // 0Bh MMM01
|
||||
{ GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // 0Ch MMM01+RAM
|
||||
{ GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // 0Dh MMM01+RAM+BATTERY
|
||||
{ GB_MMM01 , GB_STANDARD_MBC, false, false, false, false}, // 0Bh MMM01
|
||||
{ GB_MMM01 , GB_STANDARD_MBC, true , false, false, false}, // 0Ch MMM01+RAM
|
||||
{ GB_MMM01 , GB_STANDARD_MBC, true , true , false, false}, // 0Dh MMM01+RAM+BATTERY
|
||||
[0xF] =
|
||||
{ GB_MBC3 , GB_STANDARD_MBC, false, true, true , false}, // 0Fh MBC3+TIMER+BATTERY
|
||||
{ GB_MBC3 , GB_STANDARD_MBC, true , true, true , false}, // 10h MBC3+TIMER+RAM+BATTERY
|
||||
@ -103,6 +103,40 @@ void GB_update_mbc_mappings(GB_gameboy_t *gb)
|
||||
case GB_MBC7:
|
||||
gb->mbc_rom_bank = gb->mbc7.rom_bank;
|
||||
break;
|
||||
case GB_MMM01:
|
||||
if (gb->mmm01.locked) {
|
||||
if (gb->mmm01.multiplex_mode) {
|
||||
gb->mbc_rom0_bank = (gb->mmm01.rom_bank_low & (gb->mmm01.rom_bank_mask << 1)) |
|
||||
((gb->mmm01.rom_bank_low & (gb->mmm01.mbc1_mode? -1 : gb->mmm01.ram_bank_mask)) << 5) |
|
||||
(gb->mmm01.rom_bank_high << 7);
|
||||
gb->mbc_rom_bank = gb->mmm01.rom_bank_low |
|
||||
(gb->mmm01.rom_bank_low << 5) |
|
||||
(gb->mmm01.rom_bank_high << 7);
|
||||
gb->mbc_ram_bank = gb->mmm01.rom_bank_mid | (gb->mmm01.ram_bank_high << 2);
|
||||
}
|
||||
else {
|
||||
gb->mbc_rom0_bank = (gb->mmm01.rom_bank_low & (gb->mmm01.rom_bank_mask << 1)) |
|
||||
(gb->mmm01.rom_bank_mid << 5) |
|
||||
(gb->mmm01.rom_bank_high << 7);
|
||||
gb->mbc_rom_bank = gb->mmm01.rom_bank_low |
|
||||
(gb->mmm01.rom_bank_mid << 5) |
|
||||
(gb->mmm01.rom_bank_high << 7);
|
||||
if (gb->mmm01.mbc1_mode) {
|
||||
gb->mbc_ram_bank = gb->mmm01.ram_bank_low | (gb->mmm01.ram_bank_high << 2);
|
||||
}
|
||||
else {
|
||||
gb->mbc_ram_bank = (gb->mmm01.ram_bank_low & gb->mmm01.ram_bank_mask) | (gb->mmm01.ram_bank_high << 2);
|
||||
}
|
||||
}
|
||||
if (gb->mbc_rom_bank == gb->mbc_rom0_bank) {
|
||||
gb->mbc_rom_bank++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
gb->mbc_rom_bank = -1;
|
||||
gb->mbc_rom0_bank = -2;
|
||||
}
|
||||
break;
|
||||
case GB_HUC1:
|
||||
if (gb->huc1.mode == 0) {
|
||||
gb->mbc_rom_bank = gb->huc1.bank_low | (gb->mbc1.bank_high << 6);
|
||||
@ -129,6 +163,20 @@ void GB_update_mbc_mappings(GB_gameboy_t *gb)
|
||||
void GB_configure_cart(GB_gameboy_t *gb)
|
||||
{
|
||||
gb->cartridge_type = &GB_cart_defs[gb->rom[0x147]];
|
||||
if (gb->cartridge_type->mbc_type == GB_MMM01) {
|
||||
uint8_t *temp = malloc(0x8000);
|
||||
memcpy(temp, gb->rom, 0x8000);
|
||||
memmove(gb->rom, gb->rom + 0x8000, gb->rom_size - 0x8000);
|
||||
memcpy(gb->rom + gb->rom_size - 0x8000, temp, 0x8000);
|
||||
free(temp);
|
||||
}
|
||||
else {
|
||||
const GB_cartridge_t *maybe_mmm01_type = &GB_cart_defs[gb->rom[gb->rom_size - 0x8000 + 0x147]];
|
||||
if (maybe_mmm01_type->mbc_type == GB_MMM01 && memcmp(gb->rom + 0x104, gb->rom + gb->rom_size - 0x8000 + 0x104, 0x30) == 0) {
|
||||
gb->cartridge_type = maybe_mmm01_type;
|
||||
}
|
||||
}
|
||||
|
||||
if (gb->rom[0x147] == 0xBC &&
|
||||
gb->rom[0x149] == 0xC1 &&
|
||||
gb->rom[0x14A] == 0x65) {
|
||||
@ -193,16 +241,25 @@ void GB_configure_cart(GB_gameboy_t *gb)
|
||||
}
|
||||
}
|
||||
|
||||
/* Set MBC5's bank to 1 correctly */
|
||||
if (gb->cartridge_type->mbc_type == GB_MBC5) {
|
||||
GB_reset_mbc(gb);
|
||||
}
|
||||
|
||||
void GB_reset_mbc(GB_gameboy_t *gb)
|
||||
{
|
||||
if (gb->cartridge_type->mbc_type == GB_MMM01) {
|
||||
gb->mbc_rom_bank = -1;
|
||||
gb->mbc_rom0_bank = -2;
|
||||
}
|
||||
else if (gb->cartridge_type->mbc_type == GB_MBC5) {
|
||||
gb->mbc5.rom_bank_low = 1;
|
||||
}
|
||||
|
||||
/* Initial MBC7 state */
|
||||
if (gb->cartridge_type->mbc_type == GB_MBC7) {
|
||||
else if (gb->cartridge_type->mbc_type == GB_MBC7) {
|
||||
gb->mbc7.x_latch = gb->mbc7.y_latch = 0x8000;
|
||||
gb->mbc7.latch_ready = true;
|
||||
gb->mbc7.read_bits = -1;
|
||||
gb->mbc7.eeprom_do = true;
|
||||
}
|
||||
else {
|
||||
gb->mbc_rom_bank = 1;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ typedef struct {
|
||||
GB_MBC3,
|
||||
GB_MBC5,
|
||||
GB_MBC7,
|
||||
GB_MMM01,
|
||||
GB_HUC1,
|
||||
GB_HUC3,
|
||||
GB_TPP1,
|
||||
@ -26,9 +27,10 @@ typedef struct {
|
||||
} GB_cartridge_t;
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
extern const GB_cartridge_t GB_cart_defs[256];
|
||||
internal extern const GB_cartridge_t GB_cart_defs[256];
|
||||
internal void GB_update_mbc_mappings(GB_gameboy_t *gb);
|
||||
internal void GB_configure_cart(GB_gameboy_t *gb);
|
||||
internal void GB_reset_mbc(GB_gameboy_t *gb);
|
||||
#endif
|
||||
|
||||
#endif /* MBC_h */
|
||||
|
@ -838,6 +838,42 @@ static void write_mbc(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
case 0x4000: case 0x5000: gb->mbc7.secondary_ram_enable = value == 0x40; break;
|
||||
}
|
||||
break;
|
||||
case GB_MMM01:
|
||||
switch (addr & 0xF000) {
|
||||
case 0x0000: case 0x1000:
|
||||
gb->mbc_ram_enable = (value & 0xF) == 0xA;
|
||||
if (!gb->mmm01.locked) {
|
||||
gb->mmm01.ram_bank_mask = value >> 4;
|
||||
gb->mmm01.locked = value & 0x40;
|
||||
}
|
||||
break;
|
||||
case 0x2000: case 0x3000:
|
||||
if (!gb->mmm01.locked) {
|
||||
gb->mmm01.rom_bank_mid = value >> 5;
|
||||
gb->mmm01.rom_bank_low = value;
|
||||
}
|
||||
else {
|
||||
gb->mmm01.rom_bank_low &= (gb->mmm01.rom_bank_mask << 1);
|
||||
gb->mmm01.rom_bank_low |= ~(gb->mmm01.rom_bank_mask << 1) & value;
|
||||
}
|
||||
break;
|
||||
case 0x4000: case 0x5000:
|
||||
gb->mmm01.ram_bank_low = value;
|
||||
if (!gb->mmm01.locked) {
|
||||
gb->mmm01.ram_bank_high = value >> 2;
|
||||
gb->mmm01.rom_bank_high = value >> 4;
|
||||
gb->mmm01.mbc1_mode_disable = value & 0x40;
|
||||
}
|
||||
break;
|
||||
case 0x6000: case 0x7000:
|
||||
gb->mmm01.mbc1_mode = (value & 1) && !gb->mmm01.mbc1_mode_disable;
|
||||
if (!gb->mmm01.locked) {
|
||||
gb->mmm01.rom_bank_mask = value >> 2;
|
||||
gb->mmm01.multiplex_mode = value & 0x40;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GB_HUC1:
|
||||
switch (addr & 0xF000) {
|
||||
case 0x0000: case 0x1000: gb->huc1.ir_mode = (value & 0xF) == 0xE; break;
|
||||
|
@ -232,6 +232,8 @@ static size_t bess_size_for_cartridge(const GB_cartridge_t *cart)
|
||||
return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t) + (cart->has_rtc? sizeof(BESS_RTC_t) : 0);
|
||||
case GB_MBC5:
|
||||
return sizeof(BESS_block_t) + 4 * sizeof(BESS_MBC_pair_t);
|
||||
case GB_MMM01:
|
||||
return sizeof(BESS_block_t) + 4 * sizeof(BESS_MBC_pair_t);
|
||||
case GB_HUC1:
|
||||
return sizeof(BESS_block_t) + 4 * sizeof(BESS_MBC_pair_t);
|
||||
case GB_HUC3:
|
||||
@ -435,20 +437,25 @@ static int save_bess_mbc_block(GB_gameboy_t *gb, virtual_file_t *file)
|
||||
pairs[3] = (BESS_MBC_pair_t){LE16(0x4000), gb->mbc5.ram_bank};
|
||||
mbc_block.size = 4 * sizeof(pairs[0]);
|
||||
break;
|
||||
case GB_MMM01:
|
||||
pairs[0] = (BESS_MBC_pair_t){LE16(0x2000), gb->mmm01.rom_bank_low | (gb->mmm01.rom_bank_mid << 5)};
|
||||
pairs[1] = (BESS_MBC_pair_t){LE16(0x6000), gb->mmm01.mbc1_mode | (gb->mmm01.rom_bank_mask << 2) | (gb->mmm01.multiplex_mode << 6)};
|
||||
pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->mmm01.ram_bank_low | (gb->mmm01.ram_bank_high << 2) | (gb->mmm01.rom_bank_high << 4) | (gb->mmm01.mbc1_mode_disable << 6)};
|
||||
pairs[3] = (BESS_MBC_pair_t){LE16(0x0000), (gb->mbc_ram_enable? 0xA : 0x0) | (gb->mmm01.ram_bank_mask << 4) | (gb->mmm01.locked << 6)};
|
||||
mbc_block.size = 4 * sizeof(pairs[0]);
|
||||
break;
|
||||
case GB_HUC1:
|
||||
pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->huc1.ir_mode? 0xE : 0x0};
|
||||
pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->huc1.bank_low};
|
||||
pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->huc1.bank_high};
|
||||
pairs[3] = (BESS_MBC_pair_t){LE16(0x6000), gb->huc1.mode};
|
||||
mbc_block.size = 4 * sizeof(pairs[0]);
|
||||
|
||||
case GB_HUC3:
|
||||
pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->huc3.mode};
|
||||
pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->huc3.rom_bank};
|
||||
pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->huc3.ram_bank};
|
||||
mbc_block.size = 3 * sizeof(pairs[0]);
|
||||
break;
|
||||
|
||||
case GB_TPP1:
|
||||
pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->tpp1.rom_bank};
|
||||
pairs[1] = (BESS_MBC_pair_t){LE16(0x0001), gb->tpp1.rom_bank >> 8};
|
||||
|
Loading…
Reference in New Issue
Block a user