diff options
author | Ben Bridle <bridle.benjamin@gmail.com> | 2024-10-29 14:03:04 +1300 |
---|---|---|
committer | Ben Bridle <bridle.benjamin@gmail.com> | 2024-10-30 15:42:10 +1300 |
commit | 748974ef2c0e969e95cccc9cb061436d5a1d1b35 (patch) | |
tree | c9d2022669df04cdfd3d775497048222422c59c2 /src/debug.rs | |
parent | c42e2154d88c23a28f83fe96f4153e821ef00c0e (diff) | |
download | bedrock-pc-748974ef2c0e969e95cccc9cb061436d5a1d1b35.zip |
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.
Diffstat (limited to 'src/debug.rs')
-rw-r--r-- | src/debug.rs | 79 |
1 files changed, 72 insertions, 7 deletions
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 + } + } } |