Change to a command based storage card

This commit is contained in:
pjht 2022-11-18 16:03:28 -06:00
parent 8c0b923455
commit 0b1a8e1398
3 changed files with 90 additions and 63 deletions

21
Cargo.lock generated
View File

@ -178,9 +178,9 @@ dependencies = [
[[package]] [[package]]
name = "cxx" name = "cxx"
version = "1.0.81" version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97abf9f0eca9e52b7f81b945524e76710e6cb2366aead23b7d4fbf72e281f888" checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453"
dependencies = [ dependencies = [
"cc", "cc",
"cxxbridge-flags", "cxxbridge-flags",
@ -190,9 +190,9 @@ dependencies = [
[[package]] [[package]]
name = "cxx-build" name = "cxx-build"
version = "1.0.81" version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cc32cc5fea1d894b77d269ddb9f192110069a8a9c1f1d441195fba90553dea3" checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0"
dependencies = [ dependencies = [
"cc", "cc",
"codespan-reporting", "codespan-reporting",
@ -205,15 +205,15 @@ dependencies = [
[[package]] [[package]]
name = "cxxbridge-flags" name = "cxxbridge-flags"
version = "1.0.81" version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ca220e4794c934dc6b1207c3b42856ad4c302f2df1712e9f8d2eec5afaacf1f" checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71"
[[package]] [[package]]
name = "cxxbridge-macro" name = "cxxbridge-macro"
version = "1.0.81" version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b846f081361125bfc8dc9d3940c84e1fd83ba54bbca7b17cd29483c828be0704" checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -345,9 +345,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.9.1" version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@ -436,6 +436,7 @@ name = "m68k_emu"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bitflags",
"bitvec", "bitvec",
"derive-try-from-primitive", "derive-try-from-primitive",
"elf", "elf",

View File

@ -7,6 +7,7 @@ edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.66" anyhow = "1.0.66"
bitflags = "1.3.2"
bitvec = "1.0.0" bitvec = "1.0.0"
derive-try-from-primitive = "1.0.0" derive-try-from-primitive = "1.0.0"
elf = "0.7.0" elf = "0.7.0"

View File

@ -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::{ 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, m68k::BusError,
register, 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)] #[derive(Deserialize)]
struct Config { struct Config {
image: Option<String>, image: Option<String>,
} }
bitflags! {
struct Status: u16 {
const BUSY = 0b00000001;
const DATA_READY = 0b00000010;
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Storage { pub struct Storage {
data: Vec<u8>, file: Option<(File, String)>,
read_data: VecDeque<u8>,
sector: u32, sector: u32,
offset: usize, count: u32,
file_name: Option<String>, status: Status,
} }
// Registers
// 0x0-0x4: Sector
// 0x4-0x8: Sector count
// 0x8-0xA: Command (W) / Status(R)
// 0xA-0xC: Data
impl Card for Storage { impl Card for Storage {
fn new(data: Value) -> anyhow::Result<Self> { fn new(data: Value) -> anyhow::Result<Self> {
let file_name = data.try_into::<Config>()?.image; let file_name = data.try_into::<Config>()?.image;
let mut data = Vec::new(); let file = file_name
if let Some(file_name) = file_name.as_ref() { .as_ref()
File::open(file_name) .map(|file_name| {
.map_err(|e| anyhow!("Could not open disk image file {} ({})", file_name, e))? File::open(file_name)
.read_to_end(&mut data) .map_err(|e| anyhow!("Could not open disk image file {} ({})", file_name, e))
.map_err(|e| anyhow!("Failed to read disk image file {} ({})", file_name, e))?; })
}; .transpose()?;
Ok(Self { Ok(Self {
data, file: file.zip(file_name),
file_name, read_data: VecDeque::new(),
sector: 0, sector: 0,
offset: 0, count: 0,
status: Status::empty(),
}) })
} }
fn read_byte_io(&mut self, address: u8) -> NullableResult<u8, BusError> { fn read_byte_io(&mut self, address: u8) -> NullableResult<u8, BusError> {
match address { match address {
0x0..=0x3 => NullableResult::Ok(u32_get_be_byte(self.sector, address)), 0x0..=0x3 => NullableResult::Ok(u32_get_be_byte(self.sector, address)),
0x4 => { 0x4..=0x7 => NullableResult::Ok(u32_get_be_byte(self.count, address - 0x4)),
let byte = self 0x8..=0x9 => NullableResult::Ok(u16_get_be_byte(self.status.bits(), address - 0x8)),
.data 0xA..=0xB => {
.get(self.sector as usize * SECTOR_SIZE + self.offset as usize) if self.read_data.len() == 1 {
.copied() self.status.set(Status::DATA_READY, false);
.unwrap_or(0); }
self.offset += 1; NullableResult::Ok(self.read_data.pop_front().unwrap_or(0))
NullableResult::Ok(byte)
} }
0xFF => NullableResult::Ok(4), 0xFF => NullableResult::Ok(4),
_ => NullableResult::Null, _ => NullableResult::Null,
@ -64,33 +82,40 @@ impl Card for Storage {
} }
fn write_byte_io(&mut self, address: u8, data: u8) -> NullableResult<(), BusError> { fn write_byte_io(&mut self, address: u8, data: u8) -> NullableResult<(), BusError> {
if let 0x0..=0x3 = address { match address {
self.sector = u32_set_be_byte(self.sector, address, data); 0x0..=0x3 => {
self.offset = 0; 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(()) NullableResult::Ok(())
} }
fn cmd(&mut self, cmd: &[&str]) -> anyhow::Result<()> { fn cmd(&mut self, cmd: &[&str]) -> anyhow::Result<()> {
if cmd[0] == "load" && cmd.len() >= 2 { 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))?; .map_err(|e| anyhow!("Couldn't open disk image file {} ({})", cmd[1], e))?;
self.data.clear(); self.file = Some((file, cmd[1].into()));
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());
println!("Read disk image file {}", cmd[1]); 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(()) Ok(())
} }
@ -99,11 +124,11 @@ impl Card for Storage {
impl Display for Storage { impl Display for Storage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Storage card, ")?; 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!( f.write_fmt(format_args!(
"disk image {} ({})", "disk image {} ({})",
name, file_name,
self.data.len().human_count_bytes(), file.metadata().unwrap().len().human_count_bytes(),
)) ))
} else { } else {
f.write_str("no disk image") f.write_str("no disk image")