From 2accc78948fa4a18e37ab0bc405f9b2758acaa3e Mon Sep 17 00:00:00 2001 From: Ben Bridle Date: Thu, 3 Jul 2025 15:26:07 +1200 Subject: Initial commit --- src/debug.rs | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 src/debug.rs (limited to 'src/debug.rs') diff --git a/src/debug.rs b/src/debug.rs new file mode 100644 index 0000000..b007d9f --- /dev/null +++ b/src/debug.rs @@ -0,0 +1,126 @@ +use crate::*; + +use inked::{ink, InkedString}; + + +pub struct DebugState { + pub enabled: bool, + last_cycle: usize, + mark: Instant, + symbols: DebugSymbols, +} + +impl DebugState { + pub fn new>(enabled: bool, symbols_path: Option

) -> Self { + Self { + enabled, + last_cycle: 0, + mark: Instant::now(), + symbols: DebugSymbols::from_path(symbols_path), + } + } + + pub fn debug_full(&mut self, core: &BedrockCore) { + if self.enabled { + let prev_pc = core.mem.pc.wrapping_sub(1); + let cycle = core.cycle; + let delta = core.cycle.saturating_sub(self.last_cycle); + let elapsed = self.mark.elapsed(); + + eprintln!(" PC: 0x{prev_pc:04x} Cycle: {cycle} (+{delta} in {elapsed:.2?})"); + eprint!("WST: "); debug_stack(&core.wst); + eprint!("RST: "); debug_stack(&core.rst); + // Print information about the nearest symbol. + if let Some(symbol) = self.symbols.for_address(prev_pc) { + let name = &symbol.name; + let address = &symbol.address; + let mut string = InkedString::new(); + string.push(ink!("SYM: ")); + string.push(ink!("@{name}").blue()); + string.push(ink!(" 0x{address:04X}")); + if let Some(location) = &symbol.location { + string.push(ink!(" ")); + string.push(ink!("{location}").dim()); + } + string.eprintln(); + } + } + self.last_cycle = core.cycle; + self.mark = Instant::now(); + } + + pub fn debug_timing(&mut self, core: &BedrockCore) { + if self.enabled { + let cycle = core.cycle; + let delta = core.cycle.saturating_sub(self.last_cycle); + let elapsed = self.mark.elapsed(); + + eprintln!("Cycle: {cycle} (+{delta} in {elapsed:.2?})"); + } + self.last_cycle = core.cycle; + self.mark = Instant::now(); + } +} + + +fn debug_stack(stack: &Stack) { + for i in 0..(stack.sp as usize) { + eprint!("{:02X} ", stack.mem[i]); + } + eprintln!(); +} + + + +pub struct DebugSymbols { + pub symbols: Vec +} + +impl DebugSymbols { + /// Load debug symbols from a symbols file. + pub fn from_path>(path: Option

) -> Self { + let mut symbols = Vec::new(); + if let Some(path) = path { + if let Ok(string) = std::fs::read_to_string(path) { + for line in string.lines() { + if let Some(symbol) = DebugSymbol::from_line(line) { + symbols.push(symbol); + } + } + } + } + symbols.sort_by_key(|s| s.address); + Self { symbols } + } + + /// Return the symbol matching a given program address. + pub fn for_address(&self, address: u16) -> Option<&DebugSymbol> { + if self.symbols.is_empty() { return None; } + match self.symbols.binary_search_by_key(&address, |s| s.address) { + Ok(index) => self.symbols.get(index), + Err(index) => self.symbols.get(index.checked_sub(1)?), + } + } +} + + +pub struct DebugSymbol { + pub address: u16, + pub name: String, + pub location: Option, +} + +impl DebugSymbol { + pub fn from_line(line: &str) -> Option { + let (address, line) = line.split_once(' ')?; + let address = u16::from_str_radix(address, 16).ok()?; + if let Some((name, location)) = line.split_once(' ') { + let name = name.to_string(); + let location = Some(location.to_string()); + Some( DebugSymbol { address, name, location } ) + } else { + let name = line.to_string(); + Some( DebugSymbol { address, name, location: None } ) + } + } +} -- cgit v1.2.3-70-g09d2