diff --git a/Cargo.lock b/Cargo.lock index 3987847..2dee673 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -178,9 +178,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97abf9f0eca9e52b7f81b945524e76710e6cb2366aead23b7d4fbf72e281f888" +checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453" dependencies = [ "cc", "cxxbridge-flags", @@ -190,9 +190,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc32cc5fea1d894b77d269ddb9f192110069a8a9c1f1d441195fba90553dea3" +checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0" dependencies = [ "cc", "codespan-reporting", @@ -205,15 +205,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca220e4794c934dc6b1207c3b42856ad4c302f2df1712e9f8d2eec5afaacf1f" +checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71" [[package]] name = "cxxbridge-macro" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b846f081361125bfc8dc9d3940c84e1fd83ba54bbca7b17cd29483c828be0704" +checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" dependencies = [ "proc-macro2", "quote", @@ -345,9 +345,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", "hashbrown", @@ -436,6 +436,7 @@ name = "m68k_emu" version = "0.1.0" dependencies = [ "anyhow", + "bitflags", "bitvec", "derive-try-from-primitive", "elf", diff --git a/Cargo.toml b/Cargo.toml index 5b6d5a9..eab2042 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] anyhow = "1.0.66" +bitflags = "1.3.2" bitvec = "1.0.0" derive-try-from-primitive = "1.0.0" elf = "0.7.0" diff --git a/src/storage.rs b/src/storage.rs index 0c0cb53..e1b46eb 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -1,62 +1,80 @@ -use std::{fmt::Display, fs::File, io::Read}; - -use anyhow::anyhow; -use human_repr::HumanCount; -use nullable_result::NullableResult; -use serde::Deserialize; -use toml::Value; - use crate::{ - card::{u32_get_be_byte, u32_set_be_byte, Card}, + card::{u16_get_be_byte, u32_get_be_byte, u32_set_be_byte, Card}, m68k::BusError, register, }; +use anyhow::anyhow; +use bitflags::bitflags; +use human_repr::HumanCount; +use nullable_result::NullableResult; +use serde::Deserialize; +use std::{ + collections::VecDeque, + fmt::Display, + fs::File, + io::{Read, Seek, SeekFrom}, +}; +use toml::Value; -const SECTOR_SIZE: usize = 256; +const SECTOR_SIZE: u64 = 512; #[derive(Deserialize)] struct Config { image: Option, } +bitflags! { + struct Status: u16 { + const BUSY = 0b00000001; + const DATA_READY = 0b00000010; + } +} + #[derive(Debug)] pub struct Storage { - data: Vec, + file: Option<(File, String)>, + read_data: VecDeque, sector: u32, - offset: usize, - file_name: Option, + count: u32, + status: Status, } +// Registers +// 0x0-0x4: Sector +// 0x4-0x8: Sector count +// 0x8-0xA: Command (W) / Status(R) +// 0xA-0xC: Data + impl Card for Storage { fn new(data: Value) -> anyhow::Result { let file_name = data.try_into::()?.image; - let mut data = Vec::new(); - if let Some(file_name) = file_name.as_ref() { - File::open(file_name) - .map_err(|e| anyhow!("Could not open disk image file {} ({})", file_name, e))? - .read_to_end(&mut data) - .map_err(|e| anyhow!("Failed to read disk image file {} ({})", file_name, e))?; - }; + let file = file_name + .as_ref() + .map(|file_name| { + File::open(file_name) + .map_err(|e| anyhow!("Could not open disk image file {} ({})", file_name, e)) + }) + .transpose()?; Ok(Self { - data, - file_name, + file: file.zip(file_name), + read_data: VecDeque::new(), sector: 0, - offset: 0, + count: 0, + status: Status::empty(), }) } fn read_byte_io(&mut self, address: u8) -> NullableResult { match address { 0x0..=0x3 => NullableResult::Ok(u32_get_be_byte(self.sector, address)), - 0x4 => { - let byte = self - .data - .get(self.sector as usize * SECTOR_SIZE + self.offset as usize) - .copied() - .unwrap_or(0); - self.offset += 1; - NullableResult::Ok(byte) + 0x4..=0x7 => NullableResult::Ok(u32_get_be_byte(self.count, address - 0x4)), + 0x8..=0x9 => NullableResult::Ok(u16_get_be_byte(self.status.bits(), address - 0x8)), + 0xA..=0xB => { + if self.read_data.len() == 1 { + self.status.set(Status::DATA_READY, false); + } + NullableResult::Ok(self.read_data.pop_front().unwrap_or(0)) } 0xFF => NullableResult::Ok(4), _ => NullableResult::Null, @@ -64,33 +82,40 @@ impl Card for Storage { } fn write_byte_io(&mut self, address: u8, data: u8) -> NullableResult<(), BusError> { - if let 0x0..=0x3 = address { - self.sector = u32_set_be_byte(self.sector, address, data); - self.offset = 0; + match address { + 0x0..=0x3 => { + self.sector = u32_set_be_byte(self.sector, address, data); + } + 0x4..=0x7 => { + self.count = u32_set_be_byte(self.count, address - 0x4, data); + } + // More commands to be added later + #[allow(clippy::single_match)] + 0x9 => match data { + 0x0 => { + if let Some((file, _)) = &mut self.file { + file.seek(SeekFrom::Start(self.sector as u64 * SECTOR_SIZE)) + .unwrap(); + let mut buf = Vec::new(); + buf.resize(self.count as usize * SECTOR_SIZE as usize, 0); + file.read_exact(&mut buf).unwrap(); + self.read_data.extend(buf); + self.status.set(Status::DATA_READY, true); + } + } + _ => (), + }, + _ => (), } NullableResult::Ok(()) } fn cmd(&mut self, cmd: &[&str]) -> anyhow::Result<()> { if cmd[0] == "load" && cmd.len() >= 2 { - let mut file = File::open(cmd[1]) + let file = File::open(cmd[1]) .map_err(|e| anyhow!("Couldn't open disk image file {} ({})", cmd[1], e))?; - self.data.clear(); - file.read_to_end(&mut self.data) - .map_err(|e| anyhow!("Failed to read disk image file {} ({})", cmd[1], e))?; - self.file_name = Some(cmd[1].into()); + self.file = Some((file, cmd[1].into())); println!("Read disk image file {}", cmd[1]); - } else if cmd[0] == "reload" { - if let Some(file_name) = &self.file_name { - let mut file = File::open(cmd[1]) - .map_err(|e| anyhow!("Couldn't open disk image file {} ({})", cmd[1], e))?; - self.data.clear(); - file.read_to_end(&mut self.data) - .map_err(|e| anyhow!("Failed to read disk image file {} ({})", cmd[1], e))?; - println!("Reloaded disk image file {}", file_name); - } else { - println!("No disk image file to reload"); - } } Ok(()) } @@ -99,11 +124,11 @@ impl Card for Storage { impl Display for Storage { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("Storage card, ")?; - if let Some(name) = self.file_name.as_ref() { + if let Some((file, file_name)) = self.file.as_ref() { f.write_fmt(format_args!( "disk image {} ({})", - name, - self.data.len().human_count_bytes(), + file_name, + file.metadata().unwrap().len().human_count_bytes(), )) } else { f.write_str("no disk image")