feat: Fix & improve debugger, Add commands to save/load the state

Former-commit-id: cfbead1ad64c8b029bf7265f7fd975014744b287
This commit is contained in:
Michel Heily 2020-02-10 22:08:28 +02:00
parent ae7bf63d3f
commit 1a46bec3f9
4 changed files with 42 additions and 17 deletions

View file

@ -127,7 +127,7 @@ impl ArmInstruction {
} }
fn fmt_operand2(&self, f: &mut fmt::Formatter) -> Result<Option<u32>, fmt::Error> { fn fmt_operand2(&self, f: &mut fmt::Formatter) -> Result<Option<u32>, fmt::Error> {
let operand2 = self.operand2().unwrap(); let operand2 = self.operand2();
match operand2 { match operand2 {
BarrelShifterValue::RotatedImmediate(_, _) => { BarrelShifterValue::RotatedImmediate(_, _) => {
let value = operand2.decode_rotated_immediate().unwrap(); let value = operand2.decode_rotated_immediate().unwrap();

View file

@ -1,3 +1,5 @@
use std::fs;
use std::path::Path;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::time; use std::time;
@ -8,7 +10,7 @@ use crate::core::arm7tdmi::CpuState;
use crate::core::GBAError; use crate::core::GBAError;
use crate::core::{Addr, Bus}; use crate::core::{Addr, Bus};
use crate::disass::Disassembler; use crate::disass::Disassembler;
use crate::{AudioInterface, InputInterface, VideoInterface}; use crate::util::{read_bin_file, write_bin_file};
// use super::palette_view::create_palette_view; // use super::palette_view::create_palette_view;
// use super::tile_view::create_tile_view; // use super::tile_view::create_tile_view;
@ -61,6 +63,8 @@ pub enum Command {
Reset, Reset,
Quit, Quit,
TraceToggle(TraceFlags), TraceToggle(TraceFlags),
SaveState(String),
LoadState(String),
} }
impl Debugger { impl Debugger {
@ -126,7 +130,7 @@ impl Debugger {
self.gba.frame(); self.gba.frame();
} }
let end = PreciseTime::now(); let end = PreciseTime::now();
println!("that took {} seconds", start.to(end)); println!("that took {:?} seconds", start.to(end));
} }
HexDump(addr, nbytes) => { HexDump(addr, nbytes) => {
let bytes = self.gba.sysbus.get_bytes(addr..addr + nbytes); let bytes = self.gba.sysbus.get_bytes(addr..addr + nbytes);
@ -178,17 +182,6 @@ impl Debugger {
println!("cpu is restarted!") println!("cpu is restarted!")
} }
TraceToggle(flags) => { TraceToggle(flags) => {
if flags.contains(TraceFlags::TRACE_SYSBUS) {
self.gba.sysbus.trace_access = !self.gba.sysbus.trace_access;
println!(
"[*] sysbus tracing {}",
if self.gba.sysbus.trace_access {
"on"
} else {
"off"
}
)
}
if flags.contains(TraceFlags::TRACE_OPCODE) { if flags.contains(TraceFlags::TRACE_OPCODE) {
self.gba.cpu.trace_opcodes = !self.gba.cpu.trace_opcodes; self.gba.cpu.trace_opcodes = !self.gba.cpu.trace_opcodes;
println!( println!(
@ -218,6 +211,18 @@ impl Debugger {
self.gba.sysbus.io.timers.trace = !self.gba.sysbus.io.timers.trace; self.gba.sysbus.io.timers.trace = !self.gba.sysbus.io.timers.trace;
} }
} }
SaveState(save_path) => {
let state = self.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");
}
_ => println!("Not Implemented",), _ => println!("Not Implemented",),
} }
} }
@ -447,6 +452,22 @@ impl Debugger {
} }
} }
} }
"save" | "load" => {
let usage = DebuggerError::InvalidCommandFormat(String::from("save/load <path>"));
if args.len() != 1 {
Err(usage)
} else {
if let Value::Identifier(path) = &args[0] {
match command.as_ref() {
"save" => Ok(Command::SaveState(path.to_string())),
"load" => Ok(Command::LoadState(path.to_string())),
_ => unreachable!(),
}
} else {
Err(usage)
}
}
}
_ => Err(DebuggerError::InvalidCommand(command)), _ => Err(DebuggerError::InvalidCommand(command)),
} }
} }

View file

@ -203,8 +203,12 @@ impl Debugger {
match readline { match readline {
Ok(line) => { Ok(line) => {
if line.is_empty() { if line.is_empty() {
self.previous_command = None; if let Some(Command::Step(1)) = self.previous_command {
continue; self.run_command(Command::Step(1));
} else {
self.previous_command = None;
continue;
}
} }
rl.add_history_entry(line.as_str()); rl.add_history_entry(line.as_str());
let expr = parse_expr(&line); let expr = parse_expr(&line);

View file

@ -155,7 +155,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
info!("starting debugger..."); info!("starting debugger...");
debugger.repl(matches.value_of("script_file")).unwrap(); debugger.repl(matches.value_of("script_file")).unwrap();
info!("ending debugger..."); info!("ending debugger...");
return; return Ok(());
} }
#[cfg(not(feature = "debugger"))] #[cfg(not(feature = "debugger"))]
{ {