diff --git a/src/arm7tdmi/cpu.rs b/src/arm7tdmi/cpu.rs index c949d46..a069a61 100644 --- a/src/arm7tdmi/cpu.rs +++ b/src/arm7tdmi/cpu.rs @@ -1,10 +1,11 @@ use std::convert::TryFrom; use std::fmt; -use crate::num_traits::FromPrimitive; +use colored::*; -use super::arm::exec; +use super::reg_string; use super::arm::*; +use super::psr::{CpuMode, CpuState, RegPSR}; use super::sysbus::SysBus; #[derive(Debug, PartialEq)] @@ -44,31 +45,13 @@ impl fmt::Display for CpuError { "illegal instruction at address @0x{:08x} (0x{:08x})", insn.pc, insn.raw ), - e => write!(f, "error: {:#x?}", e) + e => write!(f, "error: {:#x?}", e), } } } pub type CpuResult = Result; -#[derive(Debug, PartialEq)] -pub enum CpuState { - ARM, - THUMB, -} - -#[derive(Debug, Primitive)] -#[repr(u8)] -enum CpuMode { - User = 0b10000, - Fiq = 0b10001, - Irq = 0b10010, - Supervisor = 0b10011, - Abort = 0b10111, - Undefined = 0b11011, - System = 0b11111, -} - pub struct CpuModeContext { // r8-r14 banked_gpr: [u32; 7], @@ -79,12 +62,9 @@ pub struct CpuModeContext { pub struct Core { pub pc: u32, // r0-r7 - gpr: [u32; 8], - cpsr: u32, - - mode: CpuMode, - state: CpuState, - verbose: bool + gpr: [u32; 15], + pub cpsr: RegPSR, + pub verbose: bool, } #[derive(Debug, PartialEq)] @@ -99,10 +79,8 @@ impl Core { pub fn new() -> Core { Core { pc: 0, - gpr: [0; 8], - cpsr: 0, - mode: CpuMode::System, - state: CpuState::ARM, + gpr: [0; 15], + cpsr: RegPSR::new(), verbose: false, } } @@ -113,34 +91,30 @@ impl Core { pub fn get_reg(&self, reg_num: usize) -> u32 { match reg_num { - 0...7 => self.gpr[reg_num], + 0...14 => self.gpr[reg_num], 15 => self.pc, - _ => unimplemented!("TODO banked registers"), + _ => panic!("invalid register") + // _ => 0x12345678 // unimplemented!("TODO banked registers"), } } pub fn set_reg(&mut self, reg_num: usize, val: u32) { match reg_num { - 0...7 => self.gpr[reg_num] = val, + 0...14 => self.gpr[reg_num] = val, 15 => self.pc = val, - _ => unimplemented!("TODO banked registers"), + _ => panic!("invalid register") + // _ => unimplemented!("TODO banked registers"), } } - pub fn set_state(&mut self, s: CpuState) { - self.state = s; - } - /// Resets the cpu pub fn reset(&mut self) { self.pc = 0; - self.cpsr = 0; - self.mode = CpuMode::System; - self.state = CpuState::ARM; + self.cpsr.set(0); } fn word_size(&self) -> usize { - match self.state { + match self.cpsr.state() { CpuState::ARM => 4, CpuState::THUMB => 2, } @@ -160,7 +134,7 @@ impl Core { } pub fn step(&mut self, sysbus: &mut SysBus) -> CpuResult<()> { - let (executed_insn, pipeline_action) = match self.state { + let (executed_insn, pipeline_action) = match self.cpsr.state() { CpuState::ARM => self.step_arm(sysbus), CpuState::THUMB => unimplemented!("thumb not implemented :("), }?; @@ -178,3 +152,16 @@ impl Core { Ok(()) } } + +impl fmt::Display for Core { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "ARM7TDMI Core")?; + writeln!(f, "REGISTERS:")?; + for i in 0..16 { + let mut reg = reg_string(i).to_string(); + reg.make_ascii_uppercase(); + writeln!(f, "\t{}\t= 0x{:08x}", reg.bright_yellow(), self.get_reg(i))?; + } + write!(f, "CPSR: {}", self.cpsr) + } +} diff --git a/src/arm7tdmi/psr.rs b/src/arm7tdmi/psr.rs new file mode 100644 index 0000000..c74fc77 --- /dev/null +++ b/src/arm7tdmi/psr.rs @@ -0,0 +1,200 @@ +/// The program status register +use std::fmt; + +use crate::bit::BitIndex; +use crate::num_traits::FromPrimitive; + +use colored::*; + +use super::arm::ArmCond; + +#[derive(Debug, PartialEq, Primitive)] +#[repr(u8)] +pub enum CpuState { + ARM = 0, + THUMB = 1, +} + +impl fmt::Display for CpuState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use CpuState::*; + match self { + ARM => write!(f, "ARM"), + THUMB => write!(f, "THUMB"), + } + } +} + +impl From for bool { + fn from(state: CpuState) -> bool { + match state { + CpuState::ARM => false, + CpuState::THUMB => true, + } + } +} + +impl From for CpuState { + fn from(flag: bool) -> CpuState { + if flag { + CpuState::THUMB + } else { + CpuState::ARM + } + } +} + +#[derive(Debug, Primitive)] +#[repr(u8)] +pub enum CpuMode { + User = 0b10000, + Fiq = 0b10001, + Irq = 0b10010, + Supervisor = 0b10011, + Abort = 0b10111, + Undefined = 0b11011, + System = 0b11111, +} + +impl fmt::Display for CpuMode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use CpuMode::*; + match self { + User => write!(f, "USR"), + Fiq => write!(f, "FIQ"), + Irq => write!(f, "IRQ"), + Supervisor => write!(f, "SVC"), + Abort => write!(f, "ABT"), + Undefined => write!(f, "UND"), + System => write!(f, "SYS"), + } + } +} + +#[derive(Debug, Clone, Copy)] +pub struct RegPSR { + raw: u32, +} + +const RESERVED_BIT_MASK: u32 = 0x0fffff00; +fn clear_reserved(n: u32) -> u32 { + n & !RESERVED_BIT_MASK +} + +impl RegPSR { + pub fn new() -> RegPSR { + let mut psr = RegPSR { raw: 0 }; + + psr.set_irq_disabled(true); + psr.set_fiq_disabled(true); + psr.set_mode(CpuMode::Supervisor); + psr.set_state(CpuState::ARM); + println!("RAW: 0x{:08x}", psr.raw); + + psr + } + + pub fn get(&self) -> u32 { + self.raw + } + + pub fn set(&mut self, psr: u32) { + self.raw = clear_reserved(psr); + } + + pub fn state(&self) -> CpuState { + self.raw.bit(5).into() + } + + pub fn set_state(&mut self, state: CpuState) { + self.raw.set_bit(5, state.into()); + } + + pub fn mode(&self) -> CpuMode { + CpuMode::from_u32(self.raw & 0xb11111).unwrap() + } + + pub fn set_mode(&mut self, mode: CpuMode) { + self.raw |= mode as u32; + } + + pub fn irq_disabled(&self) -> bool { + self.raw.bit(7) + } + + pub fn set_irq_disabled(&mut self, disabled: bool) { + self.raw.set_bit(7, disabled); + } + + pub fn fiq_disabled(&self) -> bool { + self.raw.bit(6) + } + + pub fn set_fiq_disabled(&mut self, disabled: bool) { + self.raw.set_bit(6, disabled); + } + + #[allow(non_snake_case)] + pub fn N(&self) -> bool { + self.raw.bit(31) + } + + #[allow(non_snake_case)] + pub fn set_N(&mut self, flag: bool) { + self.raw.set_bit(31, flag); + } + + #[allow(non_snake_case)] + pub fn Z(&self) -> bool { + self.raw.bit(30) + } + + #[allow(non_snake_case)] + pub fn set_Z(&mut self, flag: bool) { + self.raw.set_bit(30, flag); + } + + #[allow(non_snake_case)] + pub fn C(&self) -> bool { + self.raw.bit(29) + } + + #[allow(non_snake_case)] + pub fn set_C(&mut self, flag: bool) { + self.raw.set_bit(29, flag); + } + + #[allow(non_snake_case)] + pub fn V(&self) -> bool { + self.raw.bit(28) + } + + #[allow(non_snake_case)] + pub fn set_V(&mut self, flag: bool) { + self.raw.set_bit(28, flag); + } +} + +impl fmt::Display for RegPSR { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let disabled_string = |disabled: bool| -> ColoredString { + if disabled { + "disabled".bright_red() + } else { + "enabled".bright_green() + } + }; + write!( + f, + "{{ mode: {mode}, state: {state}, irq: {irq}, fiq: {fiq}, condition_flags: (N={N} Z={Z} C={C} V={V}) }}", + mode = self.mode(), + state = self.state(), + irq = disabled_string(self.irq_disabled()), + fiq = disabled_string(self.irq_disabled()), + N = self.N() as u8, + Z = self.Z() as u8, + C = self.C() as u8, + V = self.V() as u8, + ) + } +}