From b3c3c70bce6243d5cd0fa496495907a20a01d310 Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Wed, 30 Jun 2021 01:25:44 +0300 Subject: [PATCH] WIP const generics Former-commit-id: 2c38215fb57de66bfce26cfa7e61c460bd2954ac Former-commit-id: 8fe5cc4fdc58b1155590dbfd6546b280fcdcc259 --- core/build.rs | 74 +++++++++++++---------------------- core/src/arm7tdmi/alu.rs | 2 +- core/src/arm7tdmi/arm/exec.rs | 27 ++++++++----- 3 files changed, 47 insertions(+), 56 deletions(-) diff --git a/core/build.rs b/core/build.rs index 3ce4f87..89ae133 100644 --- a/core/build.rs +++ b/core/build.rs @@ -98,7 +98,7 @@ impl BitAsInt for u32 {} /// |_Cond__|1_1_1_0|CPopc|L|__CRn__|__Rd___|__CP#__|_CP__|1|__CRm__| CoRegTrans /// |_Cond__|1_1_1_1|_____________Ignored_by_Processor______________| SWI /// ``` -fn arm_decode(i: u32) -> &'static str { +fn arm_decode(i: u32) -> String { const T: bool = true; const F: bool = false; @@ -107,25 +107,25 @@ fn arm_decode(i: u32) -> &'static str { 0b00 => { /* DataProcessing and friends */ - let result: Option<&str> = match (i.bit_range(23..26), i.bit_range(4..8)) { + let result: Option = match (i.bit_range(23..26), i.bit_range(4..8)) { (0b000, 0b1001) => { if 0b0 == i.ibit(22) { - Some("Multiply") + Some(String::from("exec_arm_mul_mla")) } else { None } } - (0b001, 0b1001) => Some("MultiplyLong"), + (0b001, 0b1001) => Some(String::from("exec_arm_mull_mlal")), (0b010, 0b1001) => { if 0b00 == i.bit_range(20..22) { - Some("SingleDataSwap") + Some(String::from("exec_arm_swp")) } else { None } } (0b010, 0b0001) => { if 0b010 == i.bit_range(20..23) { - Some("BranchExchange") + Some(format!("exec_arm_bx")) } else { None } @@ -135,8 +135,8 @@ fn arm_decode(i: u32) -> &'static str { result.unwrap_or_else(|| { match (i.ibit(25), i.ibit(22), i.ibit(7), i.ibit(4)) { - (0, 0, 1, 1) => "HalfwordDataTransferRegOffset", - (0, 1, 1, 1) => "HalfwordDataTransferImmediateOffset", + (0, 0, 1, 1) => String::from("exec_arm_ldr_str_hs_reg"), + (0, 1, 1, 1) => String::from("exec_arm_ldr_str_hs_imm"), _ => { let set_cond_flags = i.bit(20); // PSR Transfers are encoded as a subset of Data Processing, @@ -144,13 +144,17 @@ fn arm_decode(i: u32) -> &'static str { let is_op_not_touching_rd = i.bit_range(21..25) & 0b1100 == 0b1000; if !set_cond_flags && is_op_not_touching_rd { if i.bit(21) { - // Since bit-16 is ignored and we can't know statically if this is a MoveToStatus or MoveToFlags - "MoveToStatus" + // Since bit-16 is ignored and we can't know statically if this is a exec_arm_transfer_to_status or exec_arm_transfer_to_status + String::from("exec_arm_transfer_to_status") } else { - "MoveFromStatus" + String::from("exec_arm_mrs") } } else { - "DataProcessing" + format!("exec_arm_data_processing::<{OP}, {IMM}, {SET_FLAGS}, {SHIFT_BY_REG}>", + OP=i.bit_range(21..25), + IMM=i.bit(25), + SET_FLAGS=i.bit(20), + SHIFT_BY_REG=i.bit(4)) } } } @@ -158,21 +162,21 @@ fn arm_decode(i: u32) -> &'static str { } 0b01 => { match (i.bit(25), i.bit(4)) { - (_, F) | (F, T) => "SingleDataTransfer", - (T, T) => "Undefined", /* Possible ARM11 but we don't implement these */ + (_, F) | (F, T) => String::from("exec_arm_ldr_str"), + (T, T) => String::from("arm_undefined"), /* Possible ARM11 but we don't implement these */ } } 0b10 => match i.bit(25) { - F => "BlockDataTransfer", - T => "BranchLink", + F => String::from("exec_arm_ldm_stm"), + T => format!("exec_arm_b_bl::<{LINK}>", LINK = i.bit(24)), }, 0b11 => { match (i.ibit(25), i.ibit(24), i.ibit(4)) { - (0b0, _, _) => "Undefined", /* CoprocessorDataTransfer not implemented */ - (0b1, 0b0, 0b0) => "Undefined", /* CoprocessorDataOperation not implemented */ - (0b1, 0b0, 0b1) => "Undefined", /* CoprocessorRegisterTransfer not implemented */ - (0b1, 0b1, _) => "SoftwareInterrupt", - _ => "Undefined", + (0b0, _, _) => String::from("arm_undefined"), /* CoprocessorDataTransfer not implemented */ + (0b1, 0b0, 0b0) => String::from("arm_undefined"), /* CoprocessorDataOperation not implemented */ + (0b1, 0b0, 0b1) => String::from("arm_undefined"), /* CoprocessorRegisterTransfer not implemented */ + (0b1, 0b1, _) => String::from("exec_arm_swi"), + _ => String::from("arm_undefined"), } } _ => unreachable!(), @@ -205,27 +209,6 @@ fn thumb_format_to_handler(thumb_fmt: &str) -> &'static str { } } -fn arm_format_to_handler(arm_fmt: &str) -> &'static str { - match arm_fmt { - "BranchExchange" => "exec_arm_bx", - "BranchLink" => "exec_arm_b_bl", - "DataProcessing" => "exec_arm_data_processing", - "SoftwareInterrupt" => "exec_arm_swi", - "SingleDataTransfer" => "exec_arm_ldr_str", - "HalfwordDataTransferImmediateOffset" => "exec_arm_ldr_str_hs_imm", - "HalfwordDataTransferRegOffset" => "exec_arm_ldr_str_hs_reg", - "BlockDataTransfer" => "exec_arm_ldm_stm", - "MoveFromStatus" => "exec_arm_mrs", - "MoveToStatus" => "exec_arm_transfer_to_status", - "MoveToFlags" => "exec_arm_transfer_to_status", - "Multiply" => "exec_arm_mul_mla", - "MultiplyLong" => "exec_arm_mull_mlal", - "SingleDataSwap" => "exec_arm_swp", - "Undefined" => "arm_undefined", - _ => unreachable!(), - } -} - fn generate_thumb_lut(file: &mut fs::File) -> Result<(), std::io::Error> { writeln!(file, "impl Core {{")?; writeln!( @@ -261,17 +244,16 @@ fn generate_arm_lut(file: &mut fs::File) -> Result<(), std::io::Error> { " pub const ARM_LUT: [ArmInstructionInfo; 4096] = [" )?; for i in 0..4096 { - let arm_fmt = arm_decode(((i & 0xff0) << 16) | ((i & 0x00f) << 4)); - let handler_name = arm_format_to_handler(arm_fmt); + let handler_name = arm_decode(((i & 0xff0) << 16) | ((i & 0x00f) << 4)); writeln!( file, " /* {:#x} */ ArmInstructionInfo {{ handler_fn: Core::{}, #[cfg(feature = \"debugger\")] - fmt: ArmFormat::{}, + fmt: ArmFormat::Undefined, }} ,", - i, handler_name, arm_fmt + i, handler_name )?; } writeln!(file, " ];")?; diff --git a/core/src/arm7tdmi/alu.rs b/core/src/arm7tdmi/alu.rs index 77fb66d..5100ce0 100644 --- a/core/src/arm7tdmi/alu.rs +++ b/core/src/arm7tdmi/alu.rs @@ -3,7 +3,7 @@ use bit::BitIndex; use super::memory::MemoryInterface; use super::{Core, REG_PC}; -#[derive(Debug, Primitive, PartialEq)] +#[derive(Debug, Primitive, Eq, PartialEq)] pub enum AluOpCode { AND = 0b0000, EOR = 0b0001, diff --git a/core/src/arm7tdmi/arm/exec.rs b/core/src/arm7tdmi/arm/exec.rs index 4787fa4..2a50264 100644 --- a/core/src/arm7tdmi/arm/exec.rs +++ b/core/src/arm7tdmi/arm/exec.rs @@ -43,11 +43,10 @@ impl Core { /// Branch and Branch with Link (B, BL) /// Execution Time: 2S + 1N - pub fn exec_arm_b_bl(&mut self, insn: u32) -> CpuAction { - if insn.link_flag() { + pub fn exec_arm_b_bl(&mut self, insn: u32) -> CpuAction { + if LINK { self.set_reg(REG_LR, (self.pc_arm() + (self.word_size() as u32)) & !0b1); } - self.pc = (self.pc as i32).wrapping_add(insn.branch_offset()) as u32 & !1; self.reload_pipeline32(); // Implies 2S + 1N @@ -165,9 +164,16 @@ 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. - pub fn exec_arm_data_processing(&mut self, insn: u32) -> CpuAction { + pub fn exec_arm_data_processing< + const OP: u8, + const IMM: bool, + const SET_FLAGS: bool, + const SHIFT_BY_REG: bool, + >( + &mut self, + insn: u32, + ) -> CpuAction { use AluOpCode::*; - let rn = insn.bit_range(16..20) as usize; let rd = insn.bit_range(12..16) as usize; let mut op1 = if rn == REG_PC { @@ -175,11 +181,14 @@ impl Core { } else { self.get_reg(rn) }; - let mut s_flag = insn.set_cond_flag(); - let opcode = insn.opcode(); + let mut s_flag = SET_FLAGS; + let opcode = + AluOpCode::from_u8(OP).unwrap_or_else(|| unsafe { std::hint::unreachable_unchecked() }); + + // println!("{:?} {} {} {}, {:?} {} {} {}", insn.opcode(), insn.bit(25), insn.set_cond_flags(), insn.bit(4), opcode, IMM, SET_FLAGS, SHIFT_BY_REG); let mut carry = self.cpsr.C(); - let op2 = if insn.bit(25) { + let op2 = if IMM { let immediate = insn & 0xff; let rotate = 2 * insn.bit_range(8..12); // TODO refactor out @@ -187,7 +196,7 @@ impl Core { } else { let reg = insn & 0xf; - let shift_by = if insn.bit(4) { + let shift_by = if SHIFT_BY_REG { if rn == REG_PC { op1 += 4; }