diff --git a/Cargo.toml b/Cargo.toml index 8aa7590..353e2e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +dirs = "5.0" sha2 = "0.10" sdl2-sys = { git = "https://github.com/Rust-SDL2/rust-sdl2.git" } diff --git a/src/device.rs b/src/device.rs index c5cf0a6..d9be928 100644 --- a/src/device.rs +++ b/src/device.rs @@ -47,7 +47,7 @@ pub struct Device { ai: ai::Ai, si: si::Si, ri: ri::Ri, - game: String, + pub game: String, } impl Device { diff --git a/src/device/cart.rs b/src/device/cart.rs index 5d1dde2..bfeb53b 100644 --- a/src/device/cart.rs +++ b/src/device/cart.rs @@ -1,4 +1,5 @@ use crate::device; +use crate::ui; pub const JCMD_STATUS: u8 = 0x00; pub const JCMD_EEPROM_READ: u8 = 0x04; @@ -9,7 +10,7 @@ pub const JCMD_RESET: u8 = 0xff; 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 EEPROM_BLOCK_SIZE: usize = 8; +pub const EEPROM_BLOCK_SIZE: usize = 8; pub fn process(device: &mut device::Device, channel: usize) { let cmd = device.pif.ram[device.pif.channels[channel].tx_buf.unwrap()]; @@ -41,15 +42,34 @@ pub fn process(device: &mut device::Device, channel: usize) { } } -pub fn eeprom_read_block(_device: &mut device::Device, _block: usize, _data: usize) { - panic!("eeprom read") +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; + } + } } -pub fn eeprom_write_block( - _device: &mut device::Device, - _block: usize, - _data: usize, - _status: usize, -) { - panic!("eeprom write") +pub fn eeprom_write_block(device: &mut device::Device, block: usize, offset: usize, status: usize) { + let address = device.pif.ram[block as usize] as usize * EEPROM_BLOCK_SIZE; + + if address + EEPROM_BLOCK_SIZE > device.ui.saves.eeprom.len() { + device + .ui + .saves + .eeprom + .resize(address + EEPROM_BLOCK_SIZE, 0) + } + + device.ui.saves.eeprom[address..address + EEPROM_BLOCK_SIZE] + .copy_from_slice(&device.pif.ram[offset..offset + EEPROM_BLOCK_SIZE]); + + device.pif.ram[status as usize] = 0x00; + + ui::storage::write_save(&mut device.ui, ui::storage::SaveTypes::Eeprom); } diff --git a/src/main.rs b/src/main.rs index 3c3cad5..5a0af97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,5 +26,9 @@ fn main() { device::rdp::init(&mut device); device::vi::init(&mut device); device::cpu::init(&mut device); + + ui::storage::init(&mut device.ui, device.game.as_str()); + ui::storage::load_saves(&mut device.ui); + device::cpu::run(&mut device); } diff --git a/src/ui.rs b/src/ui.rs index f0b4f16..dbcbb6f 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,8 +1,11 @@ pub mod audio; pub mod input; +pub mod storage; pub mod video; pub struct Ui { + pub paths: storage::Paths, + pub saves: storage::Saves, pub sdl_context: Option, pub video_subsystem: Option, pub audio_subsystem: Option, @@ -22,6 +25,10 @@ impl Ui { .build() .unwrap(); Ui { + paths: storage::Paths { + eep_file_path: std::path::PathBuf::new(), + }, + saves: storage::Saves { eeprom: Vec::new() }, sdl_context: Some(sdl_context), video_subsystem: Some(video_subsystem), audio_subsystem: Some(audio_subsystem), diff --git a/src/ui/storage.rs b/src/ui/storage.rs new file mode 100644 index 0000000..3cc4db5 --- /dev/null +++ b/src/ui/storage.rs @@ -0,0 +1,53 @@ +use crate::ui; + +pub enum SaveTypes { + Eeprom, +} + +pub struct Paths { + pub eep_file_path: std::path::PathBuf, +} + +pub struct Saves { + pub eeprom: Vec, +} + +pub fn init(ui: &mut ui::Ui, game_name: &str) { + let mut base_path = dirs::data_dir().unwrap(); + base_path.push("gopher64"); + base_path.push("saves"); + + let result = std::fs::create_dir_all(base_path.clone()); + if result.is_err() { + panic!("could not create save dir") + } + + ui.paths.eep_file_path = base_path; + ui.paths.eep_file_path.push(game_name.to_owned() + ".eep"); +} + +pub fn load_saves(ui: &mut ui::Ui) { + let eep = std::fs::read(&mut ui.paths.eep_file_path); + if eep.is_ok() { + ui.saves.eeprom = eep.unwrap(); + } +} + +pub fn write_save(ui: &mut ui::Ui, save_type: SaveTypes) { + let path: &std::path::Path; + let data: &Vec; + match save_type { + SaveTypes::Eeprom => { + path = ui.paths.eep_file_path.as_ref(); + data = ui.saves.eeprom.as_ref(); + } + } + let result = std::fs::write(path, data); + if result.is_err() { + panic!( + "could not save {} {}", + path.display(), + result.err().unwrap() + ) + } +}