From 748974ef2c0e969e95cccc9cb061436d5a1d1b35 Mon Sep 17 00:00:00 2001 From: Ben Bridle <bridle.benjamin@gmail.com> Date: Tue, 29 Oct 2024 14:03:04 +1300 Subject: Load and display symbols in debug information The assembler saves out symbols files, which are loaded automatically by the emulator when present. The name and location of the most recent label is displayed with the debug information when symbols are loaded. --- src/debug.rs | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 7 deletions(-) (limited to 'src/debug.rs') diff --git a/src/debug.rs b/src/debug.rs index d19dbec..1593d9d 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,23 +1,28 @@ use bedrock_core::*; +use std::path::Path; use std::time::Instant; -macro_rules! yellow { () => { eprint!("\x1b[33m") };} -macro_rules! normal { () => { eprint!("\x1b[0m" ) };} + +const NORMAL: &str = "\x1b[0m"; +const YELLOW: &str = "\x1b[33m"; +const BLUE: &str = "\x1b[34m"; pub struct DebugState { pub enabled: bool, last_cycle: usize, last_mark: Instant, + symbols: DebugSymbols, } impl DebugState { - pub fn new(enabled: bool) -> Self { + pub fn new<P: AsRef<Path>>(enabled: bool, symbols_path: Option<P>) -> Self { Self { enabled, last_cycle: 0, last_mark: Instant::now(), + symbols: DebugSymbols::from_path_opt(symbols_path), } } @@ -37,7 +42,12 @@ impl DebugState { debug_stack(&core.wst, 0x10); eprint!("RST: "); debug_stack(&core.rst, 0x10); - + // Print information about the current symbol. + if let Some(symbol) = self.symbols.for_address(core.mem.pc) { + eprint!("SYM: {BLUE}@{}{NORMAL}", symbol.name); + if let Some(location) = &symbol.location { eprint!(" {location}"); } + eprintln!(); + } self.last_cycle = core.cycle; self.last_mark = Instant::now(); } @@ -46,9 +56,64 @@ impl DebugState { fn debug_stack(stack: &Stack, len: usize) { for i in 0..len { - if i == stack.sp as usize { yellow!(); } + if i == stack.sp as usize { eprint!("{YELLOW}"); } eprint!("{:02x} ", stack.mem[i]); } - normal!(); - eprintln!(); + eprintln!("{NORMAL}"); +} + + +struct DebugSymbols { + symbols: Vec<DebugSymbol> +} + +impl DebugSymbols { + /// Load debug symbols from a symbols file. + pub fn from_path_opt<P: AsRef<Path>>(path: Option<P>) -> 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 } + } + + pub fn for_address(&self, address: u16) -> Option<&DebugSymbol> { + if self.symbols.is_empty() { return None; } + let symbol = 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)?)?, + }; + Some(&symbol) + } +} + +struct DebugSymbol { + address: u16, + name: String, + location: Option<String>, +} + +impl DebugSymbol { + pub fn from_line(line: &str) -> Option<Self> { + if let Some((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 } ) + } + } else { + None + } + } } -- cgit v1.2.3-70-g09d2