diff --git a/Source/3rdParty/mupen64plus-core/src/device/controllers/paks/transferpak.c b/Source/3rdParty/mupen64plus-core/src/device/controllers/paks/transferpak.c index cf3729a0..0a18d339 100644 --- a/Source/3rdParty/mupen64plus-core/src/device/controllers/paks/transferpak.c +++ b/Source/3rdParty/mupen64plus-core/src/device/controllers/paks/transferpak.c @@ -37,7 +37,7 @@ static uint16_t gb_cart_address(unsigned int bank, uint16_t address) { - return (address & 0x3fff) | ((bank & 0x3) * 0x4000) ; + return 0x4000 * bank + (address & 0x7fff) - 0x4000; } void init_transferpak(struct transferpak* tpk, struct gb_cart* gb_cart) @@ -49,10 +49,7 @@ void poweron_transferpak(struct transferpak* tpk) { tpk->enabled = 0; tpk->bank = 0; - tpk->access_mode = (tpk->gb_cart == NULL) - ? CART_NOT_INSERTED - : CART_ACCESS_MODE_0; - tpk->access_mode_changed = 0x44; + tpk->reset_state = 3; if (tpk->gb_cart != NULL) { poweron_gb_cart(tpk->gb_cart); @@ -68,9 +65,11 @@ void change_gb_cart(struct transferpak* tpk, struct gb_cart* gb_cart) } else { tpk->access_mode = CART_ACCESS_MODE_0; - poweron_gb_cart(gb_cart); + // poweron_gb_cart(gb_cart); } + + tpk->reset_state = 3; tpk->gb_cart = gb_cart; } @@ -84,131 +83,225 @@ static void unplug_transferpak(void* pak) { } -static void read_transferpak(void* pak, uint16_t address, uint8_t* data, size_t size) -{ - struct transferpak* tpk = (struct transferpak*)pak; - uint8_t value; - - DebugMessage(M64MSG_VERBOSE, "tpak read: %04x", address); - - switch(address >> 12) - { - case 0x8: - /* get gb cart state (enabled/disabled) */ - value = (tpk->enabled) - ? 0x84 - : 0x00; - - DebugMessage(M64MSG_VERBOSE, "tpak get cart state: %02x", value); - memset(data, value, size); - break; - - case 0xb: - /* get gb cart access mode */ - if (tpk->enabled) - { - DebugMessage(M64MSG_VERBOSE, "tpak get access mode: %02x", tpk->access_mode); - memset(data, tpk->access_mode, size); - if (tpk->access_mode != CART_NOT_INSERTED) - { - data[0] |= tpk->access_mode_changed; - } - tpk->access_mode_changed = 0; - } - break; - - case 0xc: - case 0xd: - case 0xe: - case 0xf: - /* read gb cart */ - if (tpk->enabled) - { - DebugMessage(M64MSG_VERBOSE, "tpak read cart: %04x", address); - - if (tpk->gb_cart != NULL) { - read_gb_cart(tpk->gb_cart, gb_cart_address(tpk->bank, address), data, size); - } - } - break; + /* Reads from the Transfer Pak. */ + static void read_transferpak(void* pak, uint16_t address, uint8_t* data, size_t size) + { + struct transferpak* tpk = (struct transferpak*)pak; + uint8_t value; + + + switch (address >> 12) + { + case 0x8: + /* + * 0x8 => read the TPak "enabled" status + * In Rust code: if (enabled) => 0x84 else => 0x00 + */ + value = (tpk->enabled) ? 0x84 : 0x00; + DebugMessage(M64MSG_VERBOSE, "TPak returning cart state: %02x", value); + memset(data, value, size); + return; + default: - DebugMessage(M64MSG_WARNING, "Unknown tpak read: %04x", address); + if (!tpk->enabled) { + DebugMessage(M64MSG_VERBOSE, "TPak read ignored because disabled"); + return; + } } -} -static void write_transferpak(void* pak, uint16_t address, const uint8_t* data, size_t size) -{ - struct transferpak* tpk = (struct transferpak*)pak; - uint8_t value = data[size-1]; - - DebugMessage(M64MSG_VERBOSE, "tpak write: %04x <- %02x", address, value); - - switch(address >> 12) + switch (address >> 12) { - case 0x8: - /* enable / disable gb cart */ - switch(value) - { - case 0xfe: - tpk->enabled = 0; - DebugMessage(M64MSG_VERBOSE, "tpak disabled"); - break; - case 0x84: - tpk->enabled = 1; - DebugMessage(M64MSG_VERBOSE, "tpak enabled"); - break; - default: - DebugMessage(M64MSG_WARNING, "Unknown tpak write: %04x <- %02x", address, value); + case 0xB: + { + uint8_t val = 0; + + if (tpk->gb_cart && tpk->gb_cart->enabled) { + val |= (1 << 0); /* bit0 => cart enabled? */ + } + val |= (uint8_t)((tpk->reset_state & 3) << 2); + + if (tpk->enabled) { + val |= (1 << 7); + } + + /* Simple state machine for reset_state (mirroring Rust logic). */ + if ( tpk->gb_cart->enabled && tpk->reset_state == 3) { + tpk->reset_state = 2; + } + else if (!tpk->gb_cart->enabled && tpk->reset_state == 2) { + tpk->reset_state = 1; + } + else if (!tpk->gb_cart->enabled && tpk->reset_state == 1) { + tpk->reset_state = 0; + } + + DebugMessage(M64MSG_VERBOSE, "TPak read 0xB => %02x", val); + + memset(data, val, size); + break; + } + + case 0xC: + case 0xD: + case 0xE: + case 0xF: + /* + * Read from the Game Boy cart. + * The address is computed as bank-based offset + * (0x4000 * bank + ((address & 0x7FFF) - 0x4000)). + */ + if (tpk->gb_cart != NULL) + { + const uint16_t cart_addr = gb_cart_address(tpk->bank, address); + read_gb_cart(tpk->gb_cart, cart_addr, data, size); + //DebugMessage(M64MSG_VERBOSE, + // "TPak reading cart: bank=%d, raw_addr=%04x => gb_addr=%04x -> %02x", tpk->bank, address, cart_addr, data[0]); + /*for(int i = 0; i < size; i++) + { + DebugMessage(M64MSG_VERBOSE, "TPak reading cart: bank=%d, raw_addr=%04x => gb_addr=%04x -> %02x", tpk->bank, address, cart_addr, data[i]); + }*/ + + } + else + { + DebugMessage(M64MSG_WARNING, "TPak read: no GB cart present"); + memset(data, 0x00, size); + } + break; + + default: + DebugMessage(M64MSG_WARNING, "Unknown TPak read at %04x", address); + memset(data, 0x00, size); + break; + } + } + + /* Writes to the Transfer Pak. */ + static void write_transferpak(void* pak, uint16_t address, const uint8_t* buf, size_t size) + { + struct transferpak* tpk = (struct transferpak*)pak; + /* The Rust code always uses the last byte as the "value" for multi-byte writes. */ + uint16_t value = buf[size - 1]; + + DebugMessage(M64MSG_VERBOSE, "TransferPak write: %04x <- %02x", address, value); + + switch (address >> 12) + { + case 0x8: + /* + * Matches the Rust approach: 0xFE => disable, 0x84 => enable + */ + switch (value) + { + case 0xFE: + tpk->enabled = 0; + DebugMessage(M64MSG_VERBOSE, "TPak disabled"); + return; + + case 0x84: + if (!tpk->enabled) + { + tpk->bank = 3; + tpk->reset_state = 0; + + if (tpk->gb_cart != NULL) + { + tpk->gb_cart->enabled = 0; + } + } + tpk->enabled = 1; + DebugMessage(M64MSG_VERBOSE, "TPak enabled (0x84)"); + return; + + default: + DebugMessage(M64MSG_WARNING, + "Unknown write to TPak (0x8 region): %02x", value); + return; + } + return; + + default: + /* If TPak not enabled, ignore writes (as in your Rust example). */ + if (!tpk->enabled) { + DebugMessage(M64MSG_VERBOSE, "TPak write ignored because disabled"); + return; + } + break; + case 0xA: + if (!tpk->enabled) { + DebugMessage(M64MSG_VERBOSE, "TPak write ignored because disabled"); + return; } - break; - - case 0xa: - /* set gb cart bank */ - if (tpk->enabled) - { - tpk->bank = value; - DebugMessage(M64MSG_VERBOSE, "tpak set bank %02x", tpk->bank); + tpk->bank = (uint16_t)value; + if (tpk->bank > 3) { + DebugMessage(M64MSG_WARNING, "TPak: invalid bank %d", tpk->bank); + tpk->bank = 0; + } + DebugMessage(M64MSG_VERBOSE, "TPak set bank => %d", tpk->bank); + break; + + case 0xB: + if (value & 1) + { + if (tpk->gb_cart != NULL && !tpk->gb_cart->enabled) + { + /* Reset state to 3, and do any "power-on" type logic on the cart. */ + tpk->reset_state = 3; + tpk->gb_cart->enabled = 1; + tpk->gb_cart->rom_bank = 1; + tpk->gb_cart->ram_bank = 0; + tpk->gb_cart->ram_enable = 0; + + /* e.g. set cart type if needed: + * tpk->gb_cart->cart_type = get_cart_type(tpk->gb_cart->rom[0x147]); + * (This depends on your real code.) + */ + DebugMessage(M64MSG_VERBOSE, "TPak: cart enabled, reset_state=3"); + } + else if (tpk->gb_cart) + { + tpk->gb_cart->enabled = 1; + DebugMessage(M64MSG_VERBOSE, "TPak: cart already enabled"); + } + } + else + { + if (tpk->gb_cart) { + tpk->gb_cart->enabled = 0; + } + DebugMessage(M64MSG_VERBOSE, "TPak: cart disabled via write to 0xB"); + } + break; + + case 0xC: + case 0xD: + case 0xE: + case 0xF: + { + if (!tpk->enabled) { + DebugMessage(M64MSG_VERBOSE, "TPak write ignored because disabled"); + return; } - break; - - case 0xb: - /* set gb cart access mode */ - if (tpk->enabled) - { - tpk->access_mode_changed = 0x04; - - tpk->access_mode = ((value & 1) == 0) - ? CART_ACCESS_MODE_0 - : CART_ACCESS_MODE_1; - - if ((value & 0xfe) != 0) - { - DebugMessage(M64MSG_WARNING, "Unknown tpak write: %04x <- %02x", address, value); - } - - DebugMessage(M64MSG_VERBOSE, "tpak set access mode %02x", tpk->access_mode); - } - break; - - case 0xc: - case 0xd: - case 0xe: - case 0xf: - /* write gb cart */ -// if (tpk->enabled) - { - DebugMessage(M64MSG_VERBOSE, "tpak write gb: %04x <- %02x", address, value); - - if (tpk->gb_cart != NULL) { - write_gb_cart(tpk->gb_cart, gb_cart_address(tpk->bank, address), data, size); - } - } - break; - default: - DebugMessage(M64MSG_WARNING, "Unknown tpak write: %04x <- %02x", address, value); - } -} + /* Write to GB cart memory. */ + if (tpk->gb_cart != NULL) + { + uint16_t cart_addr = gb_cart_address(tpk->bank, address); + DebugMessage(M64MSG_VERBOSE, + "TPak write to cart: bank=%d, raw_addr=%04x => gb_addr=%04x val=%02x", + tpk->bank, address, cart_addr, value); + write_gb_cart(tpk->gb_cart, cart_addr, buf, size); + } + else + { + DebugMessage(M64MSG_WARNING, + "TPak write to 0xC..0xF, but no GB cart present"); + } + break; + }; + } + } + /* Transfer pak definition */ const struct pak_interface g_itransferpak = @@ -219,3 +312,4 @@ const struct pak_interface g_itransferpak = read_transferpak, write_transferpak }; + diff --git a/Source/3rdParty/mupen64plus-core/src/device/controllers/paks/transferpak.h b/Source/3rdParty/mupen64plus-core/src/device/controllers/paks/transferpak.h index 37267275..18fa31a3 100644 --- a/Source/3rdParty/mupen64plus-core/src/device/controllers/paks/transferpak.h +++ b/Source/3rdParty/mupen64plus-core/src/device/controllers/paks/transferpak.h @@ -40,6 +40,7 @@ struct transferpak unsigned int bank; unsigned int access_mode; unsigned int access_mode_changed; + unsigned int reset_state; struct gb_cart* gb_cart; }; diff --git a/Source/3rdParty/mupen64plus-core/src/device/gb/gb_cart.c b/Source/3rdParty/mupen64plus-core/src/device/gb/gb_cart.c index b25992ad..061d7e31 100644 --- a/Source/3rdParty/mupen64plus-core/src/device/gb/gb_cart.c +++ b/Source/3rdParty/mupen64plus-core/src/device/gb/gb_cart.c @@ -54,7 +54,7 @@ enum gbcart_extra_devices /* various helper functions for ram, rom, or MBC uses */ -static void read_rom(const void* rom_storage, const struct storage_backend_interface* irom_storage, uint16_t address, uint8_t* data, size_t size) +static void read_rom(const void* rom_storage, const struct storage_backend_interface* irom_storage, uint32_t address, uint8_t* data, size_t size) { assert(size > 0); @@ -68,14 +68,14 @@ static void read_rom(const void* rom_storage, const struct storage_backend_inter } -static void read_ram(const void* ram_storage, const struct storage_backend_interface* iram_storage, unsigned int enabled, uint16_t address, uint8_t* data, size_t size, uint8_t mask) +static void read_ram(const void* ram_storage, const struct storage_backend_interface* iram_storage, unsigned int enabled, uint32_t address, uint8_t* data, size_t size, uint8_t mask) { size_t i; assert(size > 0); /* RAM has to be enabled before use */ if (!enabled) { - DebugMessage(M64MSG_WARNING, "Trying to read from non enabled GB RAM %04x", address); + DebugMessage(M64MSG_WARNING, "read_ram Trying to read from non enabled GB RAM %04x", address); memset(data, 0xff, size); return; } @@ -240,7 +240,7 @@ static int write_gb_cart_mbc1(struct gb_cart* gb_cart, uint16_t address, const u /* 0x2000-0x3fff: ROM bank select (low 5 bits) */ case (0x2000 >> 13): bank = value & 0x1f; - gb_cart->rom_bank = (gb_cart->rom_bank & ~UINT8_C(0x1f)) | ((bank == 0) ? 1 : bank); + gb_cart->rom_bank = (gb_cart->rom_bank & ~UINT8_C(0x1f)) | (bank == 0) ? 1 : bank; DebugMessage(M64MSG_VERBOSE, "MBC1 set rom bank %02x", gb_cart->rom_bank); break; @@ -345,25 +345,32 @@ static int write_gb_cart_mbc2(struct gb_cart* gb_cart, uint16_t address, const u return 0; } - -static int read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) +static int read_gb_cart_mbc3(struct gb_cart* gb_cart, + uint16_t address, + uint8_t* dst, + size_t size) { - switch(address >> 13) + + if (address < 0x4000) { - /* 0x0000-0x3fff: ROM bank 00 */ - case (0x0000 >> 13): - case (0x2000 >> 13): - read_rom(gb_cart->rom_storage, gb_cart->irom_storage, address, data, size); - break; + /* Bank 0 (0x0000 - 0x3FFF) */ + uint32_t banked_address = address & 0x3FFF; /* same as just address, but & 0x3FFF is explicit */ + + read_rom(gb_cart->rom_storage, gb_cart->irom_storage, banked_address, dst, size); - /* 0x4000-0x7fff: ROM bank 01-7f */ - case (0x4000 >> 13): - case (0x6000 >> 13): - read_rom(gb_cart->rom_storage, gb_cart->irom_storage, (address - 0x4000) + (gb_cart->rom_bank * 0x4000), data, size); - break; - - /* 0xa000-0xbfff: RAM bank 00-07 or RTC register 08-0c */ - case (0xa000 >> 13): + //DebugMessage(M64MSG_VERBOSE, "MBC3 read from ROM bank 0: %04x", address); + } + else if (address < 0x8000) + { + /* Switched ROM bank (0x4000 - 0x7FFF) */ + size_t banked_address = (size_t)((uint32_t)address - 0x4000) + + (gb_cart->rom_bank * 0x4000); + read_rom(gb_cart->rom_storage, gb_cart->irom_storage, banked_address, dst, size); + //DebugMessage(M64MSG_VERBOSE, "MBC3 read from ROM bank %02x: %04x", gb_cart->rom_bank, address); + } + else if (address >= 0xA000 && address < 0xC000) + { + switch(gb_cart->ram_bank) { /* RAM banks */ @@ -375,8 +382,12 @@ static int read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t* case 0x05: case 0x06: case 0x07: - read_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000) + (gb_cart->ram_bank * 0x2000), data, size, UINT8_C(0xff)); + { + size_t banked_address = (size_t)((uint32_t)address - 0xA000) + + (gb_cart->ram_bank * 0x2000); + read_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, banked_address, dst, size, UINT8_C(0xff)); break; + } /* RTC registers */ case 0x08: @@ -387,68 +398,78 @@ static int read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t* /* RAM has to be enabled before use */ if (!gb_cart->ram_enable) { DebugMessage(M64MSG_WARNING, "Trying to read from non enabled GB RAM %04x", address); - memset(data, 0xff, size); + memset(dst, 0xff, size); break; } - if (!(gb_cart->extra_devices & GED_RTC)) { DebugMessage(M64MSG_WARNING, "Trying to read from absent RTC %04x", address); - memset(data, 0xff, size); + memset(dst, 0xff, size); break; } - memset(data, read_mbc3_rtc_regs(&gb_cart->rtc, gb_cart->ram_bank - 0x08), size); + memset(dst, read_mbc3_rtc_regs(&gb_cart->rtc, gb_cart->ram_bank - 0x08), size); break; default: DebugMessage(M64MSG_WARNING, "Unknown device mapped in RAM/RTC space: %04x", address); } - break; - - default: - DebugMessage(M64MSG_WARNING, "Invalid cart read (MBC3): %04x", address); + } + else + { + /* The Rust code does a panic!("Unsupported read address {:x}", address); */ + DebugMessage(M64MSG_WARNING, "Unsupported read address %04x", address); } return 0; } -static int write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size) + +static int write_gb_cart_mbc3(struct gb_cart* gb_cart, + uint16_t address, + const uint8_t* src, + size_t size) { - uint8_t bank; - uint8_t value = data[size-1]; + if (size == 0) { + /* Nothing to write, just return */ + return 0; + } - switch(address >> 13) + uint8_t value = src[size - 1]; + + if (address < 0x2000) { - /* 0x0000-0x1fff: RAM/RTC enable */ - case (0x0000 >> 13): + /* Enable or disable RAM */ set_ram_enable(gb_cart, value); - break; - - /* 0x2000-0x3fff: ROM bank select */ - case (0x2000 >> 13): - bank = value & 0x7f; - gb_cart->rom_bank = (bank == 0) ? 1 : bank; - DebugMessage(M64MSG_VERBOSE, "MBC3 set rom bank %02x", gb_cart->rom_bank); - break; - - /* 0x4000-0x5fff: RAM bank / RTC register select */ - case (0x4000 >> 13): - gb_cart->ram_bank = value; + } + else if (address < 0x4000) + { + /* Select ROM bank (0x01..0x7F) */ + uint8_t bank = value & 0x7F; + gb_cart->rom_bank = bank; + if (gb_cart->rom_bank == 0) { + gb_cart->rom_bank = 1; + } + DebugMessage(M64MSG_VERBOSE, "MBC3 set rom bank %02x addr %04x", gb_cart->rom_bank, address); + } + else if (address < 0x6000) + { + /* Select RAM bank or RTC register */ + gb_cart->ram_bank = (value & 0x0F); DebugMessage(M64MSG_VERBOSE, "MBC3 set ram bank %02x", gb_cart->ram_bank); - break; - - /* 0x6000-0x7fff: latch clock registers */ - case (0x6000 >> 13): + } + else if (address < 0x8000) + { + /* RTC latch (not implemented here) */ + /* The Rust code simply does nothing. */ if (!(gb_cart->extra_devices & GED_RTC)) { DebugMessage(M64MSG_WARNING, "Trying to latch to absent RTC %04x", address); - break; } - - latch_mbc3_rtc_regs(&gb_cart->rtc, value); - break; - - /* 0xa000-0xbfff: RAM bank 00-07 or RTC register 08-0c */ - case (0xa000 >> 13): + else + latch_mbc3_rtc_regs(&gb_cart->rtc, value); + } + else if (address >= 0xA000 && address < 0xC000) + { + DebugMessage(M64MSG_VERBOSE, "MBC3 write to RAM: %04x <- %02x (bank %02x)", address, value, gb_cart->ram_bank); switch(gb_cart->ram_bank) { /* RAM banks */ @@ -460,7 +481,7 @@ static int write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const u case 0x05: case 0x06: case 0x07: - write_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000) + (gb_cart->ram_bank * 0x2000), data, size, UINT8_C(0xff)); + write_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000) + (gb_cart->ram_bank * 0x2000), src, size, UINT8_C(0xff)); break; /* RTC registers */ @@ -469,11 +490,11 @@ static int write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const u case 0x0a: case 0x0b: case 0x0c: - /* RAM has to be enabled before use */ - if (!gb_cart->ram_enable) { - DebugMessage(M64MSG_WARNING, "Trying to write to non enabled GB RAM %04x", address); - break; - } + /* RAM has to be enabled before use */ + if (!gb_cart->ram_enable) { + DebugMessage(M64MSG_WARNING, "Trying to write to non enabled GB RAM %04x", address); + break; + } if (!(gb_cart->extra_devices & GED_RTC)) { DebugMessage(M64MSG_WARNING, "Trying to write to absent RTC %04x", address); @@ -486,15 +507,18 @@ static int write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const u default: DebugMessage(M64MSG_WARNING, "Unknwown device mapped in RAM/RTC space: %04x", address); } - break; - - default: - DebugMessage(M64MSG_WARNING, "Invalid cart write (MBC3): %04x", address); + + } + else + { + /* The Rust code does panic!("Unsupported write address {:x}", address); */ + DebugMessage(M64MSG_WARNING, "Unsupported write address %04x", address); } return 0; } + static int read_gb_cart_mbc5(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) { switch(address >> 13) @@ -1117,3 +1141,4 @@ int write_gb_cart(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data return gb_cart->write_gb_cart(gb_cart, address, data, size); } + diff --git a/Source/3rdParty/mupen64plus-core/src/device/gb/gb_cart.h b/Source/3rdParty/mupen64plus-core/src/device/gb/gb_cart.h index c9cdae5e..f6a4ecd5 100644 --- a/Source/3rdParty/mupen64plus-core/src/device/gb/gb_cart.h +++ b/Source/3rdParty/mupen64plus-core/src/device/gb/gb_cart.h @@ -56,6 +56,7 @@ struct gb_cart void* ram_storage; const struct storage_backend_interface* iram_storage; + unsigned int enabled; unsigned int rom_bank; unsigned int ram_bank;