Change to a command based storage card
This commit is contained in:
parent
8c0b923455
commit
0b1a8e1398
21
Cargo.lock
generated
21
Cargo.lock
generated
@ -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",
|
||||||
|
@ -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"
|
||||||
|
131
src/storage.rs
131
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::{
|
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")
|
||||||
|
Loading…
Reference in New Issue
Block a user