Add continue command

This commit is contained in:
Michel Heily 2019-06-25 05:35:52 +03:00
parent 9921f1c974
commit 22a915ec85
5 changed files with 162 additions and 43 deletions

19
src/arm7tdmi/arm/exec.rs Normal file
View file

@ -0,0 +1,19 @@
use super::super::cpu::{Core, CpuPipelineAction, CpuError, CpuInstruction, CpuExecResult};
use super::super::sysbus::SysBus;
use super::{ArmInstruction, ArmInstructionFormat};
impl Core {
pub fn exec_arm(&mut self, sysbus: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
match insn.fmt {
ArmInstructionFormat::BX => {
self.pc = self.get_reg(insn.rn());
Ok((CpuInstruction::Arm(insn), CpuPipelineAction::Branch))
},
ArmInstructionFormat::B_BL => {
self.pc = (self.pc as i32).wrapping_add(insn.branch_offset()) as u32;
Ok((CpuInstruction::Arm(insn), CpuPipelineAction::Branch))
}
fmt => Err(CpuError::UnimplementedCpuInstruction(CpuInstruction::Arm(insn))),
}
}
}

View file

@ -1,4 +1,5 @@
pub mod display; pub mod display;
pub mod exec;
use crate::bit::BitIndex; use crate::bit::BitIndex;
use crate::num_traits::FromPrimitive; use crate::num_traits::FromPrimitive;

View file

