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