From ae7bf63d3fe4755b19b6a0843d6ce219d9c3319e Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Sat, 8 Feb 2020 14:19:57 +0200 Subject: [PATCH] arm7tdmi/optimize: Optimize and cleanup CPU, roughly about 10% fps improvement. This commit removes the error handling (CpuResult<>) in order to reduce overhead in the cpu implementation. Also, some cleanup of warning messages. Notice: this commit breaks '--feature debugger' for now Former-commit-id: d4484047c3f5d509eff89cef7090aa88b07a8d17 --- src/core/arm7tdmi/alu.rs | 35 +++--- src/core/arm7tdmi/arm/display.rs | 10 +- src/core/arm7tdmi/arm/exec.rs | 89 ++++++---------- src/core/arm7tdmi/arm/mod.rs | 6 +- src/core/arm7tdmi/cpu.rs | 131 ++++++++++------------- src/core/arm7tdmi/exception.rs | 12 +-- src/core/arm7tdmi/mod.rs | 7 +- src/core/arm7tdmi/thumb/display.rs | 4 + src/core/arm7tdmi/thumb/exec.rs | 166 ++++++++++++----------------- src/disass.rs | 3 +- 10 files changed, 198 insertions(+), 265 deletions(-) diff --git a/src/core/arm7tdmi/alu.rs b/src/core/arm7tdmi/alu.rs index d3dacf9..017bd30 100644 --- a/src/core/arm7tdmi/alu.rs +++ b/src/core/arm7tdmi/alu.rs @@ -1,6 +1,6 @@ use bit::BitIndex; -use super::{Core, CpuError, CpuResult, REG_PC}; +use super::{Core, REG_PC}; #[derive(Debug, Primitive, PartialEq)] pub enum AluOpCode { @@ -246,26 +246,25 @@ impl Core { } } - pub fn register_shift(&mut self, shift: ShiftedRegister) -> CpuResult { - let mut val = self.get_reg(shift.reg); + pub fn shift_by_register(&mut self, bs_op: BarrelShiftOpCode, reg: usize, rs: usize, carry: bool) -> u32 { + let mut val = self.get_reg(reg); + self.add_cycle(); // +1I + if reg == REG_PC { + val += 4; // PC prefetching + } + let amount = self.get_reg(rs) & 0xff; + self.barrel_shift_op(bs_op, val, amount, carry, false) + } + + pub fn register_shift(&mut self, shift: ShiftedRegister) -> u32 { let carry = self.cpsr.C(); match shift.shift_by { ShiftRegisterBy::ByAmount(amount) => { - let result = self.barrel_shift_op(shift.bs_op, val, amount, carry, true); - Ok(result) + let result = self.barrel_shift_op(shift.bs_op, self.get_reg(shift.reg), amount, carry, true); + result } ShiftRegisterBy::ByRegister(rs) => { - self.add_cycle(); // +1I - if shift.reg == REG_PC { - val = val + 4; // PC prefetching - } - if rs != REG_PC { - let amount = self.get_reg(rs) & 0xff; - let result = self.barrel_shift_op(shift.bs_op, val, amount, carry, false); - Ok(result) - } else { - Err(CpuError::IllegalInstruction) - } + self.shift_by_register(shift.bs_op, shift.reg, rs, carry) } } } @@ -276,7 +275,7 @@ impl Core { BarrelShifterValue::ImmediateValue(offset) => offset as u32, BarrelShifterValue::ShiftedRegister(shifted_reg) => { let added = shifted_reg.added.unwrap_or(true); - let abs = self.register_shift(shifted_reg).unwrap() as u32; + let abs = self.register_shift(shifted_reg) as u32; if added { abs as u32 } else { @@ -337,7 +336,7 @@ impl Core { self.alu_adc_flags(a, !b, carry, overflow) } - pub fn alu_update_flags(&mut self, result: u32, is_arithmetic: bool, c: bool, v: bool) { + pub fn alu_update_flags(&mut self, result: u32, _is_arithmetic: bool, c: bool, v: bool) { self.cpsr.set_N((result as i32) < 0); self.cpsr.set_Z(result == 0); self.cpsr.set_C(c); diff --git a/src/core/arm7tdmi/arm/display.rs b/src/core/arm7tdmi/arm/display.rs index 8dc89fe..290090f 100644 --- a/src/core/arm7tdmi/arm/display.rs +++ b/src/core/arm7tdmi/arm/display.rs @@ -1,10 +1,12 @@ use std::fmt; +#[cfg(feature = "debugger")] use crate::bit::BitIndex; -use super::{AluOpCode, ArmCond, ArmFormat, ArmHalfwordTransferType, ArmInstruction}; -use crate::core::arm7tdmi::alu::*; -use crate::core::arm7tdmi::psr::RegPSR; +#[cfg(feature = "debugger")] +use super::{ArmFormat, ArmInstruction}; + +use super::{AluOpCode, ArmCond, ArmHalfwordTransferType}; use crate::core::arm7tdmi::*; impl fmt::Display for ArmCond { @@ -100,6 +102,7 @@ impl fmt::Display for ShiftedRegister { } } +#[cfg(feature = "debugger")] impl ArmInstruction { fn fmt_bx(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "bx\t{Rn}", Rn = reg_string(self.rn())) @@ -408,6 +411,7 @@ impl ArmInstruction { } } +#[cfg(feature = "debugger")] impl fmt::Display for ArmInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use ArmFormat::*; diff --git a/src/core/arm7tdmi/arm/exec.rs b/src/core/arm7tdmi/arm/exec.rs index 360f9c0..8ede0a2 100644 --- a/src/core/arm7tdmi/arm/exec.rs +++ b/src/core/arm7tdmi/arm/exec.rs @@ -1,19 +1,18 @@ use crate::bit::BitIndex; use super::super::alu::*; -use crate::core::arm7tdmi::cpu::{Core, CpuExecResult}; use crate::core::arm7tdmi::psr::RegPSR; -use crate::core::arm7tdmi::{Addr, CpuError, CpuMode, CpuResult, CpuState, REG_LR, REG_PC}; +use crate::core::arm7tdmi::{Core, Addr, CpuMode, CpuState, REG_LR, REG_PC}; use crate::core::sysbus::SysBus; use crate::core::Bus; use super::*; impl Core { - pub fn exec_arm(&mut self, bus: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + pub fn exec_arm(&mut self, bus: &mut SysBus, insn: ArmInstruction) { if !self.check_arm_cond(insn.cond) { self.S_cycle32(bus, self.pc); - return Ok(()); + return; } match insn.fmt { ArmFormat::BX => self.exec_bx(bus, insn), @@ -21,7 +20,6 @@ impl Core { ArmFormat::DP => self.exec_data_processing(bus, insn), ArmFormat::SWI => { self.software_interrupt(bus, self.pc - 4, insn.swi_comment()); - Ok(()) } ArmFormat::LDR_STR => self.exec_ldr_str(bus, insn), ArmFormat::LDR_STR_HS_IMM => self.exec_ldr_str_hs(bus, insn), @@ -37,7 +35,7 @@ impl Core { } /// Cycles 2S+1N - fn exec_b_bl(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + fn exec_b_bl(&mut self, sb: &mut SysBus, insn: ArmInstruction) { self.S_cycle32(sb, self.pc); if insn.link_flag() { self.set_reg(REG_LR, (insn.pc + (self.word_size() as u32)) & !0b1); @@ -46,10 +44,9 @@ impl Core { self.pc = (self.pc as i32).wrapping_add(insn.branch_offset()) as u32 & !1; self.flush_pipeline32(sb); - Ok(()) } - pub fn branch_exchange(&mut self, sb: &mut SysBus, mut addr: Addr) -> CpuExecResult { + pub fn branch_exchange(&mut self, sb: &mut SysBus, mut addr: Addr) { match self.cpsr.state() { CpuState::ARM => self.S_cycle32(sb, self.pc), CpuState::THUMB => self.S_cycle16(sb, self.pc), @@ -65,11 +62,10 @@ impl Core { self.pc = addr; self.flush_pipeline32(sb); // +1S+1N - Ok(()) } /// Cycles 2S+1N - fn exec_bx(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + fn exec_bx(&mut self, sb: &mut SysBus, insn: ArmInstruction) { self.branch_exchange(sb, self.get_reg(insn.rn())) } @@ -78,7 +74,7 @@ impl Core { sb: &mut SysBus, rd: usize, is_spsr: bool, - ) -> CpuExecResult { + ) { let result = if is_spsr { self.spsr.get() } else { @@ -86,10 +82,9 @@ impl Core { }; self.set_reg(rd, result); self.S_cycle32(sb, self.pc); - Ok(()) } - fn exec_msr_reg(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + fn exec_msr_reg(&mut self, sb: &mut SysBus, insn: ArmInstruction) { self.write_status_register(sb, insn.spsr_flag(), self.get_reg(insn.rm())) } @@ -98,7 +93,7 @@ impl Core { sb: &mut SysBus, is_spsr: bool, value: u32, - ) -> CpuExecResult { + ) { let new_status_reg = RegPSR::new(value); match self.cpsr.mode() { CpuMode::User => { @@ -125,32 +120,27 @@ impl Core { } } self.S_cycle32(sb, self.pc); - Ok(()) } - fn exec_msr_flags(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + fn exec_msr_flags(&mut self, sb: &mut SysBus, insn: ArmInstruction) { self.S_cycle32(sb, self.pc); - let op = insn.operand2()?; - let op = self.decode_operand2(op)?; + let op = insn.operand2(); + let op = self.decode_operand2(op); - let old_mode = self.cpsr.mode(); if insn.spsr_flag() { self.spsr.set_flag_bits(op); } else { self.cpsr.set_flag_bits(op); } - Ok(()) } - fn decode_operand2(&mut self, op2: BarrelShifterValue) -> CpuResult { + fn decode_operand2(&mut self, op2: BarrelShifterValue) -> u32 { match op2 { BarrelShifterValue::RotatedImmediate(val, amount) => { - let result = self.ror(val, amount, self.cpsr.C(), false, true); - Ok(result) + self.ror(val, amount, self.cpsr.C(), false, true) } BarrelShifterValue::ShiftedRegister(x) => { - let result = self.register_shift(x)?; - Ok(result) + self.register_shift(x) } _ => unreachable!(), } @@ -168,7 +158,7 @@ impl Core { /// /// Cycles: 1S+x+y (from GBATEK) /// Add x=1I cycles if Op2 shifted-by-register. Add y=1S+1N cycles if Rd=R15. - fn exec_data_processing(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + fn exec_data_processing(&mut self, sb: &mut SysBus, insn: ArmInstruction) { use AluOpCode::*; self.S_cycle32(sb, self.pc); @@ -181,7 +171,7 @@ impl Core { let mut s_flag = insn.set_cond_flag(); let opcode = insn.opcode().unwrap(); - let op2 = insn.operand2()?; + let op2 = insn.operand2(); match op2 { BarrelShifterValue::ShiftedRegister(shifted_reg) => { if insn.rn() == REG_PC && shifted_reg.is_shifted_by_reg() { @@ -190,7 +180,7 @@ impl Core { } _ => {} } - let op2 = self.decode_operand2(op2)?; + let op2 = self.decode_operand2(op2); let reg_rd = insn.rd(); if !s_flag { @@ -212,7 +202,7 @@ impl Core { s_flag = false; } - let C = self.cpsr.C() as u32; + let carry = self.cpsr.C() as u32; let alu_res = if s_flag { let mut carry = self.bs_carry_out; let mut overflow = self.cpsr.V(); @@ -245,9 +235,9 @@ impl Core { SUB => op1.wrapping_sub(op2), RSB => op2.wrapping_sub(op1), ADD => op1.wrapping_add(op2), - ADC => op1.wrapping_add(op2).wrapping_add(C), - SBC => op1.wrapping_sub(op2.wrapping_add(1 - C)), - RSC => op2.wrapping_sub(op1.wrapping_add(1 - C)), + ADC => op1.wrapping_add(op2).wrapping_add(carry), + SBC => op1.wrapping_sub(op2.wrapping_add(1 - carry)), + RSC => op2.wrapping_sub(op1.wrapping_add(1 - carry)), ORR => op1 | op2, MOV => op2, BIC => op1 & (!op2), @@ -263,7 +253,6 @@ impl Core { self.set_reg(reg_rd, result as u32); } - Ok(()) } /// Memory Load/Store @@ -273,7 +262,7 @@ impl Core { /// STR{cond}{B}{T} Rd,
| 2N | ---- | [Rn+/-]=Rd /// ------------------------------------------------------------------------------ /// For LDR, add y=1S+1N if Rd=R15. - fn exec_ldr_str(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + fn exec_ldr_str(&mut self, sb: &mut SysBus, insn: ArmInstruction) { let load = insn.load_flag(); let pre_index = insn.pre_index_flag(); let writeback = insn.write_back_flag(); @@ -344,10 +333,9 @@ impl Core { self.change_mode(self.cpsr.mode(), old_mode); } - Ok(()) } - fn exec_ldr_str_hs(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + fn exec_ldr_str_hs(&mut self, sb: &mut SysBus, insn: ArmInstruction) { let load = insn.load_flag(); let pre_index = insn.pre_index_flag(); let writeback = insn.write_back_flag(); @@ -423,10 +411,9 @@ impl Core { } } - Ok(()) } - fn exec_ldm_stm(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + fn exec_ldm_stm(&mut self, sb: &mut SysBus, insn: ArmInstruction) { let mut full = insn.pre_index_flag(); let ascending = insn.add_offset_flag(); let s_flag = insn.raw.bit(22); @@ -569,19 +556,14 @@ impl Core { self.set_reg(base_reg, addr as u32); } - Ok(()) } - fn exec_mul_mla(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + fn exec_mul_mla(&mut self, sb: &mut SysBus, insn: ArmInstruction) { let (rd, rn, rs, rm) = (insn.rd(), insn.rn(), insn.rs(), insn.rm()); // check validity - if REG_PC == rd || REG_PC == rn || REG_PC == rs || REG_PC == rm { - return Err(CpuError::IllegalInstruction); - } - if rd == rm { - return Err(CpuError::IllegalInstruction); - } + assert!(!(REG_PC == rd || REG_PC == rn || REG_PC == rs || REG_PC == rm)); + assert!(rd != rm); let op1 = self.get_reg(rm); let op2 = self.get_reg(rs); @@ -607,20 +589,15 @@ impl Core { } self.S_cycle32(sb, self.pc); - Ok(()) } - fn exec_mull_mlal(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + fn exec_mull_mlal(&mut self, sb: &mut SysBus, insn: ArmInstruction) { let (rd_hi, rd_lo, rn, rs, rm) = (insn.rd_hi(), insn.rd_lo(), insn.rn(), insn.rs(), insn.rm()); // check validity - if REG_PC == rd_hi || REG_PC == rd_lo || REG_PC == rn || REG_PC == rs || REG_PC == rm { - return Err(CpuError::IllegalInstruction); - } - if rd_hi != rd_hi && rd_hi != rm && rd_lo != rm { - return Err(CpuError::IllegalInstruction); - } + assert!(!(REG_PC == rd_hi || REG_PC == rd_lo || REG_PC == rn || REG_PC == rs || REG_PC == rm)); + assert!(!(rd_hi != rd_hi && rd_hi != rm && rd_lo != rm)); let op1 = self.get_reg(rm); let op2 = self.get_reg(rs); @@ -655,10 +632,9 @@ impl Core { } self.S_cycle32(sb, self.pc); - Ok(()) } - fn exec_arm_swp(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + fn exec_arm_swp(&mut self, sb: &mut SysBus, insn: ArmInstruction) { let base_addr = self.get_reg(insn.rn()); self.add_cycle(); if insn.transfer_size() == 1 { @@ -675,6 +651,5 @@ impl Core { self.set_reg(insn.rd(), t as u32); } self.N_cycle32(sb, self.pc); - Ok(()) } } diff --git a/src/core/arm7tdmi/arm/mod.rs b/src/core/arm7tdmi/arm/mod.rs index c2a9f29..9df752f 100644 --- a/src/core/arm7tdmi/arm/mod.rs +++ b/src/core/arm7tdmi/arm/mod.rs @@ -338,12 +338,12 @@ impl ArmInstruction { } } - pub fn operand2(&self) -> Result { + pub fn operand2(&self) -> BarrelShifterValue { let op2 = self.raw.bit_range(0..12); if self.raw.bit(25) { let immediate = op2 & 0xff; let rotate = 2 * op2.bit_range(8..12); - Ok(BarrelShifterValue::RotatedImmediate(immediate, rotate)) + BarrelShifterValue::RotatedImmediate(immediate, rotate) } else { let reg = op2 & 0xf; let shifted_reg = ShiftedRegister { @@ -352,7 +352,7 @@ impl ArmInstruction { shift_by: self.get_shift_reg_by(op2), added: None, }; // TODO error handling - Ok(BarrelShifterValue::ShiftedRegister(shifted_reg)) + BarrelShifterValue::ShiftedRegister(shifted_reg) } } diff --git a/src/core/arm7tdmi/cpu.rs b/src/core/arm7tdmi/cpu.rs index b5b36b1..149b682 100644 --- a/src/core/arm7tdmi/cpu.rs +++ b/src/core/arm7tdmi/cpu.rs @@ -1,17 +1,20 @@ +#[cfg(feature = "debugger")] use std::fmt; - +#[cfg(feature = "debugger")] use ansi_term::{Colour, Style}; +#[cfg(feature = "debugger")] +use super::reg_string; use serde::{Deserialize, Serialize}; pub use super::exception::Exception; use super::{ - arm::*, psr::RegPSR, reg_string, thumb::ThumbInstruction, Addr, CpuMode, CpuResult, CpuState, + arm::*, psr::RegPSR, thumb::ThumbInstruction, Addr, CpuMode, CpuResult, CpuState, DecodedInstruction, InstructionDecoder, }; use crate::core::bus::Bus; use crate::core::sysbus::{ - MemoryAccess, MemoryAccessType, MemoryAccessType::*, MemoryAccessWidth::*, SysBus, + MemoryAccessType::*, MemoryAccessWidth::*, SysBus, }; #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)] @@ -67,7 +70,7 @@ pub type CpuExecResult = CpuResult<()>; impl Core { pub fn new() -> Core { - let mut cpsr = RegPSR::new(0x0000_00D3); + let cpsr = RegPSR::new(0x0000_00D3); Core { memreq: 0xffff_0000, // set memreq to an invalid addr so the first load cycle will be non-sequential cpsr: cpsr, @@ -105,7 +108,7 @@ impl Core { pub fn set_reg(&mut self, r: usize, val: u32) { match r { - 0...14 => self.gpr[r] = val, + 0..=14 => self.gpr[r] = val, 15 => { self.pc = { match self.cpsr.state() { @@ -236,20 +239,6 @@ impl Core { self.cycles += 1; } - pub(super) fn add_cycles(&mut self, addr: Addr, bus: &SysBus, access: MemoryAccess) { - let cycles_to_add = 1 + bus.get_cycles(addr, access); - // println!(" took: {}", addr, access, cycles_to_add); - self.cycles += cycles_to_add; - } - - pub(super) fn cycle_type(&self, addr: Addr) -> MemoryAccessType { - if addr == self.memreq || addr == self.memreq.wrapping_add(self.word_size() as Addr) { - Seq - } else { - NonSeq - } - } - pub(super) fn get_required_multipiler_array_cycles(&self, rs: u32) -> usize { if rs & 0xff == rs { 1 @@ -323,7 +312,7 @@ impl Core { self.pipeline_state != PipelineState::Execute } - fn step_arm_exec(&mut self, insn: u32, sb: &mut SysBus) -> CpuResult<()> { + fn step_arm_exec(&mut self, insn: u32, sb: &mut SysBus) { let pc = self.pc; match self.pipeline_state { PipelineState::Refill1 => { @@ -337,19 +326,21 @@ impl Core { self.last_executed = None; } PipelineState::Execute => { - let decoded_arm = ArmInstruction::decode(insn, self.pc.wrapping_sub(8))?; - self.gpr_previous = self.get_registers(); - self.exec_arm(sb, decoded_arm)?; + let decoded_arm = ArmInstruction::decode(insn, self.pc.wrapping_sub(8)).unwrap(); + #[cfg(feature = "debugger")] + { + self.gpr_previous = self.get_registers(); + } + self.exec_arm(sb, decoded_arm); if !self.did_pipeline_flush() { self.pc = pc.wrapping_add(4); } self.last_executed = Some(DecodedInstruction::Arm(decoded_arm)); } } - Ok(()) } - fn step_thumb_exec(&mut self, insn: u16, sb: &mut SysBus) -> CpuResult<()> { + fn step_thumb_exec(&mut self, insn: u16, sb: &mut SysBus) { let pc = self.pc; match self.pipeline_state { PipelineState::Refill1 => { @@ -363,16 +354,18 @@ impl Core { self.last_executed = None; } PipelineState::Execute => { - let decoded_thumb = ThumbInstruction::decode(insn, self.pc.wrapping_sub(4))?; - self.gpr_previous = self.get_registers(); - self.exec_thumb(sb, decoded_thumb)?; + let decoded_thumb = ThumbInstruction::decode(insn, self.pc.wrapping_sub(4)).unwrap(); + #[cfg(feature = "debugger")] + { + self.gpr_previous = self.get_registers(); + } + self.exec_thumb(sb, decoded_thumb); if !self.did_pipeline_flush() { self.pc = pc.wrapping_add(2); } self.last_executed = Some(DecodedInstruction::Thumb(decoded_thumb)); } } - Ok(()) } pub(super) fn flush_pipeline16(&mut self, sb: &mut SysBus) { @@ -387,41 +380,43 @@ impl Core { self.S_cycle32(sb, self.pc + 4); } - fn trace_opcode(&self, insn: u32) { - if self.trace_opcodes && self.pipeline_state == PipelineState::Execute { - print!("[{:08X}] PC=0x{:08x} | ", insn, self.pc); - for r in 0..15 { - print!("R{}=0x{:08x} ", r, self.gpr[r]); - } - print!( - " N={} Z={} C={} V={} T={}\n", - self.cpsr.N() as u8, - self.cpsr.Z() as u8, - self.cpsr.C() as u8, - self.cpsr.V() as u8, - self.cpsr.state() as u8, - ); - } - } + // fn trace_opcode(&self, insn: u32) { + // if self.trace_opcodes && self.pipeline_state == PipelineState::Execute { + // println!("[{:08X}] PC=0x{:08x} | ", insn, self.pc); + // for r in 0..15 { + // println!("R{}=0x{:08x} ", r, self.gpr[r]); + // } + // println!( + // " N={} Z={} C={} V={} T={}\n", + // self.cpsr.N() as u8, + // self.cpsr.Z() as u8, + // self.cpsr.C() as u8, + // self.cpsr.V() as u8, + // self.cpsr.state() as u8, + // ); + // } + // } + /// Perform a pipeline step /// If an instruction was executed in this step, return it. - pub fn step(&mut self, bus: &mut SysBus) -> CpuResult<()> { + pub fn step(&mut self, bus: &mut SysBus) { let pc = self.pc; - let fetched_now = match self.cpsr.state() { - CpuState::ARM => bus.read_32(pc), - CpuState::THUMB => bus.read_16(pc) as u32, - }; - - let insn = self.pipeline[0]; - self.pipeline[0] = self.pipeline[1]; - self.pipeline[1] = fetched_now; - - self.trace_opcode(insn.into()); - match self.cpsr.state() { - CpuState::ARM => self.step_arm_exec(insn, bus), - CpuState::THUMB => self.step_thumb_exec(insn as u16, bus), + CpuState::ARM => { + let fetched_now = bus.read_32(pc); + let insn = self.pipeline[0]; + self.pipeline[0] = self.pipeline[1]; + self.pipeline[1] = fetched_now; + self.step_arm_exec(insn, bus) + } + CpuState::THUMB => { + let fetched_now = bus.read_16(pc); + let insn = self.pipeline[0]; + self.pipeline[0] = self.pipeline[1]; + self.pipeline[1] = fetched_now as u32; + self.step_thumb_exec(insn as u16, bus) + } } } @@ -435,23 +430,6 @@ impl Core { } } - /// A step that returns only once an instruction was executed. - /// Returns the address of PC before executing an instruction, - /// and the address of the next instruction to be executed; - pub fn step_one(&mut self, bus: &mut SysBus) -> CpuResult { - loop { - match self.pipeline_state { - PipelineState::Execute => { - self.step(bus)?; - return Ok(self.last_executed.unwrap()); - } - _ => { - self.step(bus)?; - } - } - } - } - pub fn get_cpu_state(&self) -> CpuState { self.cpsr.state() } @@ -471,6 +449,7 @@ impl Core { } } +#[cfg(feature = "debugger")] impl fmt::Display for Core { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { writeln!(f, "ARM7TDMI Core Status:")?; diff --git a/src/core/arm7tdmi/exception.rs b/src/core/arm7tdmi/exception.rs index 0aee6b1..28113c8 100644 --- a/src/core/arm7tdmi/exception.rs +++ b/src/core/arm7tdmi/exception.rs @@ -69,19 +69,11 @@ impl Core { } } - pub fn software_interrupt(&mut self, sb: &mut SysBus, lr: u32, cmt: u32) { + pub fn software_interrupt(&mut self, sb: &mut SysBus, lr: u32, _cmt: u32) { match self.cpsr.state() { CpuState::ARM => self.N_cycle32(sb, self.pc), CpuState::THUMB => self.N_cycle16(sb, self.pc), }; - if cmt == 0x55 { - #[cfg(debug_assertions)] - { - println!("Special breakpoint detected!"); - host_breakpoint!(); - } - } else { - self.exception(sb, Exception::SoftwareInterrupt, lr); - } + self.exception(sb, Exception::SoftwareInterrupt, lr); } } diff --git a/src/core/arm7tdmi/mod.rs b/src/core/arm7tdmi/mod.rs index 6202c22..8ea497d 100644 --- a/src/core/arm7tdmi/mod.rs +++ b/src/core/arm7tdmi/mod.rs @@ -15,12 +15,13 @@ pub mod alu; pub use alu::*; pub mod exception; pub mod psr; +pub use psr::*; pub const REG_PC: usize = 15; pub const REG_LR: usize = 14; pub const REG_SP: usize = 13; -pub(self) use crate::core::{Addr, Bus}; +pub(self) use crate::core::Addr; #[derive(Serialize, Deserialize, Debug, PartialEq, Copy, Clone)] pub enum DecodedInstruction { @@ -36,6 +37,8 @@ impl DecodedInstruction { } } } + +#[cfg(feature = "debugger")] impl fmt::Display for DecodedInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -64,7 +67,7 @@ impl From for InstructionDecoderError { } } -pub trait InstructionDecoder: Sized + fmt::Display { +pub trait InstructionDecoder: Sized { type IntType: Num; fn decode(n: Self::IntType, addr: Addr) -> Result; diff --git a/src/core/arm7tdmi/thumb/display.rs b/src/core/arm7tdmi/thumb/display.rs index 5c6c08c..0fef2f8 100644 --- a/src/core/arm7tdmi/thumb/display.rs +++ b/src/core/arm7tdmi/thumb/display.rs @@ -1,10 +1,13 @@ use std::fmt; +#[cfg(feature = "debugger")] use crate::bit::BitIndex; use super::*; +#[cfg(feature = "debugger")] use crate::core::arm7tdmi::*; +#[cfg(feature = "debugger")] impl ThumbInstruction { fn fmt_thumb_move_shifted_reg(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( @@ -268,6 +271,7 @@ impl ThumbInstruction { } } +#[cfg(feature = "debugger")] impl fmt::Display for ThumbInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.fmt { diff --git a/src/core/arm7tdmi/thumb/exec.rs b/src/core/arm7tdmi/thumb/exec.rs index e9b43ba..4381550 100644 --- a/src/core/arm7tdmi/thumb/exec.rs +++ b/src/core/arm7tdmi/thumb/exec.rs @@ -1,4 +1,3 @@ -use crate::core::arm7tdmi::cpu::{Core, CpuExecResult}; use crate::core::arm7tdmi::*; use crate::core::sysbus::SysBus; use crate::core::Bus; @@ -18,31 +17,26 @@ fn pop(cpu: &mut Core, bus: &mut SysBus, r: usize) { } impl Core { + /// Format 1 fn exec_thumb_move_shifted_reg( &mut self, sb: &mut SysBus, insn: ThumbInstruction, - ) -> CpuExecResult { + ) { let rd = (insn.raw & 0b111) as usize; let rs = insn.raw.bit_range(3..6) as usize; - let op2 = self - .register_shift(ShiftedRegister { - reg: rs, - shift_by: ShiftRegisterBy::ByAmount(insn.offset5() as u8 as u32), - bs_op: insn.format1_op(), - added: None, - }) - .unwrap(); - self.set_reg(rd, op2); + let shift_amount = insn.offset5() as u8 as u32; + let op2 = self.barrel_shift_op(insn.format1_op(), self.gpr[rs], shift_amount, self.cpsr.C(), true); + self.gpr[rd] = op2; self.alu_update_flags(op2, false, self.bs_carry_out, self.cpsr.V()); self.S_cycle16(sb, self.pc + 2); - Ok(()) } - fn exec_thumb_add_sub(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { + /// Format 2 + fn exec_thumb_add_sub(&mut self, sb: &mut SysBus, insn: ThumbInstruction) { let rd = (insn.raw & 0b111) as usize; let op1 = self.get_reg(insn.rs()); let op2 = if insn.is_immediate_operand() { @@ -62,14 +56,14 @@ impl Core { self.set_reg(rd, result as u32); self.S_cycle16(sb, self.pc + 2); - Ok(()) } + /// Format 3 fn exec_thumb_data_process_imm( &mut self, sb: &mut SysBus, insn: ThumbInstruction, - ) -> CpuExecResult { + ) { use OpFormat3::*; let op = insn.format3_op(); let rd = insn.raw.bit_range(8..11) as usize; @@ -88,17 +82,16 @@ impl Core { self.gpr[rd] = result as u32; } self.S_cycle16(sb, self.pc + 2); - Ok(()) } - fn exec_thumb_alu_ops(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { + /// Format 4 + fn exec_thumb_alu_ops(&mut self, sb: &mut SysBus, insn: ThumbInstruction) { let rd = (insn.raw & 0b111) as usize; let rs = insn.rs(); let dst = self.get_reg(rd); let src = self.get_reg(rs); let mut carry = self.cpsr.C(); - let c = self.cpsr.C() as u32; let mut overflow = self.cpsr.V(); use ThumbAluOps::*; @@ -115,13 +108,7 @@ impl Core { ROR => BarrelShiftOpCode::ROR, _ => unreachable!(), }; - let shft = BarrelShifterValue::shifted_register( - rd, - ShiftRegisterBy::ByRegister(rs), - bs_op, - Some(true), - ); - let result = self.get_barrel_shifted_value(shft); + let result = self.shift_by_register(bs_op, rd, rs, carry); carry = self.bs_carry_out; result } @@ -150,24 +137,14 @@ impl Core { self.set_reg(rd, result as u32); } self.S_cycle16(sb, self.pc + 2); - Ok(()) - } - - /// Cycles 2S+1N - fn exec_thumb_bx(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { - let src_reg = if insn.flag(ThumbInstruction::FLAG_H2) { - insn.rs() + 8 - } else { - insn.rs() - }; - self.branch_exchange(sb, self.get_reg(src_reg)) } + /// Format 5 fn exec_thumb_hi_reg_op_or_bx( &mut self, sb: &mut SysBus, insn: ThumbInstruction, - ) -> CpuExecResult { + ) { let op = insn.format5_op(); let rd = (insn.raw & 0b111) as usize; let dst_reg = if insn.flag(ThumbInstruction::FLAG_H1) { @@ -184,7 +161,10 @@ impl Core { let op2 = self.get_reg(src_reg); match op { - OpFormat5::BX => return self.exec_thumb_bx(sb, insn), + OpFormat5::BX => { + self.branch_exchange(sb, self.get_reg(src_reg)); + return; + }, OpFormat5::ADD => { self.set_reg(dst_reg, op1.wrapping_add(op2)); if dst_reg == REG_PC { @@ -205,10 +185,10 @@ impl Core { } } self.S_cycle16(sb, self.pc + 2); - Ok(()) } - fn exec_thumb_ldr_pc(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { + /// Format 6 + fn exec_thumb_ldr_pc(&mut self, sb: &mut SysBus, insn: ThumbInstruction) { let rd = insn.raw.bit_range(8..11) as usize; let ofs = insn.word8() as Addr; @@ -223,7 +203,6 @@ impl Core { // +1I self.add_cycle(); - Ok(()) } fn do_exec_thumb_ldr_str( @@ -232,7 +211,7 @@ impl Core { insn: ThumbInstruction, addr: Addr, is_transferring_bytes: bool, - ) -> CpuExecResult { + ) { let rd = (insn.raw & 0b111) as usize; if insn.is_load() { let data = if is_transferring_bytes { @@ -259,20 +238,21 @@ impl Core { } self.N_cycle16(sb, self.pc + 2); - Ok(()) } + /// Format 7 fn exec_thumb_ldr_str_reg_offset( &mut self, bus: &mut SysBus, insn: ThumbInstruction, - ) -> CpuExecResult { + ) { let rb = insn.raw.bit_range(3..6) as usize; let addr = self.gpr[rb].wrapping_add(self.gpr[insn.ro()]); self.do_exec_thumb_ldr_str(bus, insn, addr, insn.raw.bit(10)) } - fn exec_thumb_ldr_str_shb(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { + /// Format 8 + fn exec_thumb_ldr_str_shb(&mut self, sb: &mut SysBus, insn: ThumbInstruction) { let rb = insn.raw.bit_range(3..6) as usize; let rd = (insn.raw & 0b111) as usize; @@ -313,14 +293,14 @@ impl Core { } self.N_cycle16(sb, self.pc + 2); - Ok(()) } + /// Format 9 fn exec_thumb_ldr_str_imm_offset( &mut self, sb: &mut SysBus, insn: ThumbInstruction, - ) -> CpuExecResult { + ) { let rb = insn.raw.bit_range(3..6) as usize; let offset = if insn.raw.bit(12) { @@ -332,11 +312,12 @@ impl Core { self.do_exec_thumb_ldr_str(sb, insn, addr, insn.raw.bit(12)) } + /// Format 10 fn exec_thumb_ldr_str_halfword( &mut self, sb: &mut SysBus, insn: ThumbInstruction, - ) -> CpuExecResult { + ) { let rb = insn.raw.bit_range(3..6) as usize; let rd = (insn.raw & 0b111) as usize; let base = self.gpr[rb] as i32; @@ -351,37 +332,12 @@ impl Core { self.N_cycle16(sb, addr); } self.N_cycle16(sb, self.pc + 2); - Ok(()) } - fn exec_thumb_ldr_str_sp(&mut self, bus: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { + /// Format 11 + fn exec_thumb_ldr_str_sp(&mut self, sb: &mut SysBus, insn: ThumbInstruction) { let addr = self.gpr[REG_SP] + (insn.word8() as Addr); - self.do_exec_thumb_ldr_str_with_addr(bus, insn, addr, insn.raw.bit_range(8..11) as usize) - } - - fn exec_thumb_load_address( - &mut self, - sb: &mut SysBus, - insn: ThumbInstruction, - ) -> CpuExecResult { let rd = insn.raw.bit_range(8..11) as usize; - let result = if insn.flag(ThumbInstruction::FLAG_SP) { - self.gpr[REG_SP] + (insn.word8() as Addr) - } else { - (insn.pc & !0b10) + 4 + (insn.word8() as Addr) - }; - self.gpr[rd] = result; - self.S_cycle16(sb, self.pc + 2); - Ok(()) - } - - fn do_exec_thumb_ldr_str_with_addr( - &mut self, - sb: &mut SysBus, - insn: ThumbInstruction, - addr: Addr, - rd: usize, - ) -> CpuExecResult { if insn.is_load() { let data = self.ldr_word(addr, sb); self.S_cycle16(sb, addr); @@ -392,19 +348,35 @@ impl Core { self.N_cycle16(sb, addr); } self.N_cycle16(sb, self.pc + 2); - Ok(()) } - fn exec_thumb_add_sp(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { + /// Format 12 + fn exec_thumb_load_address( + &mut self, + sb: &mut SysBus, + insn: ThumbInstruction, + ) { + let rd = insn.raw.bit_range(8..11) as usize; + let result = if insn.flag(ThumbInstruction::FLAG_SP) { + self.gpr[REG_SP] + (insn.word8() as Addr) + } else { + (insn.pc & !0b10) + 4 + (insn.word8() as Addr) + }; + self.gpr[rd] = result; + self.S_cycle16(sb, self.pc + 2); + } + + /// Format 13 + fn exec_thumb_add_sp(&mut self, sb: &mut SysBus, insn: ThumbInstruction) { let op1 = self.gpr[REG_SP] as i32; let op2 = insn.sword7(); self.gpr[REG_SP] = op1.wrapping_add(op2) as u32; self.S_cycle16(sb, self.pc + 2); - Ok(()) } - fn exec_thumb_push_pop(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { + /// Format 14 + fn exec_thumb_push_pop(&mut self, sb: &mut SysBus, insn: ThumbInstruction) { // (From GBATEK) Execution Time: nS+1N+1I (POP), (n+1)S+2N+1I (POP PC), or (n-1)S+2N (PUSH). let is_pop = insn.is_load(); let pc_lr_flag = insn.flag(ThumbInstruction::FLAG_R); @@ -445,10 +417,10 @@ impl Core { } } - Ok(()) } - fn exec_thumb_ldm_stm(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { + /// Format 15 + fn exec_thumb_ldm_stm(&mut self, sb: &mut SysBus, insn: ThumbInstruction) { // (From GBATEK) Execution Time: nS+1N+1I (POP), (n+1)S+2N+1I (POP PC), or (n-1)S+2N (PUSH). let rb = insn.raw.bit_range(8..11) as usize; @@ -518,39 +490,48 @@ impl Core { self.gpr[base_reg] = addr + align_preserve; } - Ok(()) } + /// Format 16 fn exec_thumb_branch_with_cond( &mut self, sb: &mut SysBus, insn: ThumbInstruction, - ) -> CpuExecResult { + ) { if !self.check_arm_cond(insn.cond()) { self.S_cycle16(sb, self.pc + 2); - Ok(()) } else { let offset = insn.bcond_offset(); self.S_cycle16(sb, self.pc); self.pc = (self.pc as i32).wrapping_add(offset) as u32; self.flush_pipeline16(sb); - Ok(()) } } - fn exec_thumb_branch(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { + /// Format 17 + fn exec_thumb_swi( + &mut self, + sb: &mut SysBus, + _insn: ThumbInstruction, + ) { + self.N_cycle16(sb, self.pc); + self.exception(sb, Exception::SoftwareInterrupt, self.pc - 2); + } + + /// Format 18 + fn exec_thumb_branch(&mut self, sb: &mut SysBus, insn: ThumbInstruction) { let offset = ((insn.offset11() << 21) >> 20) as i32; self.pc = (self.pc as i32).wrapping_add(offset) as u32; self.S_cycle16(sb, self.pc); self.flush_pipeline16(sb); - Ok(()) } + /// Format 19 fn exec_thumb_branch_long_with_link( &mut self, sb: &mut SysBus, insn: ThumbInstruction, - ) -> CpuExecResult { + ) { let mut off = insn.offset11(); if insn.flag(ThumbInstruction::FLAG_LOW_OFFSET) { self.S_cycle16(sb, self.pc); @@ -560,16 +541,14 @@ impl Core { self.gpr[REG_LR] = next_pc; self.flush_pipeline16(sb); - Ok(()) } else { off = (off << 21) >> 9; self.gpr[REG_LR] = (self.pc as i32).wrapping_add(off) as u32; self.S_cycle16(sb, self.pc); - Ok(()) } } - pub fn exec_thumb(&mut self, bus: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { + pub fn exec_thumb(&mut self, bus: &mut SysBus, insn: ThumbInstruction) { match insn.fmt { ThumbFormat::MoveShiftedReg => self.exec_thumb_move_shifted_reg(bus, insn), ThumbFormat::AddSub => self.exec_thumb_add_sub(bus, insn), @@ -587,10 +566,7 @@ impl Core { ThumbFormat::PushPop => self.exec_thumb_push_pop(bus, insn), ThumbFormat::LdmStm => self.exec_thumb_ldm_stm(bus, insn), ThumbFormat::BranchConditional => self.exec_thumb_branch_with_cond(bus, insn), - ThumbFormat::Swi => { - self.software_interrupt(bus, self.pc - 2, (insn.raw & 0xff) as u32); - Ok(()) - } + ThumbFormat::Swi => self.exec_thumb_swi(bus, insn), ThumbFormat::Branch => self.exec_thumb_branch(bus, insn), ThumbFormat::BranchLongWithLink => self.exec_thumb_branch_long_with_link(bus, insn), } diff --git a/src/disass.rs b/src/disass.rs index f6300a8..d41c8bb 100644 --- a/src/disass.rs +++ b/src/disass.rs @@ -1,3 +1,4 @@ +use std::fmt; use std::marker::PhantomData; use super::core::arm7tdmi::{InstructionDecoder, InstructionDecoderError}; @@ -32,7 +33,7 @@ where impl<'a, D> Iterator for Disassembler<'a, D> where - D: InstructionDecoder, + D: InstructionDecoder + fmt::Display, ::IntType: std::fmt::LowerHex, { type Item = (Addr, String);