parent
04390301c9
commit
4692e2bcb9
@ -1,5 +1,6 @@
|
||||
use crate::{device, netplay, savestates, ui};
|
||||
|
||||
pub mod gbcart;
|
||||
pub mod mempak;
|
||||
pub mod rumble;
|
||||
pub mod transferpak;
|
||||
|
||||
184
src/device/controller/gbcart.rs
Normal file
184
src/device/controller/gbcart.rs
Normal file
@ -0,0 +1,184 @@
|
||||
use crate::device;
|
||||
|
||||
#[derive(Default, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum CartType {
|
||||
#[default]
|
||||
None,
|
||||
MBC3RamBatt,
|
||||
MBC3RamBattRtc,
|
||||
MBC5RamBatt,
|
||||
}
|
||||
|
||||
fn write_mbc3(
|
||||
pif_ram: &mut [u8],
|
||||
pak: &mut device::controller::transferpak::TransferPak,
|
||||
address: u16,
|
||||
data: usize,
|
||||
size: usize,
|
||||
) {
|
||||
let value = pif_ram[data + size - 1];
|
||||
if address < 0x2000 {
|
||||
pak.ram_enabled = value & 0xf == 0xa;
|
||||
} else if address < 0x4000 {
|
||||
let bank = value & 0x7f;
|
||||
if bank == 0 {
|
||||
pak.bank = 1;
|
||||
} else {
|
||||
pak.bank = bank as u16;
|
||||
}
|
||||
} else if address < 0x6000 {
|
||||
pak.ram_bank = value as u16;
|
||||
} else if address < 0x8000 {
|
||||
println!("MBC3 RTC latch")
|
||||
} else if (0xa000..0xc000).contains(&address) {
|
||||
if !pak.ram_enabled {
|
||||
return;
|
||||
}
|
||||
if pak.ram_bank < 0x8 {
|
||||
let banked_address = (pak.ram_bank << 13) | (address & 0x1FFF);
|
||||
for i in 0..size {
|
||||
pak.ram[banked_address as usize + i] = pif_ram[data + i];
|
||||
}
|
||||
} else {
|
||||
panic!("Unsupported ram bank {:x}", pak.ram_bank);
|
||||
}
|
||||
} else {
|
||||
panic!("Unsupported write address {:x}", address);
|
||||
}
|
||||
}
|
||||
|
||||
fn read_mbc3(
|
||||
pif_ram: &mut [u8],
|
||||
pak: &mut device::controller::transferpak::TransferPak,
|
||||
address: u16,
|
||||
data: usize,
|
||||
size: usize,
|
||||
) {
|
||||
if address < 0x4000 {
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = pak.rom[address as usize + i];
|
||||
}
|
||||
} else if address < 0x8000 {
|
||||
let banked_address = (pak.bank << 14) | (address & 0x3FFF);
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = pak.rom[banked_address as usize + i];
|
||||
}
|
||||
} else if address < 0xc000 {
|
||||
if !pak.ram_enabled {
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = 0xff;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if pak.ram_bank < 0x8 {
|
||||
let banked_address = (pak.ram_bank << 13) | (address & 0x1FFF);
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = pak.ram[banked_address as usize + i];
|
||||
}
|
||||
} else {
|
||||
panic!("Unsupported ram bank {:x}", pak.ram_bank);
|
||||
}
|
||||
} else {
|
||||
panic!("Unsupported read address {:x}", address);
|
||||
}
|
||||
}
|
||||
|
||||
fn write_mbc5(
|
||||
pif_ram: &mut [u8],
|
||||
pak: &mut device::controller::transferpak::TransferPak,
|
||||
address: u16,
|
||||
data: usize,
|
||||
size: usize,
|
||||
) {
|
||||
let value = pif_ram[data + size - 1];
|
||||
if address < 0x2000 {
|
||||
pak.ram_enabled = value & 0xf == 0xa;
|
||||
} else if address < 0x6000 {
|
||||
pak.ram_bank = (value & 0xf) as u16;
|
||||
} else if address < 0xa000 {
|
||||
println!("Unknown MBC5 write address {:x}", address);
|
||||
} else if (0xa000..0xc000).contains(&address) {
|
||||
if !pak.ram_enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
let banked_address = (pak.ram_bank << 13) | (address & 0x1FFF);
|
||||
for i in 0..size {
|
||||
pak.ram[banked_address as usize + i] = pif_ram[data + i];
|
||||
}
|
||||
} else {
|
||||
panic!("Unsupported write address {:x}", address);
|
||||
}
|
||||
}
|
||||
|
||||
fn read_mbc5(
|
||||
pif_ram: &mut [u8],
|
||||
pak: &mut device::controller::transferpak::TransferPak,
|
||||
address: u16,
|
||||
data: usize,
|
||||
size: usize,
|
||||
) {
|
||||
if address < 0x4000 {
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = pak.rom[address as usize + i];
|
||||
}
|
||||
} else if address < 0x8000 {
|
||||
let banked_address = (pak.bank << 14) | (address & 0x3FFF);
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = pak.rom[banked_address as usize + i];
|
||||
}
|
||||
} else if address < 0xc000 {
|
||||
if !pak.ram_enabled {
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = 0xff;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let banked_address = (pak.ram_bank << 13) | (address & 0x1FFF);
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = pak.ram[banked_address as usize + i];
|
||||
}
|
||||
} else {
|
||||
panic!("Unsupported read address {:x}", address);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(
|
||||
pif_ram: &mut [u8],
|
||||
pak: &mut device::controller::transferpak::TransferPak,
|
||||
address: u16,
|
||||
data: usize,
|
||||
size: usize,
|
||||
) {
|
||||
match pak.cart_type {
|
||||
CartType::MBC3RamBatt => read_mbc3(pif_ram, pak, address, data, size),
|
||||
CartType::MBC3RamBattRtc => read_mbc3(pif_ram, pak, address, data, size),
|
||||
CartType::MBC5RamBatt => read_mbc5(pif_ram, pak, address, data, size),
|
||||
_ => panic!("Unsupported cart type"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(
|
||||
pif_ram: &mut [u8],
|
||||
pak: &mut device::controller::transferpak::TransferPak,
|
||||
address: u16,
|
||||
data: usize,
|
||||
size: usize,
|
||||
) {
|
||||
match pak.cart_type {
|
||||
CartType::MBC3RamBatt => write_mbc3(pif_ram, pak, address, data, size),
|
||||
CartType::MBC3RamBattRtc => write_mbc3(pif_ram, pak, address, data, size),
|
||||
CartType::MBC5RamBatt => write_mbc5(pif_ram, pak, address, data, size),
|
||||
_ => panic!("Unsupported cart type"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cart_type(data: u8) -> CartType {
|
||||
match data {
|
||||
0x10 => CartType::MBC3RamBattRtc,
|
||||
0x13 => CartType::MBC3RamBatt,
|
||||
0x1b => CartType::MBC5RamBatt,
|
||||
_ => panic!("Unsupported cart type {:x}", data),
|
||||
}
|
||||
}
|
||||
@ -5,10 +5,13 @@ pub struct TransferPak {
|
||||
pub enabled: bool,
|
||||
pub cart_enabled: bool,
|
||||
pub reset_state: u8,
|
||||
pub bank: u8,
|
||||
pub bank: u16,
|
||||
#[serde(skip)]
|
||||
pub rom: Vec<u8>,
|
||||
pub ram: Vec<u8>,
|
||||
pub cart_type: device::controller::gbcart::CartType,
|
||||
pub ram_enabled: bool,
|
||||
pub ram_bank: u16,
|
||||
}
|
||||
|
||||
pub fn read(device: &mut device::Device, channel: usize, address: u16, data: usize, size: usize) {
|
||||
@ -54,6 +57,15 @@ pub fn read(device: &mut device::Device, channel: usize, address: u16, data: usi
|
||||
device.pif.ram[data + i] = value;
|
||||
}
|
||||
}
|
||||
0xC..=0xF => {
|
||||
device::controller::gbcart::read(
|
||||
&mut device.pif.ram,
|
||||
pak,
|
||||
(address & 0x3fff) | ((pak.bank & 0x3) * 0x4000),
|
||||
data,
|
||||
size,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
panic!("unknown transfer pak read {:x}", address >> 12);
|
||||
}
|
||||
@ -91,7 +103,7 @@ pub fn write(device: &mut device::Device, channel: usize, address: u16, data: us
|
||||
|
||||
match address >> 12 {
|
||||
0xA => {
|
||||
pak.bank = value;
|
||||
pak.bank = value as u16;
|
||||
if pak.bank > 3 {
|
||||
pak.bank = 0;
|
||||
}
|
||||
@ -100,12 +112,22 @@ pub fn write(device: &mut device::Device, channel: usize, address: u16, data: us
|
||||
if value & 1 != 0 {
|
||||
if !pak.cart_enabled {
|
||||
pak.reset_state = 3;
|
||||
pak.cart_type = device::controller::gbcart::get_cart_type(pak.rom[0x147]);
|
||||
}
|
||||
pak.cart_enabled = true;
|
||||
} else {
|
||||
pak.cart_enabled = false;
|
||||
}
|
||||
}
|
||||
0xC..=0xF => {
|
||||
device::controller::gbcart::write(
|
||||
&mut device.pif.ram,
|
||||
pak,
|
||||
(address & 0x3fff) | ((pak.bank & 0x3) * 0x4000),
|
||||
data,
|
||||
size,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
panic!("unknown transfer pak write {:x}", address >> 12);
|
||||
}
|
||||
|
||||
@ -245,7 +245,7 @@ pub fn init(device: &mut device::Device) {
|
||||
device.pif.ram[0x26] = device.cart.cic_seed;
|
||||
device.pif.ram[0x27] = device.cart.cic_seed;
|
||||
|
||||
let mempak_handler = device::controller::PakHandler {
|
||||
let default_handler = device::controller::PakHandler {
|
||||
read: device::controller::mempak::read,
|
||||
write: device::controller::mempak::write,
|
||||
pak_type: device::controller::PakType::MemPak,
|
||||
@ -256,10 +256,10 @@ pub fn init(device: &mut device::Device) {
|
||||
for i in 0..4 {
|
||||
if device.netplay.is_none() {
|
||||
if device.ui.config.input.controller_enabled[i] {
|
||||
device.pif.channels[i].pak_handler = Some(mempak_handler);
|
||||
device.pif.channels[i].pak_handler = Some(default_handler);
|
||||
}
|
||||
} else if device.netplay.as_ref().unwrap().player_data[i].reg_id != 0 {
|
||||
device.pif.channels[i].pak_handler = Some(mempak_handler);
|
||||
device.pif.channels[i].pak_handler = Some(default_handler);
|
||||
}
|
||||
}
|
||||
if device.ui.config.input.emulate_vru {
|
||||
|
||||
Reference in New Issue
Block a user