transfer pak: implement transfer pak read and write

This code will not boot Pokemon Stadium 1 or 2 after extensive
debugging. The code lacks Game Boy MBC support (though this is not the
reason the games refuse to boot).
This commit is contained in:
Mike Ryan 2016-01-24 17:44:57 -08:00
parent 799b2af628
commit e83da838f7
4 changed files with 136 additions and 4 deletions

View file

@ -339,6 +339,7 @@ set(SI_SOURCES
${PROJECT_SOURCE_DIR}/si/cic.c
${PROJECT_SOURCE_DIR}/si/controller.c
${PROJECT_SOURCE_DIR}/si/pak.c
${PROJECT_SOURCE_DIR}/si/pak_transfer.c
)
set(VI_SOURCES

View file

@ -9,6 +9,7 @@
//
#include "pak.h"
#include "pak_transfer.h"
static uint8_t controller_pak_crc(uint8_t *data);
@ -27,12 +28,13 @@ int controller_pak_read(struct controller *controller,
assert(0 && "invalid mempak address");
}
else if (controller->pak == PAK_TRANSFER)
transfer_pak_read(controller, send_buf, send_bytes, recv_buf, recv_bytes);
else {
uint8_t peripheral = 0x00;
if (controller->pak == PAK_RUMBLE)
peripheral = 0x80;
else if (controller->pak == PAK_TRANSFER)
peripheral = 0x84;
memset(recv_buf, peripheral, 0x20);
}
@ -49,8 +51,13 @@ int controller_pak_write(struct controller *controller,
address &= ~0b11111; // lower 5 bits are a checksum
// printf("write to %04x\n", address);
if (address == 0x8000)
; // initializing device, do nothing
if (address == 0x8000) {
// maybe only for transfer pak, unclear
if (send_buf[3] == 0xfe)
controller->pak_enabled = 0;
else if (send_buf[3] == 0x84)
controller->pak_enabled = 1;
}
else if (controller->pak == PAK_MEM) {
if (address <= MEMPAK_SIZE - 0x20)
@ -70,6 +77,9 @@ int controller_pak_write(struct controller *controller,
; // printf("Unknown rumble address\n");
}
else if (controller->pak == PAK_TRANSFER)
transfer_pak_write(controller, send_buf, send_bytes, recv_buf, recv_bytes);
recv_buf[0] = controller_pak_crc(send_buf+3);
return 0;

99
si/pak_transfer.c Normal file
View file

@ -0,0 +1,99 @@
//
// si/pak.c: Controller pak routines
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2016, Mike Ryan.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#include "pak.h"
static void gameboy_read(struct controller *controller, uint16_t address,
uint8_t *buffer);
static void gameboy_write(struct controller *controller, uint16_t address,
uint8_t *buffer);
void transfer_pak_read(struct controller *controller,
uint8_t *send_buf, uint8_t send_bytes,
uint8_t *recv_buf, uint8_t recv_bytes) {
uint16_t address = send_buf[1] << 8 | send_buf[2];
address &= ~0b11111; // lower 5 bits are address CRC
// printf("read from %04x\n", address);
// get enable/disable state
if (address == 0x8000)
memset(recv_buf, controller->pak_enabled ? 0x84 : 0x00, 0x20);
// get insertion status and access mode
else if (address == 0xB000) {
if (controller->pak_enabled) {
// cart inserted, return mode and mode changed
if (controller->tpak_rom.ptr != NULL) {
memset(recv_buf, controller->tpak_mode == 1 ? 0x89 : 0x80, 0x20);
recv_buf[0] |= controller->tpak_mode_changed ? 0b100 : 0;
}
// cart not inserted
else
memset(recv_buf, 0x40, 0x20);
controller->tpak_mode_changed = 0;
}
}
// read from GB cart
else if (address >= 0xC000) {
if (controller->pak_enabled) {
uint16_t gb_addr = address - 0xC000
+ (controller->tpak_bank & 3) * 0x4000;
gameboy_read(controller, gb_addr, recv_buf);
}
}
}
void transfer_pak_write(struct controller *controller,
uint8_t *send_buf, uint8_t send_bytes,
uint8_t *recv_buf, uint8_t recv_bytes) {
uint16_t address = send_buf[1] << 8 | send_buf[2];
address &= ~0b11111; // lower 5 bits are address CRC
// printf("write to %04x\n", address);
// set bank
if (address == 0xA000) {
if (controller->pak_enabled)
controller->tpak_bank = send_buf[3];
}
// set access mode
else if (address == 0xB000) {
if (controller->pak_enabled) {
controller->tpak_mode = send_buf[3] & 1;
controller->tpak_mode_changed = 1;
}
}
// write to GB cart
else if (address >= 0xC000) {
uint16_t gb_addr = address - 0xC000
+ (controller->tpak_bank & 3) * 0x4000;
gameboy_write(controller, gb_addr, send_buf);
}
}
// read 0x20 bytes from Game Boy cart at address
void gameboy_read(struct controller *controller, uint16_t address,
uint8_t *buffer) {
// TODO handle mappers
if (address < 0x8000)
memcpy(buffer, controller->tpak_rom.ptr + address, 0x20);
}
// write 0x20 bytes from buffer to Game Boy cart at address
void gameboy_write(struct controller *controller, uint16_t address,
uint8_t *buffer) {
// TODO
}

22
si/pak_transfer.h Normal file
View file

@ -0,0 +1,22 @@
//
// si/pak_transfer.h: Transfer pak handling
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2016, Mike Ryan.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#ifndef __si_pak_transfer_h__
#define __si_pak_transfer_h__
#include "common.h"
void transfer_pak_read(struct controller *controller,
uint8_t *send_buf, uint8_t send_bytes,
uint8_t *recv_buf, uint8_t recv_bytes);
void transfer_pak_write(struct controller *controller,
uint8_t *send_buf, uint8_t send_bytes,
uint8_t *recv_buf, uint8_t recv_bytes);
#endif