parent
4692e2bcb9
commit
9980302d37
@ -1,5 +1,17 @@
|
||||
use crate::device;
|
||||
|
||||
#[derive(Default, serde::Serialize, serde::Deserialize)]
|
||||
pub struct GbCart {
|
||||
pub enabled: bool,
|
||||
#[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 rom_bank: u16,
|
||||
}
|
||||
|
||||
#[derive(Default, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum CartType {
|
||||
#[default]
|
||||
@ -11,36 +23,36 @@ pub enum CartType {
|
||||
|
||||
fn write_mbc3(
|
||||
pif_ram: &mut [u8],
|
||||
pak: &mut device::controller::transferpak::TransferPak,
|
||||
cart: &mut device::controller::gbcart::GbCart,
|
||||
address: u16,
|
||||
data: usize,
|
||||
size: usize,
|
||||
) {
|
||||
let value = pif_ram[data + size - 1];
|
||||
if address < 0x2000 {
|
||||
pak.ram_enabled = value & 0xf == 0xa;
|
||||
cart.ram_enabled = value & 0xf == 0xa;
|
||||
} else if address < 0x4000 {
|
||||
let bank = value & 0x7f;
|
||||
if bank == 0 {
|
||||
pak.bank = 1;
|
||||
cart.rom_bank = 1;
|
||||
} else {
|
||||
pak.bank = bank as u16;
|
||||
cart.rom_bank = bank as u16;
|
||||
}
|
||||
} else if address < 0x6000 {
|
||||
pak.ram_bank = value as u16;
|
||||
cart.ram_bank = value as u16;
|
||||
} else if address < 0x8000 {
|
||||
println!("MBC3 RTC latch")
|
||||
} else if (0xa000..0xc000).contains(&address) {
|
||||
if !pak.ram_enabled {
|
||||
if !cart.ram_enabled {
|
||||
return;
|
||||
}
|
||||
if pak.ram_bank < 0x8 {
|
||||
let banked_address = (pak.ram_bank << 13) | (address & 0x1FFF);
|
||||
if cart.ram_bank < 0x8 {
|
||||
let banked_address = (cart.ram_bank << 13) | (address & 0x1FFF);
|
||||
for i in 0..size {
|
||||
pak.ram[banked_address as usize + i] = pif_ram[data + i];
|
||||
cart.ram[banked_address as usize + i] = pif_ram[data + i];
|
||||
}
|
||||
} else {
|
||||
panic!("Unsupported ram bank {:x}", pak.ram_bank);
|
||||
panic!("Unsupported ram bank {:x}", cart.ram_bank);
|
||||
}
|
||||
} else {
|
||||
panic!("Unsupported write address {:x}", address);
|
||||
@ -49,34 +61,34 @@ fn write_mbc3(
|
||||
|
||||
fn read_mbc3(
|
||||
pif_ram: &mut [u8],
|
||||
pak: &mut device::controller::transferpak::TransferPak,
|
||||
cart: &mut device::controller::gbcart::GbCart,
|
||||
address: u16,
|
||||
data: usize,
|
||||
size: usize,
|
||||
) {
|
||||
if address < 0x4000 {
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = pak.rom[address as usize + i];
|
||||
pif_ram[data + i] = cart.rom[address as usize + i];
|
||||
}
|
||||
} else if address < 0x8000 {
|
||||
let banked_address = (pak.bank << 14) | (address & 0x3FFF);
|
||||
let banked_address = (cart.rom_bank << 14) | (address & 0x3FFF);
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = pak.rom[banked_address as usize + i];
|
||||
pif_ram[data + i] = cart.rom[banked_address as usize + i];
|
||||
}
|
||||
} else if address < 0xc000 {
|
||||
if !pak.ram_enabled {
|
||||
if !cart.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);
|
||||
if cart.ram_bank < 0x8 {
|
||||
let banked_address = (cart.ram_bank << 13) | (address & 0x1FFF);
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = pak.ram[banked_address as usize + i];
|
||||
pif_ram[data + i] = cart.ram[banked_address as usize + i];
|
||||
}
|
||||
} else {
|
||||
panic!("Unsupported ram bank {:x}", pak.ram_bank);
|
||||
panic!("Unsupported ram bank {:x}", cart.ram_bank);
|
||||
}
|
||||
} else {
|
||||
panic!("Unsupported read address {:x}", address);
|
||||
@ -85,26 +97,28 @@ fn read_mbc3(
|
||||
|
||||
fn write_mbc5(
|
||||
pif_ram: &mut [u8],
|
||||
pak: &mut device::controller::transferpak::TransferPak,
|
||||
cart: &mut device::controller::gbcart::GbCart,
|
||||
address: u16,
|
||||
data: usize,
|
||||
size: usize,
|
||||
) {
|
||||
let value = pif_ram[data + size - 1];
|
||||
if address < 0x2000 {
|
||||
pak.ram_enabled = value & 0xf == 0xa;
|
||||
cart.ram_enabled = value & 0xf == 0xa;
|
||||
} else if address < 0x4000 {
|
||||
println!("Unknown MBC5 write address {:x}", address);
|
||||
} else if address < 0x6000 {
|
||||
pak.ram_bank = (value & 0xf) as u16;
|
||||
cart.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 {
|
||||
if !cart.ram_enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
let banked_address = (pak.ram_bank << 13) | (address & 0x1FFF);
|
||||
let banked_address = (cart.ram_bank << 13) | (address & 0x1FFF);
|
||||
for i in 0..size {
|
||||
pak.ram[banked_address as usize + i] = pif_ram[data + i];
|
||||
cart.ram[banked_address as usize + i] = pif_ram[data + i];
|
||||
}
|
||||
} else {
|
||||
panic!("Unsupported write address {:x}", address);
|
||||
@ -113,31 +127,31 @@ fn write_mbc5(
|
||||
|
||||
fn read_mbc5(
|
||||
pif_ram: &mut [u8],
|
||||
pak: &mut device::controller::transferpak::TransferPak,
|
||||
cart: &mut device::controller::gbcart::GbCart,
|
||||
address: u16,
|
||||
data: usize,
|
||||
size: usize,
|
||||
) {
|
||||
if address < 0x4000 {
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = pak.rom[address as usize + i];
|
||||
pif_ram[data + i] = cart.rom[address as usize + i];
|
||||
}
|
||||
} else if address < 0x8000 {
|
||||
let banked_address = (pak.bank << 14) | (address & 0x3FFF);
|
||||
let banked_address = (cart.rom_bank << 14) | (address & 0x3FFF);
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = pak.rom[banked_address as usize + i];
|
||||
pif_ram[data + i] = cart.rom[banked_address as usize + i];
|
||||
}
|
||||
} else if address < 0xc000 {
|
||||
if !pak.ram_enabled {
|
||||
} else if (0xa000..0xc000).contains(&address) {
|
||||
if !cart.ram_enabled {
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = 0xff;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let banked_address = (pak.ram_bank << 13) | (address & 0x1FFF);
|
||||
let banked_address = (cart.ram_bank << 13) | (address & 0x1FFF);
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = pak.ram[banked_address as usize + i];
|
||||
pif_ram[data + i] = cart.ram[banked_address as usize + i];
|
||||
}
|
||||
} else {
|
||||
panic!("Unsupported read address {:x}", address);
|
||||
@ -146,30 +160,39 @@ fn read_mbc5(
|
||||
|
||||
pub fn read(
|
||||
pif_ram: &mut [u8],
|
||||
pak: &mut device::controller::transferpak::TransferPak,
|
||||
cart: &mut device::controller::gbcart::GbCart,
|
||||
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),
|
||||
if !cart.enabled {
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = 0x00;
|
||||
}
|
||||
return;
|
||||
}
|
||||
match cart.cart_type {
|
||||
CartType::MBC3RamBatt => read_mbc3(pif_ram, cart, address, data, size),
|
||||
CartType::MBC3RamBattRtc => read_mbc3(pif_ram, cart, address, data, size),
|
||||
CartType::MBC5RamBatt => read_mbc5(pif_ram, cart, address, data, size),
|
||||
_ => panic!("Unsupported cart type"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(
|
||||
pif_ram: &mut [u8],
|
||||
pak: &mut device::controller::transferpak::TransferPak,
|
||||
cart: &mut device::controller::gbcart::GbCart,
|
||||
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),
|
||||
if !cart.enabled {
|
||||
return;
|
||||
}
|
||||
match cart.cart_type {
|
||||
CartType::MBC3RamBatt => write_mbc3(pif_ram, cart, address, data, size),
|
||||
CartType::MBC3RamBattRtc => write_mbc3(pif_ram, cart, address, data, size),
|
||||
CartType::MBC5RamBatt => write_mbc5(pif_ram, cart, address, data, size),
|
||||
_ => panic!("Unsupported cart type"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,15 +3,9 @@ use crate::device;
|
||||
#[derive(Default, serde::Serialize, serde::Deserialize)]
|
||||
pub struct TransferPak {
|
||||
pub enabled: bool,
|
||||
pub cart_enabled: bool,
|
||||
pub reset_state: 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 cart: device::controller::gbcart::GbCart,
|
||||
}
|
||||
|
||||
pub fn read(device: &mut device::Device, channel: usize, address: u16, data: usize, size: usize) {
|
||||
@ -38,7 +32,7 @@ pub fn read(device: &mut device::Device, channel: usize, address: u16, data: usi
|
||||
match address >> 12 {
|
||||
0xB => {
|
||||
let mut value = 0;
|
||||
if pak.cart_enabled {
|
||||
if pak.cart.enabled {
|
||||
value |= 1 << 0;
|
||||
}
|
||||
value |= (pak.reset_state & 3) << 2;
|
||||
@ -46,11 +40,11 @@ pub fn read(device: &mut device::Device, channel: usize, address: u16, data: usi
|
||||
value |= 1 << 7;
|
||||
}
|
||||
|
||||
if pak.cart_enabled && pak.reset_state == 3 {
|
||||
if pak.cart.enabled && pak.reset_state == 3 {
|
||||
pak.reset_state = 2
|
||||
} else if !pak.cart_enabled && pak.reset_state == 2 {
|
||||
} else if !pak.cart.enabled && pak.reset_state == 2 {
|
||||
pak.reset_state = 1
|
||||
} else if !pak.cart_enabled && pak.reset_state == 1 {
|
||||
} else if !pak.cart.enabled && pak.reset_state == 1 {
|
||||
pak.reset_state = 0
|
||||
}
|
||||
for i in 0..size {
|
||||
@ -60,7 +54,7 @@ pub fn read(device: &mut device::Device, channel: usize, address: u16, data: usi
|
||||
0xC..=0xF => {
|
||||
device::controller::gbcart::read(
|
||||
&mut device.pif.ram,
|
||||
pak,
|
||||
&mut pak.cart,
|
||||
(address & 0x3fff) | ((pak.bank & 0x3) * 0x4000),
|
||||
data,
|
||||
size,
|
||||
@ -84,8 +78,8 @@ pub fn write(device: &mut device::Device, channel: usize, address: u16, data: us
|
||||
}
|
||||
0x84 => {
|
||||
if !pak.enabled {
|
||||
pak.bank = 0;
|
||||
pak.cart_enabled = false;
|
||||
pak.bank = 3;
|
||||
pak.cart.enabled = false;
|
||||
pak.reset_state = 0;
|
||||
}
|
||||
pak.enabled = true;
|
||||
@ -110,19 +104,23 @@ pub fn write(device: &mut device::Device, channel: usize, address: u16, data: us
|
||||
}
|
||||
0xB => {
|
||||
if value & 1 != 0 {
|
||||
if !pak.cart_enabled {
|
||||
if !pak.cart.enabled {
|
||||
pak.reset_state = 3;
|
||||
pak.cart_type = device::controller::gbcart::get_cart_type(pak.rom[0x147]);
|
||||
pak.cart.rom_bank = 1;
|
||||
pak.cart.ram_bank = 0;
|
||||
pak.cart.ram_enabled = false;
|
||||
pak.cart.cart_type =
|
||||
device::controller::gbcart::get_cart_type(pak.cart.rom[0x147]);
|
||||
}
|
||||
pak.cart_enabled = true;
|
||||
pak.cart.enabled = true;
|
||||
} else {
|
||||
pak.cart_enabled = false;
|
||||
pak.cart.enabled = false;
|
||||
}
|
||||
}
|
||||
0xC..=0xF => {
|
||||
device::controller::gbcart::write(
|
||||
&mut device.pif.ram,
|
||||
pak,
|
||||
&mut pak.cart,
|
||||
(address & 0x3fff) | ((pak.bank & 0x3) * 0x4000),
|
||||
data,
|
||||
size,
|
||||
|
||||
@ -110,11 +110,11 @@ pub fn load_savestate(device: &mut device::Device) {
|
||||
|
||||
let mut tpak_rom = [vec![], vec![], vec![], vec![]];
|
||||
for (i, item) in tpak_rom.iter_mut().enumerate() {
|
||||
*item = device.transferpaks[i].rom.clone();
|
||||
*item = device.transferpaks[i].cart.rom.clone();
|
||||
}
|
||||
device.transferpaks = state.transferpaks;
|
||||
for (i, item) in tpak_rom.iter().enumerate() {
|
||||
device.transferpaks[i].rom = item.clone();
|
||||
device.transferpaks[i].cart.rom = item.clone();
|
||||
}
|
||||
|
||||
device::memory::init(device);
|
||||
|
||||
Reference in New Issue
Block a user