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:
Michel Heily 2019-11-10 20:00:07 +02:00
parent bfee970592
commit c117cbe924
5 changed files with 186 additions and 51 deletions

View file

@ -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

View file

@ -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))?;

View file

@ -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(),
_ => {}
}

View file

@ -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,61 +58,101 @@ 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) => {
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!(),
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}:", last_executed.get_pc(),)),
last_executed
);
println!(
"{}",
Colour::Purple.dimmed().italic().paint(format!(
"\t\t/// Next instruction at @0x{:08x}",
debugger.gba.cpu.get_next_pc()
))
);
}
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 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 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 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)?;

View file

@ -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,
}
}