From bd7f8f2555fa139404b2526fd3d76e402e710ca8 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Sat, 9 Jul 2016 19:25:13 +0300 Subject: [PATCH] Support for an alternative MBC1 wiring, should solve most N-in-1 carts (Issue #3) --- Core/debugger.c | 7 ++++++- Core/gb.c | 7 +------ Core/gb.h | 4 ++++ Core/mbc.c | 51 ++++++++++++++++++++++++++++++++++++++++++++----- Core/mbc.h | 2 +- 5 files changed, 58 insertions(+), 13 deletions(-) diff --git a/Core/debugger.c b/Core/debugger.c index d6573fc..59399ad 100644 --- a/Core/debugger.c +++ b/Core/debugger.c @@ -854,9 +854,14 @@ static bool mbc(GB_gameboy_t *gb, char *arguments) GB_log(gb, "Current mapped RAM bank: %x\n", gb->mbc_ram_bank); GB_log(gb, "RAM is curently %s\n", gb->mbc_ram_enable? "enabled" : "disabled"); } - if (cartridge->mbc_type == GB_MBC1) { + if (cartridge->mbc_type == GB_MBC1 && gb->mbc1_wiring == GB_STANDARD_MBC1_WIRING) { GB_log(gb, "MBC1 banking mode is %s\n", gb->mbc1.mode == 1 ? "RAM" : "ROM"); } + if (cartridge->mbc_type == GB_MBC1 && gb->mbc1_wiring == GB_MBC1M_WIRING) { + GB_log(gb, "MBC1 uses MBC1M wiring. \n"); + GB_log(gb, "Current mapped ROM0 bank: %x\n", gb->mbc_rom0_bank); + GB_log(gb, "MBC1 multicart banking mode is %s\n", gb->mbc1.mode == 1 ? "enabled" : "disabled"); + } } else { diff --git a/Core/gb.c b/Core/gb.c index 90b08da..85279af 100644 --- a/Core/gb.c +++ b/Core/gb.c @@ -165,12 +165,7 @@ int GB_load_rom(GB_gameboy_t *gb, const char *path) memset(gb->rom, 0xFF, gb->rom_size); /* Pad with 0xFFs */ fread(gb->rom, gb->rom_size, 1, f); fclose(f); - gb->cartridge_type = &GB_cart_defs[gb->rom[0x147]]; - if (gb->cartridge_type->has_ram) { - static const int ram_sizes[256] = {0, 0x800, 0x2000, 0x8000, 0x20000, 0x10000}; - gb->mbc_ram_size = ram_sizes[gb->rom[0x149]]; - gb->mbc_ram = malloc(gb->mbc_ram_size); - } + GB_configure_cart(gb); return 0; } diff --git a/Core/gb.h b/Core/gb.h index aecb463..d92f496 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -312,6 +312,10 @@ typedef struct GB_gameboy_s { uint8_t *rom; uint32_t rom_size; const GB_cartridge_t *cartridge_type; + enum { + GB_STANDARD_MBC1_WIRING, + GB_MBC1M_WIRING, + } mbc1_wiring; /* Various RAMs */ uint8_t *ram; diff --git a/Core/mbc.c b/Core/mbc.c index c03ce7e..fddccb4 100644 --- a/Core/mbc.c +++ b/Core/mbc.c @@ -1,4 +1,6 @@ #include +#include +#include #include "gb.h" const GB_cartridge_t GB_cart_defs[256] = { @@ -50,14 +52,32 @@ void GB_update_mbc_mappings(GB_gameboy_t *gb) switch (gb->cartridge_type->mbc_type) { case GB_NO_MBC: case GB_MBC4: return; case GB_MBC1: - /* Standard MBC1 wiring: */ + /* Todo: some obscure behaviors of MBC1 are not supported. See http://forums.nesdev.com/viewtopic.php?f=20&t=14099 */ if (gb->mbc1.mode == 0) { - gb->mbc_rom_bank = gb->mbc1.bank_low | (gb->mbc1.bank_high << 5); - gb->mbc_ram_bank = 0; + switch (gb->mbc1_wiring) { + case GB_STANDARD_MBC1_WIRING: + gb->mbc_rom_bank = gb->mbc1.bank_low | (gb->mbc1.bank_high << 5); + gb->mbc_ram_bank = 0; + break; + + case GB_MBC1M_WIRING: + gb->mbc_rom_bank = (gb->mbc1.bank_low & 0xF) | (gb->mbc1.bank_high << 4); + gb->mbc_ram_bank = 0; + gb->mbc_rom0_bank = 0; + } } else { - gb->mbc_rom_bank = gb->mbc1.bank_low; - gb->mbc_ram_bank = gb->mbc1.bank_high; + switch (gb->mbc1_wiring) { + case GB_STANDARD_MBC1_WIRING: + gb->mbc_rom_bank = gb->mbc1.bank_low; + gb->mbc_ram_bank = gb->mbc1.bank_high; + break; + + case GB_MBC1M_WIRING: + gb->mbc_rom_bank = (gb->mbc1.bank_low & 0xF) | (gb->mbc1.bank_high << 4); + gb->mbc_rom0_bank = gb->mbc1.bank_high << 4; + gb->mbc_ram_bank = 0; + } } break; case GB_MBC2: @@ -75,4 +95,25 @@ void GB_update_mbc_mappings(GB_gameboy_t *gb) if (gb->mbc_rom_bank == 0 && gb->cartridge_type->mbc_type != GB_MBC5) { gb->mbc_rom_bank = 1; } +} + +void GB_configure_cart(GB_gameboy_t *gb) +{ + gb->cartridge_type = &GB_cart_defs[gb->rom[0x147]]; + + if (gb->cartridge_type->has_ram) { + static const int ram_sizes[256] = {0, 0x800, 0x2000, 0x8000, 0x20000, 0x10000}; + gb->mbc_ram_size = ram_sizes[gb->rom[0x149]]; + gb->mbc_ram = malloc(gb->mbc_ram_size); + } + + /* MBC1 has at least 3 types of wiring (We currently support two (Standard and 4bit-MBC1M) of these). + See http://forums.nesdev.com/viewtopic.php?f=20&t=14099 */ + + /* Attempt to "guess" wiring */ + if (gb->cartridge_type->mbc_type == GB_MBC1) { + if (gb->rom_size >= 0x44000 && memcmp(gb->rom + 0x104, gb->rom + 0x40104, 0x30) == 0) { + gb->mbc1_wiring = GB_MBC1M_WIRING; + } + } } \ No newline at end of file diff --git a/Core/mbc.h b/Core/mbc.h index 7c64fcf..cd992b0 100644 --- a/Core/mbc.h +++ b/Core/mbc.h @@ -4,5 +4,5 @@ extern const GB_cartridge_t GB_cart_defs[256]; void GB_update_mbc_mappings(GB_gameboy_t *gb); - +void GB_configure_cart(GB_gameboy_t *gb); #endif /* MBC_h */