diff --git a/core/build.rs b/core/build.rs index 55df81b..5e52062 100644 --- a/core/build.rs +++ b/core/build.rs @@ -8,6 +8,8 @@ use bit::BitIndex; // copied and slightly adjusted from src/core/arm7tdmi/thumb/mod.rs fn thumb_decode(i: u16) -> (&'static str, String) { + let offset5 = i.bit_range(6..11) as u8; + let load = i.bit(11); if i & 0xf800 == 0x1800 { ( "AddSub", @@ -22,9 +24,9 @@ fn thumb_decode(i: u16) -> (&'static str, String) { ( "MoveShiftedReg", format!( - "exec_thumb_move_shifted_reg::<{BS_OP}, {OFFSET5}>", + "exec_thumb_move_shifted_reg::<{BS_OP}, {IMM}>", BS_OP = i.bit_range(11..13) as u8, - OFFSET5 = i.bit_range(6..11) as u8 + IMM = i.bit_range(6..11) as u8 ), ) } else if i & 0xe000 == 0x2000 { @@ -64,16 +66,23 @@ fn thumb_decode(i: u16) -> (&'static str, String) { "LdrStrRegOffset", format!( "exec_thumb_ldr_str_reg_offset::<{LOAD}, {RO}, {BYTE}>", - LOAD = i.bit(11), + LOAD = load, RO = i.bit_range(6..9) as usize, BYTE = i.bit(10), ), ) } else if i & 0xf200 == 0x5200 { - ("LdrStrSHB", String::from("exec_thumb_ldr_str_shb")) + ( + "LdrStrSHB", + format!( + "exec_thumb_ldr_str_shb::<{RO}, {SIGN_EXTEND}, {HALFWORD}>", + RO = i.bit_range(6..9) as usize, + SIGN_EXTEND = i.bit(10), + HALFWORD = i.bit(11), + ), + ) } else if i & 0xe000 == 0x6000 { let is_transferring_bytes = i.bit(12); - let offset5 = i.bit_range(6..11) as u8; let offset = if is_transferring_bytes { offset5 } else { @@ -83,7 +92,7 @@ fn thumb_decode(i: u16) -> (&'static str, String) { "LdrStrImmOffset", format!( "exec_thumb_ldr_str_imm_offset::<{LOAD}, {BYTE}, {OFFSET}>", - LOAD = i.bit(11), + LOAD = load, BYTE = is_transferring_bytes, OFFSET = offset ), @@ -91,31 +100,72 @@ fn thumb_decode(i: u16) -> (&'static str, String) { } else if i & 0xf000 == 0x8000 { ( "LdrStrHalfWord", - String::from("exec_thumb_ldr_str_halfword"), + format!( + "exec_thumb_ldr_str_halfword::<{LOAD}, {OFFSET}>", + LOAD = load, + OFFSET = (offset5 << 1) as i32 + ), ) } else if i & 0xf000 == 0x9000 { - ("LdrStrSp", String::from("exec_thumb_ldr_str_sp")) + ( + "LdrStrSp", + format!( + "exec_thumb_ldr_str_sp::<{LOAD}, {RD}>", + LOAD = load, + RD = i.bit_range(8..11) + ), + ) } else if i & 0xf000 == 0xa000 { - ("LoadAddress", String::from("exec_thumb_load_address")) + ( + "LoadAddress", + format!( + "exec_thumb_load_address::<{SP}, {RD}>", + SP = i.bit(11), + RD = i.bit_range(8..11) + ), + ) } else if i & 0xff00 == 0xb000 { - ("AddSp", String::from("exec_thumb_add_sp")) + ( + "AddSp", + format!("exec_thumb_add_sp::<{FLAG_S}>", FLAG_S = i.bit(7)), + ) } else if i & 0xf600 == 0xb400 { - ("PushPop", String::from("exec_thumb_push_pop")) + ( + "PushPop", + format!( + "exec_thumb_push_pop::<{POP}, {FLAG_R}>", + POP = load, + FLAG_R = i.bit(8) + ), + ) } else if i & 0xf000 == 0xc000 { - ("LdmStm", String::from("exec_thumb_ldm_stm")) + ( + "LdmStm", + format!( + "exec_thumb_ldm_stm::<{LOAD}, {RB}>", + LOAD = load, + RB = i.bit_range(8..11) as usize + ), + ) } else if i & 0xff00 == 0xdf00 { ("Swi", String::from("exec_thumb_swi")) } else if i & 0xf000 == 0xd000 { ( "BranchConditional", - String::from("exec_thumb_branch_with_cond"), + format!( + "exec_thumb_branch_with_cond::<{COND}>", + COND = i.bit_range(8..12) as u8 + ), ) } else if i & 0xf800 == 0xe000 { ("Branch", String::from("exec_thumb_branch")) } else if i & 0xf000 == 0xf000 { ( "BranchLongWithLink", - String::from("exec_thumb_branch_long_with_link"), + format!( + "exec_thumb_branch_long_with_link::<{FLAG_LOW_OFFSET}>", + FLAG_LOW_OFFSET = i.bit(11), + ), ) } else { ("Undefined", String::from("thumb_undefined")) diff --git a/core/src/arm7tdmi/thumb/disass.rs b/core/src/arm7tdmi/thumb/disass.rs index 3cd7e51..aba6c99 100644 --- a/core/src/arm7tdmi/thumb/disass.rs +++ b/core/src/arm7tdmi/thumb/disass.rs @@ -7,6 +7,18 @@ use crate::arm7tdmi::*; use super::ThumbDecodeHelper; +pub(super) mod consts { + pub(super) mod flags { + pub const FLAG_H1: usize = 7; + pub const FLAG_H2: usize = 6; + pub const FLAG_R: usize = 8; + pub const FLAG_LOW_OFFSET: usize = 11; + pub const FLAG_SP: usize = 11; + pub const FLAG_SIGN_EXTEND: usize = 10; + pub const FLAG_HALFWORD: usize = 11; + } +} + impl ThumbInstruction { fn fmt_thumb_move_shifted_reg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( diff --git a/core/src/arm7tdmi/thumb/exec.rs b/core/src/arm7tdmi/thumb/exec.rs index ac728b8..a2e11f6 100644 --- a/core/src/arm7tdmi/thumb/exec.rs +++ b/core/src/arm7tdmi/thumb/exec.rs @@ -10,14 +10,14 @@ use MemoryAccess::*; impl Core { /// Format 1 /// Execution Time: 1S - pub(in super::super) fn exec_thumb_move_shifted_reg( + pub(in super::super) fn exec_thumb_move_shifted_reg( &mut self, insn: u16, ) -> CpuAction { let rd = (insn & 0b111) as usize; let rs = insn.bit_range(3..6) as usize; - let shift_amount = OFFSET5 as u32; + let shift_amount = IMM as u32; let mut carry = self.cpsr.C(); let bsop = match BS_OP { 0 => BarrelShiftOpCode::LSL, @@ -258,15 +258,19 @@ impl Core { /// Format 8 load/store sign-extended byte/halfword /// Execution Time: 1S+1N+1I for LDR, or 2N for STR - pub(in super::super) fn exec_thumb_ldr_str_shb(&mut self, insn: u16) -> CpuAction { + pub(in super::super) fn exec_thumb_ldr_str_shb< + const RO: usize, + const SIGN_EXTEND: bool, + const HALFWORD: bool, + >( + &mut self, + insn: u16, + ) -> CpuAction { let rb = insn.bit_range(3..6) as usize; let rd = (insn & 0b111) as usize; - let addr = self.gpr[rb].wrapping_add(self.gpr[insn.ro()]); - match ( - insn.bit(consts::flags::FLAG_SIGN_EXTEND), - insn.bit(consts::flags::FLAG_HALFWORD), - ) { + let addr = self.gpr[rb].wrapping_add(self.gpr[RO]); + match (SIGN_EXTEND, HALFWORD) { (false, false) => /* strh */ { @@ -314,12 +318,15 @@ impl Core { /// Format 10 /// Execution Time: 1S+1N+1I for LDR, or 2N for STR - pub(in super::super) fn exec_thumb_ldr_str_halfword(&mut self, insn: u16) -> CpuAction { + pub(in super::super) fn exec_thumb_ldr_str_halfword( + &mut self, + insn: u16, + ) -> CpuAction { let rb = insn.bit_range(3..6) as usize; let rd = (insn & 0b111) as usize; let base = self.gpr[rb] as i32; - let addr = base.wrapping_add((insn.offset5() << 1) as i32) as Addr; - if insn.is_load() { + let addr = base.wrapping_add(OFFSET) as Addr; + if LOAD { let data = self.ldr_half(addr, NonSeq); self.idle_cycle(); self.gpr[rd] = data as u32; @@ -332,26 +339,29 @@ impl Core { /// Format 11 load/store SP-relative /// Execution Time: 1S+1N+1I for LDR, or 2N for STR - pub(in super::super) fn exec_thumb_ldr_str_sp(&mut self, insn: u16) -> CpuAction { + pub(in super::super) fn exec_thumb_ldr_str_sp( + &mut self, + insn: u16, + ) -> CpuAction { let addr = self.gpr[REG_SP] + (insn.word8() as Addr); - let rd = insn.bit_range(8..11) as usize; - if insn.is_load() { + if LOAD { let data = self.ldr_word(addr, NonSeq); self.idle_cycle(); - self.gpr[rd] = data; + self.gpr[RD] = data; CpuAction::AdvancePC(Seq) } else { - self.store_aligned_32(addr, self.gpr[rd], NonSeq); + self.store_aligned_32(addr, self.gpr[RD], NonSeq); CpuAction::AdvancePC(NonSeq) } } /// Format 12 /// Execution Time: 1S - pub(in super::super) fn exec_thumb_load_address(&mut self, insn: u16) -> CpuAction { - let rd = insn.bit_range(8..11) as usize; - - self.gpr[rd] = if insn.bit(consts::flags::FLAG_SP) { + pub(in super::super) fn exec_thumb_load_address( + &mut self, + insn: u16, + ) -> CpuAction { + self.gpr[RD] = if SP { self.gpr[REG_SP] + (insn.word8() as Addr) } else { (self.pc_thumb() & !0b10) + 4 + (insn.word8() as Addr) @@ -362,17 +372,26 @@ impl Core { /// Format 13 /// Execution Time: 1S - pub(in super::super) fn exec_thumb_add_sp(&mut self, insn: u16) -> CpuAction { + pub(in super::super) fn exec_thumb_add_sp( + &mut self, + insn: u16, + ) -> CpuAction { let op1 = self.gpr[REG_SP] as i32; - let op2 = insn.sword7(); - - self.gpr[REG_SP] = op1.wrapping_add(op2) as u32; + let offset = ((insn & 0x7f) << 2) as i32; + self.gpr[REG_SP] = if FLAG_S { + op1.wrapping_sub(offset) as u32 + } else { + op1.wrapping_add(offset) as u32 + }; CpuAction::AdvancePC(Seq) } /// Format 14 /// Execution Time: nS+1N+1I (POP), (n+1)S+2N+1I (POP PC), or (n-1)S+2N (PUSH). - pub(in super::super) fn exec_thumb_push_pop(&mut self, insn: u16) -> CpuAction { + pub(in super::super) fn exec_thumb_push_pop( + &mut self, + insn: u16, + ) -> CpuAction { macro_rules! push { ($r:expr, $access:ident) => { self.gpr[REG_SP] -= 4; @@ -395,17 +414,15 @@ impl Core { }; } let mut result = CpuAction::AdvancePC(NonSeq); - let is_pop = insn.is_load(); - let pc_lr_flag = insn.bit(consts::flags::FLAG_R); let rlist = insn.register_list(); let mut access = MemoryAccess::NonSeq; - if is_pop { + if POP { for r in 0..8 { if rlist.bit(r) { pop!(r, access); } } - if pc_lr_flag { + if FLAG_R { pop!(REG_PC); self.pc = self.pc & !1; result = CpuAction::PipelineFlushed; @@ -414,7 +431,7 @@ impl Core { // Idle 1 cycle self.idle_cycle(); } else { - if pc_lr_flag { + if FLAG_R { push!(REG_LR, access); } for r in (0..8).rev() { @@ -429,19 +446,18 @@ impl Core { /// Format 15 /// Execution Time: nS+1N+1I for LDM, or (n-1)S+2N for STM. - pub(in super::super) fn exec_thumb_ldm_stm(&mut self, insn: u16) -> CpuAction { + pub(in super::super) fn exec_thumb_ldm_stm( + &mut self, + insn: u16, + ) -> CpuAction { let mut result = CpuAction::AdvancePC(NonSeq); - let rb = insn.bit_range(8..11) as usize; - let base_reg = rb; - let is_load = insn.is_load(); - - let align_preserve = self.gpr[base_reg] & 3; - let mut addr = self.gpr[base_reg] & !3; + let align_preserve = self.gpr[RB] & 3; + let mut addr = self.gpr[RB] & !3; let rlist = insn.register_list(); // let mut first = true; if rlist != 0 { - if is_load { + if LOAD { let mut access = NonSeq; for r in 0..8 { if rlist.bit(r) { @@ -452,15 +468,15 @@ impl Core { } } self.idle_cycle(); - if !rlist.bit(base_reg) { - self.gpr[base_reg] = addr + align_preserve; + if !rlist.bit(RB) { + self.gpr[RB] = addr + align_preserve; } } else { let mut first = true; let mut access = NonSeq; for r in 0..8 { if rlist.bit(r) { - let v = if r != base_reg { + let v = if r != RB { self.gpr[r] } else { if first { @@ -476,12 +492,12 @@ impl Core { access = Seq; addr += 4; } - self.gpr[base_reg] = addr + align_preserve; + self.gpr[RB] = addr + align_preserve; } } } else { // From gbatek.htm: Empty Rlist: R15 loaded/stored (ARMv4 only), and Rb=Rb+40h (ARMv4-v5). - if is_load { + if LOAD { let val = self.load_32(addr, NonSeq); self.pc = val & !1; result = CpuAction::PipelineFlushed; @@ -490,7 +506,7 @@ impl Core { self.store_32(addr, self.pc + 2, NonSeq); } addr += 0x40; - self.gpr[base_reg] = addr + align_preserve; + self.gpr[RB] = addr + align_preserve; } result @@ -500,8 +516,12 @@ impl Core { /// Execution Time: /// 2S+1N if condition true (jump executed) /// 1S if condition false - pub(in super::super) fn exec_thumb_branch_with_cond(&mut self, insn: u16) -> CpuAction { - if !self.check_arm_cond(insn.cond()) { + pub(in super::super) fn exec_thumb_branch_with_cond( + &mut self, + insn: u16, + ) -> CpuAction { + let cond = ArmCond::from_u8(COND).expect("bad cond"); + if !self.check_arm_cond(cond) { CpuAction::AdvancePC(Seq) } else { let offset = insn.bcond_offset(); @@ -529,9 +549,12 @@ impl Core { /// Format 19 /// Execution Time: 3S+1N (first opcode 1S, second opcode 2S+1N). - pub(in super::super) fn exec_thumb_branch_long_with_link(&mut self, insn: u16) -> CpuAction { + pub(in super::super) fn exec_thumb_branch_long_with_link( + &mut self, + insn: u16, + ) -> CpuAction { let mut off = insn.offset11(); - if insn.bit(consts::flags::FLAG_LOW_OFFSET) { + if FLAG_LOW_OFFSET { off = off << 1; let next_pc = (self.pc - 2) | 1; self.pc = ((self.gpr[REG_LR] & !1) as i32).wrapping_add(off) as u32; diff --git a/core/src/arm7tdmi/thumb/mod.rs b/core/src/arm7tdmi/thumb/mod.rs index d21b690..7ace8c8 100644 --- a/core/src/arm7tdmi/thumb/mod.rs +++ b/core/src/arm7tdmi/thumb/mod.rs @@ -208,21 +208,6 @@ impl From for AluOpCode { } } -pub(super) mod consts { - pub(super) mod flags { - #[cfg(feature = "debugger")] - pub const FLAG_H1: usize = 7; - #[cfg(feature = "debugger")] - pub const FLAG_H2: usize = 6; - pub const FLAG_R: usize = 8; - pub const FLAG_S: usize = 7; - pub const FLAG_LOW_OFFSET: usize = 11; - pub const FLAG_SP: usize = 11; - pub const FLAG_SIGN_EXTEND: usize = 10; - pub const FLAG_HALFWORD: usize = 11; - } -} - /// A trait which provides methods to extract thumb instruction fields pub trait ThumbDecodeHelper { // Consts @@ -367,7 +352,7 @@ macro_rules! thumb_decode_helper_impl { #[inline] fn sword7(&self) -> i32 { let imm7 = *self & 0x7f; - if self.bit(consts::flags::FLAG_S) { + if self.bit(7) { -((imm7 << 2) as i32) } else { (imm7 << 2) as i32