More accurate Camera MBC emulation

This commit is contained in:
Lior Halphon 2022-06-11 14:44:06 +03:00
parent 24796acccf
commit d41c188cfd
6 changed files with 64 additions and 46 deletions

View File

@ -1546,14 +1546,16 @@ static bool mbc(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg
} }
else { else {
static const char *const mapper_names[] = { static const char *const mapper_names[] = {
[GB_MBC1] = "MBC1", [GB_MBC1] = "MBC1",
[GB_MBC2] = "MBC2", [GB_MBC2] = "MBC2",
[GB_MBC3] = "MBC3", [GB_MBC3] = "MBC3",
[GB_MBC5] = "MBC5", [GB_MBC5] = "MBC5",
[GB_MBC7] = "MBC7", [GB_MBC7] = "MBC7",
[GB_MMM01] = "MMM01", [GB_MMM01] = "MMM01",
[GB_HUC1] = "HUC-1", [GB_HUC1] = "HUC-1",
[GB_HUC3] = "HUC-3", [GB_HUC3] = "HUC-3",
[GB_CAMERA] = "MAC-GBD",
}; };
GB_log(gb, "%s\n", mapper_names[cartridge->mbc_type]); GB_log(gb, "%s\n", mapper_names[cartridge->mbc_type]);
} }

View File

