Skip to content

Commit

Permalink
3rdParty: experimental transfer pak changes from @m4xw
Browse files Browse the repository at this point in the history
  • Loading branch information
Rosalie241 committed Feb 26, 2025
1 parent aebebfb commit 1decba1
Show file tree
Hide file tree
Showing 4 changed files with 314 additions and 193 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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);
Expand All @@ -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;
}

Expand All @@ -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);
}
break;

case 0xa:
/* set gb cart bank */
if (tpk->enabled)
{
tpk->bank = value;
DebugMessage(M64MSG_VERBOSE, "tpak set bank %02x", tpk->bank);
}
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);
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 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);
}
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;
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 =
Expand All @@ -219,3 +312,4 @@ const struct pak_interface g_itransferpak =
read_transferpak,
write_transferpak
};

Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
Loading

0 comments on commit 1decba1

Please sign in to comment.