mempak support (#14)

* mempak support

* fix

* read and write

* format func

* formatting

* finish
This commit is contained in:
Logan McNaughton
2023-10-12 10:19:49 -06:00
committed by GitHub
parent e9ef941707
commit 0224d75bea
6 changed files with 167 additions and 10 deletions
+2
View File
@@ -15,6 +15,7 @@ pub mod exceptions;
pub mod fpu_instructions;
pub mod is_viewer;
pub mod memory;
pub mod mempak;
pub mod mi;
pub mod pi;
pub mod pif;
@@ -154,6 +155,7 @@ impl Device {
rx: None,
rx_buf: None,
process: None,
pak_handler: None,
}; 5],
},
cart: cart_rom::Cart {
+49 -10
View File
@@ -18,9 +18,16 @@ pub const JDT_JOY_ABS_COUNTERS: u16 = 0x0001; /* joystick with absolute coordina
pub const JDT_JOY_PORT: u16 = 0x0004; /* has port for external paks */
//pub const JDT_VRU: u16 = 0x0100; /* VRU */
pub const PAK_CHUNK_SIZE: usize = 0x20;
pub const CONT_STATUS: u8 = 0;
pub const CONT_STATUS_PAK_NOT_PRESENT: u8 = 0;
pub const CONT_STATUS_PAK_PRESENT: u8 = 1;
pub const CONT_FLAVOR: u16 = JDT_JOY_ABS_COUNTERS | JDT_JOY_PORT;
#[derive(Copy, Clone)]
pub struct PakHandler {
pub read: fn(&mut device::Device, usize, u16, usize, usize),
pub write: fn(&mut device::Device, usize, u16, usize, usize),
}
pub fn process(device: &mut device::Device, channel: usize) {
let cmd = device.pif.ram[device.pif.channels[channel].tx_buf.unwrap()];
@@ -30,7 +37,13 @@ pub fn process(device: &mut device::Device, channel: usize) {
device.pif.ram[device.pif.channels[channel].rx_buf.unwrap()] = CONT_FLAVOR as u8;
device.pif.ram[device.pif.channels[channel].rx_buf.unwrap() + 1] =
(CONT_FLAVOR >> 8) as u8;
device.pif.ram[device.pif.channels[channel].rx_buf.unwrap() + 2] = CONT_STATUS;
if device.pif.channels[channel].pak_handler.is_none() {
device.pif.ram[device.pif.channels[channel].rx_buf.unwrap() + 2] =
CONT_STATUS_PAK_NOT_PRESENT;
} else {
device.pif.ram[device.pif.channels[channel].rx_buf.unwrap() + 2] =
CONT_STATUS_PAK_PRESENT;
}
}
JCMD_CONTROLLER_READ => {
let offset = device.pif.channels[channel].rx_buf.unwrap();
@@ -42,29 +55,55 @@ pub fn process(device: &mut device::Device, channel: usize) {
device.pif.channels[channel].tx_buf.unwrap() + 1,
device.pif.channels[channel].rx_buf.unwrap(),
device.pif.channels[channel].rx_buf.unwrap() + 32,
channel,
),
JCMD_PAK_WRITE => pak_write_block(
device,
device.pif.channels[channel].tx_buf.unwrap() + 1,
device.pif.channels[channel].tx_buf.unwrap() + 3,
device.pif.channels[channel].rx_buf.unwrap(),
channel,
),
_ => println!("unknown controller command {}", cmd),
}
}
pub fn pak_read_block(device: &mut device::Device, _addr_acrc: usize, data: usize, dcrc: usize) {
//let address = (device.pif.ram[addr_acrc] << 8) | (device.pif.ram[addr_acrc + 1] & 0xe0);
pub fn pak_read_block(
device: &mut device::Device,
addr_acrc: usize,
data: usize,
dcrc: usize,
channel: usize,
) {
let address =
(device.pif.ram[addr_acrc] as u16) << 8 | (device.pif.ram[addr_acrc + 1] & 0xe0) as u16;
let handler = device.pif.channels[channel].pak_handler;
//TODO: paks
device.pif.ram[dcrc] = !pak_data_crc(device, data, PAK_CHUNK_SIZE)
if !handler.is_none() {
(handler.unwrap().read)(device, channel, address, data, PAK_CHUNK_SIZE);
device.pif.ram[dcrc] = pak_data_crc(device, data, PAK_CHUNK_SIZE)
} else {
device.pif.ram[dcrc] = !pak_data_crc(device, data, PAK_CHUNK_SIZE)
}
}
pub fn pak_write_block(device: &mut device::Device, _addr_acrc: usize, data: usize, dcrc: usize) {
//let address = (device.pif.ram[addr_acrc] << 8) | (device.pif.ram[addr_acrc + 1] & 0xe0);
pub fn pak_write_block(
device: &mut device::Device,
addr_acrc: usize,
data: usize,
dcrc: usize,
channel: usize,
) {
let address =
(device.pif.ram[addr_acrc] as u16) << 8 | (device.pif.ram[addr_acrc + 1] & 0xe0) as u16;
let handler = device.pif.channels[channel].pak_handler;
//TODO: paks
device.pif.ram[dcrc] = !pak_data_crc(device, data, PAK_CHUNK_SIZE)
if !handler.is_none() {
(handler.unwrap().write)(device, channel, address, data, PAK_CHUNK_SIZE);
device.pif.ram[dcrc] = pak_data_crc(device, data, PAK_CHUNK_SIZE)
} else {
device.pif.ram[dcrc] = !pak_data_crc(device, data, PAK_CHUNK_SIZE)
}
}
pub fn pak_data_crc(device: &mut device::Device, data_offset: usize, size: usize) -> u8 {
+93
View File
@@ -0,0 +1,93 @@
use crate::device;
use crate::ui;
pub const MEMPAK_SIZE: usize = 0x8000;
pub const MPK_PAGE_SIZE: usize = 256;
pub fn format_mempak(device: &mut device::Device) {
if device.ui.saves.mempak.len() < MEMPAK_SIZE * 4 {
device.ui.saves.mempak.resize(MEMPAK_SIZE * 4, 0);
let page_0: [u8; MPK_PAGE_SIZE] = [
/* Label area */
0x81, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f, /* Main ID area */
0xff, 0xff, 0xff, 0xff, 0x05, 0x1a, 0x5f, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff,
0x66, 0x25, 0x99, 0xcd, /* Unused */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, /* ID area backup #1 */
0xff, 0xff, 0xff, 0xff, 0x05, 0x1a, 0x5f, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff,
0x66, 0x25, 0x99, 0xcd, /* ID area backup #2 */
0xff, 0xff, 0xff, 0xff, 0x05, 0x1a, 0x5f, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff,
0x66, 0x25, 0x99, 0xcd, /* Unused */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, /* ID area backup #3 */
0xff, 0xff, 0xff, 0xff, 0x05, 0x1a, 0x5f, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff,
0x66, 0x25, 0x99, 0xcd, /* Unused */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
];
for i in 0..4 {
let offset = i * MEMPAK_SIZE;
/* Fill Page 0 with pre-initialized content */
device.ui.saves.mempak[offset..offset + MPK_PAGE_SIZE].copy_from_slice(&page_0);
/* Fill INODE page 1 and update it's checkum */
let start_page = 5;
for i in 1 * MPK_PAGE_SIZE..2 * start_page {
device.ui.saves.mempak[offset + i] = 0;
}
for i in (1 * MPK_PAGE_SIZE + 2 * start_page..2 * MPK_PAGE_SIZE).step_by(2) {
device.ui.saves.mempak[offset + i + 0] = 0x00;
device.ui.saves.mempak[offset + i + 1] = 0x03;
}
device.ui.saves.mempak[offset + (1 * MPK_PAGE_SIZE + 1)] = 0x71;
/* Page 2 is identical to page 1 */
let page1 = offset + 1 * MPK_PAGE_SIZE;
let page2 = offset + 2 * MPK_PAGE_SIZE;
let page1data = device.ui.saves.mempak[page1..page1 + MPK_PAGE_SIZE].to_vec();
device.ui.saves.mempak[page2..page2 + MPK_PAGE_SIZE].copy_from_slice(&page1data);
/* Remaining pages DIR+DATA (3...) are initialized with 0x00 */
for i in 3 * MPK_PAGE_SIZE..MEMPAK_SIZE - 3 * MPK_PAGE_SIZE {
device.ui.saves.mempak[offset + i] = 0;
}
}
}
}
pub fn read(device: &mut device::Device, channel: usize, address: u16, data: usize, size: usize) {
if (address as usize) < MEMPAK_SIZE {
format_mempak(device);
let offset = (channel * MEMPAK_SIZE) + address as usize;
device.pif.ram[data..data + size]
.copy_from_slice(&device.ui.saves.mempak[offset..offset + size])
} else {
for i in 0..size {
device.pif.ram[data + i] = 0;
}
}
}
pub fn write(device: &mut device::Device, channel: usize, address: u16, data: usize, size: usize) {
if (address as usize) < MEMPAK_SIZE {
format_mempak(device);
let offset = (channel * MEMPAK_SIZE) + address as usize;
device.ui.saves.mempak[offset..offset + size]
.copy_from_slice(&device.pif.ram[data..data + size]);
ui::storage::write_save(&mut device.ui, ui::storage::SaveTypes::Mempak);
}
}
+7
View File
@@ -14,6 +14,7 @@ pub struct PifChannel {
pub rx: Option<usize>,
pub rx_buf: Option<usize>,
pub process: Option<fn(&mut device::Device, usize)>,
pub pak_handler: Option<device::controller::PakHandler>,
}
pub const PIF_RAM_SIZE: usize = 64;
@@ -224,6 +225,12 @@ 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 {
read: device::mempak::read,
write: device::mempak::write,
};
device.pif.channels[0].pak_handler = Some(mempak_handler);
device.pif.channels[0].process = Some(device::controller::process);
device.pif.channels[4].process = Some(device::cart::process)
}
+1
View File
@@ -41,6 +41,7 @@ impl Ui {
eeprom: Vec::new(),
sram: Vec::new(),
flash: Vec::new(),
mempak: Vec::new(),
},
sdl_context: Some(sdl_context),
video_subsystem: Some(video_subsystem),
+15
View File
@@ -6,6 +6,7 @@ pub enum SaveTypes {
Eeprom16k,
Sram,
Flash,
Mempak,
}
pub struct Paths {
@@ -19,6 +20,7 @@ pub struct Saves {
pub eeprom: Vec<u8>,
pub sram: Vec<u8>,
pub flash: Vec<u8>,
pub mempak: Vec<u8>,
}
pub fn get_save_type(game_id: &str) -> Vec<SaveTypes> {
@@ -106,6 +108,11 @@ pub fn init(ui: &mut ui::Ui) {
ui.paths
.fla_file_path
.push(ui.game_name.to_owned() + ".fla");
ui.paths.pak_file_path = base_path.clone();
ui.paths
.pak_file_path
.push(ui.game_name.to_owned() + ".mpk");
}
pub fn load_saves(ui: &mut ui::Ui) {
@@ -121,6 +128,10 @@ pub fn load_saves(ui: &mut ui::Ui) {
if fla.is_ok() {
ui.saves.flash = fla.unwrap();
}
let mempak = std::fs::read(&mut ui.paths.pak_file_path);
if mempak.is_ok() {
ui.saves.mempak = mempak.unwrap();
}
}
pub fn write_save(ui: &mut ui::Ui, save_type: SaveTypes) {
@@ -139,6 +150,10 @@ pub fn write_save(ui: &mut ui::Ui, save_type: SaveTypes) {
path = ui.paths.fla_file_path.as_ref();
data = ui.saves.flash.as_ref();
}
SaveTypes::Mempak => {
path = ui.paths.pak_file_path.as_ref();
data = ui.saves.mempak.as_ref();
}
}
let result = std::fs::write(path, data);
if result.is_err() {