From 8ededb86127393397905bb67817ae4d42061f10b Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Sun, 22 Dec 2024 21:33:15 +0100 Subject: [PATCH] adding standard instruction logging utility Signed-off-by: Jakub Doka --- bytecode/build.rs | 21 +++++++++++++++ lang/src/backend/hbvm.rs | 55 +++++----------------------------------- vm/src/mem/mod.rs | 44 +++++++++++++++++++++++++++++++- vm/src/vmrun.rs | 1 + 4 files changed, 72 insertions(+), 49 deletions(-) diff --git a/bytecode/build.rs b/bytecode/build.rs index e7aaad4..2a10399 100644 --- a/bytecode/build.rs +++ b/bytecode/build.rs @@ -98,6 +98,27 @@ fn gen_instrs(generated: &mut String) -> Result<(), Box> writeln!(generated, " {name} = {id},")?; } writeln!(generated, "}}")?; + + writeln!(generated, "impl {instr} {{")?; + writeln!(generated, " pub fn size(self) -> usize {{")?; + writeln!(generated, " match self {{")?; + let mut instrs = instructions().collect::>(); + instrs.sort_unstable_by_key(|&[.., ty, _]| iter_args(ty).map(arg_to_width).sum::()); + for group in instrs.chunk_by(|[.., a, _], [.., b, _]| { + iter_args(a).map(arg_to_width).sum::() + == iter_args(b).map(arg_to_width).sum::() + }) { + let ty = group[0][2]; + for &[_, name, ..] in group { + writeln!(generated, " | {instr}::{name}")?; + } + generated.pop(); + let size = iter_args(ty).map(arg_to_width).sum::() + 1; + writeln!(generated, " => {size},")?; + } + writeln!(generated, " }}")?; + writeln!(generated, " }}")?; + writeln!(generated, "}}")?; } '_arg_kind: { diff --git a/lang/src/backend/hbvm.rs b/lang/src/backend/hbvm.rs index c3dc80c..af18293 100644 --- a/lang/src/backend/hbvm.rs +++ b/lang/src/backend/hbvm.rs @@ -697,42 +697,7 @@ fn binary_prelude(to: &mut Vec) { #[derive(Default)] pub struct LoggedMem { pub mem: hbvm::mem::HostMemory, - op_buf: Vec, - disp_buf: String, - prev_instr: Option, -} - -impl LoggedMem { - unsafe fn display_instr(&mut self, instr: hbbytecode::Instr, addr: hbvm::mem::Address) { - let novm: *const hbvm::Vm = core::ptr::null(); - let offset = core::ptr::addr_of!((*novm).memory) as usize; - let regs = unsafe { - &*core::ptr::addr_of!( - (*(((self as *mut _ as *mut u8).sub(offset)) as *const hbvm::Vm)) - .registers - ) - }; - - let mut bytes = core::slice::from_raw_parts( - (addr.get() - 1) as *const u8, - core::mem::size_of::() + 1, - ); - use core::fmt::Write; - hbbytecode::parse_args(&mut bytes, instr, &mut self.op_buf).unwrap(); - debug_assert!(bytes.is_empty()); - self.disp_buf.clear(); - write!(self.disp_buf, "{:<10}", format!("{instr:?}")).unwrap(); - for (i, op) in self.op_buf.drain(..).enumerate() { - if i != 0 { - write!(self.disp_buf, ", ").unwrap(); - } - write!(self.disp_buf, "{op:?}").unwrap(); - if let hbbytecode::Oper::R(r) = op { - write!(self.disp_buf, "({})", regs[r as usize].0).unwrap() - } - } - log::trace!("read-typed: {:x}: {}", addr.get(), self.disp_buf); - } + logger: hbvm::mem::InstrLogger, } impl hbvm::mem::Memory for LoggedMem { @@ -765,20 +730,14 @@ impl hbvm::mem::Memory for LoggedMem { } unsafe fn prog_read(&mut self, addr: hbvm::mem::Address) -> T { - if log::log_enabled!(log::Level::Trace) { - if core::any::TypeId::of::() == core::any::TypeId::of::() { - if let Some(instr) = self.prev_instr { - self.display_instr::<()>(instr, addr); - } - self.prev_instr = hbbytecode::Instr::try_from(*(addr.get() as *const u8)).ok(); - } else { - let instr = self.prev_instr.take().unwrap(); - self.display_instr::(instr, addr); - } - } - self.mem.prog_read(addr) } + + fn log_instr(&mut self, at: hbvm::mem::Address, regs: &[hbvm::value::Value]) { + log::trace!("read-typed: {:x}: {}", at.get(), unsafe { + self.logger.display_instr(at, regs) + }); + } } struct AsHex<'a>(&'a [u8]); diff --git a/vm/src/mem/mod.rs b/vm/src/mem/mod.rs index 535a30b..c82db5c 100644 --- a/vm/src/mem/mod.rs +++ b/vm/src/mem/mod.rs @@ -4,7 +4,7 @@ pub mod softpaging; pub(crate) mod addr; -use crate::utils::impl_display; +use crate::{utils::impl_display, value::Value}; pub use addr::Address; /// Load-store memory access @@ -36,6 +36,48 @@ pub trait Memory { /// # Safety /// - Data read have to be valid unsafe fn prog_read(&mut self, addr: Address) -> T; + + /// Log instruction to be executed + fn log_instr(&mut self, _at: Address, _regs: &[Value]) {} +} + +#[derive(Default)] +pub struct InstrLogger { + #[cfg(debug_assertions)] + op_buf: alloc::vec::Vec, + #[cfg(debug_assertions)] + disp_buf: alloc::string::String, +} + +impl InstrLogger { + /// # Safety + /// - `addr` needs to point to a valid instruction + #[cfg(debug_assertions)] + pub unsafe fn display_instr(&mut self, addr: Address, regs: &[Value]) -> &str { + let instr = hbbytecode::Instr::try_from(unsafe { *(addr.get() as *const u8) }).unwrap(); + let mut bytes = + unsafe { core::slice::from_raw_parts(addr.get() as *const u8, instr.size()) }; + use core::fmt::Write; + hbbytecode::parse_args(&mut bytes, instr, &mut self.op_buf).unwrap(); + debug_assert!(bytes.is_empty()); + self.disp_buf.clear(); + write!(self.disp_buf, "{:<10}", alloc::format!("{instr:?}")).unwrap(); + for (i, op) in self.op_buf.drain(..).enumerate() { + if i != 0 { + write!(self.disp_buf, ", ").unwrap(); + } + write!(self.disp_buf, "{op:?}").unwrap(); + if let hbbytecode::Oper::R(r) = op { + write!(self.disp_buf, "({})", regs[r as usize].0).unwrap() + } + } + &self.disp_buf + } + + #[cfg(not(debug_assertions))] + pub unsafe fn display_instr(&mut self, addr: Address, regs: &[Value]) -> &str { + "" + } } /// Unhandled load access trap diff --git a/vm/src/vmrun.rs b/vm/src/vmrun.rs index 2d84218..ea43974 100644 --- a/vm/src/vmrun.rs +++ b/vm/src/vmrun.rs @@ -55,6 +55,7 @@ where // - Yes, we assume you run 64 bit CPU. Else ?conradluget a better CPU // sorry 8 bit fans, HBVM won't run on your Speccy :( unsafe { + self.memory.log_instr(self.pc, &self.registers); match self .memory .prog_read::(self.pc as _)