mirror of
https://github.com/Rosalie241/RMG.git
synced 2026-07-11 01:24:01 +02:00
3rdParty: experimental transfer pak changes from @m4xw
This commit is contained in:
+218
-124
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
+93
-68
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user