@ -1,14 +1,23 @@
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt;
use crate::num_traits::FromPrimitive; use crate::num_traits::FromPrimitive;
use super::arm::exec;
use super::arm::*; use super::arm::*;
use super::sysbus::SysBus; use super::sysbus::SysBus;
#[derive(Debug, PartialEq)]
pub enum CpuInstruction {
Arm(ArmInstruction),
Thumb,
}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum CpuError { pub enum CpuError {
ArmDecodeError(ArmDecodeError), ArmDecodeError(ArmDecodeError),
IllegalInstruction, IllegalInstruction(CpuInstruction),
UnimplementedCpuInstruction(CpuInstruction),
} }
impl From<ArmDecodeError> for CpuError { impl From<ArmDecodeError> for CpuError {
@ -17,6 +26,29 @@ impl From<ArmDecodeError> for CpuError {
} }
} }
impl fmt::Display for CpuError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CpuError::ArmDecodeError(e) => write!(
f,
"arm decoding error at address @0x{:08x} (instruction 0x{:08x}): {:?}",
e.addr, e.insn, e.kind
),
CpuError::UnimplementedCpuInstruction(CpuInstruction::Arm(insn)) => write!(
f,
"unimplemented instruction: 0x{:08x}:\t0x{:08x}\t{}",
insn.pc, insn.raw, insn
),
CpuError::IllegalInstruction(CpuInstruction::Arm(insn)) => write!(
f,
"illegal instruction at address @0x{:08x} (0x{:08x})",
insn.pc, insn.raw
),
e => write!(f, "error: {:#x?}", e)
}
}
}
pub type CpuResult<T> = Result<T, CpuError>; pub type CpuResult<T> = Result<T, CpuError>;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -45,15 +77,24 @@ pub struct CpuModeContext {
#[derive(Debug)] #[derive(Debug)]
pub struct Core { pub struct Core {
pc: u32, pub pc: u32,
// r0-r7 // r0-r7
gpr: [u32; 8], gpr: [u32; 8],
cpsr: u32, cpsr: u32,
mode: CpuMode, mode: CpuMode,
state: CpuState, state: CpuState,
verbose: bool
} }
#[derive(Debug, PartialEq)]
pub enum CpuPipelineAction {
AdvancePc,
Branch,
}
pub type CpuExecResult = CpuResult<(CpuInstruction, CpuPipelineAction)>;
impl Core { impl Core {
pub fn new() -> Core { pub fn new() -> Core {
Core { Core {
@ -62,9 +103,14 @@ impl Core {
cpsr: 0, cpsr: 0,
mode: CpuMode::System, mode: CpuMode::System,
state: CpuState::ARM, state: CpuState::ARM,
verbose: false,
} }
} }
pub fn set_verbose(&mut self, v: bool) {
self.verbose = v;
}
pub fn get_reg(&self, reg_num: usize) -> u32 { pub fn get_reg(&self, reg_num: usize) -> u32 {
match reg_num { match reg_num {
0...7 => self.gpr[reg_num], 0...7 => self.gpr[reg_num],
@ -100,22 +146,30 @@ impl Core {
self.pc = self.pc.wrapping_add(self.word_size() as u32) self.pc = self.pc.wrapping_add(self.word_size() as u32)
} }
fn step_arm(&mut self, sysbus: &mut SysBus) -> CpuResult<()> { fn step_arm(&mut self, sysbus: &mut SysBus) -> CpuExecResult {
// fetch // fetch
let insn = sysbus.read_32(self.pc); let insn = sysbus.read_32(self.pc);
// decode // decode
let insn = ArmInstruction::try_from((insn, self.pc))?; let insn = ArmInstruction::try_from((insn, self.pc))?;
// exec
Ok(()) self.exec_arm(sysbus, insn)
} }
pub fn step(&mut self, sysbus: &mut SysBus) -> CpuResult<()> { pub fn step(&mut self, sysbus: &mut SysBus) -> CpuResult<()> {
match self.state { let (executed_insn, pipeline_action) = match self.state {
CpuState::ARM => self.step_arm(sysbus)?, CpuState::ARM => self.step_arm(sysbus),
CpuState::THUMB => unimplemented!("thumb not implemented :("), CpuState::THUMB => unimplemented!("thumb not implemented :("),
}; }?;
if self.verbose {
if let CpuInstruction::Arm(insn) = executed_insn {
println!("{:8x}:\t{:08x} \t{}", insn.pc, insn.raw, insn)
}
}
if CpuPipelineAction::AdvancePc == pipeline_action {
self.advance_pc(); self.advance_pc();
}
Ok(()) Ok(())
} }

View file

@ -19,6 +19,7 @@ use super::sysbus::SysBus;
pub struct Debugger { pub struct Debugger {
cpu: cpu::Core, cpu: cpu::Core,
sysbus: SysBus, sysbus: SysBus,
running: bool,
breakpoints: Vec<u32>, breakpoints: Vec<u32>,
} }
@ -118,31 +119,60 @@ impl Debugger {
cpu: cpu, cpu: cpu,
sysbus: sysbus, sysbus: sysbus,
breakpoints: Vec::new(), breakpoints: Vec::new(),
running: false,
} }
} }
pub fn repl(&mut self) -> DebuggerResult<()> { fn is_breakpoint_reached(&self) -> bool {
let mut rl = Editor::<()>::new(); let pc = self.cpu.pc;
loop { for b in &self.breakpoints {
let readline = rl.readline(&format!("({}) >> ", "rustboyadvance-dbg".cyan())); if *b == pc {
match readline { return true;
Ok(line) => { }
let command = parse_debugger_command(&line); }
match command {
Ok(Nop) => (), false
Ok(Info) => { }
println!("cpu info: {:#?}", self.cpu)
fn command(&mut self, cmd: DebuggerCommand) {
match cmd {
Nop => (),
Info => {
println!("cpu info: {:#x?}", self.cpu)
}
SingleStep => {
;
match self.cpu.step(&mut self.sysbus) {
Ok(_) => (),
Err(e) => {
println!("{}: {}", "cpu encountered an error".red(), e);
println!("cpu: {:#x?}", self.cpu);
}
};
if self.is_breakpoint_reached() {
println!("breakpoint 0x{:08x} reached!", self.cpu.pc)
} }
Ok(SingleStep) => {
println!("single step:");
self.cpu.step(&mut self.sysbus)?;
()
}, },
Ok(Quit) => { Continue => {
print!("Quitting!"); loop {
match self.cpu.step(&mut self.sysbus) {
Ok(_) => (),
Err(e) => {
println!("{}: {}", "cpu encountered an error".red(), e);
println!("cpu: {:#x?}", self.cpu);
break break
}
};
if self.is_breakpoint_reached() {
println!("breakpoint 0x{:08x} reached!", self.cpu.pc)
}
}
}
Quit => {
print!("Quitting!");
self.running = false;
}, },
Ok(AddBreakpoint(addr)) => { AddBreakpoint(addr) => {
if !self.breakpoints.contains(&addr) { if !self.breakpoints.contains(&addr) {
let new_index = self.breakpoints.len(); let new_index = self.breakpoints.len();
self.breakpoints.push(addr); self.breakpoints.push(addr);
@ -151,16 +181,31 @@ impl Debugger {
println!("breakpoint already exists!") println!("breakpoint already exists!")
} }
} }
Ok(ListBreakpoints) => { ListBreakpoints => {
println!("breakpoint list:"); println!("breakpoint list:");
for (i, b) in self.breakpoints.iter().enumerate() { for (i, b) in self.breakpoints.iter().enumerate() {
println!("[{}] 0x{:08x}", i, b) println!("[{}] 0x{:08x}", i, b)
} }
} }
Ok(Reset) => { Reset => {
println!("resetting cpu..."); println!("resetting cpu...");
self.cpu.reset(); self.cpu.reset();
println!("cpu is restarted!") println!("cpu is restarted!")
},
_ => panic!("command {:?} not implemented", cmd)
}
}
pub fn repl(&mut self) -> DebuggerResult<()> {
self.running = true;
let mut rl = Editor::<()>::new();
while self.running {
let readline = rl.readline(&format!("({}) >> ", "rustboyadvance-dbg".cyan()));
match readline {
Ok(line) => {
let command = parse_debugger_command(&line);
match command {
Ok(cmd) => {
self.command(cmd)
} }
Err(DebuggerError::InvalidCommand(command)) => { Err(DebuggerError::InvalidCommand(command)) => {
println!("invalid command: {}", command) println!("invalid command: {}", command)
@ -171,7 +216,6 @@ impl Debugger {
Err(e) => { Err(e) => {
return Err(e); return Err(e);
} }
Ok(command) => println!("got command: {:?}", command),
} }
} }
Err(ReadlineError::Interrupted) => { Err(ReadlineError::Interrupted) => {

View file

@ -108,6 +108,7 @@ fn run_debug(matches: &ArgMatches) -> GBAResult<()> {
let mut sysbus = SysBus::new(bios_bin); let mut sysbus = SysBus::new(bios_bin);
let mut core = cpu::Core::new(); let mut core = cpu::Core::new();
core.set_verbose(true);
let mut debugger = Debugger::new(core, sysbus); let mut debugger = Debugger::new(core, sysbus);
println!("starting debugger..."); println!("starting debugger...");