From ff472db2498b26e3c25384e1a039ce177856e481 Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Wed, 9 Jun 2021 01:24:31 +0300 Subject: [PATCH] core: debugger: Use mut references for GameBoyAdvance Former-commit-id: e1490c0777537e7d8eee4e9d1fbb53f8c957fdc7 Former-commit-id: f6be5b7940c4f3d517fa564830be607321ade534 --- core/src/debugger/command.rs | 122 ++++++++++++----------- core/src/debugger/mod.rs | 59 ++++++----- platform/rustboyadvance-sdl2/src/main.rs | 13 ++- 3 files changed, 106 insertions(+), 88 deletions(-) diff --git a/core/src/debugger/command.rs b/core/src/debugger/command.rs index 8636ab7..ba89203 100644 --- a/core/src/debugger/command.rs +++ b/core/src/debugger/command.rs @@ -11,6 +11,7 @@ use crate::util::{read_bin_file, write_bin_file}; // use super::palette_view::create_palette_view; // use super::tile_view::create_tile_view; +use super::GameBoyAdvance; use super::{parser::Value, Debugger, DebuggerError, DebuggerResult}; use ansi_term::Colour; @@ -92,32 +93,32 @@ fn find_nearest_symbol(addr: u32, symbols: &HashMap) -> Option<(Str } impl Debugger { - pub fn run_command(&mut self, command: Command) { + pub fn run_command(&mut self, gba: &mut GameBoyAdvance, command: Command) { use Command::*; #[allow(unreachable_patterns)] match command { Info => { - let pc = self.gba.cpu.pc; + let pc = gba.cpu.pc; if let Some((sym, addr)) = find_nearest_symbol(pc, &self.symbols) { println!("PC at {}+{:#x} ({:08x})", sym, addr - pc, pc); } else { println!("PC at {:08x}", pc); } - println!("{}", self.gba.cpu); - println!("IME={}", self.gba.io_devs.intc.interrupt_master_enable); - println!("IE={:#?}", self.gba.io_devs.intc.interrupt_enable); - println!("IF={:#?}", self.gba.io_devs.intc.interrupt_flags); + println!("{}", gba.cpu); + // println!("IME={}", gba.io_devs.intc.interrupt_master_enable); + // println!("IE={:#?}", gba.io_devs.intc.interrupt_enable); + // println!("IF={:#?}", gba.io_devs.intc.interrupt_flags); } - GpuInfo => println!("GPU: {:#?}", self.gba.io_devs.gpu), - GpioInfo => println!("GPIO: {:#?}", self.gba.sysbus.cartridge.get_gpio()), + GpuInfo => println!("GPU: {:#?}", gba.io_devs.gpu), + GpioInfo => println!("GPIO: {:#?}", gba.sysbus.cartridge.get_gpio()), Step(count) => { for _ in 0..count { - self.gba.step_debugger(); - while self.gba.cpu.dbg.last_executed.is_none() { - self.gba.step_debugger(); + gba.step_debugger(); + while gba.cpu.dbg.last_executed.is_none() { + gba.step_debugger(); } - if let Some(last_executed) = &self.gba.cpu.dbg.last_executed { + if let Some(last_executed) = &gba.cpu.dbg.last_executed { let pc = last_executed.get_pc(); let symbol = self.symbols @@ -138,19 +139,19 @@ impl Debugger { "{}", Colour::Purple.dimmed().italic().paint(format!( "\t\t/// Next instruction at @0x{:08x}", - self.gba.cpu.get_next_pc() + gba.cpu.get_next_pc() )) ); } } - println!("cycles: {}", self.gba.scheduler.timestamp()); - println!("{}\n", self.gba.cpu); + println!("cycles: {}", gba.scheduler.timestamp()); + println!("{}\n", gba.cpu); } Continue => 'running: loop { - self.gba.key_poll(); - if let Some(breakpoint) = self.gba.step_debugger() { + gba.key_poll(); + if let Some(breakpoint) = gba.step_debugger() { let mut bp_sym = None; - if let Some(symbols) = self.gba.sysbus.cartridge.get_symbols() { + if let Some(symbols) = gba.sysbus.cartridge.get_symbols() { for s in symbols.keys() { if symbols.get(s).unwrap() == &breakpoint { bp_sym = Some(s.clone()); @@ -168,22 +169,22 @@ impl Debugger { Frame(count) => { let start = time::Instant::now(); for _ in 0..count { - self.gba.frame(); + gba.frame(); } let end = time::Instant::now(); println!("that took {:?} seconds", end - start); } HexDump(addr, nbytes) => { - let bytes = self.gba.sysbus.debug_get_bytes(addr..addr + nbytes); + let bytes = gba.sysbus.debug_get_bytes(addr..addr + nbytes); hexdump::hexdump(&bytes); } MemWrite(size, addr, val) => match size { - MemWriteCommandSize::Byte => self.gba.sysbus.write_8(addr, val as u8), - MemWriteCommandSize::Half => self.gba.sysbus.write_16(addr, val as u16), - MemWriteCommandSize::Word => self.gba.sysbus.write_32(addr, val as u32), + MemWriteCommandSize::Byte => gba.sysbus.write_8(addr, val as u8), + MemWriteCommandSize::Half => gba.sysbus.write_16(addr, val as u16), + MemWriteCommandSize::Word => gba.sysbus.write_32(addr, val as u32), }, Disass(mode, addr, n) => { - let bytes = self.gba.sysbus.debug_get_bytes(addr..addr + n); + let bytes = gba.sysbus.debug_get_bytes(addr..addr + n); match mode { DisassMode::ModeArm => { let disass = Disassembler::::new(addr, &bytes); @@ -203,31 +204,31 @@ impl Debugger { print!("Quitting!"); self.stop(); } - AddBreakpoint(addr) => match self.gba.add_breakpoint(addr) { + AddBreakpoint(addr) => match gba.add_breakpoint(addr) { Some(index) => println!("Added breakpoint [{}] 0x{:08x}", index, addr), None => println!("Breakpint already exists."), }, - DelBreakpoint(addr) => self.delete_breakpoint(addr), - ClearBreakpoints => self.gba.cpu.dbg.breakpoints.clear(), + DelBreakpoint(addr) => self.delete_breakpoint(gba, addr), + ClearBreakpoints => gba.cpu.dbg.breakpoints.clear(), ListBreakpoints => { println!("breakpoint list:"); - for (i, b) in self.gba.cpu.dbg.breakpoints.iter().enumerate() { + for (i, b) in gba.cpu.dbg.breakpoints.iter().enumerate() { println!("[{}] 0x{:08x}", i, b) } } - // PaletteView => create_palette_view(&self.gba.sysbus.palette_ram.mem), - // TileView(bg) => create_tile_view(bg, &self.gba), + // PaletteView => create_palette_view(&gba.sysbus.palette_ram.mem), + // TileView(bg) => create_tile_view(bg, &gba), Reset => { println!("resetting cpu..."); - self.gba.cpu.reset(); + gba.cpu.reset(); println!("cpu is restarted!") } TraceToggle(flags) => { if flags.contains(TraceFlags::TRACE_OPCODE) { - self.gba.cpu.dbg.trace_opcodes = !self.gba.cpu.dbg.trace_opcodes; + gba.cpu.dbg.trace_opcodes = !gba.cpu.dbg.trace_opcodes; println!( "[*] opcode tracing {}", - if self.gba.cpu.dbg.trace_opcodes { + if gba.cpu.dbg.trace_opcodes { "on" } else { "off" @@ -235,10 +236,10 @@ impl Debugger { ) } if flags.contains(TraceFlags::TRACE_EXCEPTIONS) { - self.gba.cpu.dbg.trace_exceptions = !self.gba.cpu.dbg.trace_exceptions; + gba.cpu.dbg.trace_exceptions = !gba.cpu.dbg.trace_exceptions; println!( "[*] exception tracing {}", - if self.gba.cpu.dbg.trace_exceptions { + if gba.cpu.dbg.trace_exceptions { "on" } else { "off" @@ -249,20 +250,18 @@ impl Debugger { println!("[*] dma tracing not implemented"); } if flags.contains(TraceFlags::TRACE_TIMERS) { - self.gba.sysbus.io.timers.trace = !self.gba.sysbus.io.timers.trace; + gba.sysbus.io.timers.trace = !gba.sysbus.io.timers.trace; } } SaveState(save_path) => { - let state = self.gba.save_state().expect("failed to serialize"); + let state = gba.save_state().expect("failed to serialize"); write_bin_file(&Path::new(&save_path), &state) .expect("failed to save state to file"); } LoadState(load_path) => { let save = read_bin_file(&Path::new(&load_path)) .expect("failed to read save state from file"); - self.gba - .restore_state(&save) - .expect("failed to deserialize"); + gba.restore_state(&save).expect("failed to deserialize"); } ListSymbols(Some(pattern)) => { let matcher = SkimMatcherV2::default(); @@ -305,16 +304,20 @@ impl Debugger { } } - fn get_disassembler_args(&self, args: Vec) -> DebuggerResult<(Addr, u32)> { + fn get_disassembler_args( + &self, + gba: &GameBoyAdvance, + args: Vec, + ) -> DebuggerResult<(Addr, u32)> { match args.len() { 2 => { - let addr = self.val_address(&args[0])?; + let addr = self.val_address(gba, &args[0])?; let n = self.val_number(&args[1])?; Ok((addr, n)) } 1 => { - let addr = self.val_address(&args[0])?; + let addr = self.val_address(gba, &args[0])?; Ok((addr, 10)) } @@ -322,7 +325,7 @@ impl Debugger { if let Some(Command::Disass(_mode, addr, n)) = &self.previous_command { Ok((*addr + (4 * (*n as u32)), 10)) } else { - Ok((self.gba.cpu.get_next_pc(), 10)) + Ok((gba.cpu.get_next_pc(), 10)) } } _ => { @@ -333,7 +336,12 @@ impl Debugger { } } - pub fn eval_command(&self, command: Value, args: Vec) -> DebuggerResult { + pub fn eval_command( + &self, + gba: &GameBoyAdvance, + command: Value, + args: Vec, + ) -> DebuggerResult { let command = match command { Value::Identifier(command) => command, _ => { @@ -373,13 +381,13 @@ impl Debugger { "x" | "hexdump" => { let (addr, n) = match args.len() { 2 => { - let addr = self.val_address(&args[0])?; + let addr = self.val_address(gba, &args[0])?; let n = self.val_number(&args[1])?; (addr, n) } 1 => { - let addr = self.val_address(&args[0])?; + let addr = self.val_address(gba, &args[0])?; (addr, 0x100) } @@ -387,7 +395,7 @@ impl Debugger { if let Some(Command::HexDump(addr, n)) = self.previous_command { (addr + (4 * n as u32), 0x100) } else { - (self.gba.cpu.get_reg(15), 0x100) + (gba.cpu.get_reg(15), 0x100) } } _ => { @@ -401,7 +409,7 @@ impl Debugger { "mwb" => { let (addr, val) = match args.len() { 2 => { - let addr = self.val_address(&args[0])?; + let addr = self.val_address(gba, &args[0])?; let val = self.val_number(&args[1])? as u8; (addr, val) @@ -421,7 +429,7 @@ impl Debugger { "mwh" => { let (addr, val) = match args.len() { 2 => { - let addr = self.val_address(&args[0])?; + let addr = self.val_address(gba, &args[0])?; let val = self.val_number(&args[1])? as u16; (addr, val) @@ -441,7 +449,7 @@ impl Debugger { "mww" => { let (addr, val) = match args.len() { 2 => { - let addr = self.val_address(&args[0])?; + let addr = self.val_address(gba, &args[0])?; let val = self.val_number(&args[1])? as u32; (addr, val) @@ -459,21 +467,21 @@ impl Debugger { )) } "d" | "disass" => { - let (addr, n) = self.get_disassembler_args(args)?; + let (addr, n) = self.get_disassembler_args(gba, args)?; - let m = match self.gba.cpu.get_cpu_state() { + let m = match gba.cpu.get_cpu_state() { CpuState::ARM => DisassMode::ModeArm, CpuState::THUMB => DisassMode::ModeThumb, }; Ok(Command::Disass(m, addr, n)) } "da" | "disass-arm" => { - let (addr, n) = self.get_disassembler_args(args)?; + let (addr, n) = self.get_disassembler_args(gba, args)?; Ok(Command::Disass(DisassMode::ModeArm, addr, n)) } "dt" | "disass-thumb" => { - let (addr, n) = self.get_disassembler_args(args)?; + let (addr, n) = self.get_disassembler_args(gba, args)?; Ok(Command::Disass(DisassMode::ModeThumb, addr, n)) } @@ -483,14 +491,14 @@ impl Debugger { "break ".to_string(), )) } else { - let addr = self.val_address(&args[0])?; + let addr = self.val_address(gba, &args[0])?; Ok(Command::AddBreakpoint(addr)) } } "bd" | "breakdel" => match args.len() { 0 => Ok(Command::ClearBreakpoints), 1 => { - let addr = self.val_address(&args[0])?; + let addr = self.val_address(gba, &args[0])?; Ok(Command::DelBreakpoint(addr)) } _ => Err(DebuggerError::InvalidCommandFormat(String::from( diff --git a/core/src/debugger/mod.rs b/core/src/debugger/mod.rs index 3c6e1d0..24b10e6 100644 --- a/core/src/debugger/mod.rs +++ b/core/src/debugger/mod.rs @@ -37,25 +37,23 @@ impl From<::std::io::Error> for DebuggerError { type DebuggerResult = Result; pub struct Debugger { - pub gba: GameBoyAdvance, running: bool, pub previous_command: Option, pub symbols: HashMap, } impl Debugger { - pub fn new(gba: GameBoyAdvance) -> Debugger { + pub fn new() -> Debugger { Debugger { - gba: gba, running: false, previous_command: None, symbols: HashMap::new(), } } - pub fn check_breakpoint(&self) -> Option { - let next_pc = self.gba.cpu.get_next_pc(); - for bp in &self.gba.cpu.dbg.breakpoints { + pub fn check_breakpoint(&self, gba: &GameBoyAdvance) -> Option { + let next_pc = gba.cpu.get_next_pc(); + for bp in &gba.cpu.dbg.breakpoints { if *bp == next_pc { return Some(next_pc); } @@ -64,8 +62,8 @@ impl Debugger { None } - pub fn delete_breakpoint(&mut self, addr: u32) { - self.gba.cpu.dbg.breakpoints.retain(|&a| a != addr); + pub fn delete_breakpoint(&mut self, gba: &mut GameBoyAdvance, addr: u32) { + gba.cpu.dbg.breakpoints.retain(|&a| a != addr); } fn decode_reg(&self, s: &str) -> DebuggerResult { @@ -104,11 +102,11 @@ impl Debugger { } } - fn val_address(&self, arg: &Value) -> DebuggerResult { + fn val_address(&self, gba: &GameBoyAdvance, arg: &Value) -> DebuggerResult { match arg { Value::Num(n) => Ok(*n), Value::Identifier(ident) => { - let symbol = if let Some(symbols) = self.gba.sysbus.cartridge.get_symbols() { + let symbol = if let Some(symbols) = gba.sysbus.cartridge.get_symbols() { symbols.get(ident) } else { None @@ -119,7 +117,7 @@ impl Debugger { } else { // otherwise, decode as register (TODO special token to separate symbol and register) let reg = self.decode_reg(&ident)?; - Ok(self.gba.cpu.get_reg(reg)) + Ok(gba.cpu.get_reg(reg)) } } v => Err(DebuggerError::InvalidArgument(format!( @@ -129,29 +127,34 @@ impl Debugger { } } - fn eval_assignment(&mut self, lvalue: Value, rvalue: Value) -> DebuggerResult<()> { + fn eval_assignment( + &mut self, + gba: &mut GameBoyAdvance, + lvalue: Value, + rvalue: Value, + ) -> DebuggerResult<()> { let lvalue = self.val_reg(&lvalue)?; let rvalue = match rvalue { Value::Deref(addr_value, deref_type) => { - let addr = self.val_address(&addr_value)?; + let addr = self.val_address(gba, &addr_value)?; match deref_type { - DerefType::Word => self.gba.sysbus.read_32(addr), - DerefType::HalfWord => self.gba.sysbus.read_16(addr) as u32, - DerefType::Byte => self.gba.sysbus.read_8(addr) as u32, + DerefType::Word => gba.sysbus.read_32(addr), + DerefType::HalfWord => gba.sysbus.read_16(addr) as u32, + DerefType::Byte => gba.sysbus.read_8(addr) as u32, } } - _ => self.val_address(&rvalue)?, + _ => self.val_address(gba, &rvalue)?, }; - self.gba.cpu.set_reg(lvalue, rvalue); + gba.cpu.set_reg(lvalue, rvalue); Ok(()) } - fn eval_expr(&mut self, expr: Expr) { + fn eval_expr(&mut self, gba: &mut GameBoyAdvance, expr: Expr) { match expr { - Expr::Command(c, a) => match self.eval_command(c, a) { + Expr::Command(c, a) => match self.eval_command(gba, c, a) { Ok(cmd) => { self.previous_command = Some(cmd.clone()); - self.run_command(cmd) + self.run_command(gba, cmd) } Err(DebuggerError::InvalidCommand(c)) => { println!("{}: {:?}", "invalid command".red(), c) @@ -164,7 +167,7 @@ impl Debugger { } Err(e) => println!("{} {:?}", "failed to build command".red(), e), }, - Expr::Assignment(lvalue, rvalue) => match self.eval_assignment(lvalue, rvalue) { + Expr::Assignment(lvalue, rvalue) => match self.eval_assignment(gba, lvalue, rvalue) { Err(DebuggerError::InvalidArgument(m)) => { println!("{}: {}", "assignment error".red(), m) } @@ -178,7 +181,11 @@ impl Debugger { self.running = false; } - pub fn repl(&mut self, script_file: Option<&str>) -> DebuggerResult<()> { + pub fn repl( + &mut self, + gba: &mut GameBoyAdvance, + script_file: Option<&str>, + ) -> DebuggerResult<()> { println!("Welcome to rustboyadvance-NG debugger 😎!\n"); self.running = true; let mut rl = Editor::<()>::new(); @@ -189,7 +196,7 @@ impl Debugger { let reader = BufReader::new(file); for line in reader.lines() { let expr = parse_expr(&line.unwrap())?; - self.eval_expr(expr); + self.eval_expr(gba, expr); } } while self.running { @@ -198,7 +205,7 @@ impl Debugger { Ok(line) => { if line.is_empty() { if let Some(Command::Step(1)) = self.previous_command { - self.run_command(Command::Step(1)); + self.run_command(gba, Command::Step(1)); } else { self.previous_command = None; continue; @@ -207,7 +214,7 @@ impl Debugger { rl.add_history_entry(line.as_str()); let expr = parse_expr(&line); match expr { - Ok(expr) => self.eval_expr(expr), + Ok(expr) => self.eval_expr(gba, expr), Err(DebuggerError::ParsingError(msg)) => println!("Parsing error: {}", msg), _ => (), } diff --git a/platform/rustboyadvance-sdl2/src/main.rs b/platform/rustboyadvance-sdl2/src/main.rs index 2b9ff5f..3e19041 100644 --- a/platform/rustboyadvance-sdl2/src/main.rs +++ b/platform/rustboyadvance-sdl2/src/main.rs @@ -223,9 +223,11 @@ fn main() -> Result<(), Box> { #[cfg(feature = "debugger")] { gba.cpu.set_verbose(true); - let mut debugger = Debugger::new(gba); + let mut debugger = Debugger::new(); info!("starting debugger..."); - debugger.repl(matches.value_of("script_file")).unwrap(); + debugger + .repl(&mut gba, matches.value_of("script_file")) + .unwrap(); info!("ending debugger..."); return Ok(()); } @@ -259,10 +261,11 @@ fn main() -> Result<(), Box> { } => match scancode { #[cfg(feature = "debugger")] Scancode::F1 => { - let mut debugger = Debugger::new(gba); + let mut debugger = Debugger::new(); info!("starting debugger..."); - debugger.repl(matches.value_of("script_file")).unwrap(); - gba = debugger.gba; + debugger + .repl(&mut gba, matches.value_of("script_file")) + .unwrap(); info!("ending debugger...") } #[cfg(feature = "gdb")]