Make the debugger work again, but currently breakpoints are not supported.
Added memory write command and the ability to pause the debugger with Ctrl-C Former-commit-id: 83d141fa191dadefb84f7c9de163631a69af8324
This commit is contained in:
parent
bfee970592
commit
c117cbe924
|
@ -22,6 +22,7 @@ time = "0.1.42"
|
|||
bitfield = "0.13.1"
|
||||
bitflags = "1.1.0"
|
||||
zip = "0.5.3"
|
||||
ctrlc = "3.1.3"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
|
|
|
@ -46,7 +46,7 @@ pub struct Core {
|
|||
decoded_arm: u32,
|
||||
fetched_thumb: u16,
|
||||
decoded_thumb: u16,
|
||||
last_executed: Option<DecodedInstruction>,
|
||||
pub last_executed: Option<DecodedInstruction>,
|
||||
|
||||
pub cycles: usize,
|
||||
|
||||
|
@ -325,10 +325,12 @@ impl Core {
|
|||
PipelineState::Refill1 => {
|
||||
self.pc = pc.wrapping_add(4);
|
||||
self.pipeline_state = PipelineState::Refill2;
|
||||
self.last_executed = None;
|
||||
}
|
||||
PipelineState::Refill2 => {
|
||||
self.pc = pc.wrapping_add(4);
|
||||
self.pipeline_state = PipelineState::Execute;
|
||||
self.last_executed = None;
|
||||
}
|
||||
PipelineState::Execute => {
|
||||
let insn = ArmInstruction::decode(insn, self.pc.wrapping_sub(8))?;
|
||||
|
|
|
@ -36,7 +36,6 @@ impl GameBoyAdvance {
|
|||
while self.sysbus.io.gpu.state != GpuState::VBlank {
|
||||
self.step_new();
|
||||
}
|
||||
self.backend.render(self.sysbus.io.gpu.get_framebuffer());
|
||||
while self.sysbus.io.gpu.state == GpuState::VBlank {
|
||||
self.step_new();
|
||||
}
|
||||
|
@ -73,7 +72,10 @@ impl GameBoyAdvance {
|
|||
io.timers.step(cycles, &mut self.sysbus, &mut irqs);
|
||||
if let Some(new_gpu_state) = io.gpu.step(cycles, &mut self.sysbus, &mut irqs) {
|
||||
match new_gpu_state {
|
||||
GpuState::VBlank => io.dmac.notify_vblank(),
|
||||
GpuState::VBlank => {
|
||||
self.backend.render(io.gpu.get_framebuffer());
|
||||
io.dmac.notify_vblank();
|
||||
}
|
||||
GpuState::HBlank => io.dmac.notify_hblank(),
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time;
|
||||
|
||||
use crate::core::arm7tdmi::arm::ArmInstruction;
|
||||
use crate::core::arm7tdmi::bus::Bus;
|
||||
use crate::core::arm7tdmi::thumb::ThumbInstruction;
|
||||
|
@ -20,6 +24,13 @@ pub enum DisassMode {
|
|||
ModeThumb,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum MemWriteCommandSize {
|
||||
Byte,
|
||||
Half,
|
||||
Word,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Command {
|
||||
Info,
|
||||
|
@ -28,6 +39,7 @@ pub enum Command {
|
|||
Continue,
|
||||
Frame(usize),
|
||||
HexDump(Addr, u32),
|
||||
MemWrite(MemWriteCommandSize, Addr, u32),
|
||||
Disass(DisassMode, Addr, u32),
|
||||
AddBreakpoint(Addr),
|
||||
DelBreakpoint(Addr),
|
||||
|
@ -46,17 +58,24 @@ impl Command {
|
|||
Info => println!("{}", debugger.gba.cpu),
|
||||
DisplayInfo => { /*println!("GPU: {:#?}", debugger.gba.sysbus.io.gpu)*/ }
|
||||
Step(count) => {
|
||||
debugger.ctrlc_flag.store(true, Ordering::SeqCst);
|
||||
for _ in 0..count {
|
||||
match debugger.gba.step() {
|
||||
Ok(insn) => {
|
||||
if !debugger.ctrlc_flag.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
debugger.gba.step_new();
|
||||
while debugger.gba.cpu.last_executed.is_none() {
|
||||
debugger.gba.step_new();
|
||||
}
|
||||
let last_executed = debugger.gba.cpu.last_executed.unwrap();
|
||||
print!(
|
||||
"{}\t{}",
|
||||
Colour::Black
|
||||
.bold()
|
||||
.italic()
|
||||
.on(Colour::White)
|
||||
.paint(format!("Executed at @0x{:08x}:", insn.get_pc(),)),
|
||||
insn
|
||||
.paint(format!("Executed at @0x{:08x}:", last_executed.get_pc(),)),
|
||||
last_executed
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
|
@ -64,43 +83,76 @@ impl Command {
|
|||
"\t\t/// Next instruction at @0x{:08x}",
|
||||
debugger.gba.cpu.get_next_pc()
|
||||
))
|
||||
)
|
||||
}
|
||||
Err(GBAError::CpuError(e)) => {
|
||||
println!("{}: {}", "cpu encountered an error".red(), e);
|
||||
println!("cpu: {:x?}", debugger.gba.cpu)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
);
|
||||
}
|
||||
println!("{}\n", debugger.gba.cpu);
|
||||
// match debugger.gba.step() {
|
||||
// Ok(insn) => {
|
||||
// print!(
|
||||
// "{}\t{}",
|
||||
// Colour::Black
|
||||
// .bold()
|
||||
// .italic()
|
||||
// .on(Colour::White)
|
||||
// .paint(format!("Executed at @0x{:08x}:", insn.get_pc(),)),
|
||||
// insn
|
||||
// );
|
||||
// println!(
|
||||
// "{}",
|
||||
// Colour::Purple.dimmed().italic().paint(format!(
|
||||
// "\t\t/// Next instruction at @0x{:08x}",
|
||||
// debugger.gba.cpu.get_next_pc()
|
||||
// ))
|
||||
// )
|
||||
// }
|
||||
// Err(GBAError::CpuError(e)) => {
|
||||
// println!("{}: {}", "cpu encountered an error".red(), e);
|
||||
// println!("cpu: {:x?}", debugger.gba.cpu)
|
||||
// }
|
||||
// _ => unreachable!(),
|
||||
// }
|
||||
}
|
||||
Continue => {
|
||||
let start_cycles = debugger.gba.cpu.cycles();
|
||||
loop {
|
||||
if let Some(bp) = debugger.check_breakpoint() {
|
||||
match debugger.gba.step() {
|
||||
Err(GBAError::CpuError(e)) => {
|
||||
println!("{}: {}", "cpu encountered an error".red(), e);
|
||||
println!("cpu: {:x?}", debugger.gba.cpu);
|
||||
break;
|
||||
let frame_time = time::Duration::new(0, 1_000_000_000u32 / 60);
|
||||
debugger.ctrlc_flag.store(true, Ordering::SeqCst);
|
||||
while debugger.ctrlc_flag.load(Ordering::SeqCst) {
|
||||
let start_time = time::Instant::now();
|
||||
debugger.gba.frame();
|
||||
|
||||
let time_passed = start_time.elapsed();
|
||||
let delay = frame_time.checked_sub(time_passed);
|
||||
match delay {
|
||||
None => {}
|
||||
Some(delay) => {
|
||||
::std::thread::sleep(delay);
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
let num_cycles = debugger.gba.cpu.cycles() - start_cycles;
|
||||
println!("hit breakpoint #0x{:08x} after {} cycles !", bp, num_cycles);
|
||||
break;
|
||||
} else {
|
||||
match debugger.gba.step() {
|
||||
Err(GBAError::CpuError(e)) => {
|
||||
println!("{}: {}", "cpu encountered an error".red(), e);
|
||||
println!("cpu: {:x?}", debugger.gba.cpu);
|
||||
break;
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
// let start_cycles = debugger.gba.cpu.cycles();
|
||||
// loop {
|
||||
// if let Some(bp) = debugger.check_breakpoint() {
|
||||
// match debugger.gba.step() {
|
||||
// Err(GBAError::CpuError(e)) => {
|
||||
// println!("{}: {}", "cpu encountered an error".red(), e);
|
||||
// println!("cpu: {:x?}", debugger.gba.cpu);
|
||||
// break;
|
||||
// }
|
||||
// _ => (),
|
||||
// };
|
||||
// let num_cycles = debugger.gba.cpu.cycles() - start_cycles;
|
||||
// println!("hit breakpoint #0x{:08x} after {} cycles !", bp, num_cycles);
|
||||
// break;
|
||||
// } else {
|
||||
// match debugger.gba.step() {
|
||||
// Err(GBAError::CpuError(e)) => {
|
||||
// println!("{}: {}", "cpu encountered an error".red(), e);
|
||||
// println!("cpu: {:x?}", debugger.gba.cpu);
|
||||
// break;
|
||||
// }
|
||||
// _ => (),
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
}
|
||||
Frame(count) => {
|
||||
use super::time::PreciseTime;
|
||||
|
@ -115,6 +167,11 @@ impl Command {
|
|||
let bytes = debugger.gba.sysbus.get_bytes(addr..addr + nbytes);
|
||||
hexdump::hexdump(&bytes);
|
||||
}
|
||||
MemWrite(size, addr, val) => match size {
|
||||
MemWriteCommandSize::Byte => debugger.gba.sysbus.write_8(addr, val as u8),
|
||||
MemWriteCommandSize::Half => debugger.gba.sysbus.write_16(addr, val as u16),
|
||||
MemWriteCommandSize::Word => debugger.gba.sysbus.write_32(addr, val as u32),
|
||||
},
|
||||
Disass(mode, addr, n) => {
|
||||
let bytes = debugger.gba.sysbus.get_bytes(addr..addr + n);
|
||||
match mode {
|
||||
|
@ -257,6 +314,66 @@ impl Debugger {
|
|||
};
|
||||
Ok(Command::HexDump(addr, n))
|
||||
}
|
||||
"mwb" => {
|
||||
let (addr, val) = match args.len() {
|
||||
2 => {
|
||||
let addr = self.val_address(&args[0])?;
|
||||
let val = self.val_number(&args[1])? as u8;
|
||||
|
||||
(addr, val)
|
||||
}
|
||||
_ => {
|
||||
return Err(DebuggerError::InvalidCommandFormat(
|
||||
"mwb [addr] [n]".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
Ok(Command::MemWrite(
|
||||
MemWriteCommandSize::Byte,
|
||||
addr,
|
||||
val as u32,
|
||||
))
|
||||
}
|
||||
"mwh" => {
|
||||
let (addr, val) = match args.len() {
|
||||
2 => {
|
||||
let addr = self.val_address(&args[0])?;
|
||||
let val = self.val_number(&args[1])? as u16;
|
||||
|
||||
(addr, val)
|
||||
}
|
||||
_ => {
|
||||
return Err(DebuggerError::InvalidCommandFormat(
|
||||
"mwb [addr] [n]".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
Ok(Command::MemWrite(
|
||||
MemWriteCommandSize::Half,
|
||||
addr,
|
||||
val as u32,
|
||||
))
|
||||
}
|
||||
"mww" => {
|
||||
let (addr, val) = match args.len() {
|
||||
2 => {
|
||||
let addr = self.val_address(&args[0])?;
|
||||
let val = self.val_number(&args[1])? as u32;
|
||||
|
||||
(addr, val)
|
||||
}
|
||||
_ => {
|
||||
return Err(DebuggerError::InvalidCommandFormat(
|
||||
"mwb [addr] [n]".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
Ok(Command::MemWrite(
|
||||
MemWriteCommandSize::Half,
|
||||
addr,
|
||||
val as u32,
|
||||
))
|
||||
}
|
||||
"d" | "disass" => {
|
||||
let (addr, n) = self.get_disassembler_args(args)?;
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
extern crate ctrlc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::Editor;
|
||||
|
||||
|
@ -36,14 +40,23 @@ type DebuggerResult<T> = Result<T, DebuggerError>;
|
|||
pub struct Debugger {
|
||||
pub gba: GameBoyAdvance,
|
||||
running: bool,
|
||||
pub ctrlc_flag: Arc<AtomicBool>,
|
||||
pub previous_command: Option<Command>,
|
||||
}
|
||||
|
||||
impl Debugger {
|
||||
pub fn new(gba: GameBoyAdvance) -> Debugger {
|
||||
let ctrlc_flag = Arc::new(AtomicBool::new(true));
|
||||
let r = ctrlc_flag.clone();
|
||||
ctrlc::set_handler(move || {
|
||||
println!("Stopping, Ctrl-C detected!");
|
||||
r.store(false, Ordering::SeqCst);
|
||||
})
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
Debugger {
|
||||
gba: gba,
|
||||
running: false,
|
||||
ctrlc_flag: ctrlc_flag,
|
||||
previous_command: None,
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue