From b82874809fac750d47de76794a2f67ebd3534d03 Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Wed, 3 Jul 2019 01:26:48 +0300 Subject: [PATCH] Implement thumb format3 instruction and add a test for it. Former-commit-id: 8cf6664027dc3d5dbeb6d2ca3d089820baac2709 --- src/arm7tdmi/arm/exec.rs | 2 +- src/arm7tdmi/mod.rs | 2 +- src/arm7tdmi/thumb/display.rs | 2 +- src/arm7tdmi/thumb/exec.rs | 35 ++++++++++++++++++--- src/arm7tdmi/thumb/mod.rs | 59 +++++++++++++++++++++++++++++++++-- src/sysbus.rs | 20 +++++++++--- 6 files changed, 106 insertions(+), 14 deletions(-) diff --git a/src/arm7tdmi/arm/exec.rs b/src/arm7tdmi/arm/exec.rs index 8427968..701127f 100644 --- a/src/arm7tdmi/arm/exec.rs +++ b/src/arm7tdmi/arm/exec.rs @@ -162,7 +162,7 @@ impl Core { res } - fn alu(&mut self, opcode: ArmOpCode, op1: i32, op2: i32, set_cond_flags: bool) -> Option { + pub fn alu(&mut self, opcode: ArmOpCode, op1: i32, op2: i32, set_cond_flags: bool) -> Option { let C = self.cpsr.C() as i32; let mut carry = self.cpsr.C(); diff --git a/src/arm7tdmi/mod.rs b/src/arm7tdmi/mod.rs index a42d491..9ffc6ea 100644 --- a/src/arm7tdmi/mod.rs +++ b/src/arm7tdmi/mod.rs @@ -39,7 +39,7 @@ impl fmt::Display for DecodedInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { DecodedInstruction::Arm(a) => write!(f, "{}", a), - DecodedInstruction::Thumb(t) => write!(f, "{:#?}", t), + DecodedInstruction::Thumb(t) => write!(f, "{}", t), } } } diff --git a/src/arm7tdmi/thumb/display.rs b/src/arm7tdmi/thumb/display.rs index 1eed6e3..875bece 100644 --- a/src/arm7tdmi/thumb/display.rs +++ b/src/arm7tdmi/thumb/display.rs @@ -20,7 +20,7 @@ impl ThumbInstruction { fn fmt_data_process_imm(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, - "{op}\t{Rd}, #{Offset8}", + "{op}\t{Rd}, #{Offset8:#x}", op = self.format3_op(), Rd = reg_string(self.rd()), Offset8 = self.offset8() diff --git a/src/arm7tdmi/thumb/exec.rs b/src/arm7tdmi/thumb/exec.rs index bbfe2ff..d24f77f 100644 --- a/src/arm7tdmi/thumb/exec.rs +++ b/src/arm7tdmi/thumb/exec.rs @@ -1,9 +1,36 @@ -use super::super::cpu::{Core, CpuExecResult}; -use super::ThumbInstruction; -use crate::arm7tdmi::bus::Bus; +use crate::arm7tdmi::arm::exec::*; +use crate::arm7tdmi::arm::ArmOpCode; +use crate::arm7tdmi::bus::{Bus, MemoryAccessType::*, MemoryAccessWidth::*}; +use crate::arm7tdmi::cpu::{Core, CpuExecResult, CpuPipelineAction}; + +use super::{ThumbFormat, ThumbInstruction}; impl Core { + fn exec_thumb_data_process_imm( + &mut self, + sysbus: &mut Bus, + insn: ThumbInstruction, + ) -> CpuExecResult { + let arm_alu_op: ArmOpCode = insn.format3_op().into(); + let op1 = self.get_reg(insn.rd()) as i32; + let op2 = insn.offset8() as i32; + let result = self.alu(arm_alu_op, op1, op2, true); + if let Some(result) = result { + self.set_reg(insn.rd(), result as u32); + } + // +1S + self.add_cycles( + self.pc + (self.word_size() as u32), + sysbus, + Seq + MemoryAccess32, + ); + Ok(CpuPipelineAction::IncPC) + } + pub fn exec_thumb(&mut self, sysbus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { - unimplemented!("thumb not implemented {:#}", insn) + match insn.fmt { + ThumbFormat::DataProcessImm => self.exec_thumb_data_process_imm(sysbus, insn), + _ => unimplemented!("thumb not implemented {:#}", insn), + } } } diff --git a/src/arm7tdmi/thumb/mod.rs b/src/arm7tdmi/thumb/mod.rs index 2ab3905..81f45be 100644 --- a/src/arm7tdmi/thumb/mod.rs +++ b/src/arm7tdmi/thumb/mod.rs @@ -4,7 +4,7 @@ use crate::bit::BitIndex; use crate::byteorder::{LittleEndian, ReadBytesExt}; use crate::num::FromPrimitive; -use super::arm::{ArmCond, ArmShiftType}; +use super::arm::{ArmCond, ArmOpCode, ArmShiftType}; use super::{Addr, InstructionDecoder, InstructionDecoderError}; pub mod display; @@ -159,6 +159,17 @@ pub enum OpFormat3 { SUB = 3, } +impl From for ArmOpCode { + fn from(op: OpFormat3) -> ArmOpCode { + match op { + OpFormat3::MOV => ArmOpCode::MOV, + OpFormat3::CMP => ArmOpCode::CMP, + OpFormat3::ADD => ArmOpCode::ADD, + OpFormat3::SUB => ArmOpCode::SUB, + } + } +} + #[derive(Debug, Primitive)] pub enum OpFormat5 { ADD = 0, @@ -167,12 +178,29 @@ pub enum OpFormat5 { BX = 3, } +impl From for ArmOpCode { + fn from(op: OpFormat5) -> ArmOpCode { + match op { + OpFormat5::ADD => ArmOpCode::ADD, + OpFormat5::CMP => ArmOpCode::CMP, + OpFormat5::MOV => ArmOpCode::MOV, + _ => unreachable!(), // this should not be called if op = BX + } + } +} + impl ThumbInstruction { const FLAG_H1: usize = 7; const FLAG_H2: usize = 6; pub fn rd(&self) -> usize { - (self.raw & 0b111) as usize + match self.fmt { + ThumbFormat::DataProcessImm + | ThumbFormat::LdrPc + | ThumbFormat::LdrStrSp + | ThumbFormat::LdrAddress => self.raw.bit_range(8..11) as usize, + _ => (self.raw & 0b111) as usize, + } } pub fn rs(&self) -> usize { @@ -239,3 +267,30 @@ impl ThumbInstruction { self.raw.bit(bit) } } + +#[cfg(test)] +/// All instructions constants were generated using an ARM assembler. +mod tests { + use super::*; + + #[test] + fn mov_low_reg() { + use crate::arm7tdmi::cpu::{Core, CpuPipelineAction}; + use crate::sysbus::BoxedMemory; + + let bytes = vec![]; + let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); + let mut core = Core::new(); + core.set_reg(0, 0); + + // movs r0, #0x27 + let insn = ThumbInstruction::decode(0x2027, 0).unwrap(); + + assert_eq!(format!("{}", insn), "mov\tr0, #0x27"); + assert_eq!( + core.exec_thumb(&mut mem, insn), + Ok(CpuPipelineAction::IncPC) + ); + assert_eq!(core.get_reg(0), 0x27); + } +} diff --git a/src/sysbus.rs b/src/sysbus.rs index 00dc3b8..7e958cb 100644 --- a/src/sysbus.rs +++ b/src/sysbus.rs @@ -10,13 +10,23 @@ const PALETTE_RAM_SIZE: usize = 1 * 1024; const OAM_SIZE: usize = 1 * 1024; #[derive(Debug)] -struct BoxedMemory(Box<[u8]>, WaitState); +pub struct BoxedMemory(Box<[u8]>, WaitState); + +impl BoxedMemory { + pub fn new(boxed_slice: Box<[u8]>) -> BoxedMemory { + BoxedMemory(boxed_slice, Default::default()) + } + + pub fn new_with_waitstate(boxed_slice: Box<[u8]>, ws: WaitState) -> BoxedMemory { + BoxedMemory(boxed_slice, ws) + } +} #[derive(Debug)] -struct WaitState { - access8: usize, - access16: usize, - access32: usize, +pub struct WaitState { + pub access8: usize, + pub access16: usize, + pub access32: usize, } impl WaitState {