From 668d235dfde328b6629685a6d074e36b837da18b Mon Sep 17 00:00:00 2001 From: Mazzie Date: Wed, 27 Mar 2024 10:01:44 -0700 Subject: [PATCH] style: revert formatting back to standard --- examples/cli.rs | 418 +++++++------- rustfmt.toml | 1 - src/cpu.rs | 296 +++++----- src/emulator.rs | 1478 +++++++++++++++++++++++------------------------ src/ic.rs | 198 +++---- src/ioc.rs | 138 ++--- src/mmu.rs | 326 +++++------ 7 files changed, 1427 insertions(+), 1428 deletions(-) delete mode 100644 rustfmt.toml diff --git a/examples/cli.rs b/examples/cli.rs index aaed49e..1399791 100644 --- a/examples/cli.rs +++ b/examples/cli.rs @@ -1,15 +1,15 @@ use std::{ - fs::read, - io, - path::PathBuf, - thread::sleep, - time::{Duration, Instant}, + fs::read, + io, + path::PathBuf, + thread::sleep, + time::{Duration, Instant}, }; use aphelion_util::{io::Port, registers::Register}; use clap::{ - error::{ErrorKind, RichFormatter}, - Parser, + error::{ErrorKind, RichFormatter}, + Parser, }; use meteor_rs::emulator::{Callback, Emulator, State}; use thiserror::Error; @@ -22,242 +22,242 @@ use thiserror::Error; arg_required_else_help = true, )] struct Args { - path: PathBuf, - #[arg(short, long)] - /// launch window with debug interface - debug: bool, - #[arg(short, long, value_name = "INT", default_value_t = 0)] - /// halt after cycle count has been reached (will run forever if unset) - max_cycles: usize, - #[arg(short = 'M', long, value_name = "INT", default_value_t = 1 << 26)] - /// use a custom address space size; the maximum addressable byte will be [int]-1 - /// if not provided, defaults to 2^26 (64 MiB) - memory: usize, - #[arg(short, long)] - /// output benchmark info after execution is halted - bench: bool, - /// wait time between cycles (in milliseconds). - #[arg(short, long, default_value_t = 0)] - wait: u16, + path: PathBuf, + #[arg(short, long)] + /// launch window with debug interface + debug: bool, + #[arg(short, long, value_name = "INT", default_value_t = 0)] + /// halt after cycle count has been reached (will run forever if unset) + max_cycles: usize, + #[arg(short = 'M', long, value_name = "INT", default_value_t = 1 << 26)] + /// use a custom address space size; the maximum addressable byte will be [int]-1 + /// if not provided, defaults to 2^26 (64 MiB) + memory: usize, + #[arg(short, long)] + /// output benchmark info after execution is halted + bench: bool, + /// wait time between cycles (in milliseconds). + #[arg(short, long, default_value_t = 0)] + wait: u16, } #[derive(Debug, Clone, Copy, Error)] enum FileLoadError { - #[error("no such file exists.")] - NoSuchFile, - #[error("path exists but is a directory, not a file.")] - IsDirectory, - #[error("no access.")] - NoAccess, - #[error("{0}")] - Unknown(io::ErrorKind), + #[error("no such file exists.")] + NoSuchFile, + #[error("path exists but is a directory, not a file.")] + IsDirectory, + #[error("no access.")] + NoAccess, + #[error("{0}")] + Unknown(io::ErrorKind), } #[derive(Debug, Clone, Copy, Error)] enum Error { - #[error("failed to load file: {0}")] - FileLoad(FileLoadError), - #[error("could not initialize memory, file is likely too big. requires {file} bytes, but only {cap} bytes are available.")] - CouldNotInitialize { cap: usize, file: usize }, + #[error("failed to load file: {0}")] + FileLoad(FileLoadError), + #[error("could not initialize memory, file is likely too big. requires {file} bytes, but only {cap} bytes are available.")] + CouldNotInitialize { cap: usize, file: usize }, } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] enum PrintBuffLen { - Zero = 0, - One = 1, - Two = 2, - Three = 3, - Four = 4, + Zero = 0, + One = 1, + Two = 2, + Three = 3, + Four = 4, } impl PrintBuffLen { - const fn incremented(self) -> Self { - match self { - Self::Zero => Self::One, - Self::One => Self::Two, - Self::Two => Self::Three, - Self::Three => Self::Four, - Self::Four => Self::Zero, - } - } - fn increment(&mut self) { - *self = self.incremented(); - } + const fn incremented(self) -> Self { + match self { + Self::Zero => Self::One, + Self::One => Self::Two, + Self::Two => Self::Three, + Self::Three => Self::Four, + Self::Four => Self::Zero, + } + } + fn increment(&mut self) { + *self = self.incremented(); + } } #[derive(Debug, Clone, Copy)] struct PrintBuff { - data: [u8; 4], - len: PrintBuffLen, + data: [u8; 4], + len: PrintBuffLen, } impl PrintBuff { - const fn new() -> Self { - Self { - data: [0; 4], - len: PrintBuffLen::Zero, - } - } - fn push(&mut self, byte: u8) -> Option<&str> { - if self.len == PrintBuffLen::Four { - self.len = PrintBuffLen::One; - } else { - self.len.increment(); - } + const fn new() -> Self { + Self { + data: [0; 4], + len: PrintBuffLen::Zero, + } + } + fn push(&mut self, byte: u8) -> Option<&str> { + if self.len == PrintBuffLen::Four { + self.len = PrintBuffLen::One; + } else { + self.len.increment(); + } - self.data[self.len as usize - 1] = byte; - match std::str::from_utf8(&self.data[0..{ self.len as usize }]) { - Ok(val) => { - self.len = PrintBuffLen::Zero; - Some(val) - } - Err(_) => { - if self.len == PrintBuffLen::Four { - Some("�") - } else { - None - } - } - } - } + self.data[self.len as usize - 1] = byte; + match std::str::from_utf8(&self.data[0..{ self.len as usize }]) { + Ok(val) => { + self.len = PrintBuffLen::Zero; + Some(val) + } + Err(_) => { + if self.len == PrintBuffLen::Four { + Some("�") + } else { + None + } + } + } + } } #[derive(Debug, Clone)] struct CliCallback { - should_stop: bool, - debug: bool, - max_cycles: usize, - print_buff: PrintBuff, - bench: bool, - now: Instant, - wait: u16, + should_stop: bool, + debug: bool, + max_cycles: usize, + print_buff: PrintBuff, + bench: bool, + now: Instant, + wait: u16, } impl CliCallback { - const STDOUT: Port = Port(10); - fn new(debug: bool, max_cycles: usize, bench: bool, wait: u16) -> Self { - Self { - should_stop: false, - debug, - max_cycles, - print_buff: PrintBuff::new(), - bench, - now: Instant::now(), - wait, - } - } + const STDOUT: Port = Port(10); + fn new(debug: bool, max_cycles: usize, bench: bool, wait: u16) -> Self { + Self { + should_stop: false, + debug, + max_cycles, + print_buff: PrintBuff::new(), + bench, + now: Instant::now(), + wait, + } + } } impl Callback for CliCallback { - fn should_stop + AsMut<[u8]>>( - &mut self, - state: &meteor_rs::emulator::State, - ) -> bool { - if self.max_cycles != 0 && state.cpu.cycle >= self.max_cycles as u64 { - self.should_stop = true; - } - self.should_stop - } - fn on_instruction_loaded + AsMut<[u8]>>(&mut self, state: &mut State) { - if self.debug { - println!("\n[ {} ]", state.current_instr()); - println!( - "\t ra: 0x{:016X} rb: 0x{:016X} rc: 0x{:016X}", - state.regval(Register::Ra), - state.regval(Register::Rb), - state.regval(Register::Rc), - ); - println!( - "\trd: 0x{:016X} re: 0x{:016X} rf: 0x{:016X} rg: 0x{:016X}", - state.regval(Register::Rd), - state.regval(Register::Re), - state.regval(Register::Rf), - state.regval(Register::Rg), - ); - println!( - "\trh: 0x{:016X} ri: 0x{:016X} rj: 0x{:016X} rk: 0x{:016X}", - state.regval(Register::Rh), - state.regval(Register::Ri), - state.regval(Register::Rj), - state.regval(Register::Rk), - ); - println!( - "\tsp: 0x{:016X} fp: 0x{:016X} ip: 0x{:016X} st: 0x{:016X}", - state.regval(Register::Sp), - state.regval(Register::Fp), - state.regval(Register::Ip), - state.regval(Register::St), - ); - } - } + fn should_stop + AsMut<[u8]>>( + &mut self, + state: &meteor_rs::emulator::State, + ) -> bool { + if self.max_cycles != 0 && state.cpu.cycle >= self.max_cycles as u64 { + self.should_stop = true; + } + self.should_stop + } + fn on_instruction_loaded + AsMut<[u8]>>(&mut self, state: &mut State) { + if self.debug { + println!("\n[ {} ]", state.current_instr()); + println!( + "\t ra: 0x{:016X} rb: 0x{:016X} rc: 0x{:016X}", + state.regval(Register::Ra), + state.regval(Register::Rb), + state.regval(Register::Rc), + ); + println!( + "\trd: 0x{:016X} re: 0x{:016X} rf: 0x{:016X} rg: 0x{:016X}", + state.regval(Register::Rd), + state.regval(Register::Re), + state.regval(Register::Rf), + state.regval(Register::Rg), + ); + println!( + "\trh: 0x{:016X} ri: 0x{:016X} rj: 0x{:016X} rk: 0x{:016X}", + state.regval(Register::Rh), + state.regval(Register::Ri), + state.regval(Register::Rj), + state.regval(Register::Rk), + ); + println!( + "\tsp: 0x{:016X} fp: 0x{:016X} ip: 0x{:016X} st: 0x{:016X}", + state.regval(Register::Sp), + state.regval(Register::Fp), + state.regval(Register::Ip), + state.regval(Register::St), + ); + } + } - fn on_output_received + AsMut<[u8]>>( - &mut self, - _state: &State, - port: Port, - data: u64, - ) { - #[allow(clippy::single_match)] - match port { - Self::STDOUT => { - if let Some(str) = self.print_buff.push(data as u8) { - print!("{str}"); - } - } - _ => {} - } - } + fn on_output_received + AsMut<[u8]>>( + &mut self, + _state: &State, + port: Port, + data: u64, + ) { + #[allow(clippy::single_match)] + match port { + Self::STDOUT => { + if let Some(str) = self.print_buff.push(data as u8) { + print!("{str}"); + } + } + _ => {} + } + } - fn on_run_ended + AsMut<[u8]>>(&mut self, state: &mut State) { - println!(); - if self.bench { - let elapsed = self.now.elapsed(); - let cycles = state.cpu.cycle; - let persec = cycles as f64 / elapsed.as_secs_f64(); - let (s, ms) = (elapsed.as_secs(), elapsed.subsec_millis()); - println!("\n-------- [ benchmark result ] --------"); - println!("\ttime : {s}.{ms:03}s"); - println!("\tcycles : {cycles}"); - println!("\tcycles/s : {persec:.3}"); - } - } - fn on_iteration_ended + AsMut<[u8]>>(&mut self, _state: &mut State) { - if self.wait != 0 { - sleep(Duration::from_millis(self.wait as u64)) - } - } + fn on_run_ended + AsMut<[u8]>>(&mut self, state: &mut State) { + println!(); + if self.bench { + let elapsed = self.now.elapsed(); + let cycles = state.cpu.cycle; + let persec = cycles as f64 / elapsed.as_secs_f64(); + let (s, ms) = (elapsed.as_secs(), elapsed.subsec_millis()); + println!("\n-------- [ benchmark result ] --------"); + println!("\ttime : {s}.{ms:03}s"); + println!("\tcycles : {cycles}"); + println!("\tcycles/s : {persec:.3}"); + } + } + fn on_iteration_ended + AsMut<[u8]>>(&mut self, _state: &mut State) { + if self.wait != 0 { + sleep(Duration::from_millis(self.wait as u64)) + } + } } fn cli_main( - Args { - path, - debug, - max_cycles, - memory, - bench, - wait, - }: Args, + Args { + path, + debug, + max_cycles, + memory, + bench, + wait, + }: Args, ) -> Result<(), Error> { - if path.is_dir() { - Err(Error::FileLoad(FileLoadError::IsDirectory))? - } - let file = read(path).map_err(|err| match err.kind() { - io::ErrorKind::NotFound => Error::FileLoad(FileLoadError::NoSuchFile), - io::ErrorKind::PermissionDenied => Error::FileLoad(FileLoadError::NoAccess), - err => Error::FileLoad(FileLoadError::Unknown(err)), - })?; - let Some(state) = State::new_boxed(memory.try_into().ok(), &file) else { - Err(Error::CouldNotInitialize { - cap: memory, - file: file.len(), - })? - }; - let callback = CliCallback::new(debug, max_cycles, bench, wait); - let emulator = Emulator::new(state, callback); - let _ = emulator.run(); - Ok(()) + if path.is_dir() { + Err(Error::FileLoad(FileLoadError::IsDirectory))? + } + let file = read(path).map_err(|err| match err.kind() { + io::ErrorKind::NotFound => Error::FileLoad(FileLoadError::NoSuchFile), + io::ErrorKind::PermissionDenied => Error::FileLoad(FileLoadError::NoAccess), + err => Error::FileLoad(FileLoadError::Unknown(err)), + })?; + let Some(state) = State::new_boxed(memory.try_into().ok(), &file) else { + Err(Error::CouldNotInitialize { + cap: memory, + file: file.len(), + })? + }; + let callback = CliCallback::new(debug, max_cycles, bench, wait); + let emulator = Emulator::new(state, callback); + let _ = emulator.run(); + Ok(()) } fn main() { - let args = Args::parse(); - if let Err(err) = cli_main(args) { - println!( - "{}", - clap::error::Error::::raw(ErrorKind::ValueValidation, err) - ); - } + let args = Args::parse(); + if let Err(err) = cli_main(args) { + println!( + "{}", + clap::error::Error::::raw(ErrorKind::ValueValidation, err) + ); + } } diff --git a/rustfmt.toml b/rustfmt.toml deleted file mode 100644 index 218e203..0000000 --- a/rustfmt.toml +++ /dev/null @@ -1 +0,0 @@ -hard_tabs = true diff --git a/src/cpu.rs b/src/cpu.rs index 775a019..620ecd9 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -1,19 +1,19 @@ use core::ops::{Index, IndexMut}; use aphelion_util::{ - helper::ops::{f16, BitAccess, Float}, - instruction::{ - instruction_set::{BranchCond, FloatPrecision}, - Instruction, - }, - registers::Register, + helper::ops::{f16, BitAccess, Float}, + instruction::{ + instruction_set::{BranchCond, FloatPrecision}, + Instruction, + }, + registers::Register, }; use bitflags::bitflags; macro_rules! nth_bit { - ($v: expr) => { - (1 << $v) - }; + ($v: expr) => { + (1 << $v) + }; } // TODO: put this in the util lib @@ -21,160 +21,160 @@ macro_rules! nth_bit { pub struct Registers(pub [u64; 16]); impl Registers { - #[must_use] - pub const fn index(self, index: Register) -> u64 { - self.0[index as usize] - } - #[must_use] - pub const fn default() -> Self { - Self([0; 16]) - } - #[must_use] - pub const fn get_flag(&self, flag: StFlag) -> bool { - (*self).index(Register::St) & flag.bits() != 0 - } - pub fn set_flag(&mut self, flag: StFlag, value: bool) { - if value { - self[Register::St] |= flag.bits(); - } else { - self[Register::St] &= !flag.bits(); - } - } - #[must_use] - pub const fn current_instr(&self) -> Instruction { - Instruction(((*self).index(Register::St) >> 32) as u32) - } - pub fn set_current_instr(&mut self, instr: Instruction) { - self[Register::St].write::<1>(instr.0); - } - #[allow(clippy::fn_params_excessive_bools)] - pub fn set_cmp( - &mut self, - equal: bool, - less: bool, - less_unsigned: bool, - sign: bool, - zero: bool, - ) { - self.set_flag(StFlag::EQUAL, equal); - self.set_flag(StFlag::LESS, less); - self.set_flag(StFlag::LESS_UNSIGNED, less_unsigned); - self.set_flag(StFlag::SIGN, sign); - self.set_flag(StFlag::ZERO, zero); - } + #[must_use] + pub const fn index(self, index: Register) -> u64 { + self.0[index as usize] + } + #[must_use] + pub const fn default() -> Self { + Self([0; 16]) + } + #[must_use] + pub const fn get_flag(&self, flag: StFlag) -> bool { + (*self).index(Register::St) & flag.bits() != 0 + } + pub fn set_flag(&mut self, flag: StFlag, value: bool) { + if value { + self[Register::St] |= flag.bits(); + } else { + self[Register::St] &= !flag.bits(); + } + } + #[must_use] + pub const fn current_instr(&self) -> Instruction { + Instruction(((*self).index(Register::St) >> 32) as u32) + } + pub fn set_current_instr(&mut self, instr: Instruction) { + self[Register::St].write::<1>(instr.0); + } + #[allow(clippy::fn_params_excessive_bools)] + pub fn set_cmp( + &mut self, + equal: bool, + less: bool, + less_unsigned: bool, + sign: bool, + zero: bool, + ) { + self.set_flag(StFlag::EQUAL, equal); + self.set_flag(StFlag::LESS, less); + self.set_flag(StFlag::LESS_UNSIGNED, less_unsigned); + self.set_flag(StFlag::SIGN, sign); + self.set_flag(StFlag::ZERO, zero); + } } impl Index for Registers { - type Output = u64; - fn index(&self, index: Register) -> &Self::Output { - &self.0[index as usize] - } + type Output = u64; + fn index(&self, index: Register) -> &Self::Output { + &self.0[index as usize] + } } impl IndexMut for Registers { - fn index_mut(&mut self, index: Register) -> &mut Self::Output { - &mut self.0[index as usize] - } + fn index_mut(&mut self, index: Register) -> &mut Self::Output { + &mut self.0[index as usize] + } } // TODO: put this in the util lib bitflags! { - #[derive(Debug, Clone, Copy)] - pub struct StFlag: u64 { - const SIGN = nth_bit!(0); - const ZERO = nth_bit!(1); - const CARRY_BORROW = nth_bit!(2); - const CARRY_BORROW_UNSIGNED = nth_bit!(3); - const EQUAL = nth_bit!(4); - const LESS = nth_bit!(5); - const LESS_UNSIGNED = nth_bit!(6); - const MODE = nth_bit!(7); + #[derive(Debug, Clone, Copy)] + pub struct StFlag: u64 { + const SIGN = nth_bit!(0); + const ZERO = nth_bit!(1); + const CARRY_BORROW = nth_bit!(2); + const CARRY_BORROW_UNSIGNED = nth_bit!(3); + const EQUAL = nth_bit!(4); + const LESS = nth_bit!(5); + const LESS_UNSIGNED = nth_bit!(6); + const MODE = nth_bit!(7); - const EXT_F = nth_bit!(31); - } + const EXT_F = nth_bit!(31); + } } #[derive(Debug, Clone, Copy)] pub struct Cpu { - pub registers: Registers, - pub cycle: u64, + pub registers: Registers, + pub cycle: u64, } impl Cpu { - #[must_use] - pub const fn new() -> Self { - Self { - registers: Registers([0; 16]), - cycle: 0, - } - } - #[must_use] - pub const fn get_flag(&self, flag: StFlag) -> bool { - self.registers.get_flag(flag) - } - pub fn set_flag(&mut self, flag: StFlag, value: bool) { - self.registers.set_flag(flag, value); - } - #[must_use] - pub const fn cond(&self, cond: BranchCond) -> bool { - match cond { - BranchCond::Bra => true, - BranchCond::Beq => self.get_flag(StFlag::EQUAL), - BranchCond::Bez => self.get_flag(StFlag::ZERO), - BranchCond::Blt => self.get_flag(StFlag::LESS), - BranchCond::Ble => self.get_flag(StFlag::LESS) || self.get_flag(StFlag::EQUAL), - BranchCond::Bltu => self.get_flag(StFlag::LESS_UNSIGNED), - BranchCond::Bleu => { - self.get_flag(StFlag::LESS_UNSIGNED) || self.get_flag(StFlag::EQUAL) - } - BranchCond::Bne => !self.get_flag(StFlag::EQUAL), - BranchCond::Bnz => !self.get_flag(StFlag::ZERO), - BranchCond::Bge => !self.get_flag(StFlag::LESS), - BranchCond::Bgt => !self.get_flag(StFlag::LESS) && !self.get_flag(StFlag::EQUAL), - BranchCond::Bgeu => !self.get_flag(StFlag::LESS_UNSIGNED), - BranchCond::Bgtu => { - !self.get_flag(StFlag::LESS_UNSIGNED) && !self.get_flag(StFlag::EQUAL) - } - } - } - #[allow(clippy::fn_params_excessive_bools)] - pub fn set_cmp( - &mut self, - equal: bool, - less: bool, - less_unsigned: bool, - sign: bool, - zero: bool, - ) { - self.registers - .set_cmp(equal, less, less_unsigned, sign, zero); - } - #[allow(clippy::cast_possible_wrap)] - pub fn set_cmp_u64(&mut self, a: u64, b: u64) { - self.set_cmp( - a == b, - (a as i64) < (b as i64), - a < b, - (a as i64) < 0, - a == 0, - ); - } - pub fn set_cmp_float(&mut self, a: F, b: F) { - self.set_cmp(a == b, a < b, a < b, a.is_sign_negative(), a.is_zero()); - } - pub fn set_cmp_float_bits(&mut self, a: u64, b: u64) { - self.set_cmp_float(F::from_u64(a), F::from_u64(b)); - } - pub fn set_cmp_float_precision(&mut self, a: u64, b: u64, p: FloatPrecision) { - match p { - FloatPrecision::F16 => self.set_cmp_float_bits::(a, b), - FloatPrecision::F32 => self.set_cmp_float_bits::(a, b), - FloatPrecision::F64 => self.set_cmp_float_bits::(a, b), - } - } + #[must_use] + pub const fn new() -> Self { + Self { + registers: Registers([0; 16]), + cycle: 0, + } + } + #[must_use] + pub const fn get_flag(&self, flag: StFlag) -> bool { + self.registers.get_flag(flag) + } + pub fn set_flag(&mut self, flag: StFlag, value: bool) { + self.registers.set_flag(flag, value); + } + #[must_use] + pub const fn cond(&self, cond: BranchCond) -> bool { + match cond { + BranchCond::Bra => true, + BranchCond::Beq => self.get_flag(StFlag::EQUAL), + BranchCond::Bez => self.get_flag(StFlag::ZERO), + BranchCond::Blt => self.get_flag(StFlag::LESS), + BranchCond::Ble => self.get_flag(StFlag::LESS) || self.get_flag(StFlag::EQUAL), + BranchCond::Bltu => self.get_flag(StFlag::LESS_UNSIGNED), + BranchCond::Bleu => { + self.get_flag(StFlag::LESS_UNSIGNED) || self.get_flag(StFlag::EQUAL) + } + BranchCond::Bne => !self.get_flag(StFlag::EQUAL), + BranchCond::Bnz => !self.get_flag(StFlag::ZERO), + BranchCond::Bge => !self.get_flag(StFlag::LESS), + BranchCond::Bgt => !self.get_flag(StFlag::LESS) && !self.get_flag(StFlag::EQUAL), + BranchCond::Bgeu => !self.get_flag(StFlag::LESS_UNSIGNED), + BranchCond::Bgtu => { + !self.get_flag(StFlag::LESS_UNSIGNED) && !self.get_flag(StFlag::EQUAL) + } + } + } + #[allow(clippy::fn_params_excessive_bools)] + pub fn set_cmp( + &mut self, + equal: bool, + less: bool, + less_unsigned: bool, + sign: bool, + zero: bool, + ) { + self.registers + .set_cmp(equal, less, less_unsigned, sign, zero); + } + #[allow(clippy::cast_possible_wrap)] + pub fn set_cmp_u64(&mut self, a: u64, b: u64) { + self.set_cmp( + a == b, + (a as i64) < (b as i64), + a < b, + (a as i64) < 0, + a == 0, + ); + } + pub fn set_cmp_float(&mut self, a: F, b: F) { + self.set_cmp(a == b, a < b, a < b, a.is_sign_negative(), a.is_zero()); + } + pub fn set_cmp_float_bits(&mut self, a: u64, b: u64) { + self.set_cmp_float(F::from_u64(a), F::from_u64(b)); + } + pub fn set_cmp_float_precision(&mut self, a: u64, b: u64, p: FloatPrecision) { + match p { + FloatPrecision::F16 => self.set_cmp_float_bits::(a, b), + FloatPrecision::F32 => self.set_cmp_float_bits::(a, b), + FloatPrecision::F64 => self.set_cmp_float_bits::(a, b), + } + } } impl Default for Cpu { - fn default() -> Self { - Self { - registers: Registers::default(), - cycle: 0, - } - } + fn default() -> Self { + Self { + registers: Registers::default(), + cycle: 0, + } + } } diff --git a/src/emulator.rs b/src/emulator.rs index 76dd4b4..5ec0885 100644 --- a/src/emulator.rs +++ b/src/emulator.rs @@ -1,332 +1,332 @@ use aphelion_util::{ - helper::{ - ops::{self, AddResult, BitAccess}, - sign_extend, - }, - instruction::{ - instruction_set::{InstructionSet, LiType}, - Instruction, - }, - interrupt::Interrupt, - io::Port, - nibble::Nibble, - registers::Register, + helper::{ + ops::{self, AddResult, BitAccess}, + sign_extend, + }, + instruction::{ + instruction_set::{InstructionSet, LiType}, + Instruction, + }, + interrupt::Interrupt, + io::Port, + nibble::Nibble, + registers::Register, }; use crate::{ - cpu::{Cpu, StFlag}, - ic::Ic, - ioc::{IcStatus, Ioc, IocStatus, NUM_PORTS}, - mmu::{AccessMode, Mmu, Response}, + cpu::{Cpu, StFlag}, + ic::Ic, + ioc::{IcStatus, Ioc, IocStatus, NUM_PORTS}, + mmu::{AccessMode, Mmu, Response}, }; pub trait Callback: Sized { - fn should_stop + AsMut<[u8]>>(&mut self, state: &State) -> bool; - fn on_run_started + AsMut<[u8]>>(&mut self, _state: &mut State) {} - fn on_run_ended + AsMut<[u8]>>(&mut self, _state: &mut State) {} - fn on_iteration_started + AsMut<[u8]>>(&mut self, _state: &mut State) {} - fn on_iteration_ended + AsMut<[u8]>>(&mut self, _state: &mut State) {} - fn on_instruction_loaded + AsMut<[u8]>>(&mut self, _state: &mut State) {} - fn on_output_received + AsMut<[u8]>>( - &mut self, - _state: &State, - _port: Port, - _data: u64, - ) { - } - fn send_input + AsMut<[u8]>>( - &mut self, - _state: &State, - ) -> Option<(Port, u64)> { - None - } + fn should_stop + AsMut<[u8]>>(&mut self, state: &State) -> bool; + fn on_run_started + AsMut<[u8]>>(&mut self, _state: &mut State) {} + fn on_run_ended + AsMut<[u8]>>(&mut self, _state: &mut State) {} + fn on_iteration_started + AsMut<[u8]>>(&mut self, _state: &mut State) {} + fn on_iteration_ended + AsMut<[u8]>>(&mut self, _state: &mut State) {} + fn on_instruction_loaded + AsMut<[u8]>>(&mut self, _state: &mut State) {} + fn on_output_received + AsMut<[u8]>>( + &mut self, + _state: &State, + _port: Port, + _data: u64, + ) { + } + fn send_input + AsMut<[u8]>>( + &mut self, + _state: &State, + ) -> Option<(Port, u64)> { + None + } } #[derive(Debug, Clone, Copy)] struct ProcMode; impl ProcMode { - // const KERNEL: bool = false; - const USER: bool = true; + // const KERNEL: bool = false; + const USER: bool = true; } macro_rules! read { - ($fn_name: ident, $phys_get: ident, $ty: ty) => { - /// # Errors - /// - /// its straight forward dummy - pub fn $fn_name(&self, addr: u64) -> Result<$ty, Response> { - let addr = if self.cpu.get_flag(StFlag::MODE) == ProcMode::USER { - self.mmu.translate_address(addr, AccessMode::Read)? - } else { - addr - }; - self.mmu.$phys_get(addr) - } - }; + ($fn_name: ident, $phys_get: ident, $ty: ty) => { + /// # Errors + /// + /// its straight forward dummy + pub fn $fn_name(&self, addr: u64) -> Result<$ty, Response> { + let addr = if self.cpu.get_flag(StFlag::MODE) == ProcMode::USER { + self.mmu.translate_address(addr, AccessMode::Read)? + } else { + addr + }; + self.mmu.$phys_get(addr) + } + }; } macro_rules! read_to { - ($fn_name: ident, $read: ident) => { - /// # Errors - /// - /// its straight forward dummy - pub fn $fn_name(&mut self, addr: u64, to: Register) -> Result<(), Response> { - let v = self.$read(addr)?; - // Not zeroing out! this is only used for lb etc - self.regval_mut(to).write::<0>(v); - Ok(()) - } - }; + ($fn_name: ident, $read: ident) => { + /// # Errors + /// + /// its straight forward dummy + pub fn $fn_name(&mut self, addr: u64, to: Register) -> Result<(), Response> { + let v = self.$read(addr)?; + // Not zeroing out! this is only used for lb etc + self.regval_mut(to).write::<0>(v); + Ok(()) + } + }; } macro_rules! read_to_signed { - ($fn_name: ident, $read: ident, $by: expr) => { - /// # Errors - /// - /// its straight forward dummy - pub fn $fn_name(&mut self, addr: u64, to: Register) -> Result<(), Response> { - let v = self.$read(addr)?; - *self.regval_mut(to) = sign_extend::<$by>(v as u64); - Ok(()) - } - }; + ($fn_name: ident, $read: ident, $by: expr) => { + /// # Errors + /// + /// its straight forward dummy + pub fn $fn_name(&mut self, addr: u64, to: Register) -> Result<(), Response> { + let v = self.$read(addr)?; + *self.regval_mut(to) = sign_extend::<$by>(v as u64); + Ok(()) + } + }; } macro_rules! write { - ($fn_name: ident, $phys_write: ident, $ty: ty) => { - /// # Errors - /// - /// its straight forward dummy - pub fn $fn_name(&mut self, addr: u64, value: $ty) -> Result<(), Response> { - let addr = if self.cpu.get_flag(StFlag::MODE) == ProcMode::USER { - self.mmu.translate_address(addr, AccessMode::Write)? - } else { - addr - }; - self.mmu.$phys_write(addr, value) - } - }; + ($fn_name: ident, $phys_write: ident, $ty: ty) => { + /// # Errors + /// + /// its straight forward dummy + pub fn $fn_name(&mut self, addr: u64, value: $ty) -> Result<(), Response> { + let addr = if self.cpu.get_flag(StFlag::MODE) == ProcMode::USER { + self.mmu.translate_address(addr, AccessMode::Write)? + } else { + addr + }; + self.mmu.$phys_write(addr, value) + } + }; } #[derive(Debug, Clone)] pub struct State + AsMut<[u8]>> { - pub mmu: Mmu, - pub ic: Ic, - pub cpu: Cpu, - pub ioc: Ioc, + pub mmu: Mmu, + pub ic: Ic, + pub cpu: Cpu, + pub ioc: Ioc, } impl + AsMut<[u8]>> State { - #[must_use] - pub const fn current_instr(&self) -> Instruction { - self.cpu.registers.current_instr() - } - pub fn set_current_instr(&mut self, instr: Instruction) { - self.cpu.registers.set_current_instr(instr); - } + #[must_use] + pub const fn current_instr(&self) -> Instruction { + self.cpu.registers.current_instr() + } + pub fn set_current_instr(&mut self, instr: Instruction) { + self.cpu.registers.set_current_instr(instr); + } - /// # Errors - /// - /// omg shut up about having errors doc fucking compiler bich - pub fn read_instruction(&self, addr: u64) -> Result { - let addr = if self.cpu.get_flag(StFlag::MODE) == ProcMode::USER { - self.mmu.translate_address(addr, AccessMode::Execute)? - } else { - addr - }; - self.mmu.phys_get_u32(addr).map(Instruction) - } - read! {read_u8, phys_get_u8, u8} - read! {read_u16, phys_get_u16, u16} - read! {read_u32, phys_get_u32, u32} - read! {read_u64, phys_get_u64, u64} - read_to! {read_to_u8, read_u8} - read_to! {read_to_u16, read_u16} - read_to! {read_to_u32, read_u32} - read_to! {read_to_u64, read_u64} - read_to_signed! {read_to_u8_signed, read_u8, 8} - read_to_signed! {read_to_u16_signed, read_u16, 16} - read_to_signed! {read_to_u32_signed, read_u32, 32} - write! {write_u8, phys_write_u8, u8} - write! {write_u16, phys_write_u16, u16} - write! {write_u32, phys_write_u32, u32} - write! {write_u64, phys_write_u64, u64} - pub fn push_interrupt(&mut self, err: Interrupt) { - if self.ic.queue.is_empty() { - self.ic.ret_addr = self.cpu.registers[Register::Ip]; - self.ic.ret_status = self.cpu.registers[Register::St]; - self.cpu.set_flag(StFlag::MODE, ProcMode::USER); - } - let err = if self.ic.queue.reached_capacity() { - // interrupt queue overflow - self.ic.queue.clear(); - Interrupt::INTERRUPT_OVERFLOW - } else { - err - }; - // hijack instruction pointer - match self - .mmu - .phys_get_u64(self.ic.ivt_base_address + 8 * u64::from(err.0)) - { - Err(err) => { - self.push_interrupt_from_mmu(err); - } - Ok(value) => { - self.cpu.registers[Register::Ip] = value; - self.ic.queue.push_back(err); - } - } - } - pub fn push_interrupt_from_mmu(&mut self, res: Response) { - self.push_interrupt(match res { - Response::AccViolation | Response::NoPerms | Response::OutOfBounds => { - Interrupt::ACCESS_VIOLATION - } - Response::Unaligned => Interrupt::UNALIGNED_ACCESS, - }); - } - #[must_use] - pub const fn regval(&self, reg: Register) -> u64 { - self.cpu.registers.index(reg) - } - pub fn regval_mut(&mut self, reg: Register) -> &mut u64 { - &mut self.cpu.registers[reg] - } - /// BE CAREFUL! opposite order than normal assignment. - pub fn regval_write(&mut self, from: Register, to: Register) { - *self.regval_mut(to) = self.regval(from); - } + /// # Errors + /// + /// omg shut up about having errors doc fucking compiler bich + pub fn read_instruction(&self, addr: u64) -> Result { + let addr = if self.cpu.get_flag(StFlag::MODE) == ProcMode::USER { + self.mmu.translate_address(addr, AccessMode::Execute)? + } else { + addr + }; + self.mmu.phys_get_u32(addr).map(Instruction) + } + read! {read_u8, phys_get_u8, u8} + read! {read_u16, phys_get_u16, u16} + read! {read_u32, phys_get_u32, u32} + read! {read_u64, phys_get_u64, u64} + read_to! {read_to_u8, read_u8} + read_to! {read_to_u16, read_u16} + read_to! {read_to_u32, read_u32} + read_to! {read_to_u64, read_u64} + read_to_signed! {read_to_u8_signed, read_u8, 8} + read_to_signed! {read_to_u16_signed, read_u16, 16} + read_to_signed! {read_to_u32_signed, read_u32, 32} + write! {write_u8, phys_write_u8, u8} + write! {write_u16, phys_write_u16, u16} + write! {write_u32, phys_write_u32, u32} + write! {write_u64, phys_write_u64, u64} + pub fn push_interrupt(&mut self, err: Interrupt) { + if self.ic.queue.is_empty() { + self.ic.ret_addr = self.cpu.registers[Register::Ip]; + self.ic.ret_status = self.cpu.registers[Register::St]; + self.cpu.set_flag(StFlag::MODE, ProcMode::USER); + } + let err = if self.ic.queue.reached_capacity() { + // interrupt queue overflow + self.ic.queue.clear(); + Interrupt::INTERRUPT_OVERFLOW + } else { + err + }; + // hijack instruction pointer + match self + .mmu + .phys_get_u64(self.ic.ivt_base_address + 8 * u64::from(err.0)) + { + Err(err) => { + self.push_interrupt_from_mmu(err); + } + Ok(value) => { + self.cpu.registers[Register::Ip] = value; + self.ic.queue.push_back(err); + } + } + } + pub fn push_interrupt_from_mmu(&mut self, res: Response) { + self.push_interrupt(match res { + Response::AccViolation | Response::NoPerms | Response::OutOfBounds => { + Interrupt::ACCESS_VIOLATION + } + Response::Unaligned => Interrupt::UNALIGNED_ACCESS, + }); + } + #[must_use] + pub const fn regval(&self, reg: Register) -> u64 { + self.cpu.registers.index(reg) + } + pub fn regval_mut(&mut self, reg: Register) -> &mut u64 { + &mut self.cpu.registers[reg] + } + /// BE CAREFUL! opposite order than normal assignment. + pub fn regval_write(&mut self, from: Register, to: Register) { + *self.regval_mut(to) = self.regval(from); + } - pub fn return_interrupt(&mut self) { - if self.ic.queue.is_empty() { - return; - } - let _ = self.ic.queue.pop_front(); - if self.ic.queue.is_empty() { - self.cpu.registers[Register::Ip] = self.ic.ret_addr; - self.cpu.registers[Register::St] = self.ic.ret_status; - } else { - // hijack instruction pointer - let code = self.ic.queue[self.ic.queue.len() - 1].0; - match self - .mmu - .phys_get_u64(self.ic.ivt_base_address + 8 * u64::from(code)) - { - Err(err) => self.push_interrupt_from_mmu(err), - Ok(res) => self.cpu.registers[Register::Ip] = res, - } - } - } - fn proc_mode_is_user_then_invalid(&mut self) -> Result<(), Interrupt> { - if self.cpu.get_flag(StFlag::MODE) == ProcMode::USER { - Err(Interrupt::INVALID_OPERATION) - } else { - Ok(()) - } - } - pub fn push_stack(&mut self, data: u64) { - *self.regval_mut(Register::Sp) -= 8; - if let Err(err) = self.write_u64(self.regval(Register::Sp), data) { - self.push_interrupt_from_mmu(err); - } - } - pub fn push_stack_from(&mut self, reg: Register) { - self.push_stack(self.regval(reg)); - } - pub fn pop_stack_to(&mut self, reg: Register) { - match self.read_u64(self.regval(Register::Sp)) { - Ok(val) => { - *self.regval_mut(Register::Sp) += 8; - *self.regval_mut(reg) = val; - } - Err(err) => self.push_interrupt_from_mmu(err), - } - } - pub const fn load_address(&self, rs: Register, off: u8, rn: Register, sh: Nibble) -> u64 { - self.regval(rs) + sign_extend::<8>(off as u64) + (self.regval(rn) << sh as u8) - } - #[allow(clippy::cast_possible_truncation)] - #[allow(clippy::cast_sign_loss)] - #[allow(clippy::cast_possible_wrap)] - #[allow(clippy::too_many_lines)] - /// # Errors - /// - /// is obvious - /// - pub fn interpret_code(&mut self) -> Result<(), Interrupt> { - use InstructionSet as I; - let instr = self - .current_instr() - .try_into_instruction_set() - .ok_or(Interrupt::INVALID_OPERATION)?; - match instr { - // system control - I::Int { imm8 } => Err(imm8)?, - I::Iret => { - self.proc_mode_is_user_then_invalid()?; - self.return_interrupt(); - } - I::Ires => { - self.proc_mode_is_user_then_invalid()?; - self.return_interrupt(); - } - I::Usr { rd } => { - self.proc_mode_is_user_then_invalid()?; - self.cpu.set_flag(StFlag::MODE, ProcMode::USER); - self.cpu.registers[Register::Ip] = self.regval(rd); - } - // io - I::Outr { rd, rs } => { - self.proc_mode_is_user_then_invalid()?; - self.ioc - .send_out(Port(self.regval(rd) as u16), self.regval(rs)); - } - I::Outi { imm16, rs } => { - self.proc_mode_is_user_then_invalid()?; - self.ioc.send_out(imm16, self.regval(rs)); - } - I::Inr { rd, rs } => { - self.proc_mode_is_user_then_invalid()?; - *self.regval_mut(rd) = self.ioc.port_data(Port(self.regval(rs) as u16)); - } - I::Ini { rd, imm16 } => { - self.proc_mode_is_user_then_invalid()?; - *self.regval_mut(rd) = self.ioc.port_data(imm16); - } - // control flow - I::Jal { rs, imm16 } => { - self.push_stack_from(Register::Ip); - *self.regval_mut(Register::Ip) = - self.regval(rs) + (sign_extend::<16>(imm16.into()) as i64 * 4) as u64; - } - I::Jalr { rd, rs, imm16 } => { - self.regval_write(Register::Ip, rd); - *self.regval_mut(Register::Ip) = - self.regval(rs) + (sign_extend::<16>(imm16.into()) as i64 * 4) as u64; - } - I::Ret => self.pop_stack_to(Register::Ip), - I::Retr { rs } => self.regval_write(rs, Register::Ip), - I::Branch { cc, imm20 } => { - if self.cpu.cond(cc) { - // wrapping add, since we don't want to panic. - *self.regval_mut(Register::Ip) = self - .regval(Register::Ip) - .wrapping_add((sign_extend::<20>(imm20.into()) as i64 * 4) as u64); - } - } - // stack - I::Push { rs } => { - self.push_stack_from(rs); - } - I::Pop { rd } => { - self.pop_stack_to(rd); - } - I::Enter => { - self.push_stack_from(Register::Fp); - self.regval_write(Register::Sp, Register::Fp); - } - I::Leave => { - self.regval_write(Register::Fp, Register::Sp); - self.pop_stack_to(Register::Fp); - } - #[rustfmt::skip] + pub fn return_interrupt(&mut self) { + if self.ic.queue.is_empty() { + return; + } + let _ = self.ic.queue.pop_front(); + if self.ic.queue.is_empty() { + self.cpu.registers[Register::Ip] = self.ic.ret_addr; + self.cpu.registers[Register::St] = self.ic.ret_status; + } else { + // hijack instruction pointer + let code = self.ic.queue[self.ic.queue.len() - 1].0; + match self + .mmu + .phys_get_u64(self.ic.ivt_base_address + 8 * u64::from(code)) + { + Err(err) => self.push_interrupt_from_mmu(err), + Ok(res) => self.cpu.registers[Register::Ip] = res, + } + } + } + fn proc_mode_is_user_then_invalid(&mut self) -> Result<(), Interrupt> { + if self.cpu.get_flag(StFlag::MODE) == ProcMode::USER { + Err(Interrupt::INVALID_OPERATION) + } else { + Ok(()) + } + } + pub fn push_stack(&mut self, data: u64) { + *self.regval_mut(Register::Sp) -= 8; + if let Err(err) = self.write_u64(self.regval(Register::Sp), data) { + self.push_interrupt_from_mmu(err); + } + } + pub fn push_stack_from(&mut self, reg: Register) { + self.push_stack(self.regval(reg)); + } + pub fn pop_stack_to(&mut self, reg: Register) { + match self.read_u64(self.regval(Register::Sp)) { + Ok(val) => { + *self.regval_mut(Register::Sp) += 8; + *self.regval_mut(reg) = val; + } + Err(err) => self.push_interrupt_from_mmu(err), + } + } + pub const fn load_address(&self, rs: Register, off: u8, rn: Register, sh: Nibble) -> u64 { + self.regval(rs) + sign_extend::<8>(off as u64) + (self.regval(rn) << sh as u8) + } + #[allow(clippy::cast_possible_truncation)] + #[allow(clippy::cast_sign_loss)] + #[allow(clippy::cast_possible_wrap)] + #[allow(clippy::too_many_lines)] + /// # Errors + /// + /// is obvious + /// + pub fn interpret_code(&mut self) -> Result<(), Interrupt> { + use InstructionSet as I; + let instr = self + .current_instr() + .try_into_instruction_set() + .ok_or(Interrupt::INVALID_OPERATION)?; + match instr { + // system control + I::Int { imm8 } => Err(imm8)?, + I::Iret => { + self.proc_mode_is_user_then_invalid()?; + self.return_interrupt(); + } + I::Ires => { + self.proc_mode_is_user_then_invalid()?; + self.return_interrupt(); + } + I::Usr { rd } => { + self.proc_mode_is_user_then_invalid()?; + self.cpu.set_flag(StFlag::MODE, ProcMode::USER); + self.cpu.registers[Register::Ip] = self.regval(rd); + } + // io + I::Outr { rd, rs } => { + self.proc_mode_is_user_then_invalid()?; + self.ioc + .send_out(Port(self.regval(rd) as u16), self.regval(rs)); + } + I::Outi { imm16, rs } => { + self.proc_mode_is_user_then_invalid()?; + self.ioc.send_out(imm16, self.regval(rs)); + } + I::Inr { rd, rs } => { + self.proc_mode_is_user_then_invalid()?; + *self.regval_mut(rd) = self.ioc.port_data(Port(self.regval(rs) as u16)); + } + I::Ini { rd, imm16 } => { + self.proc_mode_is_user_then_invalid()?; + *self.regval_mut(rd) = self.ioc.port_data(imm16); + } + // control flow + I::Jal { rs, imm16 } => { + self.push_stack_from(Register::Ip); + *self.regval_mut(Register::Ip) = + self.regval(rs) + (sign_extend::<16>(imm16.into()) as i64 * 4) as u64; + } + I::Jalr { rd, rs, imm16 } => { + self.regval_write(Register::Ip, rd); + *self.regval_mut(Register::Ip) = + self.regval(rs) + (sign_extend::<16>(imm16.into()) as i64 * 4) as u64; + } + I::Ret => self.pop_stack_to(Register::Ip), + I::Retr { rs } => self.regval_write(rs, Register::Ip), + I::Branch { cc, imm20 } => { + if self.cpu.cond(cc) { + // wrapping add, since we don't want to panic. + *self.regval_mut(Register::Ip) = self + .regval(Register::Ip) + .wrapping_add((sign_extend::<20>(imm20.into()) as i64 * 4) as u64); + } + } + // stack + I::Push { rs } => { + self.push_stack_from(rs); + } + I::Pop { rd } => { + self.pop_stack_to(rd); + } + I::Enter => { + self.push_stack_from(Register::Fp); + self.regval_write(Register::Sp, Register::Fp); + } + I::Leave => { + self.regval_write(Register::Fp, Register::Sp); + self.pop_stack_to(Register::Fp); + } + #[rustfmt::skip] I::Li { rd, func, imm } => { match func { LiType::Lli => self.regval_mut(rd).write::<0>(imm), @@ -339,464 +339,464 @@ impl + AsMut<[u8]>> State { LiType::Ltuis => *self.regval_mut(rd) = sign_extend::<16>(imm.into()) << 48, } }, - I::Lw { - rd, - rs, - rn, - sh, - off, - } => { - if let Err(err) = self.read_to_u64(self.load_address(rs, off, rn, sh), rd) { - self.push_interrupt_from_mmu(err); - } - } - I::Lh { - rd, - rs, - rn, - sh, - off, - } => { - if let Err(err) = self.read_to_u32(self.load_address(rs, off, rn, sh), rd) { - self.push_interrupt_from_mmu(err); - } - } - I::Lhs { - rd, - rs, - rn, - sh, - off, - } => { - if let Err(err) = self.read_to_u32_signed(self.load_address(rs, off, rn, sh), rd) { - self.push_interrupt_from_mmu(err); - } - } - I::Lq { - rd, - rs, - rn, - sh, - off, - } => { - if let Err(err) = self.read_to_u16(self.load_address(rs, off, rn, sh), rd) { - self.push_interrupt_from_mmu(err); - } - } - I::Lqs { - rd, - rs, - rn, - sh, - off, - } => { - if let Err(err) = self.read_to_u16_signed(self.load_address(rs, off, rn, sh), rd) { - self.push_interrupt_from_mmu(err); - } - } - I::Lb { - rd, - rs, - rn, - sh, - off, - } => { - if let Err(err) = self.read_to_u8(self.load_address(rs, off, rn, sh), rd) { - self.push_interrupt_from_mmu(err); - } - } - I::Lbs { - rd, - rs, - rn, - sh, - off, - } => { - if let Err(err) = self.read_to_u8_signed(self.load_address(rs, off, rn, sh), rd) { - self.push_interrupt_from_mmu(err); - } - } - I::Sw { - rs, - off, - rn, - sh, - rd, - } => { - if let Err(err) = - self.write_u64(self.load_address(rs, off, rn, sh), self.regval(rd)) - { - self.push_interrupt_from_mmu(err); - } - } - I::Sh { - rs, - off, - rn, - sh, - rd, - } => { - if let Err(err) = - self.write_u32(self.load_address(rs, off, rn, sh), self.regval(rd) as u32) - { - self.push_interrupt_from_mmu(err); - } - } - I::Sq { - rs, - off, - rn, - sh, - rd, - } => { - if let Err(err) = - self.write_u16(self.load_address(rs, off, rn, sh), self.regval(rd) as u16) - { - self.push_interrupt_from_mmu(err); - } - } - I::Sb { - rs, - off, - rn, - sh, - rd, - } => { - if let Err(err) = - self.write_u8(self.load_address(rs, off, rn, sh), self.regval(rd) as u8) - { - self.push_interrupt_from_mmu(err); - } - } - // comparisons - I::Cmpr { r1, r2 } => self.cpu.set_cmp_u64(self.regval(r1), self.regval(r2)), - I::Cmpi { r1, s, imm } => { - if s { - self.cpu - .set_cmp_u64(sign_extend::<16>(imm.into()), self.regval(r1)); - } else { - self.cpu - .set_cmp_u64(self.regval(r1), sign_extend::<16>(imm.into())); - } - } - // arithmetic operations - I::Addr { rd, r1, r2 } => self.arithmetic_r(Self::add, r1, r2, rd), - I::Addi { rd, r1, imm16 } => self.arithmetic_i(Self::add, r1, imm16, rd), - I::Subr { rd, r1, r2 } => self.arithmetic_r(Self::sub, r1, r2, rd), - I::Subi { rd, r1, imm16 } => self.arithmetic_i(Self::sub, r1, imm16, rd), - I::Imulr { rd, r1, r2 } => self.arithmetic_r(Self::imul, r1, r2, rd), - I::Imuli { rd, r1, imm16 } => self.arithmetic_i(Self::imul, r1, imm16, rd), - I::Idivr { rd, r1, r2 } => self.arithmetic_r(Self::idiv, r1, r2, rd)?, - I::Idivi { rd, r1, imm16 } => self.arithmetic_i(Self::idiv, r1, imm16, rd)?, - I::Umulr { rd, r1, r2 } => self.arithmetic_r(Self::umul, r1, r2, rd), - I::Umuli { rd, r1, imm16 } => self.arithmetic_i(Self::umul, r1, imm16, rd), - I::Udivr { rd, r1, r2 } => self.arithmetic_r(Self::udiv, r1, r2, rd)?, - I::Udivi { rd, r1, imm16 } => self.arithmetic_i(Self::udiv, r1, imm16, rd)?, - I::Remr { rd, r1, r2 } => self.arithmetic_r(Self::rem, r1, r2, rd), - I::Remi { rd, r1, imm16 } => self.arithmetic_i(Self::rem, r1, imm16, rd), - I::Modr { rd, r1, r2 } => self.arithmetic_r(Self::r#mod, r1, r2, rd), - I::Modi { rd, r1, imm16 } => self.arithmetic_i(Self::r#mod, r1, imm16, rd), - // bitwise operations - I::Andr { rd, r1, r2 } => self.bitwise_r(Self::and, r1, r2, rd), - I::Andi { rd, r1, imm16 } => self.bitwise_i(Self::and, r1, imm16, rd), - I::Orr { rd, r1, r2 } => self.bitwise_r(Self::or, r1, r2, rd), - I::Ori { rd, r1, imm16 } => self.bitwise_i(Self::or, r1, imm16, rd), - I::Norr { rd, r1, r2 } => self.bitwise_r(Self::nor, r1, r2, rd), - I::Nori { rd, r1, imm16 } => self.bitwise_i(Self::nor, r1, imm16, rd), - I::Xorr { rd, r1, r2 } => self.bitwise_r(Self::xor, r1, r2, rd), - I::Xori { rd, r1, imm16 } => self.bitwise_i(Self::xor, r1, imm16, rd), - I::Shlr { rd, r1, r2 } => self.bitwise_r(Self::shl, r1, r2, rd), - I::Shli { rd, r1, imm16 } => self.bitwise_i(Self::shl, r1, imm16, rd), - I::Asrr { rd, r1, r2 } => self.bitwise_r(Self::asr, r1, r2, rd), - I::Asri { rd, r1, imm16 } => self.bitwise_i(Self::asr, r1, imm16, rd), - I::Lsrr { rd, r1, r2 } => self.bitwise_r(Self::lsr, r1, r2, rd), - I::Lsri { rd, r1, imm16 } => self.bitwise_i(Self::lsr, r1, imm16, rd), - I::Bitr { rd, r1, r2 } => self.bitwise_r(Self::bit, r1, r2, rd), - I::Biti { rd, r1, imm16 } => self.bitwise_i(Self::bit, r1, imm16, rd), - // float operations - I::Fcmp { r1, r2, p } => { - self.cpu - .set_cmp_float_precision(self.regval(r1), self.regval(r2), p) - } - I::Fto { rd, rs, p } => *self.regval_mut(rd) = p.fto(self.regval(rs)), - I::Ffrom { rd, rs, p } => *self.regval_mut(rd) = p.ffrom(self.regval(rs)), - I::Fneg { rd, rs, p } => *self.regval_mut(rd) = p.fneg(self.regval(rs)), - I::Fabs { rd, rs, p } => *self.regval_mut(rd) = p.fabs(self.regval(rs)), - I::Fadd { rd, r1, r2, p } => { - *self.regval_mut(rd) = p.fadd(self.regval(r1), self.regval(r2)) - } - I::Fsub { rd, r1, r2, p } => { - *self.regval_mut(rd) = p.fsub(self.regval(r1), self.regval(r2)) - } - I::Fmul { rd, r1, r2, p } => { - *self.regval_mut(rd) = p.fmul(self.regval(r1), self.regval(r2)) - } - I::Fdiv { rd, r1, r2, p } => { - *self.regval_mut(rd) = p.fdiv(self.regval(r1), self.regval(r2)) - } - I::Fma { rd, r1, r2, p } => { - p.fma(self.regval(r1), self.regval(r2), self.regval_mut(rd)) - } - I::Fsqrt { rd, r1, p } => *self.regval_mut(rd) = p.fsqrt(self.regval(r1)), - I::Fmin { rd, r1, r2, p } => { - *self.regval_mut(rd) = p.fmin(self.regval(r1), self.regval(r2)) - } - I::Fmax { rd, r1, r2, p } => { - *self.regval_mut(rd) = p.fmax(self.regval(r1), self.regval(r2)) - } - I::Fsat { rd, r1, p } => *self.regval_mut(rd) = p.fsat(self.regval(r1)), - I::Fcnv { rd, r1, p } => *self.regval_mut(rd) = p.cast(self.regval(r1)), - I::Fnan { rd, r1, p } => *self.regval_mut(rd) = p.fnan(self.regval(r1)), - } - Ok(()) - } - /* ops */ - const fn carry(&self) -> bool { - self.cpu.get_flag(StFlag::CARRY_BORROW_UNSIGNED) - } - /* arithmetic */ - fn arithmetic_r( - &mut self, - func: impl Fn(&mut Self, u64, u64, Register) -> Ret, - r1: Register, - r2: Register, - rd: Register, - ) -> Ret { - func(self, self.regval(r1), self.regval(r2), rd) - } - fn arithmetic_i( - &mut self, - func: impl Fn(&mut Self, u64, u64, Register) -> Ret, - r1: Register, - imm16: u16, - rd: Register, - ) -> Ret { - func(self, self.regval(r1), sign_extend::<16>(imm16.into()), rd) - } - fn add(&mut self, a: u64, b: u64, to: Register) { - let AddResult { - result, - unsigned_overflow, - signed_overflow, - } = ops::add(a, b, self.carry()); - *self.regval_mut(to) = result; - self.cpu - .set_flag(StFlag::CARRY_BORROW_UNSIGNED, unsigned_overflow); - self.cpu.set_flag(StFlag::CARRY_BORROW, signed_overflow); - } - fn sub(&mut self, a: u64, b: u64, to: Register) { - let AddResult { - result, - unsigned_overflow, - signed_overflow, - } = ops::sub(a, b, self.carry()); - *self.regval_mut(to) = result; - self.cpu - .set_flag(StFlag::CARRY_BORROW_UNSIGNED, unsigned_overflow); - self.cpu.set_flag(StFlag::CARRY_BORROW, signed_overflow); - } - fn imul(&mut self, a: u64, b: u64, to: Register) { - *self.regval_mut(to) = ops::imul(a, b); - } - fn idiv(&mut self, a: u64, b: u64, to: Register) -> Result<(), Interrupt> { - *self.regval_mut(to) = ops::idiv(a, b).ok_or(Interrupt::DIVIDE_BY_ZERO)?; - Ok(()) - } - fn umul(&mut self, a: u64, b: u64, to: Register) { - *self.regval_mut(to) = ops::umul(a, b); - } - fn udiv(&mut self, a: u64, b: u64, to: Register) -> Result<(), Interrupt> { - *self.regval_mut(to) = ops::udiv(a, b).ok_or(Interrupt::DIVIDE_BY_ZERO)?; - Ok(()) - } - // maybe interrupt instead? - fn rem(&mut self, a: u64, b: u64, to: Register) { - *self.regval_mut(to) = ops::rem(a, b).unwrap_or(0); - } - fn r#mod(&mut self, a: u64, b: u64, to: Register) { - *self.regval_mut(to) = ops::r#mod(a, b).unwrap_or(0); - } - /* bitwise */ - fn bitwise_r( - &mut self, - func: impl Fn(&mut Self, u64, u64, Register) -> Ret, - r1: Register, - r2: Register, - rd: Register, - ) -> Ret { - func(self, self.regval(r1), self.regval(r2), rd) - } - fn bitwise_i( - &mut self, - func: impl Fn(&mut Self, u64, u64, Register) -> Ret, - r1: Register, - imm16: u16, - rd: Register, - ) -> Ret { - func(self, self.regval(r1), imm16.into(), rd) - } - fn and(&mut self, a: u64, b: u64, to: Register) { - *self.regval_mut(to) = ops::and(a, b); - } - fn or(&mut self, a: u64, b: u64, to: Register) { - *self.regval_mut(to) = ops::or(a, b); - } - fn nor(&mut self, a: u64, b: u64, to: Register) { - *self.regval_mut(to) = ops::nor(a, b); - } - fn xor(&mut self, a: u64, b: u64, to: Register) { - *self.regval_mut(to) = ops::xor(a, b); - } - fn shl(&mut self, a: u64, b: u64, to: Register) { - *self.regval_mut(to) = ops::shl(a, b); - } - fn asr(&mut self, a: u64, b: u64, to: Register) { - *self.regval_mut(to) = ops::asr(a, b); - } - fn lsr(&mut self, a: u64, b: u64, to: Register) { - *self.regval_mut(to) = ops::shr(a, b); - } - fn bit(&mut self, a: u64, b: u64, to: Register) { - *self.regval_mut(to) = ops::bit(a, b); - } + I::Lw { + rd, + rs, + rn, + sh, + off, + } => { + if let Err(err) = self.read_to_u64(self.load_address(rs, off, rn, sh), rd) { + self.push_interrupt_from_mmu(err); + } + } + I::Lh { + rd, + rs, + rn, + sh, + off, + } => { + if let Err(err) = self.read_to_u32(self.load_address(rs, off, rn, sh), rd) { + self.push_interrupt_from_mmu(err); + } + } + I::Lhs { + rd, + rs, + rn, + sh, + off, + } => { + if let Err(err) = self.read_to_u32_signed(self.load_address(rs, off, rn, sh), rd) { + self.push_interrupt_from_mmu(err); + } + } + I::Lq { + rd, + rs, + rn, + sh, + off, + } => { + if let Err(err) = self.read_to_u16(self.load_address(rs, off, rn, sh), rd) { + self.push_interrupt_from_mmu(err); + } + } + I::Lqs { + rd, + rs, + rn, + sh, + off, + } => { + if let Err(err) = self.read_to_u16_signed(self.load_address(rs, off, rn, sh), rd) { + self.push_interrupt_from_mmu(err); + } + } + I::Lb { + rd, + rs, + rn, + sh, + off, + } => { + if let Err(err) = self.read_to_u8(self.load_address(rs, off, rn, sh), rd) { + self.push_interrupt_from_mmu(err); + } + } + I::Lbs { + rd, + rs, + rn, + sh, + off, + } => { + if let Err(err) = self.read_to_u8_signed(self.load_address(rs, off, rn, sh), rd) { + self.push_interrupt_from_mmu(err); + } + } + I::Sw { + rs, + off, + rn, + sh, + rd, + } => { + if let Err(err) = + self.write_u64(self.load_address(rs, off, rn, sh), self.regval(rd)) + { + self.push_interrupt_from_mmu(err); + } + } + I::Sh { + rs, + off, + rn, + sh, + rd, + } => { + if let Err(err) = + self.write_u32(self.load_address(rs, off, rn, sh), self.regval(rd) as u32) + { + self.push_interrupt_from_mmu(err); + } + } + I::Sq { + rs, + off, + rn, + sh, + rd, + } => { + if let Err(err) = + self.write_u16(self.load_address(rs, off, rn, sh), self.regval(rd) as u16) + { + self.push_interrupt_from_mmu(err); + } + } + I::Sb { + rs, + off, + rn, + sh, + rd, + } => { + if let Err(err) = + self.write_u8(self.load_address(rs, off, rn, sh), self.regval(rd) as u8) + { + self.push_interrupt_from_mmu(err); + } + } + // comparisons + I::Cmpr { r1, r2 } => self.cpu.set_cmp_u64(self.regval(r1), self.regval(r2)), + I::Cmpi { r1, s, imm } => { + if s { + self.cpu + .set_cmp_u64(sign_extend::<16>(imm.into()), self.regval(r1)); + } else { + self.cpu + .set_cmp_u64(self.regval(r1), sign_extend::<16>(imm.into())); + } + } + // arithmetic operations + I::Addr { rd, r1, r2 } => self.arithmetic_r(Self::add, r1, r2, rd), + I::Addi { rd, r1, imm16 } => self.arithmetic_i(Self::add, r1, imm16, rd), + I::Subr { rd, r1, r2 } => self.arithmetic_r(Self::sub, r1, r2, rd), + I::Subi { rd, r1, imm16 } => self.arithmetic_i(Self::sub, r1, imm16, rd), + I::Imulr { rd, r1, r2 } => self.arithmetic_r(Self::imul, r1, r2, rd), + I::Imuli { rd, r1, imm16 } => self.arithmetic_i(Self::imul, r1, imm16, rd), + I::Idivr { rd, r1, r2 } => self.arithmetic_r(Self::idiv, r1, r2, rd)?, + I::Idivi { rd, r1, imm16 } => self.arithmetic_i(Self::idiv, r1, imm16, rd)?, + I::Umulr { rd, r1, r2 } => self.arithmetic_r(Self::umul, r1, r2, rd), + I::Umuli { rd, r1, imm16 } => self.arithmetic_i(Self::umul, r1, imm16, rd), + I::Udivr { rd, r1, r2 } => self.arithmetic_r(Self::udiv, r1, r2, rd)?, + I::Udivi { rd, r1, imm16 } => self.arithmetic_i(Self::udiv, r1, imm16, rd)?, + I::Remr { rd, r1, r2 } => self.arithmetic_r(Self::rem, r1, r2, rd), + I::Remi { rd, r1, imm16 } => self.arithmetic_i(Self::rem, r1, imm16, rd), + I::Modr { rd, r1, r2 } => self.arithmetic_r(Self::r#mod, r1, r2, rd), + I::Modi { rd, r1, imm16 } => self.arithmetic_i(Self::r#mod, r1, imm16, rd), + // bitwise operations + I::Andr { rd, r1, r2 } => self.bitwise_r(Self::and, r1, r2, rd), + I::Andi { rd, r1, imm16 } => self.bitwise_i(Self::and, r1, imm16, rd), + I::Orr { rd, r1, r2 } => self.bitwise_r(Self::or, r1, r2, rd), + I::Ori { rd, r1, imm16 } => self.bitwise_i(Self::or, r1, imm16, rd), + I::Norr { rd, r1, r2 } => self.bitwise_r(Self::nor, r1, r2, rd), + I::Nori { rd, r1, imm16 } => self.bitwise_i(Self::nor, r1, imm16, rd), + I::Xorr { rd, r1, r2 } => self.bitwise_r(Self::xor, r1, r2, rd), + I::Xori { rd, r1, imm16 } => self.bitwise_i(Self::xor, r1, imm16, rd), + I::Shlr { rd, r1, r2 } => self.bitwise_r(Self::shl, r1, r2, rd), + I::Shli { rd, r1, imm16 } => self.bitwise_i(Self::shl, r1, imm16, rd), + I::Asrr { rd, r1, r2 } => self.bitwise_r(Self::asr, r1, r2, rd), + I::Asri { rd, r1, imm16 } => self.bitwise_i(Self::asr, r1, imm16, rd), + I::Lsrr { rd, r1, r2 } => self.bitwise_r(Self::lsr, r1, r2, rd), + I::Lsri { rd, r1, imm16 } => self.bitwise_i(Self::lsr, r1, imm16, rd), + I::Bitr { rd, r1, r2 } => self.bitwise_r(Self::bit, r1, r2, rd), + I::Biti { rd, r1, imm16 } => self.bitwise_i(Self::bit, r1, imm16, rd), + // float operations + I::Fcmp { r1, r2, p } => { + self.cpu + .set_cmp_float_precision(self.regval(r1), self.regval(r2), p) + } + I::Fto { rd, rs, p } => *self.regval_mut(rd) = p.fto(self.regval(rs)), + I::Ffrom { rd, rs, p } => *self.regval_mut(rd) = p.ffrom(self.regval(rs)), + I::Fneg { rd, rs, p } => *self.regval_mut(rd) = p.fneg(self.regval(rs)), + I::Fabs { rd, rs, p } => *self.regval_mut(rd) = p.fabs(self.regval(rs)), + I::Fadd { rd, r1, r2, p } => { + *self.regval_mut(rd) = p.fadd(self.regval(r1), self.regval(r2)) + } + I::Fsub { rd, r1, r2, p } => { + *self.regval_mut(rd) = p.fsub(self.regval(r1), self.regval(r2)) + } + I::Fmul { rd, r1, r2, p } => { + *self.regval_mut(rd) = p.fmul(self.regval(r1), self.regval(r2)) + } + I::Fdiv { rd, r1, r2, p } => { + *self.regval_mut(rd) = p.fdiv(self.regval(r1), self.regval(r2)) + } + I::Fma { rd, r1, r2, p } => { + p.fma(self.regval(r1), self.regval(r2), self.regval_mut(rd)) + } + I::Fsqrt { rd, r1, p } => *self.regval_mut(rd) = p.fsqrt(self.regval(r1)), + I::Fmin { rd, r1, r2, p } => { + *self.regval_mut(rd) = p.fmin(self.regval(r1), self.regval(r2)) + } + I::Fmax { rd, r1, r2, p } => { + *self.regval_mut(rd) = p.fmax(self.regval(r1), self.regval(r2)) + } + I::Fsat { rd, r1, p } => *self.regval_mut(rd) = p.fsat(self.regval(r1)), + I::Fcnv { rd, r1, p } => *self.regval_mut(rd) = p.cast(self.regval(r1)), + I::Fnan { rd, r1, p } => *self.regval_mut(rd) = p.fnan(self.regval(r1)), + } + Ok(()) + } + /* ops */ + const fn carry(&self) -> bool { + self.cpu.get_flag(StFlag::CARRY_BORROW_UNSIGNED) + } + /* arithmetic */ + fn arithmetic_r( + &mut self, + func: impl Fn(&mut Self, u64, u64, Register) -> Ret, + r1: Register, + r2: Register, + rd: Register, + ) -> Ret { + func(self, self.regval(r1), self.regval(r2), rd) + } + fn arithmetic_i( + &mut self, + func: impl Fn(&mut Self, u64, u64, Register) -> Ret, + r1: Register, + imm16: u16, + rd: Register, + ) -> Ret { + func(self, self.regval(r1), sign_extend::<16>(imm16.into()), rd) + } + fn add(&mut self, a: u64, b: u64, to: Register) { + let AddResult { + result, + unsigned_overflow, + signed_overflow, + } = ops::add(a, b, self.carry()); + *self.regval_mut(to) = result; + self.cpu + .set_flag(StFlag::CARRY_BORROW_UNSIGNED, unsigned_overflow); + self.cpu.set_flag(StFlag::CARRY_BORROW, signed_overflow); + } + fn sub(&mut self, a: u64, b: u64, to: Register) { + let AddResult { + result, + unsigned_overflow, + signed_overflow, + } = ops::sub(a, b, self.carry()); + *self.regval_mut(to) = result; + self.cpu + .set_flag(StFlag::CARRY_BORROW_UNSIGNED, unsigned_overflow); + self.cpu.set_flag(StFlag::CARRY_BORROW, signed_overflow); + } + fn imul(&mut self, a: u64, b: u64, to: Register) { + *self.regval_mut(to) = ops::imul(a, b); + } + fn idiv(&mut self, a: u64, b: u64, to: Register) -> Result<(), Interrupt> { + *self.regval_mut(to) = ops::idiv(a, b).ok_or(Interrupt::DIVIDE_BY_ZERO)?; + Ok(()) + } + fn umul(&mut self, a: u64, b: u64, to: Register) { + *self.regval_mut(to) = ops::umul(a, b); + } + fn udiv(&mut self, a: u64, b: u64, to: Register) -> Result<(), Interrupt> { + *self.regval_mut(to) = ops::udiv(a, b).ok_or(Interrupt::DIVIDE_BY_ZERO)?; + Ok(()) + } + // maybe interrupt instead? + fn rem(&mut self, a: u64, b: u64, to: Register) { + *self.regval_mut(to) = ops::rem(a, b).unwrap_or(0); + } + fn r#mod(&mut self, a: u64, b: u64, to: Register) { + *self.regval_mut(to) = ops::r#mod(a, b).unwrap_or(0); + } + /* bitwise */ + fn bitwise_r( + &mut self, + func: impl Fn(&mut Self, u64, u64, Register) -> Ret, + r1: Register, + r2: Register, + rd: Register, + ) -> Ret { + func(self, self.regval(r1), self.regval(r2), rd) + } + fn bitwise_i( + &mut self, + func: impl Fn(&mut Self, u64, u64, Register) -> Ret, + r1: Register, + imm16: u16, + rd: Register, + ) -> Ret { + func(self, self.regval(r1), imm16.into(), rd) + } + fn and(&mut self, a: u64, b: u64, to: Register) { + *self.regval_mut(to) = ops::and(a, b); + } + fn or(&mut self, a: u64, b: u64, to: Register) { + *self.regval_mut(to) = ops::or(a, b); + } + fn nor(&mut self, a: u64, b: u64, to: Register) { + *self.regval_mut(to) = ops::nor(a, b); + } + fn xor(&mut self, a: u64, b: u64, to: Register) { + *self.regval_mut(to) = ops::xor(a, b); + } + fn shl(&mut self, a: u64, b: u64, to: Register) { + *self.regval_mut(to) = ops::shl(a, b); + } + fn asr(&mut self, a: u64, b: u64, to: Register) { + *self.regval_mut(to) = ops::asr(a, b); + } + fn lsr(&mut self, a: u64, b: u64, to: Register) { + *self.regval_mut(to) = ops::shr(a, b); + } + fn bit(&mut self, a: u64, b: u64, to: Register) { + *self.regval_mut(to) = ops::bit(a, b); + } - /* end ops */ - #[allow(clippy::cast_possible_truncation)] - pub fn ioc_receive(&mut self, data: u64) { - match self.ioc.ioc_data.status { - IocStatus::StandBy => { - if self.ioc.port_data(Port::IO) == 0 { - self.ioc.ioc_data.status = IocStatus::BindIntWaitingForPort; - } - } - IocStatus::BindIntWaitingForPort => { - self.ioc.ioc_data.bindport = Port(data as u16); - self.ioc.ioc_data.status = IocStatus::BindIntWaitingForInt; - } - IocStatus::BindIntWaitingForInt => { - self.ioc - .bind_port(self.ioc.ioc_data.bindport, Interrupt(data as u8)); - self.ioc.ioc_data.status = IocStatus::StandBy; - } - } - } - pub fn ic_receive(&mut self, data: u64) { - match self.ioc.ic_data.status { - IcStatus::StandBy => { - if self.ioc.port_data(Port::IO) == 0 { - self.ioc.ic_data.status = IcStatus::WaitingForIvt; - } - } - IcStatus::WaitingForIvt => { - self.ic.ivt_base_address = data; - self.ioc.ic_data.status = IcStatus::StandBy; - } - } - } - pub fn mmu_receive(&mut self, _data: u64) { - todo!("mmu IO") - } - pub fn systimer_receive(&mut self, _data: u64) { - todo!("systimer IO") - } - pub fn send_in(&mut self, port: Port, data: u64) { - let port = port.0 as usize % NUM_PORTS; - self.ioc.ports[port] = data; - if self.ioc.is_bound[port] { - self.push_interrupt(self.ioc.binding[port]); - } - } + /* end ops */ + #[allow(clippy::cast_possible_truncation)] + pub fn ioc_receive(&mut self, data: u64) { + match self.ioc.ioc_data.status { + IocStatus::StandBy => { + if self.ioc.port_data(Port::IO) == 0 { + self.ioc.ioc_data.status = IocStatus::BindIntWaitingForPort; + } + } + IocStatus::BindIntWaitingForPort => { + self.ioc.ioc_data.bindport = Port(data as u16); + self.ioc.ioc_data.status = IocStatus::BindIntWaitingForInt; + } + IocStatus::BindIntWaitingForInt => { + self.ioc + .bind_port(self.ioc.ioc_data.bindport, Interrupt(data as u8)); + self.ioc.ioc_data.status = IocStatus::StandBy; + } + } + } + pub fn ic_receive(&mut self, data: u64) { + match self.ioc.ic_data.status { + IcStatus::StandBy => { + if self.ioc.port_data(Port::IO) == 0 { + self.ioc.ic_data.status = IcStatus::WaitingForIvt; + } + } + IcStatus::WaitingForIvt => { + self.ic.ivt_base_address = data; + self.ioc.ic_data.status = IcStatus::StandBy; + } + } + } + pub fn mmu_receive(&mut self, _data: u64) { + todo!("mmu IO") + } + pub fn systimer_receive(&mut self, _data: u64) { + todo!("systimer IO") + } + pub fn send_in(&mut self, port: Port, data: u64) { + let port = port.0 as usize % NUM_PORTS; + self.ioc.ports[port] = data; + if self.ioc.is_bound[port] { + self.push_interrupt(self.ioc.binding[port]); + } + } } #[cfg(feature = "std")] impl State> { - #[must_use] - pub fn new_boxed(mem_cap: Option, image: &[u8]) -> Option { - Some(Self { - mmu: Mmu::new_boxed(mem_cap, image)?, - ic: Ic::new(), - cpu: Cpu::new(), - ioc: Ioc::new(), - }) - } + #[must_use] + pub fn new_boxed(mem_cap: Option, image: &[u8]) -> Option { + Some(Self { + mmu: Mmu::new_boxed(mem_cap, image)?, + ic: Ic::new(), + cpu: Cpu::new(), + ioc: Ioc::new(), + }) + } } impl State<[u8; N]> { - #[must_use] - pub fn new(image: &[u8]) -> Option { - Some(Self { - mmu: Mmu::new([0; N], image)?, - ic: Ic::new(), - cpu: Cpu::new(), - ioc: Ioc::new(), - }) - } + #[must_use] + pub fn new(image: &[u8]) -> Option { + Some(Self { + mmu: Mmu::new([0; N], image)?, + ic: Ic::new(), + cpu: Cpu::new(), + ioc: Ioc::new(), + }) + } } #[derive(Debug, Clone)] pub struct Emulator + AsMut<[u8]>, U: Callback> { - pub state: State, - pub callback: U, + pub state: State, + pub callback: U, } impl + AsMut<[u8]>, U: Callback> Emulator { - pub const fn new(state: State, callback: U) -> Self { - Self { state, callback } - } - pub fn run(mut self) -> U { - self.callback.on_run_started(&mut self.state); - loop { - if self.callback.should_stop(&self.state) { - break; - } - self.callback.on_iteration_started(&mut self.state); - 'inner: { - match self.state.read_instruction(self.state.regval(Register::Ip)) { - Ok(instr) => self.state.set_current_instr(instr), - Err(err) => { - self.state.push_interrupt_from_mmu(err); - break 'inner; - } - } - self.callback.on_instruction_loaded(&mut self.state); + pub const fn new(state: State, callback: U) -> Self { + Self { state, callback } + } + pub fn run(mut self) -> U { + self.callback.on_run_started(&mut self.state); + loop { + if self.callback.should_stop(&self.state) { + break; + } + self.callback.on_iteration_started(&mut self.state); + 'inner: { + match self.state.read_instruction(self.state.regval(Register::Ip)) { + Ok(instr) => self.state.set_current_instr(instr), + Err(err) => { + self.state.push_interrupt_from_mmu(err); + break 'inner; + } + } + self.callback.on_instruction_loaded(&mut self.state); - *self.state.regval_mut(Register::Ip) += 4; + *self.state.regval_mut(Register::Ip) += 4; - if let Err(err) = self.state.interpret_code() { - self.state.push_interrupt(err); - } + if let Err(err) = self.state.interpret_code() { + self.state.push_interrupt(err); + } - // TODO: do io stuff + // TODO: do io stuff - if self.state.ioc.out_pin { - let data = self.state.ioc.port_data(self.state.ioc.port); - match self.state.ioc.port { - Port::INT => self.state.ioc_receive(data), - Port::IO => self.state.ic_receive(data), - Port::MMU => self.state.mmu_receive(data), - Port::SYSTIMER => self.state.systimer_receive(data), - port => self.callback.on_output_received( - &self.state, - port, - self.state.ioc.port_data(port), - ), - } - self.state.ioc.out_pin = false; - } + if self.state.ioc.out_pin { + let data = self.state.ioc.port_data(self.state.ioc.port); + match self.state.ioc.port { + Port::INT => self.state.ioc_receive(data), + Port::IO => self.state.ic_receive(data), + Port::MMU => self.state.mmu_receive(data), + Port::SYSTIMER => self.state.systimer_receive(data), + port => self.callback.on_output_received( + &self.state, + port, + self.state.ioc.port_data(port), + ), + } + self.state.ioc.out_pin = false; + } - self.state.cpu.registers[Register::Rz] = 0; - if self.state.regval(Register::Sp) > self.state.regval(Register::Fp) { - self.state.push_interrupt(Interrupt::STACK_UNDERFLOW); - } + self.state.cpu.registers[Register::Rz] = 0; + if self.state.regval(Register::Sp) > self.state.regval(Register::Fp) { + self.state.push_interrupt(Interrupt::STACK_UNDERFLOW); + } - if let Some((port, data)) = self.callback.send_input(&self.state) { - self.state.send_in(port, data); - } - } + if let Some((port, data)) = self.callback.send_input(&self.state) { + self.state.send_in(port, data); + } + } - self.callback.on_iteration_ended(&mut self.state); - self.state.cpu.cycle += 1; - } - self.callback.on_run_ended(&mut self.state); - self.callback - } + self.callback.on_iteration_ended(&mut self.state); + self.state.cpu.cycle += 1; + } + self.callback.on_run_ended(&mut self.state); + self.callback + } } diff --git a/src/ic.rs b/src/ic.rs index 6903184..be381cf 100644 --- a/src/ic.rs +++ b/src/ic.rs @@ -1,6 +1,6 @@ use core::{ - fmt::Debug, - ops::{Index, IndexMut}, + fmt::Debug, + ops::{Index, IndexMut}, }; use aphelion_util::interrupt::Interrupt; @@ -8,115 +8,115 @@ use aphelion_util::interrupt::Interrupt; /// Look ma, no heap allocation! #[derive(Debug, Clone, Copy)] pub struct IntQueue { - data: [Interrupt; IntQueue::MAX_CAPACITY as usize], - offset: u8, - len: u8, + data: [Interrupt; IntQueue::MAX_CAPACITY as usize], + offset: u8, + len: u8, } impl IntQueue { - pub const MAX_CAPACITY: u8 = 32; - #[allow(clippy::cast_possible_truncation)] - const fn loc(&self, idx: usize) -> usize { - debug_assert!(idx < (self.len as usize)); - ((self.offset + (idx as u8)) % Self::MAX_CAPACITY) as usize - } - #[must_use] - pub const fn offset(&self) -> usize { - self.offset as usize - } - #[must_use] - pub const fn len(&self) -> usize { - self.len as usize - } - #[must_use] - pub const fn is_empty(&self) -> bool { - self.len == 0 - } - #[must_use] - pub const fn new() -> Self { - Self { - data: [Interrupt(0); IntQueue::MAX_CAPACITY as usize], - offset: 0, - len: 0, - } - } - #[must_use] - pub const fn reached_capacity(&self) -> bool { - self.len == Self::MAX_CAPACITY - } - pub fn pop_back(&mut self) -> Option { - (!self.is_empty()).then_some({ - let res = self[self.len as usize - 1]; - self.len -= 1; - res - }) - } - pub fn pop_front(&mut self) -> Option { - (!self.is_empty()).then_some({ - let res = self[0]; - self.offset = (self.offset + 1) % Self::MAX_CAPACITY; - self.len -= 1; - res - }) - } - pub fn push_back(&mut self, int: Interrupt) -> bool { - if self.len == Self::MAX_CAPACITY { - false - } else { - debug_assert!(self.offset < Self::MAX_CAPACITY); - self.len += 1; - let len = self.len as usize; - self[len - 1] = int; - true - } - } - pub fn push_front(&mut self, int: Interrupt) -> bool { - if self.len == Self::MAX_CAPACITY { - false - } else { - self.len += 1; - self.offset = (self.offset + Self::MAX_CAPACITY - 1) % Self::MAX_CAPACITY; - self[0] = int; - true - } - } - pub fn clear(&mut self) { - self.offset = 0; - self.len = 0; - } - pub fn total_clear(&mut self) { - *self = Self::new(); - } + pub const MAX_CAPACITY: u8 = 32; + #[allow(clippy::cast_possible_truncation)] + const fn loc(&self, idx: usize) -> usize { + debug_assert!(idx < (self.len as usize)); + ((self.offset + (idx as u8)) % Self::MAX_CAPACITY) as usize + } + #[must_use] + pub const fn offset(&self) -> usize { + self.offset as usize + } + #[must_use] + pub const fn len(&self) -> usize { + self.len as usize + } + #[must_use] + pub const fn is_empty(&self) -> bool { + self.len == 0 + } + #[must_use] + pub const fn new() -> Self { + Self { + data: [Interrupt(0); IntQueue::MAX_CAPACITY as usize], + offset: 0, + len: 0, + } + } + #[must_use] + pub const fn reached_capacity(&self) -> bool { + self.len == Self::MAX_CAPACITY + } + pub fn pop_back(&mut self) -> Option { + (!self.is_empty()).then_some({ + let res = self[self.len as usize - 1]; + self.len -= 1; + res + }) + } + pub fn pop_front(&mut self) -> Option { + (!self.is_empty()).then_some({ + let res = self[0]; + self.offset = (self.offset + 1) % Self::MAX_CAPACITY; + self.len -= 1; + res + }) + } + pub fn push_back(&mut self, int: Interrupt) -> bool { + if self.len == Self::MAX_CAPACITY { + false + } else { + debug_assert!(self.offset < Self::MAX_CAPACITY); + self.len += 1; + let len = self.len as usize; + self[len - 1] = int; + true + } + } + pub fn push_front(&mut self, int: Interrupt) -> bool { + if self.len == Self::MAX_CAPACITY { + false + } else { + self.len += 1; + self.offset = (self.offset + Self::MAX_CAPACITY - 1) % Self::MAX_CAPACITY; + self[0] = int; + true + } + } + pub fn clear(&mut self) { + self.offset = 0; + self.len = 0; + } + pub fn total_clear(&mut self) { + *self = Self::new(); + } } impl Index for IntQueue { - type Output = Interrupt; - fn index(&self, index: usize) -> &Self::Output { - &self.data[self.loc(index)] - } + type Output = Interrupt; + fn index(&self, index: usize) -> &Self::Output { + &self.data[self.loc(index)] + } } impl IndexMut for IntQueue { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.data[self.loc(index)] - } + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.data[self.loc(index)] + } } /* impl Debug for IntQueue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.as_slice().fmt(f) } + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.as_slice().fmt(f) } } */ #[derive(Debug, Clone, Copy)] pub struct Ic { - pub ivt_base_address: u64, - pub ret_addr: u64, - pub ret_status: u64, - pub queue: IntQueue, + pub ivt_base_address: u64, + pub ret_addr: u64, + pub ret_status: u64, + pub queue: IntQueue, } impl Ic { - #[must_use] - pub const fn new() -> Self { - Self { - ivt_base_address: 0, - ret_addr: 0, - ret_status: 0, - queue: IntQueue::new(), - } - } + #[must_use] + pub const fn new() -> Self { + Self { + ivt_base_address: 0, + ret_addr: 0, + ret_status: 0, + queue: IntQueue::new(), + } + } } diff --git a/src/ioc.rs b/src/ioc.rs index 81e5e91..80aedbd 100644 --- a/src/ioc.rs +++ b/src/ioc.rs @@ -5,100 +5,100 @@ pub const NUM_PORTS_U16: u16 = NUM_PORTS as u16; #[derive(Debug, Clone, Copy)] pub struct Ioc { - pub in_pin: bool, - pub out_pin: bool, - pub port: Port, - pub binding: [Interrupt; NUM_PORTS], - pub is_bound: [bool; NUM_PORTS], - pub ports: [u64; NUM_PORTS], - pub ioc_data: IocData, - pub ic_data: IcData, + pub in_pin: bool, + pub out_pin: bool, + pub port: Port, + pub binding: [Interrupt; NUM_PORTS], + pub is_bound: [bool; NUM_PORTS], + pub ports: [u64; NUM_PORTS], + pub ioc_data: IocData, + pub ic_data: IcData, } impl Ioc { - pub const NUM_PORTS: usize = 256; - #[must_use] - pub const fn new() -> Self { - Self { - in_pin: false, - out_pin: false, - port: Port(0), - binding: [Interrupt(0); NUM_PORTS], - is_bound: [false; NUM_PORTS], - ports: [0; NUM_PORTS], - ioc_data: IocData::DFLT, - ic_data: IcData::DFLT, - } - } - pub fn send_out(&mut self, port: Port, data: u64) { - let port = Port(port.0 % NUM_PORTS_U16); - self.out_pin = true; - self.port = port; - self.ports[port.0 as usize] = data; - } + pub const NUM_PORTS: usize = 256; + #[must_use] + pub const fn new() -> Self { + Self { + in_pin: false, + out_pin: false, + port: Port(0), + binding: [Interrupt(0); NUM_PORTS], + is_bound: [false; NUM_PORTS], + ports: [0; NUM_PORTS], + ioc_data: IocData::DFLT, + ic_data: IcData::DFLT, + } + } + pub fn send_out(&mut self, port: Port, data: u64) { + let port = Port(port.0 % NUM_PORTS_U16); + self.out_pin = true; + self.port = port; + self.ports[port.0 as usize] = data; + } - #[must_use] - pub const fn port_data(&self, port: Port) -> u64 { - self.ports[port.0 as usize % NUM_PORTS] - } - pub fn bind_port(&mut self, port: Port, interrupt: Interrupt) { - let port = port.0 as usize % NUM_PORTS; - self.is_bound[port] = true; - self.binding[port] = interrupt; - } + #[must_use] + pub const fn port_data(&self, port: Port) -> u64 { + self.ports[port.0 as usize % NUM_PORTS] + } + pub fn bind_port(&mut self, port: Port, interrupt: Interrupt) { + let port = port.0 as usize % NUM_PORTS; + self.is_bound[port] = true; + self.binding[port] = interrupt; + } } impl Default for Ioc { - fn default() -> Self { - Self { - in_pin: false, - out_pin: false, - port: Port(0), - binding: [Interrupt(0); Self::NUM_PORTS], - is_bound: [false; Self::NUM_PORTS], - ports: [0; Self::NUM_PORTS], - ioc_data: <_>::default(), - ic_data: <_>::default(), - } - } + fn default() -> Self { + Self { + in_pin: false, + out_pin: false, + port: Port(0), + binding: [Interrupt(0); Self::NUM_PORTS], + is_bound: [false; Self::NUM_PORTS], + ports: [0; Self::NUM_PORTS], + ioc_data: <_>::default(), + ic_data: <_>::default(), + } + } } #[allow(clippy::module_name_repetitions)] #[derive(Debug, Clone, Copy, Default)] pub enum IocStatus { - #[default] - StandBy, - BindIntWaitingForPort, - BindIntWaitingForInt, + #[default] + StandBy, + BindIntWaitingForPort, + BindIntWaitingForInt, } #[allow(clippy::module_name_repetitions)] #[derive(Debug, Clone, Copy)] pub struct IocData { - pub status: IocStatus, - pub bindport: Port, + pub status: IocStatus, + pub bindport: Port, } impl IocData { - pub const DFLT: Self = Self { - status: IocStatus::StandBy, - bindport: Port(0), - }; + pub const DFLT: Self = Self { + status: IocStatus::StandBy, + bindport: Port(0), + }; } impl Default for IocData { - fn default() -> Self { - Self::DFLT - } + fn default() -> Self { + Self::DFLT + } } #[derive(Debug, Clone, Copy, Default)] pub enum IcStatus { - #[default] - StandBy, - WaitingForIvt, + #[default] + StandBy, + WaitingForIvt, } #[derive(Debug, Clone, Copy, Default)] pub struct IcData { - pub status: IcStatus, + pub status: IcStatus, } impl IcData { - pub const DFLT: Self = Self { - status: IcStatus::StandBy, - }; + pub const DFLT: Self = Self { + status: IcStatus::StandBy, + }; } diff --git a/src/mmu.rs b/src/mmu.rs index 0bb7702..9bb4119 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -1,23 +1,23 @@ #[derive(Debug, Clone)] pub struct Mmu + AsMut<[u8]>> { - pub memory: T, - pub page_table_base: u64, + pub memory: T, + pub page_table_base: u64, } #[derive(Debug, Clone, Copy)] pub enum Response { - AccViolation, - NoPerms, - OutOfBounds, - Unaligned, + AccViolation, + NoPerms, + OutOfBounds, + Unaligned, } /// TODO: put this in the library instead #[derive(Debug, Clone, Copy)] pub enum AccessMode { - Valid = 0, - Override = 1, - Read = 2, - Write = 3, - Execute = 4, + Valid = 0, + Override = 1, + Read = 2, + Write = 3, + Execute = 4, } /// TODO: put this in the library instead @@ -25,129 +25,129 @@ pub enum AccessMode { pub struct Pde(pub u64); impl Pde { - #[must_use] - pub const fn valid(self) -> bool { - self.0 & (1 << 0) != 0 - } - #[must_use] - pub const fn r#override(self) -> bool { - self.0 & (1 << 1) != 0 - } - #[must_use] - pub const fn read(self) -> bool { - self.0 & (1 << 2) != 0 - } - #[must_use] - pub const fn write(self) -> bool { - self.0 & (1 << 3) != 0 - } - #[must_use] - pub const fn execute(self) -> bool { - self.0 & (1 << 4) != 0 - } - #[must_use] - pub const fn next(self) -> u64 { - self.0 & (!0b11_1111_1111_1111) - } - #[must_use] - pub const fn has_perm(self, mode: AccessMode) -> bool { - self.0 & (mode as u64) != 0 - } + #[must_use] + pub const fn valid(self) -> bool { + self.0 & (1 << 0) != 0 + } + #[must_use] + pub const fn r#override(self) -> bool { + self.0 & (1 << 1) != 0 + } + #[must_use] + pub const fn read(self) -> bool { + self.0 & (1 << 2) != 0 + } + #[must_use] + pub const fn write(self) -> bool { + self.0 & (1 << 3) != 0 + } + #[must_use] + pub const fn execute(self) -> bool { + self.0 & (1 << 4) != 0 + } + #[must_use] + pub const fn next(self) -> u64 { + self.0 & (!0b11_1111_1111_1111) + } + #[must_use] + pub const fn has_perm(self, mode: AccessMode) -> bool { + self.0 & (mode as u64) != 0 + } } macro_rules! phys_get { - ($fn_name: ident, $ty: ty) => { - /// # Errors - /// - /// Either [`Response::OutOfBounds`] or [`Response::Unaligned`] is returned as error. They should be straight forward. - /// - pub fn $fn_name(&self, addr: u64) -> Result<$ty, Response> { - self.phys_get_sized(addr) - .map(|val| <$ty>::from_le_bytes(*val)) - } - }; + ($fn_name: ident, $ty: ty) => { + /// # Errors + /// + /// Either [`Response::OutOfBounds`] or [`Response::Unaligned`] is returned as error. They should be straight forward. + /// + pub fn $fn_name(&self, addr: u64) -> Result<$ty, Response> { + self.phys_get_sized(addr) + .map(|val| <$ty>::from_le_bytes(*val)) + } + }; } macro_rules! phys_write { - ($fn_name: ident, $ty: ty) => { - /// # Errors - /// - /// Either [`Response::OutOfBounds`] or [`Response::Unaligned`] is returned as error. They should be straight forward. - /// - pub fn $fn_name(&mut self, addr: u64, with: $ty) -> Result<(), Response> { - self.phys_write_sized(addr, &with.to_le_bytes()) - } - }; + ($fn_name: ident, $ty: ty) => { + /// # Errors + /// + /// Either [`Response::OutOfBounds`] or [`Response::Unaligned`] is returned as error. They should be straight forward. + /// + pub fn $fn_name(&mut self, addr: u64, with: $ty) -> Result<(), Response> { + self.phys_write_sized(addr, &with.to_le_bytes()) + } + }; } impl + AsMut<[u8]>> Mmu { - #[must_use] - pub fn new(zeroed: T, image: &[u8]) -> Option { - let mem_cap = zeroed.as_ref().len(); - if image.len() > mem_cap { - return None; - } - let mut mem = zeroed; - mem.as_mut()[..image.len()].copy_from_slice(image); - Some(Self { - memory: mem, - page_table_base: 0, - }) - } + #[must_use] + pub fn new(zeroed: T, image: &[u8]) -> Option { + let mem_cap = zeroed.as_ref().len(); + if image.len() > mem_cap { + return None; + } + let mut mem = zeroed; + mem.as_mut()[..image.len()].copy_from_slice(image); + Some(Self { + memory: mem, + page_table_base: 0, + }) + } - pub fn size(&self) -> usize { - self.memory.as_ref().len() - } + pub fn size(&self) -> usize { + self.memory.as_ref().len() + } - /// # Errors - /// - /// Either [`Response::OutOfBounds`] or [`Response::Unaligned`] is returned as error. They should be straight forward. - /// - pub fn phys_get_sized(&self, addr: u64) -> Result<&[u8; SIZE], Response> { - let addr = usize::try_from(addr).map_err(|_| Response::OutOfBounds)?; - if addr >= self.size() { - Err(Response::OutOfBounds) - } else if addr % SIZE != 0 { - Err(Response::Unaligned) - } else { - let Ok(res) = self.memory.as_ref()[addr..(addr + SIZE)].try_into() else { - unreachable!() - }; - Ok(res) - } - } - /// # Errors - /// - /// Either [`Response::OutOfBounds`] or [`Response::Unaligned`] is returned as error. They should be straight forward. - /// - pub fn phys_write_sized( - &mut self, - addr: u64, - with: &[u8; SIZE], - ) -> Result<(), Response> { - let addr = usize::try_from(addr).map_err(|_| Response::OutOfBounds)?; - if addr >= self.size() { - Err(Response::OutOfBounds) - } else if addr % SIZE != 0 { - Err(Response::Unaligned) - } else { - self.memory.as_mut()[addr..(addr + SIZE)].copy_from_slice(with); - Ok(()) - } - } - phys_get! {phys_get_u8, u8} - phys_get! {phys_get_u16, u16} - phys_get! {phys_get_u32, u32} - phys_get! {phys_get_u64, u64} - phys_write! {phys_write_u8, u8} - phys_write! {phys_write_u16, u16} - phys_write! {phys_write_u32, u32} - phys_write! {phys_write_u64, u64} + /// # Errors + /// + /// Either [`Response::OutOfBounds`] or [`Response::Unaligned`] is returned as error. They should be straight forward. + /// + pub fn phys_get_sized(&self, addr: u64) -> Result<&[u8; SIZE], Response> { + let addr = usize::try_from(addr).map_err(|_| Response::OutOfBounds)?; + if addr >= self.size() { + Err(Response::OutOfBounds) + } else if addr % SIZE != 0 { + Err(Response::Unaligned) + } else { + let Ok(res) = self.memory.as_ref()[addr..(addr + SIZE)].try_into() else { + unreachable!() + }; + Ok(res) + } + } + /// # Errors + /// + /// Either [`Response::OutOfBounds`] or [`Response::Unaligned`] is returned as error. They should be straight forward. + /// + pub fn phys_write_sized( + &mut self, + addr: u64, + with: &[u8; SIZE], + ) -> Result<(), Response> { + let addr = usize::try_from(addr).map_err(|_| Response::OutOfBounds)?; + if addr >= self.size() { + Err(Response::OutOfBounds) + } else if addr % SIZE != 0 { + Err(Response::Unaligned) + } else { + self.memory.as_mut()[addr..(addr + SIZE)].copy_from_slice(with); + Ok(()) + } + } + phys_get! {phys_get_u8, u8} + phys_get! {phys_get_u16, u16} + phys_get! {phys_get_u32, u32} + phys_get! {phys_get_u64, u64} + phys_write! {phys_write_u8, u8} + phys_write! {phys_write_u16, u16} + phys_write! {phys_write_u32, u32} + phys_write! {phys_write_u64, u64} #[rustfmt::skip] - /// # Errors - /// - /// The error should be straight fowarsd. - /// - pub fn translate_address(&self, r#virtual: u64, mode: AccessMode) -> Result { + /// # Errors + /// + /// The error should be straight fowarsd. + /// + pub fn translate_address(&self, r#virtual: u64, mode: AccessMode) -> Result { let level_1_index = r#virtual >> (11 + 11 + 11 + 11 + 14); let level_2_index = (r#virtual >> ( 11 + 11 + 11 + 14)) & 0b00_0111_1111_1111; let level_3_index = (r#virtual >> ( 11 + 11 + 14)) & 0b00_0111_1111_1111; @@ -163,48 +163,48 @@ impl + AsMut<[u8]>> Mmu { let next = self.translate_address_level(next, level_5_index, mode, &mut auth_pde)?; Ok(next + level_6_index) } - fn translate_address_level( - &self, - next: u64, - level_index: u64, - mode: AccessMode, - auth_pde: &mut Option, - ) -> Result { - let pde = match self.phys_get_u64(next + level_index * 8) { - Ok(pde) if Pde(pde).valid() => Pde(pde), - _ => return Err(Response::AccViolation), - }; - if pde.r#override() { - *auth_pde = Some(pde); - } - if !(auth_pde.unwrap_or(pde).has_perm(mode)) { - return Err(Response::NoPerms); - } - Ok(pde.next()) - } + fn translate_address_level( + &self, + next: u64, + level_index: u64, + mode: AccessMode, + auth_pde: &mut Option, + ) -> Result { + let pde = match self.phys_get_u64(next + level_index * 8) { + Ok(pde) if Pde(pde).valid() => Pde(pde), + _ => return Err(Response::AccViolation), + }; + if pde.r#override() { + *auth_pde = Some(pde); + } + if !(auth_pde.unwrap_or(pde).has_perm(mode)) { + return Err(Response::NoPerms); + } + Ok(pde.next()) + } } pub mod std { - #![cfg(feature = "std")] - use super::Mmu; - use std::{boxed::Box, num::NonZeroUsize, vec}; + #![cfg(feature = "std")] + use super::Mmu; + use std::{boxed::Box, num::NonZeroUsize, vec}; - impl Mmu> { - pub const MEM_PAGE_SIZE: usize = 0x4000; - pub const MEM_DEFAULT_SIZE: usize = 4096 * Self::MEM_PAGE_SIZE; + impl Mmu> { + pub const MEM_PAGE_SIZE: usize = 0x4000; + pub const MEM_DEFAULT_SIZE: usize = 4096 * Self::MEM_PAGE_SIZE; - #[must_use] - pub fn new_boxed(mem_cap: Option, image: &[u8]) -> Option { - let mem_cap = mem_cap.map_or(Self::MEM_DEFAULT_SIZE, std::convert::Into::into); - if image.len() > mem_cap { - return None; - } - // perhaps there is a better way to do it - let mut mem = vec![0u8; mem_cap]; - mem[..image.len()].copy_from_slice(image); - Some(Self { - memory: mem.into_boxed_slice(), - page_table_base: 0, - }) - } - } + #[must_use] + pub fn new_boxed(mem_cap: Option, image: &[u8]) -> Option { + let mem_cap = mem_cap.map_or(Self::MEM_DEFAULT_SIZE, std::convert::Into::into); + if image.len() > mem_cap { + return None; + } + // perhaps there is a better way to do it + let mut mem = vec![0u8; mem_cap]; + mem[..image.len()].copy_from_slice(image); + Some(Self { + memory: mem.into_boxed_slice(), + page_table_base: 0, + }) + } + } }