sram support (#5)

* sram support

* more
This commit is contained in:
Logan McNaughton 2023-10-05 11:43:13 -06:00 committed by GitHub
parent 7dc0a3902a
commit b7d133cb37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 244 additions and 29 deletions

View File

@ -47,7 +47,6 @@ pub struct Device {
ai: ai::Ai,
si: si::Si,
ri: ri::Ri,
pub game: String,
}
impl Device {
@ -60,7 +59,6 @@ impl Device {
byte_swap = 3;
}
Device {
game: String::new(),
ui: ui::Ui::new(),
byte_swap: byte_swap,
cpu: cpu::Cpu {

View File

@ -8,8 +8,7 @@ pub const JCMD_RESET: u8 = 0xff;
//pub const JDT_AF_RTC: u16 = 0x1000; /* RTC */
pub const JDT_EEPROM_4K: u16 = 0x8000; /* 4k EEPROM */
//pub const JDT_EEPROM_16K: u16 = 0xc000; /* 16k EEPROM */
pub const EEPROM_TYPE: u16 = JDT_EEPROM_4K; // todo, support 16k eeprom
pub const JDT_EEPROM_16K: u16 = 0xc000; /* 16k EEPROM */
pub const EEPROM_BLOCK_SIZE: usize = 8;
pub fn process(device: &mut device::Device, channel: usize) {
@ -18,9 +17,19 @@ pub fn process(device: &mut device::Device, channel: usize) {
match cmd {
JCMD_RESET => { /* reset */ }
JCMD_STATUS => {
device.pif.ram[device.pif.channels[channel].rx_buf.unwrap()] = EEPROM_TYPE as u8;
let eeprom_type;
if device
.ui
.save_type
.contains(&ui::storage::SaveTypes::Eeprom16k)
{
eeprom_type = JDT_EEPROM_16K;
} else {
eeprom_type = JDT_EEPROM_4K;
}
device.pif.ram[device.pif.channels[channel].rx_buf.unwrap()] = eeprom_type as u8;
device.pif.ram[device.pif.channels[channel].rx_buf.unwrap() + 1] =
(EEPROM_TYPE >> 8) as u8;
(eeprom_type >> 8) as u8;
device.pif.ram[device.pif.channels[channel].rx_buf.unwrap() + 2] = 0;
}
JCMD_EEPROM_READ => {
@ -45,14 +54,16 @@ pub fn process(device: &mut device::Device, channel: usize) {
pub fn eeprom_read_block(device: &mut device::Device, block: usize, offset: usize) {
let address = device.pif.ram[block as usize] as usize * EEPROM_BLOCK_SIZE;
if address < device.ui.saves.eeprom.len() {
device.pif.ram[offset..offset + EEPROM_BLOCK_SIZE]
.copy_from_slice(&device.ui.saves.eeprom[address..address + EEPROM_BLOCK_SIZE]);
} else {
for i in 0..EEPROM_BLOCK_SIZE {
device.pif.ram[offset + i] = 0;
}
if address + EEPROM_BLOCK_SIZE > device.ui.saves.eeprom.len() {
device
.ui
.saves
.eeprom
.resize(address + EEPROM_BLOCK_SIZE, 0)
}
device.pif.ram[offset..offset + EEPROM_BLOCK_SIZE]
.copy_from_slice(&device.ui.saves.eeprom[address..address + EEPROM_BLOCK_SIZE]);
}
pub fn eeprom_write_block(device: &mut device::Device, block: usize, offset: usize, status: usize) {
@ -71,5 +82,13 @@ pub fn eeprom_write_block(device: &mut device::Device, block: usize, offset: usi
device.pif.ram[status as usize] = 0x00;
ui::storage::write_save(&mut device.ui, ui::storage::SaveTypes::Eeprom);
let mut save_type = ui::storage::SaveTypes::Eeprom4k;
if device
.ui
.save_type
.contains(&ui::storage::SaveTypes::Eeprom16k)
{
save_type = ui::storage::SaveTypes::Eeprom16k
}
ui::storage::write_save(&mut device.ui, save_type);
}

View File

@ -99,7 +99,8 @@ pub fn init(device: &mut device::Device, rom_file: Vec<u8>) {
let data =
std::str::from_utf8(&device.cart.rom[0x20 as usize..(0x20 + 0x14) as usize]).unwrap();
let hash = calculate_hash(&device.cart.rom);
device.game = format!("{}-{}", data.trim(), hash);
device.ui.game_name = format!("{}-{}", data.trim(), hash);
device.ui.game_id = String::from_utf8(device.cart.rom[0x3B..0x3E].to_vec()).unwrap();
}
pub fn set_system_region(device: &mut device::Device, country: u8) {

View File

@ -94,8 +94,8 @@ pub fn get_handler(address: u32) -> PiHandler {
handler.write = device::cart_rom::dma_write;
}
} else if address >= device::memory::MM_DOM2_ADDR2 as u32 {
panic!("sram handler")
//RW(cart, cart_dom2);
handler.read = device::sram::dma_read;
handler.write = device::sram::dma_write;
} else {
panic!("unknown pi handler")
}

View File

@ -1,13 +1,101 @@
use crate::device;
use crate::ui;
pub const SRAM_MASK: usize = 0xFFFF;
pub fn read_mem(
_device: &mut device::Device,
_address: u64,
device: &mut device::Device,
address: u64,
_access_size: device::memory::AccessSize,
) -> u32 {
panic!("sream read");
if device.ui.save_type.contains(&ui::storage::SaveTypes::Sram) {
let masked_address = address as usize & SRAM_MASK;
if masked_address + 4 > device.ui.saves.sram.len() {
device.ui.saves.sram.resize(masked_address + 4, 0)
}
return u32::from_be_bytes(
device.ui.saves.sram[masked_address..masked_address + 4]
.try_into()
.unwrap(),
);
} else {
panic!("flash read")
}
}
pub fn write_mem(_device: &mut device::Device, _address: u64, _value: u32, _mask: u32) {
panic!("sram write");
pub fn write_mem(device: &mut device::Device, address: u64, value: u32, mask: u32) {
if device.ui.save_type.contains(&ui::storage::SaveTypes::Sram) {
let masked_address = address as usize & SRAM_MASK;
if masked_address + 4 > device.ui.saves.sram.len() {
device.ui.saves.sram.resize(masked_address + 4, 0)
}
let mut data = u32::from_be_bytes(
device.ui.saves.sram[masked_address..masked_address + 4]
.try_into()
.unwrap(),
);
device::memory::masked_write_32(&mut data, value, mask);
device.ui.saves.sram[masked_address..masked_address + 4]
.copy_from_slice(&data.to_be_bytes());
ui::storage::write_save(&mut device.ui, ui::storage::SaveTypes::Sram);
} else {
panic!("flash write")
}
}
// cart is big endian, rdram is native endian
pub fn dma_read(device: &mut device::Device, cart_addr: u32, dram_addr: u32, length: u32) -> u64 {
if device.ui.save_type.contains(&ui::storage::SaveTypes::Sram) {
let mut i = dram_addr & device::rdram::RDRAM_MASK as u32;
let mut j = cart_addr & SRAM_MASK as u32;
if (cart_addr + length) as usize > device.ui.saves.sram.len() {
device
.ui
.saves
.sram
.resize((cart_addr + length) as usize, 0)
}
while j < cart_addr + length {
device.ui.saves.sram[j as usize] = device.rdram.mem[i as usize ^ device.byte_swap];
i += 1;
j += 1;
}
ui::storage::write_save(&mut device.ui, ui::storage::SaveTypes::Sram);
return device::pi::calculate_cycles(device, 2, length);
} else {
panic!("flash dma read")
}
}
// cart is big endian, rdram is native endian
pub fn dma_write(device: &mut device::Device, cart_addr: u32, dram_addr: u32, length: u32) -> u64 {
if device.ui.save_type.contains(&ui::storage::SaveTypes::Sram) {
let mut i = dram_addr & device::rdram::RDRAM_MASK as u32;
let mut j = cart_addr & SRAM_MASK as u32;
if (cart_addr + length) as usize > device.ui.saves.sram.len() {
device
.ui
.saves
.sram
.resize((cart_addr + length) as usize, 0)
}
while i < dram_addr + length {
device.rdram.mem[i as usize ^ device.byte_swap] = device.ui.saves.sram[j as usize];
i += 1;
j += 1;
}
return device::pi::calculate_cycles(device, 2, length);
} else {
panic!("flash dma write")
}
}

View File

@ -27,7 +27,7 @@ fn main() {
device::vi::init(&mut device);
device::cpu::init(&mut device);
ui::storage::init(&mut device.ui, device.game.as_str());
ui::storage::init(&mut device.ui);
ui::storage::load_saves(&mut device.ui);
device::cpu::run(&mut device);

View File

@ -4,6 +4,9 @@ pub mod storage;
pub mod video;
pub struct Ui {
pub save_type: Vec<storage::SaveTypes>,
pub game_name: String,
pub game_id: String,
pub paths: storage::Paths,
pub saves: storage::Saves,
pub sdl_context: Option<sdl2::Sdl>,
@ -25,10 +28,20 @@ impl Ui {
.build()
.unwrap();
Ui {
save_type: vec![],
game_name: String::new(),
game_id: String::new(),
paths: storage::Paths {
eep_file_path: std::path::PathBuf::new(),
fla_file_path: std::path::PathBuf::new(),
sra_file_path: std::path::PathBuf::new(),
pak_file_path: std::path::PathBuf::new(),
},
saves: storage::Saves {
eeprom: Vec::new(),
sram: Vec::new(),
flash: Vec::new(),
},
saves: storage::Saves { eeprom: Vec::new() },
sdl_context: Some(sdl_context),
video_subsystem: Some(video_subsystem),
audio_subsystem: Some(audio_subsystem),

View File

@ -1,18 +1,86 @@
use crate::ui;
#[derive(PartialEq)]
pub enum SaveTypes {
Eeprom,
Eeprom4k,
Eeprom16k,
Sram,
Flash,
}
pub struct Paths {
pub eep_file_path: std::path::PathBuf,
pub sra_file_path: std::path::PathBuf,
pub fla_file_path: std::path::PathBuf,
pub pak_file_path: std::path::PathBuf,
}
pub struct Saves {
pub eeprom: Vec<u8>,
pub sram: Vec<u8>,
pub flash: Vec<u8>,
}
pub fn init(ui: &mut ui::Ui, game_name: &str) {
pub fn get_save_type(game_id: &str) -> Vec<SaveTypes> {
match game_id {
"NB7" | // Banjo-Tooie [Banjo to Kazooie no Daiboken 2 (J)]
"NGT" | // City Tour GrandPrix - Zen Nihon GT Senshuken
"NFU" | // Conker's Bad Fur Day
"NCW" | // Cruis'n World
"NCZ" | // Custom Robo V2
"ND6" | // Densha de Go! 64
"NDO" | // Donkey Kong 64
"ND2" | // Doraemon 2: Nobita to Hikari no Shinden
"N3D" | // Doraemon 3: Nobita no Machi SOS!
"NMX" | // Excitebike 64
"NGC" | // GT 64: Championship Edition
"NIM" | // Ide Yosuke no Mahjong Juku
"NNB" | // Kobe Bryant in NBA Courtside
"NMV" | // Mario Party 3
"NM8" | // Mario Tennis
"NEV" | // Neon Genesis Evangelion
"NPP" | // Parlor! Pro 64: Pachinko Jikki Simulation Game
"NUB" | // PD Ultraman Battle Collection 64
"NPD" | // Perfect Dark
"NRZ" | // Ridge Racer 64
"NR7" | // Robot Poncots 64: 7tsu no Umi no Caramel
"NEP" | // Star Wars Episode I: Racer
"NYS" // Yoshi's Story
=> {
return vec![SaveTypes::Eeprom16k]
}
"NCC" | // Command & Conquer
"NDA" | // Derby Stallion 64
"NAF" | // Doubutsu no Mori
"NJF" | // Jet Force Gemini [Star Twins (J)]
"NKJ" | // Ken Griffey Jr.'s Slugfest
"NZS" | // Legend of Zelda: Majora's Mask [Zelda no Densetsu - Mujura no Kamen (J)]
"NM6" | // Mega Man 64
"NCK" | // NBA Courtside 2 featuring Kobe Bryant
"NMQ" | // Paper Mario
"NPN" | // Pokemon Puzzle League
"NPF" | // Pokemon Snap [Pocket Monsters Snap (J)]
"NPO" | // Pokemon Stadium
"CP2" | // Pocket Monsters Stadium 2 (J)
"NP3" | // Pokemon Stadium 2 [Pocket Monsters Stadium - Kin Gin (J)]
"NRH" | // Rockman Dash - Hagane no Boukenshin (J)
"NSQ" | // StarCraft 64
"NT9" | // Tigger's Honey Hunt
"NW4" | // WWF No Mercy
"NDP" // Dinosaur Planet (Unlicensed)
=>{
return vec![SaveTypes::Flash]
}
_ => {
return vec![SaveTypes::Eeprom4k, SaveTypes::Sram]
}
}
}
pub fn init(ui: &mut ui::Ui) {
let id = ui.game_id.as_str();
ui.save_type = get_save_type(id);
let mut base_path = dirs::data_dir().unwrap();
base_path.push("gopher64");
base_path.push("saves");
@ -22,8 +90,20 @@ pub fn init(ui: &mut ui::Ui, game_name: &str) {
panic!("could not create save dir")
}
ui.paths.eep_file_path = base_path;
ui.paths.eep_file_path.push(game_name.to_owned() + ".eep");
ui.paths.eep_file_path = base_path.clone();
ui.paths
.eep_file_path
.push(ui.game_name.to_owned() + ".eep");
ui.paths.sra_file_path = base_path.clone();
ui.paths
.sra_file_path
.push(ui.game_name.to_owned() + ".sra");
ui.paths.fla_file_path = base_path.clone();
ui.paths
.fla_file_path
.push(ui.game_name.to_owned() + ".fla");
}
pub fn load_saves(ui: &mut ui::Ui) {
@ -31,16 +111,32 @@ pub fn load_saves(ui: &mut ui::Ui) {
if eep.is_ok() {
ui.saves.eeprom = eep.unwrap();
}
let sra = std::fs::read(&mut ui.paths.sra_file_path);
if sra.is_ok() {
ui.saves.sram = sra.unwrap();
}
let fla = std::fs::read(&mut ui.paths.fla_file_path);
if fla.is_ok() {
ui.saves.flash = fla.unwrap();
}
}
pub fn write_save(ui: &mut ui::Ui, save_type: SaveTypes) {
let path: &std::path::Path;
let data: &Vec<u8>;
match save_type {
SaveTypes::Eeprom => {
SaveTypes::Eeprom4k | SaveTypes::Eeprom16k => {
path = ui.paths.eep_file_path.as_ref();
data = ui.saves.eeprom.as_ref();
}
SaveTypes::Sram => {
path = ui.paths.sra_file_path.as_ref();
data = ui.saves.sram.as_ref();
}
SaveTypes::Flash => {
path = ui.paths.fla_file_path.as_ref();
data = ui.saves.flash.as_ref();
}
}
let result = std::fs::write(path, data);
if result.is_err() {