@ -466,7 +466,7 @@ struct GB_gameboy_internal_s {
uint8_t rom_bank_low; uint8_t rom_bank_low;
uint8_t rom_bank_high:1; uint8_t rom_bank_high:1;
uint8_t ram_bank:4; uint8_t ram_bank:4;
} mbc5; } mbc5; // Also used for GB_CAMERA
struct { struct {
uint8_t rom_bank; uint8_t rom_bank;

View File

@ -5,41 +5,41 @@
const GB_cartridge_t GB_cart_defs[256] = { const GB_cartridge_t GB_cart_defs[256] = {
// From http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header#0147_-_Cartridge_Type // From http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header#0147_-_Cartridge_Type
/* MBC SUBTYPE RAM BAT. RTC RUMB. */ /* MBC RAM BAT. RTC RUMB. */
{ GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // 00h ROM ONLY { GB_NO_MBC, false, false, false, false}, // 00h ROM ONLY
{ GB_MBC1 , GB_STANDARD_MBC, false, false, false, false}, // 01h MBC1 { GB_MBC1 , false, false, false, false}, // 01h MBC1
{ GB_MBC1 , GB_STANDARD_MBC, true , false, false, false}, // 02h MBC1+RAM { GB_MBC1 , true , false, false, false}, // 02h MBC1+RAM
{ GB_MBC1 , GB_STANDARD_MBC, true , true , false, false}, // 03h MBC1+RAM+BATTERY { GB_MBC1 , true , true , false, false}, // 03h MBC1+RAM+BATTERY
[5] = [5] =
{ GB_MBC2 , GB_STANDARD_MBC, true , false, false, false}, // 05h MBC2 { GB_MBC2 , true , false, false, false}, // 05h MBC2
{ GB_MBC2 , GB_STANDARD_MBC, true , true , false, false}, // 06h MBC2+BATTERY { GB_MBC2 , true , true , false, false}, // 06h MBC2+BATTERY
[8] = [8] =
{ GB_NO_MBC, GB_STANDARD_MBC, true , false, false, false}, // 08h ROM+RAM { GB_NO_MBC, true , false, false, false}, // 08h ROM+RAM
{ GB_NO_MBC, GB_STANDARD_MBC, true , true , false, false}, // 09h ROM+RAM+BATTERY { GB_NO_MBC, true , true , false, false}, // 09h ROM+RAM+BATTERY
[0xB] = [0xB] =
{ GB_MMM01 , GB_STANDARD_MBC, false, false, false, false}, // 0Bh MMM01 { GB_MMM01 , false, false, false, false}, // 0Bh MMM01
{ GB_MMM01 , GB_STANDARD_MBC, true , false, false, false}, // 0Ch MMM01+RAM { GB_MMM01 , true , false, false, false}, // 0Ch MMM01+RAM
{ GB_MMM01 , GB_STANDARD_MBC, true , true , false, false}, // 0Dh MMM01+RAM+BATTERY { GB_MMM01 , true , true , false, false}, // 0Dh MMM01+RAM+BATTERY
[0xF] = [0xF] =
{ GB_MBC3 , GB_STANDARD_MBC, false, true, true , false}, // 0Fh MBC3+TIMER+BATTERY { GB_MBC3 , false, true, true , false}, // 0Fh MBC3+TIMER+BATTERY
{ GB_MBC3 , GB_STANDARD_MBC, true , true, true , false}, // 10h MBC3+TIMER+RAM+BATTERY { GB_MBC3 , true , true, true , false}, // 10h MBC3+TIMER+RAM+BATTERY
{ GB_MBC3 , GB_STANDARD_MBC, false, false, false, false}, // 11h MBC3 { GB_MBC3 , false, false, false, false}, // 11h MBC3
{ GB_MBC3 , GB_STANDARD_MBC, true , false, false, false}, // 12h MBC3+RAM { GB_MBC3 , true , false, false, false}, // 12h MBC3+RAM
{ GB_MBC3 , GB_STANDARD_MBC, true , true , false, false}, // 13h MBC3+RAM+BATTERY { GB_MBC3 , true , true , false, false}, // 13h MBC3+RAM+BATTERY
[0x19] = [0x19] =
{ GB_MBC5 , GB_STANDARD_MBC, false, false, false, false}, // 19h MBC5 { GB_MBC5 , false, false, false, false}, // 19h MBC5
{ GB_MBC5 , GB_STANDARD_MBC, true , false, false, false}, // 1Ah MBC5+RAM { GB_MBC5 , true , false, false, false}, // 1Ah MBC5+RAM
{ GB_MBC5 , GB_STANDARD_MBC, true , true , false, false}, // 1Bh MBC5+RAM+BATTERY { GB_MBC5 , true , true , false, false}, // 1Bh MBC5+RAM+BATTERY
{ GB_MBC5 , GB_STANDARD_MBC, false, false, false, true }, // 1Ch MBC5+RUMBLE { GB_MBC5 , false, false, false, true }, // 1Ch MBC5+RUMBLE
{ GB_MBC5 , GB_STANDARD_MBC, true , false, false, true }, // 1Dh MBC5+RUMBLE+RAM { GB_MBC5 , true , false, false, true }, // 1Dh MBC5+RUMBLE+RAM
{ GB_MBC5 , GB_STANDARD_MBC, true , true , false, true }, // 1Eh MBC5+RUMBLE+RAM+BATTERY { GB_MBC5 , true , true , false, true }, // 1Eh MBC5+RUMBLE+RAM+BATTERY
[0x22] = [0x22] =
{ GB_MBC7 , GB_STANDARD_MBC, true, true, false, false}, // 22h MBC7+ACCEL+EEPROM { GB_MBC7 , true, true, false, false}, // 22h MBC7+ACCEL+EEPROM
[0xFC] = [0xFC] =
{ GB_MBC5 , GB_CAMERA , true , true , false, false}, // FCh POCKET CAMERA { GB_CAMERA, true , true , false, false}, // FCh POCKET CAMERA
{ GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // FDh BANDAI TAMA5 (Todo: Not supported) { GB_NO_MBC, false, false, false, false}, // FDh BANDAI TAMA5 (Todo: Not supported)
{ GB_HUC3 , GB_STANDARD_MBC, true , true , true, false}, // FEh HuC3 { GB_HUC3 , true , true , true, false}, // FEh HuC3
{ GB_HUC1 , GB_STANDARD_MBC, true , true , false, false}, // FFh HuC1+RAM+BATTERY { GB_HUC1 , true , true , false, false}, // FFh HuC1+RAM+BATTERY
}; };
void GB_update_mbc_mappings(GB_gameboy_t *gb) void GB_update_mbc_mappings(GB_gameboy_t *gb)
@ -96,6 +96,7 @@ void GB_update_mbc_mappings(GB_gameboy_t *gb)
} }
break; break;
case GB_MBC5: case GB_MBC5:
case GB_CAMERA:
gb->mbc_rom_bank = gb->mbc5.rom_bank_low | (gb->mbc5.rom_bank_high << 8); gb->mbc_rom_bank = gb->mbc5.rom_bank_low | (gb->mbc5.rom_bank_high << 8);
gb->mbc_ram_bank = gb->mbc5.ram_bank; gb->mbc_ram_bank = gb->mbc5.ram_bank;
break; break;
@ -185,7 +186,7 @@ void GB_configure_cart(GB_gameboy_t *gb)
if (gb->rom[0x147] == 0xBC && if (gb->rom[0x147] == 0xBC &&
gb->rom[0x149] == 0xC1 && gb->rom[0x149] == 0xC1 &&
gb->rom[0x14A] == 0x65) { gb->rom[0x14A] == 0x65) {
static const GB_cartridge_t tpp1 = {GB_TPP1, GB_STANDARD_MBC, true, true, true, true}; static const GB_cartridge_t tpp1 = {GB_TPP1, true, true, true, true};
gb->cartridge_type = &tpp1; gb->cartridge_type = &tpp1;
gb->tpp1.rom_bank = 1; gb->tpp1.rom_bank = 1;
} }
@ -255,7 +256,8 @@ void GB_reset_mbc(GB_gameboy_t *gb)
gb->mbc_rom_bank = -1; gb->mbc_rom_bank = -1;
gb->mbc_rom0_bank = -2; gb->mbc_rom0_bank = -2;
} }
else if (gb->cartridge_type->mbc_type == GB_MBC5) { else if (gb->cartridge_type->mbc_type == GB_MBC5 ||
gb->cartridge_type->mbc_type == GB_CAMERA) {
gb->mbc5.rom_bank_low = 1; gb->mbc5.rom_bank_low = 1;
gb->mbc_rom_bank = 1; gb->mbc_rom_bank = 1;
} }

