feat: Fix & improve debugger, Add commands to save/load the state
Former-commit-id: cfbead1ad64c8b029bf7265f7fd975014744b287
This commit is contained in:
parent
ae7bf63d3f
commit
1a46bec3f9
|
@ -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();
|
||||||
|
|
|
@ -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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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"))]
|
||||||
{
|
{
|
||||||
|
|
Reference in a new issue