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]]
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",

View File

@ -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"

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::{
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<String>,
}
bitflags! {
struct Status: u16 {
const BUSY = 0b00000001;
const DATA_READY = 0b00000010;
}
}
#[derive(Debug)]
pub struct Storage {
data: Vec<u8>,
file: Option<(File, String)>,
read_data: VecDeque<u8>,
sector: u32,
offset: usize,
file_name: Option<String>,
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<Self> {
let file_name = data.try_into::<Config>()?.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<u8, BusError> {
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")