View File

@ -15,11 +15,8 @@ typedef struct {
GB_HUC1, GB_HUC1,
GB_HUC3, GB_HUC3,
GB_TPP1, GB_TPP1,
} mbc_type;
enum {
GB_STANDARD_MBC,
GB_CAMERA, GB_CAMERA,
} mbc_subtype; } mbc_type;
bool has_ram; bool has_ram;
bool has_battery; bool has_battery;
bool has_rtc; bool has_rtc;

View File

@ -383,7 +383,7 @@ static uint8_t read_mbc_ram(GB_gameboy_t *gb, uint16_t addr)
} }
} }
else if ((!gb->mbc_ram_enable) && else if ((!gb->mbc_ram_enable) &&
gb->cartridge_type->mbc_subtype != GB_CAMERA && gb->cartridge_type->mbc_type != GB_CAMERA &&
gb->cartridge_type->mbc_type != GB_HUC1 && gb->cartridge_type->mbc_type != GB_HUC1 &&
gb->cartridge_type->mbc_type != GB_HUC3) { gb->cartridge_type->mbc_type != GB_HUC3) {
return 0xFF; return 0xFF;
@ -414,7 +414,7 @@ static uint8_t read_mbc_ram(GB_gameboy_t *gb, uint16_t addr)
return 0xFF; return 0xFF;
} }
if (gb->cartridge_type->mbc_subtype == GB_CAMERA && gb->mbc_ram_bank == 0 && addr >= 0xA100 && addr < 0xAF00) { if (gb->cartridge_type->mbc_type == GB_CAMERA && gb->mbc_ram_bank == 0 && addr >= 0xA100 && addr < 0xAF00) {
return GB_camera_read_image(gb, addr - 0xA100); return GB_camera_read_image(gb, addr - 0xA100);
} }
@ -827,7 +827,16 @@ static void write_mbc(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
value &= 7; value &= 7;
} }
gb->mbc5.ram_bank = value; gb->mbc5.ram_bank = value;
gb->camera_registers_mapped = (value & 0x10) && gb->cartridge_type->mbc_subtype == GB_CAMERA; break;
}
break;
case GB_CAMERA:
switch (addr & 0xF000) {
case 0x0000: case 0x1000: gb->mbc_ram_enable = (value & 0xF) == 0xA; break;
case 0x2000: case 0x3000: gb->mbc5.rom_bank_low = value; break;
case 0x4000: case 0x5000:
gb->mbc5.ram_bank = value;
gb->camera_registers_mapped = (value & 0x10);
break; break;
} }
break; break;

View File

@ -254,6 +254,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); return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t) + (cart->has_rtc? sizeof(BESS_RTC_t) : 0);
case GB_MBC5: case GB_MBC5:
return sizeof(BESS_block_t) + 4 * sizeof(BESS_MBC_pair_t); return sizeof(BESS_block_t) + 4 * sizeof(BESS_MBC_pair_t);
case GB_CAMERA:
return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t);
case GB_MBC7: case GB_MBC7:
return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t) + sizeof(BESS_MBC7_t); return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t) + sizeof(BESS_MBC7_t);
case GB_MMM01: case GB_MMM01:
@ -459,6 +461,12 @@ 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}; pairs[3] = (BESS_MBC_pair_t){LE16(0x4000), gb->mbc5.ram_bank};
mbc_block.size = 4 * sizeof(pairs[0]); mbc_block.size = 4 * sizeof(pairs[0]);
break; break;
case GB_CAMERA:
pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0};
pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->mbc5.rom_bank_low};
pairs[2] = (BESS_MBC_pair_t){LE16(0x4000), gb->mbc5.ram_bank};
mbc_block.size = 3 * sizeof(pairs[0]);
break;
case GB_MBC7: case GB_MBC7:
pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0}; pairs[0] = (BESS_MBC_pair_t){LE16(0x0000), gb->mbc_ram_enable? 0xA : 0x0};
pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->mbc7.rom_bank}; pairs[1] = (BESS_MBC_pair_t){LE16(0x2000), gb->mbc7.rom_bank};