From 68e7e714d02cebe4a98095886d9c4b0397a39b6e Mon Sep 17 00:00:00 2001 From: Muhammad Nauman Raza Date: Sat, 23 Mar 2024 20:29:49 +0000 Subject: [PATCH] chore: clean unused directory Former-commit-id: 46120f40cc46143b3c7cf85130fdcb28e3af837c [formerly c344087beacd01a48175dbea614038a15e801350] Former-commit-id: b1b5f6b362ec39f640077f0257c60fca374d9dd3 --- a/Cargo.toml | 27 -- a/build.rs | 435 ----------------------- a/src/alu.rs | 362 -------------------- a/src/arm/disass.rs | 481 -------------------------- a/src/arm/exec.rs | 720 --------------------------------------- a/src/arm/mod.rs | 604 -------------------------------- a/src/cpu.rs | 566 ------------------------------ a/src/disass.rs | 51 --- a/src/exception.rs | 72 ---- a/src/gdb/breakpoints.rs | 36 -- a/src/gdb/mod.rs | 50 --- a/src/gdb/target.rs | 113 ------ a/src/lib.rs | 146 -------- a/src/memory.rs | 265 -------------- a/src/psr.rs | 161 --------- a/src/simple_memory.rs | 84 ----- a/src/thumb/disass.rs | 350 ------------------- a/src/thumb/exec.rs | 575 ------------------------------- a/src/thumb/mod.rs | 485 -------------------------- 19 files changed, 5583 deletions(-) delete mode 100644 a/Cargo.toml delete mode 100644 a/build.rs delete mode 100644 a/src/alu.rs delete mode 100644 a/src/arm/disass.rs delete mode 100644 a/src/arm/exec.rs delete mode 100644 a/src/arm/mod.rs delete mode 100644 a/src/cpu.rs delete mode 100644 a/src/disass.rs delete mode 100644 a/src/exception.rs delete mode 100644 a/src/gdb/breakpoints.rs delete mode 100644 a/src/gdb/mod.rs delete mode 100644 a/src/gdb/target.rs delete mode 100644 a/src/lib.rs delete mode 100644 a/src/memory.rs delete mode 100644 a/src/psr.rs delete mode 100644 a/src/simple_memory.rs delete mode 100644 a/src/thumb/disass.rs delete mode 100644 a/src/thumb/exec.rs delete mode 100644 a/src/thumb/mod.rs diff --git a/a/Cargo.toml b/a/Cargo.toml deleted file mode 100644 index 3479def..0000000 --- a/a/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "arm7tdmi" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -rustboyadvance-utils = {"path" = "./utils" } -log = "0.4.8" -bit = "^0.1" -cfg-if = "1.0.0" -serde = { version = "1.0.104", features = ["derive", "rc"] } -ansi_term = "0.12.1" -colored = "1.9" -byteorder = "1" -num = "0.2.1" -num-traits = "0.2" -enum-primitive-derive = "^0.1" -gdbstub = "0.6.3" -gdbstub_arch = "0.2.4" - -[dev-dependencies] -simple_logger = "2.3.0" # For the examples - -[build-dependencies] -bit = "^0.1" diff --git a/a/build.rs b/a/build.rs deleted file mode 100644 index 80e3757..0000000 --- a/a/build.rs +++ /dev/null @@ -1,435 +0,0 @@ -/// This build script creates ARM_LUT and THUMB_LUT opcode lookup table used cpu.rs -use std::env; -use std::fs; -use std::io::Write; -use std::path::Path; - -extern crate bit; -use bit::BitIndex; - -// copied and slightly adjusted from 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", - format!( - "exec_thumb_add_sub::<{SUB}, {IMM}, {RN}>", - SUB = i.bit(9), - IMM = i.bit(10), - RN = i.bit_range(6..9) as usize - ), - ) - } else if i & 0xe000 == 0x0000 { - ( - "MoveShiftedReg", - format!( - "exec_thumb_move_shifted_reg::<{BS_OP}, {IMM}>", - BS_OP = i.bit_range(11..13) as u8, - IMM = i.bit_range(6..11) as u8 - ), - ) - } else if i & 0xe000 == 0x2000 { - ( - "DataProcessImm", - format!( - "exec_thumb_data_process_imm::<{OP}, {RD}>", - OP = i.bit_range(11..13) as u8, - RD = i.bit_range(8..11) - ), - ) - } else if i & 0xfc00 == 0x4000 { - ( - "AluOps", - format!("exec_thumb_alu_ops::<{OP}>", OP = i.bit_range(6..10)), - ) - } else if i & 0xfc00 == 0x4400 { - ( - "HiRegOpOrBranchExchange", - format!( - "exec_thumb_hi_reg_op_or_bx::<{OP}, {FLAG_H1}, {FLAG_H2}>", - OP = i.bit_range(8..10) as u8, - FLAG_H1 = i.bit(7), - FLAG_H2 = i.bit(6), - ), - ) - } else if i & 0xf800 == 0x4800 { - ( - "LdrPc", - format!( - "exec_thumb_ldr_pc::<{RD}>", - RD = i.bit_range(8..11) as usize - ), - ) - } else if i & 0xf200 == 0x5000 { - ( - "LdrStrRegOffset", - format!( - "exec_thumb_ldr_str_reg_offset::<{LOAD}, {RO}, {BYTE}>", - LOAD = load, - RO = i.bit_range(6..9) as usize, - BYTE = i.bit(10), - ), - ) - } else if i & 0xf200 == 0x5200 { - ( - "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 offset = if is_transferring_bytes { - offset5 - } else { - (offset5 << 3) >> 1 - }; - ( - "LdrStrImmOffset", - format!( - "exec_thumb_ldr_str_imm_offset::<{LOAD}, {BYTE}, {OFFSET}>", - LOAD = load, - BYTE = is_transferring_bytes, - OFFSET = offset - ), - ) - } else if i & 0xf000 == 0x8000 { - ( - "LdrStrHalfWord", - format!( - "exec_thumb_ldr_str_halfword::<{LOAD}, {OFFSET}>", - LOAD = load, - OFFSET = (offset5 << 1) as i32 - ), - ) - } else if i & 0xf000 == 0x9000 { - ( - "LdrStrSp", - format!( - "exec_thumb_ldr_str_sp::<{LOAD}, {RD}>", - LOAD = load, - RD = i.bit_range(8..11) - ), - ) - } else if i & 0xf000 == 0xa000 { - ( - "LoadAddress", - format!( - "exec_thumb_load_address::<{SP}, {RD}>", - SP = i.bit(11), - RD = i.bit_range(8..11) - ), - ) - } else if i & 0xff00 == 0xb000 { - ( - "AddSp", - format!("exec_thumb_add_sp::<{FLAG_S}>", FLAG_S = i.bit(7)), - ) - } else if i & 0xf600 == 0xb400 { - ( - "PushPop", - format!( - "exec_thumb_push_pop::<{POP}, {FLAG_R}>", - POP = load, - FLAG_R = i.bit(8) - ), - ) - } else if i & 0xf000 == 0xc000 { - ( - "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", - 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", - format!( - "exec_thumb_branch_long_with_link::<{FLAG_LOW_OFFSET}>", - FLAG_LOW_OFFSET = i.bit(11), - ), - ) - } else { - ("Undefined", String::from("thumb_undefined")) - } -} - -trait BitAsInt>: BitIndex { - fn ibit(&self, i: usize) -> T { - self.bit(i).into() - } -} - -impl BitAsInt for u32 {} - -/// Returns a string representation of arm7tdmi::arm::ArmFormat enum member -/// # Arguments -/// * `i` - A 32bit ARM instruction -/// -/// Decoding is according to this table from http://problemkaputt.de/gbatek.htm#ARMBinaryOpcodeFormat -/// ``` -/// |..3 ..................2 ..................1 ..................0| -/// |1_0_9_8_7_6_5_4_3_2_1_0_9_8_7_6_5_4_3_2_1_0_9_8_7_6_5_4_3_2_1_0| -/// |_Cond__|0_0_0|___Op__|S|__Rn___|__Rd___|__Shift__|Typ|0|__Rm___| DataProc -/// |_Cond__|0_0_0|___Op__|S|__Rn___|__Rd___|__Rs___|0|Typ|1|__Rm___| DataProc -/// |_Cond__|0_0_1|___Op__|S|__Rn___|__Rd___|_Shift_|___Immediate___| DataProc -/// |_Cond__|0_0_1_1_0_0_1_0_0_0_0_0_1_1_1_1_0_0_0_0|_____Hint______| ARM11:Hint -/// |_Cond__|0_0_1_1_0|P|1|0|_Field_|__Rd___|_Shift_|___Immediate___| PSR Imm -/// |_Cond__|0_0_0_1_0|P|L|0|_Field_|__Rd___|0_0_0_0|0_0_0_0|__Rm___| PSR Reg -/// |_Cond__|0_0_0_1_0_0_1_0_1_1_1_1_1_1_1_1_1_1_1_1|0_0|L|1|__Rn___| BX,BLX -/// |1_1_1_0|0_0_0_1_0_0_1_0|_____immediate_________|0_1_1_1|_immed_| ARM9:BKPT -/// |_Cond__|0_0_0_1_0_1_1_0_1_1_1_1|__Rd___|1_1_1_1|0_0_0_1|__Rm___| ARM9:CLZ -/// |_Cond__|0_0_0_1_0|Op_|0|__Rn___|__Rd___|0_0_0_0|0_1_0_1|__Rm___| ARM9:QALU -/// |_Cond__|0_0_0_0_0_0|A|S|__Rd___|__Rn___|__Rs___|1_0_0_1|__Rm___| Multiply -/// |_Cond__|0_0_0_0_0_1_0_0|_RdHi__|_RdLo__|__Rs___|1_0_0_1|__Rm___| ARM11:UMAAL -/// |_Cond__|0_0_0_0_1|U|A|S|_RdHi__|_RdLo__|__Rs___|1_0_0_1|__Rm___| MulLong -/// |_Cond__|0_0_0_1_0|Op_|0|Rd/RdHi|Rn/RdLo|__Rs___|1|y|x|0|__Rm___| MulHalfARM9 -/// |_Cond__|0_0_0_1_0|B|0_0|__Rn___|__Rd___|0_0_0_0|1_0_0_1|__Rm___| TransSwp12 -/// |_Cond__|0_0_0_1_1|_Op__|__Rn___|__Rd___|1_1_1_1|1_0_0_1|__Rm___| ARM11:LDREX -/// |_Cond__|0_0_0|P|U|0|W|L|__Rn___|__Rd___|0_0_0_0|1|S|H|1|__Rm___| TransReg10 -/// |_Cond__|0_0_0|P|U|1|W|L|__Rn___|__Rd___|OffsetH|1|S|H|1|OffsetL| TransImm10 -/// |_Cond__|0_1_0|P|U|B|W|L|__Rn___|__Rd___|_________Offset________| TransImm9 -/// |_Cond__|0_1_1|P|U|B|W|L|__Rn___|__Rd___|__Shift__|Typ|0|__Rm___| TransReg9 -/// |_Cond__|0_1_1|________________xxx____________________|1|__xxx__| Undefined -/// |_Cond__|0_1_1|Op_|x_x_x_x_x_x_x_x_x_x_x_x_x_x_x_x_x_x|1|x_x_x_x| ARM11:Media -/// |1_1_1_1_0_1_0_1_0_1_1_1_1_1_1_1_1_1_1_1_0_0_0_0_0_0_0_1_1_1_1_1| ARM11:CLREX -/// |_Cond__|1_0_0|P|U|S|W|L|__Rn___|__________Register_List________| BlockTrans -/// |_Cond__|1_0_1|L|___________________Offset______________________| B,BL,BLX -/// |_Cond__|1_1_0|P|U|N|W|L|__Rn___|__CRd__|__CP#__|____Offset_____| CoDataTrans -/// |_Cond__|1_1_0_0_0_1_0|L|__Rn___|__Rd___|__CP#__|_CPopc_|__CRm__| CoRR ARM9 -/// |_Cond__|1_1_1_0|_CPopc_|__CRn__|__CRd__|__CP#__|_CP__|0|__CRm__| CoDataOp -/// |_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, String) { - const T: bool = true; - const F: bool = false; - - // First, decode the the top-most non-condition bits - match i.bit_range(26..28) { - 0b00 => { - /* DataProcessing and friends */ - - let result = match (i.bit_range(23..26), i.bit_range(4..8)) { - (0b000, 0b1001) => { - if 0b0 == i.ibit(22) { - Some(( - "Multiply", - format!( - "exec_arm_mul_mla::<{UPDATE_FLAGS}, {ACCUMULATE}>", - UPDATE_FLAGS = i.bit(20), - ACCUMULATE = i.bit(21), - ), - )) - } else { - None - } - } - (0b001, 0b1001) => Some(( - "MultiplyLong", - format!( - "exec_arm_mull_mlal::<{UPDATE_FLAGS}, {ACCUMULATE}, {U_FLAG}>", - UPDATE_FLAGS = i.bit(20), - ACCUMULATE = i.bit(21), - U_FLAG = i.bit(22), - ), - )), - (0b010, 0b1001) => { - if 0b00 == i.bit_range(20..22) { - Some(( - "SingleDataSwap", - format!("exec_arm_swp::<{BYTE}>", BYTE = i.bit(22)), - )) - } else { - None - } - } - (0b010, 0b0001) => { - if 0b010 == i.bit_range(20..23) { - Some(("BranchExchange", "exec_arm_bx".to_string())) - } else { - None - } - } - _ => None, - }; - - if let Some(result) = result { - result - } else { - match (i.ibit(25), i.ibit(22), i.ibit(7), i.ibit(4)) { - (0, 0, 1, 1) => ( - "HalfwordDataTransferRegOffset", - format!( - "exec_arm_ldr_str_hs_reg::<{HS}, {LOAD}, {WRITEBACK}, {PRE_INDEX}, {ADD}>", - HS = (i & 0b1100000) >> 5, - LOAD = i.bit(20), - WRITEBACK = i.bit(21), - ADD = i.bit(23), - PRE_INDEX = i.bit(24), - ), - ), - (0, 1, 1, 1) => ( - "HalfwordDataTransferImmediateOffset", - format!( - "exec_arm_ldr_str_hs_imm::<{HS}, {LOAD}, {WRITEBACK}, {PRE_INDEX}, {ADD}>", - HS = (i & 0b1100000) >> 5, - LOAD = i.bit(20), - WRITEBACK = i.bit(21), - ADD = i.bit(23), - PRE_INDEX = i.bit(24) - ), - ), - _ => { - let set_cond_flags = i.bit(20); - // PSR Transfers are encoded as a subset of Data Processing, - // with S bit OFF and the encode opcode is one of TEQ,CMN,TST,CMN - 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) { - ("MoveToStatus", format!("exec_arm_transfer_to_status::<{IMM}, {SPSR_FLAG}>", - IMM = i.bit(25), SPSR_FLAG = i.bit(22))) - } else { - ("MoveFromStatus", format!("exec_arm_mrs::<{SPSR_FLAG}>", SPSR_FLAG = i.bit(22))) - } - } 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))) - } - } - } - } - } - 0b01 => { - match (i.bit(25), i.bit(4)) { - (_, F) | (F, T) => ("SingleDataTransfer", format!( - "exec_arm_ldr_str::<{LOAD}, {WRITEBACK}, {PRE_INDEX}, {BYTE}, {SHIFT}, {ADD}, {BS_OP}, {SHIFT_BY_REG}>", - LOAD = i.bit(20), - WRITEBACK = i.bit(21), - BYTE = i.bit(22), - ADD = i.bit(23), - PRE_INDEX = i.bit(24), - SHIFT = i.bit(25), - BS_OP = i.bit_range(5..7) as u8, - SHIFT_BY_REG = i.bit(4), - )), - (T, T) => ("Undefined", String::from("arm_undefined")), /* Possible ARM11 but we don't implement these */ - } - } - 0b10 => match i.bit(25) { - F => ( - "BlockDataTransfer", - format!( - "exec_arm_ldm_stm::<{LOAD}, {WRITEBACK}, {FLAG_S}, {ADD}, {PRE_INDEX}>", - LOAD = i.bit(20), - WRITEBACK = i.bit(21), - FLAG_S = i.bit(22), - ADD = i.bit(23), - PRE_INDEX = i.bit(24), - ), - ), - T => ( - "BranchLink", - format!("exec_arm_b_bl::<{LINK}>", LINK = i.bit(24)), - ), - }, - 0b11 => { - match (i.ibit(25), i.ibit(24), i.ibit(4)) { - (0b0, _, _) => ("Undefined", String::from("arm_undefined")), /* CoprocessorDataTransfer not implemented */ - (0b1, 0b0, 0b0) => ("Undefined", String::from("arm_undefined")), /* CoprocessorDataOperation not implemented */ - (0b1, 0b0, 0b1) => ("Undefined", String::from("arm_undefined")), /* CoprocessorRegisterTransfer not implemented */ - (0b1, 0b1, _) => ("SoftwareInterrupt", String::from("exec_arm_swi")), - _ => ("Undefined", String::from("arm_undefined")), - } - } - _ => unreachable!(), - } -} - -fn generate_thumb_lut(file: &mut fs::File) -> Result<(), std::io::Error> { - writeln!(file, "impl Arm7tdmiCore {{")?; - writeln!( - file, - " pub const THUMB_LUT: [ThumbInstructionInfo; 1024] = [" - )?; - - for i in 0..1024 { - let (thumb_fmt, handler_name) = thumb_decode(i << 6); - writeln!( - file, - " /* {:#x} */ - ThumbInstructionInfo {{ - handler_fn: Arm7tdmiCore::{}, - #[cfg(feature = \"debugger\")] - fmt: ThumbFormat::{}, - }},", - i, handler_name, thumb_fmt - )?; - } - - writeln!(file, " ];")?; - writeln!(file, "}}")?; - - Ok(()) -} - -fn generate_arm_lut(file: &mut fs::File) -> Result<(), std::io::Error> { - writeln!(file, "impl Arm7tdmiCore {{")?; - writeln!( - file, - " pub const ARM_LUT: [ArmInstructionInfo; 4096] = [" - )?; - for i in 0..4096 { - let (arm_fmt, handler_name) = arm_decode(((i & 0xff0) << 16) | ((i & 0x00f) << 4)); - writeln!( - file, - " /* {:#x} */ - ArmInstructionInfo {{ - handler_fn: Arm7tdmiCore::{}, - #[cfg(feature = \"debugger\")] - fmt: ArmFormat::{}, - }} ,", - i, handler_name, arm_fmt - )?; - } - writeln!(file, " ];")?; - writeln!(file, "}}")?; - - Ok(()) -} - -fn main() { - // TODO - don't do this in the build script and use `const fn` instead when it becomes stable - let out_dir = env::var_os("OUT_DIR").unwrap(); - let thumb_lut_path = Path::new(&out_dir).join("thumb_lut.rs"); - let mut thumb_lut_file = fs::File::create(thumb_lut_path).expect("failed to create file"); - generate_thumb_lut(&mut thumb_lut_file).expect("failed to generate thumb table"); - - let arm_lut_path = Path::new(&out_dir).join("arm_lut.rs"); - let mut arm_lut_file = fs::File::create(arm_lut_path).expect("failed to create file"); - generate_arm_lut(&mut arm_lut_file).expect("failed to generate arm table"); - - println!("cargo:rerun-if-changed=build.rs"); -} diff --git a/a/src/alu.rs b/a/src/alu.rs deleted file mode 100644 index d23996d..0000000 --- a/a/src/alu.rs +++ /dev/null @@ -1,362 +0,0 @@ -use bit::BitIndex; - -use crate::{memory::MemoryInterface, registers_consts::REG_PC, Arm7tdmiCore}; - -#[derive(Debug, Primitive, Eq, PartialEq)] -pub enum AluOpCode { - AND = 0b0000, - EOR = 0b0001, - SUB = 0b0010, - RSB = 0b0011, - ADD = 0b0100, - ADC = 0b0101, - SBC = 0b0110, - RSC = 0b0111, - TST = 0b1000, - TEQ = 0b1001, - CMP = 0b1010, - CMN = 0b1011, - ORR = 0b1100, - MOV = 0b1101, - BIC = 0b1110, - MVN = 0b1111, -} - -impl AluOpCode { - pub fn is_setting_flags(&self) -> bool { - use AluOpCode::*; - matches!(self, TST | TEQ | CMP | CMN) - } - - pub fn is_logical(&self) -> bool { - use AluOpCode::*; - matches!(self, MOV | MVN | ORR | EOR | AND | BIC | TST | TEQ) - } - pub fn is_arithmetic(&self) -> bool { - use AluOpCode::*; - matches!(self, ADD | ADC | SUB | SBC | RSB | RSC | CMP | CMN) - } -} - -#[derive(Debug, PartialEq, Eq, Primitive, Copy, Clone)] -pub enum BarrelShiftOpCode { - LSL = 0, - LSR = 1, - ASR = 2, - ROR = 3, -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum ShiftRegisterBy { - ByAmount(u32), - ByRegister(usize), -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub struct ShiftedRegister { - pub reg: usize, - pub shift_by: ShiftRegisterBy, - pub bs_op: BarrelShiftOpCode, - pub added: Option, -} - -impl ShiftedRegister { - pub fn is_shifted_by_reg(&self) -> bool { - matches!(self.shift_by, ShiftRegisterBy::ByRegister(_)) - } -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum BarrelShifterValue { - ImmediateValue(u32), - RotatedImmediate(u32, u32), - ShiftedRegister(ShiftedRegister), -} - -impl BarrelShifterValue { - /// Decode operand2 as an immediate value - pub fn decode_rotated_immediate(&self) -> Option { - if let BarrelShifterValue::RotatedImmediate(immediate, rotate) = self { - return Some(immediate.rotate_right(*rotate)); - } - None - } - pub fn shifted_register( - reg: usize, - shift_by: ShiftRegisterBy, - bs_op: BarrelShiftOpCode, - added: Option, - ) -> BarrelShifterValue { - let shft_reg = ShiftedRegister { - reg, - shift_by, - bs_op, - added, - }; - BarrelShifterValue::ShiftedRegister(shft_reg) - } -} - -impl Arm7tdmiCore { - pub fn lsl(&mut self, val: u32, amount: u32, carry: &mut bool) -> u32 { - match amount { - 0 => val, - x if x < 32 => { - *carry = val.wrapping_shr(32 - x) & 1 == 1; - val << x - } - 32 => { - *carry = val & 1 == 1; - 0 - } - _ => { - *carry = false; - 0 - } - } - } - - pub fn lsr(&mut self, val: u32, amount: u32, carry: &mut bool, immediate: bool) -> u32 { - if amount != 0 { - match amount { - x if x < 32 => { - *carry = (val >> (amount - 1) & 1) == 1; - val >> amount - } - 32 => { - *carry = val.bit(31); - 0 - } - _ => { - *carry = false; - 0 - } - } - } else if immediate { - *carry = val.bit(31); - 0 - } else { - val - } - } - - pub fn asr(&mut self, val: u32, amount: u32, carry: &mut bool, immediate: bool) -> u32 { - let amount = if immediate && amount == 0 { 32 } else { amount }; - match amount { - 0 => val, - x if x < 32 => { - *carry = val.wrapping_shr(amount - 1) & 1 == 1; - (val as i32).wrapping_shr(amount) as u32 - } - _ => { - let bit31 = val.bit(31); - *carry = bit31; - if bit31 { - 0xffffffff - } else { - 0 - } - } - } - } - - pub fn rrx(&mut self, val: u32, carry: &mut bool) -> u32 { - let old_c = *carry as i32; - *carry = val & 0b1 != 0; - ((val >> 1) as i32 | (old_c << 31)) as u32 - } - - pub fn ror( - &mut self, - val: u32, - amount: u32, - carry: &mut bool, - immediate: bool, - rrx: bool, - ) -> u32 { - match amount { - 0 => { - if immediate & rrx { - self.rrx(val, carry) - } else { - val - } - } - _ => { - let amount = amount % 32; - let val = if amount != 0 { - val.rotate_right(amount) - } else { - val - }; - *carry = (val).bit(31); - val - } - } - } - - /// Performs a generic barrel shifter operation - #[inline] - pub fn barrel_shift_op( - &mut self, - shift: BarrelShiftOpCode, - val: u32, - amount: u32, - carry: &mut bool, - immediate: bool, - ) -> u32 { - // - // From GBATEK: - // Zero Shift Amount (Shift Register by Immediate, with Immediate=0) - // LSL#0: No shift performed, ie. directly Op2=Rm, the C flag is NOT affected. - // LSR#0: Interpreted as LSR#32, ie. Op2 becomes zero, C becomes Bit 31 of Rm. - // ASR#0: Interpreted as ASR#32, ie. Op2 and C are filled by Bit 31 of Rm. - // ROR#0: Interpreted as RRX#1 (RCR), like ROR#1, but Op2 Bit 31 set to old C. - // - // From ARM7TDMI Datasheet: - // 1 LSL by 32 has result zero, carry out equal to bit 0 of Rm. - // 2 LSL by more than 32 has result zero, carry out zero. - // 3 LSR by 32 has result zero, carry out equal to bit 31 of Rm. - // 4 LSR by more than 32 has result zero, carry out zero. - // 5 ASR by 32 or more has result filled with and carry out equal to bit 31 of Rm. - // 6 ROR by 32 has result equal to Rm, carry out equal to bit 31 of Rm. - // 7 ROR by n where n is greater than 32 will give the same result and carry out - // as ROR by n-32; therefore repeatedly subtract 32 from n until the amount is - // in the range 1 to 32 and see above. - // - match shift { - BarrelShiftOpCode::LSL => self.lsl(val, amount, carry), - BarrelShiftOpCode::LSR => self.lsr(val, amount, carry, immediate), - BarrelShiftOpCode::ASR => self.asr(val, amount, carry, immediate), - BarrelShiftOpCode::ROR => self.ror(val, amount, carry, immediate, true), - } - } - - #[inline] - pub fn shift_by_register( - &mut self, - bs_op: BarrelShiftOpCode, - reg: usize, - rs: usize, - carry: &mut bool, - ) -> u32 { - let mut val = self.get_reg(reg); - 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_const( - &mut self, - offset: u32, - reg: usize, - carry: &mut bool, - ) -> u32 { - let op = match BS_OP { - 0 => BarrelShiftOpCode::LSL, - 1 => BarrelShiftOpCode::LSR, - 2 => BarrelShiftOpCode::ASR, - 3 => BarrelShiftOpCode::ROR, - _ => unsafe { std::hint::unreachable_unchecked() }, - }; - if SHIFT_BY_REG { - let rs = offset.bit_range(8..12) as usize; - self.shift_by_register(op, reg, rs, carry) - } else { - let amount = offset.bit_range(7..12); - self.barrel_shift_op(op, self.get_reg(reg), amount, carry, true) - } - } - - pub fn register_shift(&mut self, shift: &ShiftedRegister, carry: &mut bool) -> u32 { - match shift.shift_by { - ShiftRegisterBy::ByAmount(amount) => { - self.barrel_shift_op(shift.bs_op, self.get_reg(shift.reg), amount, carry, true) - } - ShiftRegisterBy::ByRegister(rs) => { - self.shift_by_register(shift.bs_op, shift.reg, rs, carry) - } - } - } - - pub fn get_barrel_shifted_value(&mut self, sval: &BarrelShifterValue, carry: &mut bool) -> u32 { - // TODO decide if error handling or panic here - match sval { - BarrelShifterValue::ImmediateValue(offset) => *offset, - BarrelShifterValue::ShiftedRegister(shifted_reg) => { - let added = (shifted_reg).added.unwrap_or(true); - let abs = self.register_shift(shifted_reg, carry); - if added { - abs - } else { - (-(abs as i32)) as u32 - } - } - _ => panic!("bad barrel shift"), - } - } - - pub(super) fn alu_sub_flags( - &self, - a: u32, - b: u32, - carry: &mut bool, - overflow: &mut bool, - ) -> u32 { - let res = a.wrapping_sub(b); - *carry = b <= a; - *overflow = (a as i32).overflowing_sub(b as i32).1; - res - } - - pub(super) fn alu_add_flags( - &self, - a: u32, - b: u32, - carry: &mut bool, - overflow: &mut bool, - ) -> u32 { - let res = a.wrapping_add(b); - *carry = add_carry_result(a as u64, b as u64); - *overflow = (a as i32).overflowing_add(b as i32).1; - res - } - - pub(super) fn alu_adc_flags( - &self, - a: u32, - b: u32, - carry: &mut bool, - overflow: &mut bool, - ) -> u32 { - let c = self.cpsr.C() as u64; - let res = (a as u64) + (b as u64) + c; - *carry = res > 0xffffffff; - *overflow = (!(a ^ b) & (b ^ (res as u32))).bit(31); - res as u32 - } - - pub(super) fn alu_sbc_flags( - &self, - a: u32, - b: u32, - carry: &mut bool, - overflow: &mut bool, - ) -> u32 { - self.alu_adc_flags(a, !b, carry, overflow) - } - - 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); - self.cpsr.set_V(v); - } -} - -#[inline] -fn add_carry_result(a: u64, b: u64) -> bool { - a.wrapping_add(b) > 0xffffffff -} diff --git a/a/src/arm/disass.rs b/a/src/arm/disass.rs deleted file mode 100644 index 04bd400..0000000 --- a/a/src/arm/disass.rs +++ /dev/null @@ -1,481 +0,0 @@ -use std::fmt; - -use crate::bit::BitIndex; - -use super::{ArmDecodeHelper, ArmFormat, ArmInstruction}; - -use super::{AluOpCode, ArmCond, ArmHalfwordTransferType}; -use crate::arm7tdmi::*; - -impl fmt::Display for ArmCond { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use ArmCond::*; - match self { - Invalid => panic!("Invalid condition code"), - EQ => write!(f, "eq"), - NE => write!(f, "ne"), - HS => write!(f, "cs"), - LO => write!(f, "cc"), - MI => write!(f, "mi"), - PL => write!(f, "pl"), - VS => write!(f, "vs"), - VC => write!(f, "vc"), - HI => write!(f, "hi"), - LS => write!(f, "ls"), - GE => write!(f, "ge"), - LT => write!(f, "lt"), - GT => write!(f, "gt"), - LE => write!(f, "le"), - AL => write!(f, ""), // the dissasembly should ignore this - } - } -} - -impl fmt::Display for AluOpCode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use AluOpCode::*; - match self { - AND => write!(f, "and"), - EOR => write!(f, "eor"), - SUB => write!(f, "sub"), - RSB => write!(f, "rsb"), - ADD => write!(f, "add"), - ADC => write!(f, "adc"), - SBC => write!(f, "sbc"), - RSC => write!(f, "rsc"), - TST => write!(f, "tst"), - TEQ => write!(f, "teq"), - CMP => write!(f, "cmp"), - CMN => write!(f, "cmn"), - ORR => write!(f, "orr"), - MOV => write!(f, "mov"), - BIC => write!(f, "bic"), - MVN => write!(f, "mvn"), - } - } -} - -impl fmt::Display for BarrelShiftOpCode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use BarrelShiftOpCode::*; - match self { - LSL => write!(f, "lsl"), - LSR => write!(f, "lsr"), - ASR => write!(f, "asr"), - ROR => write!(f, "ror"), - } - } -} - -impl fmt::Display for ArmHalfwordTransferType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use ArmHalfwordTransferType::*; - match self { - UnsignedHalfwords => write!(f, "h"), - SignedHalfwords => write!(f, "sh"), - SignedByte => write!(f, "sb"), - } - } -} - -fn is_lsl0(shift: &ShiftedRegister) -> bool { - if let ShiftRegisterBy::ByAmount(val) = shift.shift_by { - return !(val == 0 && shift.bs_op == BarrelShiftOpCode::LSL); - } - true -} - -impl fmt::Display for ShiftedRegister { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let reg = reg_string(self.reg).to_string(); - if !is_lsl0(&self) { - write!(f, "{}", reg) - } else { - match self.shift_by { - ShiftRegisterBy::ByAmount(imm) => write!(f, "{}, {} #{}", reg, self.bs_op, imm), - ShiftRegisterBy::ByRegister(rs) => { - write!(f, "{}, {} {}", reg, self.bs_op, reg_string(rs)) - } - } - } - } -} - -impl ArmInstruction { - fn fmt_bx(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "bx\t{Rn}", - Rn = reg_string(self.raw.bit_range(0..4) as usize) - ) - } - - fn fmt_branch(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "b{link}{cond}\t{ofs:#x}", - link = if self.raw.link_flag() { "l" } else { "" }, - cond = self.raw.cond(), - ofs = 8 + self.pc.wrapping_add(self.raw.branch_offset() as Addr) - ) - } - - fn set_cond_mark(&self) -> &str { - if self.raw.set_cond_flag() { - "s" - } else { - "" - } - } - - fn fmt_operand2(&self, f: &mut fmt::Formatter<'_>) -> Result, fmt::Error> { - let operand2 = self.raw.operand2(); - match operand2 { - BarrelShifterValue::RotatedImmediate(_, _) => { - let value = operand2.decode_rotated_immediate().unwrap(); - write!(f, "#{}\t; {:#x}", value, value)?; - Ok(Some(value as u32)) - } - BarrelShifterValue::ShiftedRegister(shift) => { - write!(f, "{}", shift)?; - Ok(None) - } - _ => panic!("invalid operand2"), - } - } - - fn fmt_data_processing(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use AluOpCode::*; - - let opcode = self.raw.opcode(); - - let rd = self.raw.bit_range(16..20) as usize; - let rn = self.raw.bit_range(16..20) as usize; - - match opcode { - MOV | MVN => write!( - f, - "{opcode}{S}{cond}\t{Rd}, ", - opcode = opcode, - cond = self.raw.cond(), - S = self.set_cond_mark(), - Rd = reg_string(rd) - ), - CMP | CMN | TEQ | TST => write!( - f, - "{opcode}{cond}\t{Rn}, ", - opcode = opcode, - cond = self.raw.cond(), - Rn = reg_string(rn) - ), - _ => write!( - f, - "{opcode}{S}{cond}\t{Rd}, {Rn}, ", - opcode = opcode, - cond = self.raw.cond(), - S = self.set_cond_mark(), - Rd = reg_string(rd), - Rn = reg_string(rn) - ), - }?; - - self.fmt_operand2(f).unwrap(); - Ok(()) - } - - fn auto_incremenet_mark(&self) -> &str { - if self.raw.write_back_flag() { - "!" - } else { - "" - } - } - - fn fmt_rn_offset( - &self, - f: &mut fmt::Formatter<'_>, - offset: BarrelShifterValue, - rn: usize, - ) -> fmt::Result { - write!(f, "[{Rn}", Rn = reg_string(rn))?; - let (ofs_string, comment) = match offset { - BarrelShifterValue::ImmediateValue(value) => { - let value_for_commnet = if rn == REG_PC { - value + self.pc + 8 // account for pipelining - } else { - value - }; - ( - format!("#{}", value), - Some(format!("\t; {:#x}", value_for_commnet)), - ) - } - BarrelShifterValue::ShiftedRegister(shift) => ( - format!( - "{}{}", - if shift.added.unwrap_or(true) { "" } else { "-" }, - shift - ), - None, - ), - _ => panic!("bad barrel shifter"), - }; - - if self.raw.pre_index_flag() { - write!(f, ", {}]{}", ofs_string, self.auto_incremenet_mark())?; - } else { - write!(f, "], {}", ofs_string)?; - } - - if let Some(comment) = comment { - write!(f, "{}", comment) - } else { - Ok(()) - } - } - - fn fmt_ldr_str(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{mnem}{B}{T}{cond}\t{Rd}, ", - mnem = if self.raw.load_flag() { "ldr" } else { "str" }, - B = if self.raw.transfer_size() == 1 { - "b" - } else { - "" - }, - cond = self.raw.cond(), - T = if !self.raw.pre_index_flag() && self.raw.write_back_flag() { - "t" - } else { - "" - }, - Rd = reg_string(self.raw.bit_range(12..16) as usize), - )?; - - self.fmt_rn_offset( - f, - self.raw.ldr_str_offset(), - self.raw.bit_range(16..20) as usize, - ) - } - - fn fmt_ldm_stm(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{mnem}{inc_dec}{pre_post}{cond}\t{Rn}{auto_inc}, {{", - mnem = if self.raw.load_flag() { "ldm" } else { "stm" }, - inc_dec = if self.raw.add_offset_flag() { 'i' } else { 'd' }, - pre_post = if self.raw.pre_index_flag() { 'b' } else { 'a' }, - cond = self.raw.cond(), - Rn = reg_string(self.raw.bit_range(16..20) as usize), - auto_inc = if self.raw.write_back_flag() { "!" } else { "" } - )?; - - let register_list = self.raw.register_list(); - let mut has_first = false; - for i in 0..16 { - if register_list.bit(i) { - if has_first { - write!(f, ", {}", reg_string(i))?; - } else { - write!(f, "{}", reg_string(i))?; - has_first = true; - } - } - } - - write!( - f, - "}}{}", - if self.raw.psr_and_force_user_flag() { - "^" - } else { - "" - } - ) - } - - /// MRS - transfer PSR contents to a register - fn fmt_mrs(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "mrs{cond}\t{Rd}, {psr}", - cond = self.raw.cond(), - Rd = reg_string(self.raw.bit_range(12..16) as usize), - psr = if self.raw.spsr_flag() { "SPSR" } else { "CPSR" } - ) - } - - /// MSR - transfer register/immediate contents to PSR - fn fmt_msr(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "msr{cond}\t{psr}, ", - cond = self.raw.cond(), - psr = if self.raw.spsr_flag() { "SPSR" } else { "CPSR" }, - )?; - self.fmt_operand2(f).unwrap(); - Ok(()) - } - - fn fmt_msr_flags(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "msr{cond}\t{psr}, ", - cond = self.raw.cond(), - psr = if self.raw.spsr_flag() { - "SPSR_f" - } else { - "CPSR_f" - }, - )?; - if let Ok(Some(op)) = self.fmt_operand2(f) { - let psr = RegPSR::new(op & 0xf000_0000); - write!( - f, - "\t; N={} Z={} C={} V={}", - psr.N(), - psr.Z(), - psr.C(), - psr.V() - )?; - } - Ok(()) - } - - fn fmt_mul_mla(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let rd = self.raw.bit_range(16..20) as usize; - if self.raw.accumulate_flag() { - write!( - f, - "mla{S}{cond}\t{Rd}, {Rm}, {Rs}, {Rn}", - S = self.set_cond_mark(), - cond = self.raw.cond(), - Rd = reg_string(rd), - Rm = reg_string(self.raw.rm()), - Rs = reg_string(self.raw.rs()), - Rn = reg_string(self.raw.bit_range(12..16) as usize), - ) - } else { - write!( - f, - "mul{S}{cond}\t{Rd}, {Rm}, {Rs}", - S = self.set_cond_mark(), - cond = self.raw.cond(), - Rd = reg_string(rd), - Rm = reg_string(self.raw.rm()), - Rs = reg_string(self.raw.rs()), - ) - } - } - - fn sign_mark(&self) -> &str { - if self.raw.u_flag() { - "s" - } else { - "u" - } - } - - fn fmt_mull_mlal(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{sign}{mnem}{S}{cond}\t{RdLo}, {RdHi}, {Rm}, {Rs}", - sign = self.sign_mark(), - mnem = if self.raw.accumulate_flag() { - "mlal" - } else { - "mull" - }, - S = self.set_cond_mark(), - cond = self.raw.cond(), - RdLo = reg_string(self.raw.rd_lo()), - RdHi = reg_string(self.raw.rd_hi()), - Rm = reg_string(self.raw.rm()), - Rs = reg_string(self.raw.rs()), - ) - } - - fn fmt_ldr_str_hs_imm_offset(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let transfer_type = self.raw.halfword_data_transfer_type(); - write!( - f, - "{mnem}{type}{cond}\t{Rd}, ", - mnem = if self.raw.load_flag() { "ldr" } else { "str" }, - cond = self.raw.cond(), - type = transfer_type, - Rd = reg_string(self.raw.bit_range(12..16) as usize), - )?; - self.fmt_rn_offset( - f, - self.raw.ldr_str_hs_imm_offset(), - self.raw.bit_range(16..20) as usize, - ) - } - - fn fmt_ldr_str_hs_reg_offset(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let transfer_type = self.raw.halfword_data_transfer_type(); - write!( - f, - "{mnem}{type}{cond}\t{Rd}, ", - mnem = if self.raw.load_flag() { "ldr" } else { "str" }, - cond = self.raw.cond(), - type = transfer_type, - Rd = reg_string(self.raw.bit_range(12..16) as usize), - )?; - self.fmt_rn_offset( - f, - self.raw.ldr_str_hs_reg_offset(), - self.raw.bit_range(16..20) as usize, - ) - } - - fn fmt_swi(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "swi{cond}\t#{comm:#x}", - cond = self.raw.cond(), - comm = self.raw.swi_comment() - ) - } - - fn fmt_swp(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "swp{B}{cond}\t{Rd}, {Rm}, [{Rn}]", - B = if self.raw.transfer_size() == 1 { - "b" - } else { - "" - }, - cond = self.raw.cond(), - Rd = reg_string(self.raw.bit_range(12..16) as usize), - Rm = reg_string(self.raw.rm()), - Rn = reg_string(self.raw.bit_range(16..20) as usize), - ) - } -} - -impl fmt::Display for ArmInstruction { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use ArmFormat::*; - match self.fmt { - BranchExchange => self.fmt_bx(f), - BranchLink => self.fmt_branch(f), - DataProcessing => self.fmt_data_processing(f), - SingleDataTransfer => self.fmt_ldr_str(f), - BlockDataTransfer => self.fmt_ldm_stm(f), - MoveFromStatus => self.fmt_mrs(f), - MoveToStatus => self.fmt_msr(f), - MoveToFlags => self.fmt_msr_flags(f), - Multiply => self.fmt_mul_mla(f), - MultiplyLong => self.fmt_mull_mlal(f), - HalfwordDataTransferImmediateOffset => self.fmt_ldr_str_hs_imm_offset(f), - HalfwordDataTransferRegOffset => self.fmt_ldr_str_hs_reg_offset(f), - SoftwareInterrupt => self.fmt_swi(f), - SingleDataSwap => self.fmt_swp(f), - Undefined => write!(f, ""), - } - } -} diff --git a/a/src/arm/exec.rs b/a/src/arm/exec.rs deleted file mode 100644 index 11db301..0000000 --- a/a/src/arm/exec.rs +++ /dev/null @@ -1,720 +0,0 @@ -use crate::{ - alu::*, - memory::{MemoryAccess, MemoryInterface}, - psr::RegPSR, - registers_consts::{REG_LR, REG_PC}, - Arm7tdmiCore, CpuAction, CpuMode, CpuState, -}; - -use MemoryAccess::*; - -use super::*; - -impl Arm7tdmiCore { - pub fn arm_undefined(&mut self, insn: u32) -> CpuAction { - panic!( - "executing undefined arm instruction {:08x} at @{:08x}", - insn, - self.pc_arm() - ) - } - - /// Branch and Branch with Link (B, BL) - /// Execution Time: 2S + 1N - 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 - CpuAction::PipelineFlushed - } - - pub fn branch_exchange(&mut self, mut addr: Addr) -> CpuAction { - if addr.bit(0) { - addr &= !0x1; - self.cpsr.set_state(CpuState::THUMB); - self.pc = addr; - self.reload_pipeline16(); - } else { - addr &= !0x3; - self.cpsr.set_state(CpuState::ARM); - self.pc = addr; - self.reload_pipeline32(); - } - CpuAction::PipelineFlushed - } - /// Branch and Exchange (BX) - /// Cycles 2S+1N - pub fn exec_arm_bx(&mut self, insn: u32) -> CpuAction { - self.branch_exchange(self.get_reg(insn.bit_range(0..4) as usize)) - } - - /// Move from status register - /// 1S - pub fn exec_arm_mrs(&mut self, insn: u32) -> CpuAction { - let rd = insn.bit_range(12..16) as usize; - let result = if SPSR_FLAG { - self.spsr.get() - } else { - self.cpsr.get() - }; - self.set_reg(rd, result); - - CpuAction::AdvancePC(Seq) - } - - /// Move to status register - /// 1S - pub fn exec_arm_transfer_to_status( - &mut self, - insn: u32, - ) -> CpuAction { - let value = if IMM { - let immediate = insn & 0xff; - let rotate = 2 * insn.bit_range(8..12); - let mut carry = self.cpsr.C(); - let v = self.ror(immediate, rotate, &mut carry, false, true); - self.cpsr.set_C(carry); - v - } else { - self.get_reg((insn & 0b1111) as usize) - }; - - let f = insn.bit(19); - let s = insn.bit(18); - let x = insn.bit(17); - let c = insn.bit(16); - - let mut mask = 0; - if f { - mask |= 0xff << 24; - } - if s { - mask |= 0xff << 16; - } - if x { - mask |= 0xff << 8; - } - if c { - mask |= 0xff; - } - - match self.cpsr.mode() { - CpuMode::User => { - if SPSR_FLAG { - panic!("User mode can't access SPSR") - } - self.cpsr.set_flag_bits(value); - } - _ => { - if SPSR_FLAG { - self.spsr.set(value); - } else { - let old_mode = self.cpsr.mode(); - let new_psr = RegPSR::new((self.cpsr.get() & !mask) | (value & mask)); - let new_mode = new_psr.mode(); - if old_mode != new_mode { - self.change_mode(old_mode, new_mode); - } - self.cpsr = new_psr; - } - } - } - - CpuAction::AdvancePC(Seq) - } - - fn transfer_spsr_mode(&mut self) { - let spsr = self.spsr; - if self.cpsr.mode() != spsr.mode() { - self.change_mode(self.cpsr.mode(), spsr.mode()); - } - self.cpsr = spsr; - } - - /// Logical/Arithmetic ALU operations - /// - /// 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< - 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 { - self.pc_arm() + 8 - } else { - self.get_reg(rn) - }; - let mut s_flag = SET_FLAGS; - let opcode = - AluOpCode::from_u8(OP).unwrap_or_else(|| unsafe { std::hint::unreachable_unchecked() }); - - let mut carry = self.cpsr.C(); - let op2 = if IMM { - let immediate = insn & 0xff; - let rotate = 2 * insn.bit_range(8..12); - // TODO refactor out - self.ror(immediate, rotate, &mut carry, false, true) - } else { - let reg = insn & 0xf; - - let shift_by = if SHIFT_BY_REG { - if rn == REG_PC { - op1 += 4; - } - self.idle_cycle(); - let rs = insn.bit_range(8..12) as usize; - ShiftRegisterBy::ByRegister(rs) - } else { - let amount = insn.bit_range(7..12); - ShiftRegisterBy::ByAmount(amount) - }; - - let shifted_reg = ShiftedRegister { - reg: reg as usize, - bs_op: insn.get_bs_op(), - shift_by, - added: None, - }; - self.register_shift(&shifted_reg, &mut carry) - }; - - if rd == REG_PC && s_flag { - self.transfer_spsr_mode(); - s_flag = false; - } - - let alu_res = if s_flag { - let mut overflow = self.cpsr.V(); - let result = match opcode { - AND | TST => op1 & op2, - EOR | TEQ => op1 ^ op2, - SUB | CMP => self.alu_sub_flags(op1, op2, &mut carry, &mut overflow), - RSB => self.alu_sub_flags(op2, op1, &mut carry, &mut overflow), - ADD | CMN => self.alu_add_flags(op1, op2, &mut carry, &mut overflow), - ADC => self.alu_adc_flags(op1, op2, &mut carry, &mut overflow), - SBC => self.alu_sbc_flags(op1, op2, &mut carry, &mut overflow), - RSC => self.alu_sbc_flags(op2, op1, &mut carry, &mut overflow), - ORR => op1 | op2, - MOV => op2, - BIC => op1 & (!op2), - MVN => !op2, - }; - - self.alu_update_flags(result, opcode.is_arithmetic(), carry, overflow); - - if opcode.is_setting_flags() { - None - } else { - Some(result) - } - } else { - let c = carry as u32; - Some(match opcode { - AND => op1 & op2, - EOR => op1 ^ op2, - 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)), - ORR => op1 | op2, - MOV => op2, - BIC => op1 & (!op2), - MVN => !op2, - _ => panic!("DataProcessing should be a PSR transfer"), - }) - }; - - let mut result = CpuAction::AdvancePC(Seq); - if let Some(alu_res) = alu_res { - self.set_reg(rd, alu_res); - if rd == REG_PC { - // T bit might have changed - match self.cpsr.state() { - CpuState::ARM => self.reload_pipeline32(), - CpuState::THUMB => self.reload_pipeline16(), - }; - result = CpuAction::PipelineFlushed; - } - } - - result - } - - /// Memory Load/Store - /// Instruction | Cycles | Flags | Expl. - /// ------------------------------------------------------------------------------ - /// LDR{cond}{B}{T} Rd,
| 1S+1N+1I+y | ---- | Rd=[Rn+/-] - /// STR{cond}{B}{T} Rd,
| 2N | ---- | [Rn+/-]=Rd - /// ------------------------------------------------------------------------------ - /// For LDR, add y=1S+1N if Rd=R15. - pub fn exec_arm_ldr_str< - const LOAD: bool, - const WRITEBACK: bool, - const PRE_INDEX: bool, - const BYTE: bool, - const SHIFT: bool, - const ADD: bool, - const BS_OP: u8, - const SHIFT_BY_REG: bool, - >( - &mut self, - insn: u32, - ) -> CpuAction { - let mut result = CpuAction::AdvancePC(NonSeq); - - let base_reg = insn.bit_range(16..20) as usize; - let dest_reg = insn.bit_range(12..16) as usize; - let mut addr = self.get_reg(base_reg); - if base_reg == REG_PC { - addr = self.pc_arm() + 8; // prefetching - } - let mut offset = insn.bit_range(0..12); - if SHIFT { - let mut carry = self.cpsr.C(); - let rm = offset & 0xf; - offset = - self.register_shift_const::(offset, rm as usize, &mut carry); - } - let offset = if ADD { - offset - } else { - (-(offset as i32)) as u32 - }; - let effective_addr = (addr as i32).wrapping_add(offset as i32) as Addr; - - // TODO - confirm this - let old_mode = self.cpsr.mode(); - if !PRE_INDEX && WRITEBACK { - self.change_mode(old_mode, CpuMode::User); - } - - addr = if PRE_INDEX { effective_addr } else { addr }; - - if LOAD { - let data = if BYTE { - self.load_8(addr, NonSeq) as u32 - } else { - self.ldr_word(addr, NonSeq) - }; - - self.set_reg(dest_reg, data); - - // +1I - self.idle_cycle(); - - if dest_reg == REG_PC { - self.reload_pipeline32(); - result = CpuAction::PipelineFlushed; - } - } else { - let value = if dest_reg == REG_PC { - self.pc_arm() + 12 - } else { - self.get_reg(dest_reg) - }; - if BYTE { - self.store_8(addr, value as u8, NonSeq); - } else { - self.store_aligned_32(addr & !0x3, value, NonSeq); - }; - } - - if (!LOAD || base_reg != dest_reg) && (!PRE_INDEX || WRITEBACK) { - self.set_reg(base_reg, effective_addr); - } - - if !PRE_INDEX && WRITEBACK { - self.change_mode(self.cpsr.mode(), old_mode); - } - - result - } - - pub fn exec_arm_ldr_str_hs_reg< - const HS: u8, - const LOAD: bool, - const WRITEBACK: bool, - const PRE_INDEX: bool, - const ADD: bool, - >( - &mut self, - insn: u32, - ) -> CpuAction { - let offset = self.get_reg((insn & 0xf) as usize); - self.ldr_str_hs_common::(insn, offset) - } - - pub fn exec_arm_ldr_str_hs_imm< - const HS: u8, - const LOAD: bool, - const WRITEBACK: bool, - const PRE_INDEX: bool, - const ADD: bool, - >( - &mut self, - insn: u32, - ) -> CpuAction { - let offset8 = (insn.bit_range(8..12) << 4) + insn.bit_range(0..4); - self.ldr_str_hs_common::(insn, offset8) - } - - #[inline(always)] - pub fn ldr_str_hs_common< - const HS: u8, - const LOAD: bool, - const WRITEBACK: bool, - const PRE_INDEX: bool, - const ADD: bool, - >( - &mut self, - insn: u32, - offset: u32, - ) -> CpuAction { - let mut result = CpuAction::AdvancePC(NonSeq); - - let offset = if ADD { - offset - } else { - (-(offset as i32)) as u32 - }; - let base_reg = insn.bit_range(16..20) as usize; - let dest_reg = insn.bit_range(12..16) as usize; - let mut addr = self.get_reg(base_reg); - if base_reg == REG_PC { - addr = self.pc_arm() + 8; // prefetching - } - - // TODO - confirm this - let old_mode = self.cpsr.mode(); - if !PRE_INDEX && WRITEBACK { - self.change_mode(old_mode, CpuMode::User); - } - - let effective_addr = (addr as i32).wrapping_add(offset as i32) as Addr; - addr = if PRE_INDEX { effective_addr } else { addr }; - - let transfer_type = ArmHalfwordTransferType::from_u8(HS).unwrap(); - - if LOAD { - let data = match transfer_type { - ArmHalfwordTransferType::SignedByte => self.load_8(addr, NonSeq) as u32, - ArmHalfwordTransferType::SignedHalfwords => self.ldr_sign_half(addr, NonSeq), - ArmHalfwordTransferType::UnsignedHalfwords => self.ldr_half(addr, NonSeq), - }; - - self.set_reg(dest_reg, data); - - // +1I - self.idle_cycle(); - - if dest_reg == REG_PC { - self.reload_pipeline32(); - result = CpuAction::PipelineFlushed; - } - } else { - let value = if dest_reg == REG_PC { - self.pc_arm() + 12 - } else { - self.get_reg(dest_reg) - }; - - match transfer_type { - ArmHalfwordTransferType::UnsignedHalfwords => { - self.store_aligned_16(addr, value as u16, NonSeq); - } - _ => panic!("invalid HS flags for L=0"), - }; - } - - if (!LOAD || base_reg != dest_reg) && (!PRE_INDEX || WRITEBACK) { - self.set_reg(base_reg, effective_addr); - } - - result - } - - pub fn exec_arm_ldm_stm< - const LOAD: bool, - const WRITEBACK: bool, - const FLAG_S: bool, - const ADD: bool, - const PRE_INDEX: bool, - >( - &mut self, - insn: u32, - ) -> CpuAction { - let mut result = CpuAction::AdvancePC(NonSeq); - - let mut full = PRE_INDEX; - let ascending = ADD; - let mut writeback = WRITEBACK; - let base_reg = insn.bit_range(16..20) as usize; - let mut base_addr = self.get_reg(base_reg); - - let rlist = insn.register_list(); - - if FLAG_S { - match self.cpsr.mode() { - CpuMode::User | CpuMode::System => { - panic!("LDM/STM with S bit in unprivileged mode") - } - _ => {} - }; - } - - let user_bank_transfer = if FLAG_S { - if LOAD { - !rlist.bit(REG_PC) - } else { - true - } - } else { - false - }; - - let old_mode = self.cpsr.mode(); - if user_bank_transfer { - self.change_mode(old_mode, CpuMode::User); - } - - let psr_transfer = FLAG_S & LOAD & rlist.bit(REG_PC); - - let rlist_count = rlist.count_ones(); - - let old_base = base_addr; - - if rlist != 0 && !ascending { - base_addr = base_addr.wrapping_sub(rlist_count * 4); - if writeback { - self.set_reg(base_reg, base_addr); - writeback = false; - } - full = !full; - } - - let mut addr = base_addr; - - if rlist != 0 { - if LOAD { - let mut access = NonSeq; - for r in 0..16 { - if rlist.bit(r) { - if r == base_reg { - writeback = false; - } - if full { - addr = addr.wrapping_add(4); - } - let val = self.load_32(addr, access); - access = Seq; - self.set_reg(r, val); - if r == REG_PC { - if psr_transfer { - self.transfer_spsr_mode(); - } - self.reload_pipeline32(); - result = CpuAction::PipelineFlushed; - } - if !full { - addr = addr.wrapping_add(4); - } - } - } - self.idle_cycle(); - } else { - let mut first = true; - let mut access = NonSeq; - for r in 0..16 { - if rlist.bit(r) { - let val = if r != base_reg { - if r == REG_PC { - self.pc_arm() + 12 - } else { - self.get_reg(r) - } - } else if first { - old_base - } else { - let x = rlist_count * 4; - if ascending { - old_base + x - } else { - old_base - x - } - }; - - if full { - addr = addr.wrapping_add(4); - } - - first = false; - - self.store_aligned_32(addr, val, access); - access = Seq; - if !full { - addr = addr.wrapping_add(4); - } - } - } - } - } else { - if LOAD { - let val = self.ldr_word(addr, NonSeq); - self.set_reg(REG_PC, val & !3); - self.reload_pipeline32(); - result = CpuAction::PipelineFlushed; - } else { - // block data store with empty rlist - let addr = match (ascending, full) { - (false, false) => addr.wrapping_sub(0x3c), - (false, true) => addr.wrapping_sub(0x40), - (true, false) => addr, - (true, true) => addr.wrapping_add(4), - }; - self.store_aligned_32(addr, self.pc + 4, NonSeq); - } - addr = if ascending { - addr.wrapping_add(0x40) - } else { - addr.wrapping_sub(0x40) - }; - } - - if user_bank_transfer { - self.change_mode(self.cpsr.mode(), old_mode); - } - - if writeback { - self.set_reg(base_reg, addr); - } - - result - } - - /// Multiply and Multiply-Accumulate (MUL, MLA) - /// Execution Time: 1S+mI for MUL, and 1S+(m+1)I for MLA. - pub fn exec_arm_mul_mla( - &mut self, - insn: u32, - ) -> CpuAction { - let rd = insn.bit_range(16..20) as usize; - let rn = insn.bit_range(12..16) as usize; - let rs = insn.bit_range(8..12) as usize; - let rm = insn.bit_range(0..4) as usize; - - // // check validity - // 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); - let mut result = op1.wrapping_mul(op2); - - if ACCUMULATE { - result = result.wrapping_add(self.get_reg(rn)); - self.idle_cycle(); - } - - self.set_reg(rd, result); - - let m = self.get_required_multipiler_array_cycles(op2); - for _ in 0..m { - self.idle_cycle(); - } - - if UPDATE_FLAGS { - self.cpsr.set_N((result as i32) < 0); - self.cpsr.set_Z(result == 0); - self.cpsr.set_C(false); - self.cpsr.set_V(false); - } - - CpuAction::AdvancePC(Seq) - } - - /// Multiply Long and Multiply-Accumulate Long (MULL, MLAL) - /// Execution Time: 1S+(m+1)I for MULL, and 1S+(m+2)I for MLAL - pub fn exec_arm_mull_mlal< - const UPDATE_FLAGS: bool, - const ACCUMULATE: bool, - const U_FLAG: bool, - >( - &mut self, - insn: u32, - ) -> CpuAction { - let rd_hi = insn.rd_hi(); - let rd_lo = insn.rd_lo(); - let rs = insn.rs(); - let rm = insn.rm(); - - let op1 = self.get_reg(rm); - let op2 = self.get_reg(rs); - let mut result: u64 = if U_FLAG { - // signed - (op1 as i32 as i64).wrapping_mul(op2 as i32 as i64) as u64 - } else { - (op1 as u64).wrapping_mul(op2 as u64) - }; - if ACCUMULATE { - let hi = self.get_reg(rd_hi) as u64; - let lo = self.get_reg(rd_lo) as u64; - result = result.wrapping_add(hi << 32 | lo); - self.idle_cycle(); - } - self.set_reg(rd_hi, (result >> 32) as i32 as u32); - self.set_reg(rd_lo, (result & 0xffffffff) as i32 as u32); - self.idle_cycle(); - let m = self.get_required_multipiler_array_cycles(self.get_reg(rs)); - for _ in 0..m { - self.idle_cycle(); - } - - if UPDATE_FLAGS { - self.cpsr.set_N(result.bit(63)); - self.cpsr.set_Z(result == 0); - self.cpsr.set_C(false); - self.cpsr.set_V(false); - } - - CpuAction::AdvancePC(Seq) - } - - /// ARM Opcodes: Memory: Single Data Swap (SWP) - /// Execution Time: 1S+2N+1I. That is, 2N data cycles, 1S code cycle, plus 1I. - pub fn exec_arm_swp(&mut self, insn: u32) -> CpuAction { - let base_addr = self.get_reg(insn.bit_range(16..20) as usize); - let rd = insn.bit_range(12..16) as usize; - if BYTE { - let t = self.load_8(base_addr, NonSeq); - self.store_8(base_addr, self.get_reg(insn.rm()) as u8, Seq); - self.set_reg(rd, t as u32); - } else { - let t = self.ldr_word(base_addr, NonSeq); - self.store_aligned_32(base_addr, self.get_reg(insn.rm()), Seq); - self.set_reg(rd, t); - } - self.idle_cycle(); - - CpuAction::AdvancePC(NonSeq) - } - - /// ARM Software Interrupt - /// Execution Time: 2S+1N - pub fn exec_arm_swi(&mut self, insn: u32) -> CpuAction { - self.software_interrupt(self.pc - 4, insn.swi_comment()); // Implies 2S + 1N - CpuAction::PipelineFlushed - } -} diff --git a/a/src/arm/mod.rs b/a/src/arm/mod.rs deleted file mode 100644 index f3a08df..0000000 --- a/a/src/arm/mod.rs +++ /dev/null @@ -1,604 +0,0 @@ -#[cfg(feature = "debugger")] -pub mod disass; -pub mod exec; - -use serde::{Deserialize, Serialize}; - -use super::alu::*; -use super::memory::Addr; -use super::InstructionDecoder; - -use bit::BitIndex; -use byteorder::{LittleEndian, ReadBytesExt}; -use num::FromPrimitive; - -use std::io; - -#[derive(Debug, PartialEq, Eq)] -pub enum ArmDecodeErrorKind { - UnknownInstructionFormat, - DecodedPartDoesNotBelongToInstruction, - UndefinedConditionCode(u32), - InvalidShiftType(u32), - InvalidHSBits(u32), - IoError(io::ErrorKind), -} - -#[derive(Debug, PartialEq, Eq)] -pub struct ArmDecodeError { - pub kind: ArmDecodeErrorKind, - pub insn: u32, - pub addr: Addr, -} - -#[allow(dead_code)] -impl ArmDecodeError { - fn new(kind: ArmDecodeErrorKind, insn: u32, addr: Addr) -> ArmDecodeError { - ArmDecodeError { kind, insn, addr } - } -} - -#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Primitive)] -pub enum ArmCond { - EQ = 0b0000, - NE = 0b0001, - HS = 0b0010, - LO = 0b0011, - MI = 0b0100, - PL = 0b0101, - VS = 0b0110, - VC = 0b0111, - HI = 0b1000, - LS = 0b1001, - GE = 0b1010, - LT = 0b1011, - GT = 0b1100, - LE = 0b1101, - AL = 0b1110, - Invalid = 0b1111, -} - -#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)] -pub enum ArmFormat { - BranchExchange = 0, - BranchLink, - SoftwareInterrupt, - Multiply, - MultiplyLong, - SingleDataTransfer, - HalfwordDataTransferRegOffset, - HalfwordDataTransferImmediateOffset, - DataProcessing, - BlockDataTransfer, - SingleDataSwap, - /// Transfer PSR contents to a register - MoveFromStatus, - /// Transfer register contents to PSR - MoveToStatus, - /// Tanssfer immediate/register to PSR flags only - MoveToFlags, - - Undefined, -} - -impl From for ArmFormat { - fn from(raw: u32) -> ArmFormat { - use ArmFormat::*; - if (0x0fff_fff0 & raw) == 0x012f_ff10 { - BranchExchange - } else if (0x0E00_0000 & raw) == 0x0A00_0000 { - BranchLink - } else if (0x0E00_0010 & raw) == 0x0600_0000 { - Undefined - } else if (0x0FB0_0FF0 & raw) == 0x0100_0090 { - SingleDataSwap - } else if (0x0FC0_00F0 & raw) == 0x0000_0090 { - Multiply - } else if (0x0F80_00F0 & raw) == 0x0080_0090 { - MultiplyLong - } else if (0x0FBF_0FFF & raw) == 0x010F_0000 { - MoveFromStatus - } else if (0x0FBF_FFF0 & raw) == 0x0129_F000 { - MoveToStatus - } else if (0x0DBF_F000 & raw) == 0x0128_F000 { - MoveToFlags - } else if (0x0C00_0000 & raw) == 0x0400_0000 { - SingleDataTransfer - } else if (0x0E40_0F90 & raw) == 0x0000_0090 { - HalfwordDataTransferRegOffset - } else if (0x0E40_0090 & raw) == 0x0040_0090 { - HalfwordDataTransferImmediateOffset - } else if (0x0E00_0000 & raw) == 0x0800_0000 { - BlockDataTransfer - } else if (0x0F00_0000 & raw) == 0x0F00_0000 { - SoftwareInterrupt - } else if (0x0C00_0000 & raw) == 0x0000_0000 { - DataProcessing - } else { - Undefined - } - } -} - -#[derive(Debug, PartialEq, Eq, Primitive)] -pub enum ArmHalfwordTransferType { - UnsignedHalfwords = 0b01, - SignedByte = 0b10, - SignedHalfwords = 0b11, -} - -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] -pub struct ArmInstruction { - pub fmt: ArmFormat, - pub raw: u32, - pub pc: Addr, -} - -impl ArmInstruction { - pub fn new(raw: u32, pc: Addr, fmt: ArmFormat) -> ArmInstruction { - ArmInstruction { fmt, raw, pc } - } -} - -impl InstructionDecoder for ArmInstruction { - type IntType = u32; - - fn decode(raw: u32, addr: Addr) -> Self { - let fmt = ArmFormat::from(raw); - - ArmInstruction { fmt, raw, pc: addr } - } - - fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Self { - let mut rdr = std::io::Cursor::new(bytes); - let raw = rdr.read_u32::().unwrap(); - Self::decode(raw, addr) - } - - fn get_raw(&self) -> u32 { - self.raw - } -} - -pub trait ArmDecodeHelper { - fn cond(&self) -> ArmCond; - - fn rm(&self) -> usize; - - fn rs(&self) -> usize; - - fn rd_lo(&self) -> usize; - - fn rd_hi(&self) -> usize; - - fn opcode(&self) -> AluOpCode; - - fn branch_offset(&self) -> i32; - - fn load_flag(&self) -> bool; - - fn set_cond_flag(&self) -> bool; - - fn write_back_flag(&self) -> bool; - - fn accumulate_flag(&self) -> bool; - - fn u_flag(&self) -> bool; - - fn halfword_data_transfer_type(&self) -> ArmHalfwordTransferType; - - fn transfer_size(&self) -> usize; - - fn psr_and_force_user_flag(&self) -> bool; - - fn spsr_flag(&self) -> bool; - - fn add_offset_flag(&self) -> bool; - - fn pre_index_flag(&self) -> bool; - - fn link_flag(&self) -> bool; - - /// gets offset used by ldr/str instructions - fn ldr_str_offset(&self) -> BarrelShifterValue; - - fn get_bs_op(&self) -> BarrelShiftOpCode; - - fn get_shift_reg_by(&self) -> ShiftRegisterBy; - - fn ldr_str_hs_imm_offset(&self) -> BarrelShifterValue; - - fn ldr_str_hs_reg_offset(&self) -> BarrelShifterValue; - - fn operand2(&self) -> BarrelShifterValue; - - fn register_list(&self) -> u16; - - fn swi_comment(&self) -> u32; -} - -macro_rules! arm_decode_helper_impl { - ($($t:ty),*) => {$( - - impl ArmDecodeHelper for $t { - #[inline(always)] - fn cond(&self) -> ArmCond { - ArmCond::from_u32(self.bit_range(28..32)).unwrap() - } - - #[inline(always)] - fn rm(&self) -> usize { - self.bit_range(0..4) as usize - } - - #[inline(always)] - fn rs(&self) -> usize { - self.bit_range(8..12) as usize - } - - #[inline(always)] - fn rd_lo(&self) -> usize { - self.bit_range(12..16) as usize - } - - #[inline(always)] - fn rd_hi(&self) -> usize { - self.bit_range(16..20) as usize - } - - #[inline(always)] - fn opcode(&self) -> AluOpCode { - use std::hint::unreachable_unchecked; - - unsafe { - if let Some(opc) = AluOpCode::from_u16(self.bit_range(21..25) as u16) { - opc - } else { - unreachable_unchecked() - } - } - } - - #[inline(always)] - fn branch_offset(&self) -> i32 { - ((self.bit_range(0..24) << 8) as i32) >> 6 - } - - #[inline(always)] - fn load_flag(&self) -> bool { - self.bit(20) - } - - #[inline(always)] - fn set_cond_flag(&self) -> bool { - self.bit(20) - } - - #[inline(always)] - fn write_back_flag(&self) -> bool { - self.bit(21) - } - - #[inline(always)] - fn accumulate_flag(&self) -> bool { - self.bit(21) - } - - #[inline(always)] - fn u_flag(&self) -> bool { - self.bit(22) - } - - #[inline(always)] - fn halfword_data_transfer_type(&self) -> ArmHalfwordTransferType { - let bits = (*self & 0b1100000) >> 5; - ArmHalfwordTransferType::from_u32(bits).unwrap() - } - - #[inline(always)] - fn transfer_size(&self) -> usize { - if self.bit(22) { - 1 - } else { - 4 - } - } - - #[inline(always)] - fn psr_and_force_user_flag(&self) -> bool { - self.bit(22) - } - - #[inline(always)] - fn spsr_flag(&self) -> bool { - self.bit(22) - } - - #[inline(always)] - fn add_offset_flag(&self) -> bool { - self.bit(23) - } - - #[inline(always)] - fn pre_index_flag(&self) -> bool { - self.bit(24) - } - - #[inline(always)] - fn link_flag(&self) -> bool { - self.bit(24) - } - - /// gets offset used by ldr/str instructions - #[inline(always)] - fn ldr_str_offset(&self) -> BarrelShifterValue { - let ofs = self.bit_range(0..12); - if self.bit(25) { - let rm = ofs & 0xf; - BarrelShifterValue::ShiftedRegister(ShiftedRegister { - reg: rm as usize, - shift_by: self.get_shift_reg_by(), - bs_op: self.get_bs_op(), - added: Some(self.add_offset_flag()), - }) - } else { - let ofs = if self.add_offset_flag() { - ofs as u32 - } else { - -(ofs as i32) as u32 - }; - BarrelShifterValue::ImmediateValue(ofs) - } - } - - #[inline(always)] - fn get_bs_op(&self) -> BarrelShiftOpCode { - BarrelShiftOpCode::from_u8(self.bit_range(5..7) as u8).unwrap() - } - - #[inline(always)] - fn get_shift_reg_by(&self) -> ShiftRegisterBy { - if self.bit(4) { - let rs = self.bit_range(8..12) as usize; - ShiftRegisterBy::ByRegister(rs) - } else { - let amount = self.bit_range(7..12) as u32; - ShiftRegisterBy::ByAmount(amount) - } - } - - #[inline(always)] - fn ldr_str_hs_imm_offset(&self) -> BarrelShifterValue { - let offset8 = (self.bit_range(8..12) << 4) + self.bit_range(0..4); - let offset8 = if self.add_offset_flag() { - offset8 - } else { - (-(offset8 as i32)) as u32 - }; - BarrelShifterValue::ImmediateValue(offset8) - } - - #[inline(always)] - fn ldr_str_hs_reg_offset(&self) -> BarrelShifterValue { - BarrelShifterValue::ShiftedRegister( - ShiftedRegister { - reg: (self & 0xf) as usize, - shift_by: ShiftRegisterBy::ByAmount(0), - bs_op: BarrelShiftOpCode::LSL, - added: Some(self.add_offset_flag()), - }) - } - - fn operand2(&self) -> BarrelShifterValue { - if self.bit(25) { - let immediate = self & 0xff; - let rotate = 2 * self.bit_range(8..12); - BarrelShifterValue::RotatedImmediate(immediate, rotate) - } else { - let reg = self & 0xf; - let shifted_reg = ShiftedRegister { - reg: reg as usize, - bs_op: self.get_bs_op(), - shift_by: self.get_shift_reg_by(), - added: None, - }; // TODO error handling - BarrelShifterValue::ShiftedRegister(shifted_reg) - } - } - - fn register_list(&self) -> u16 { - (self & 0xffff) as u16 - } - - fn swi_comment(&self) -> u32 { - self.bit_range(0..24) - } - } - )*} - -} - -arm_decode_helper_impl!(u32); - -// #[cfg(test)] -// /// All instructions constants were generated using an ARM assembler. -// mod tests { -// use super::*; -// use crate::arm7tdmi::*; -// use crate::sysbus::BoxedMemory; - -// #[test] -// fn swi() { -// let mut core = Core::new(); - -// let bytes = vec![]; -// let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); - -// // swi #0x1337 -// let decoded = ArmInstruction::decode(0xef001337, 0).unwrap(); -// assert_eq!(decoded.fmt, ArmFormat::SoftwareInterrupt); -// assert_eq!(decoded.swi_comment(), 0x1337); -// assert_eq!(format!("{}", decoded), "swi\t#0x1337"); - -// core.exec_arm(&mut mem, decoded).unwrap(); -// assert_eq!(core.did_pipeline_flush(), true); - -// assert_eq!(core.cpsr.mode(), CpuMode::Supervisor); -// assert_eq!(core.pc, Exception::SoftwareInterrupt as u32); -// } - -// #[test] -// fn branch_forwards() { -// // 0x20: b 0x30 -// let decoded = ArmInstruction::decode(0xea_00_00_02, 0x20).unwrap(); -// assert_eq!(decoded.fmt, ArmFormat::BranchLink); -// assert_eq!(decoded.link_flag(), false); -// assert_eq!( -// (decoded.pc as i32).wrapping_add(decoded.branch_offset()) + 8, -// 0x30 -// ); -// assert_eq!(format!("{}", decoded), "b\t0x30"); - -// let mut core = Core::new(); -// core.pc = 0x20 + 8; - -// let bytes = vec![]; -// let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); - -// core.exec_arm(&mut mem, decoded).unwrap(); -// assert_eq!(core.did_pipeline_flush(), true); -// assert_eq!(core.pc, 0x30); -// } - -// #[test] -// fn branch_link_backwards() { -// // 0x20: bl 0x10 -// let decoded = ArmInstruction::decode(0xeb_ff_ff_fa, 0x20).unwrap(); -// assert_eq!(decoded.fmt, ArmFormat::BranchLink); -// assert_eq!(decoded.link_flag(), true); -// assert_eq!( -// (decoded.pc as i32).wrapping_add(decoded.branch_offset()) + 8, -// 0x10 -// ); -// assert_eq!(format!("{}", decoded), "bl\t0x10"); - -// let mut core = Core::new(); -// core.pc = 0x20 + 8; - -// let bytes = vec![]; -// let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); - -// core.exec_arm(&mut mem, decoded).unwrap(); -// assert_eq!(core.did_pipeline_flush(), true); -// assert_eq!(core.pc, 0x10); -// } - -// #[test] -// fn ldr_pre_index() { -// // ldreq r2, [r5, -r6, lsl #5] -// let decoded = ArmInstruction::decode(0x07_15_22_86, 0).unwrap(); -// assert_eq!(decoded.fmt, ArmFormat::SingleDataTransfer); -// assert_eq!(decoded.cond, ArmCond::EQ); -// assert_eq!(decoded.load_flag(), true); -// assert_eq!(decoded.pre_index_flag(), true); -// assert_eq!(decoded.write_back_flag(), false); -// assert_eq!(decoded.rd(), 2); -// assert_eq!(decoded.rn(), 5); -// assert_eq!( -// decoded.ldr_str_offset(), -// BarrelShifterValue::ShiftedRegister(ShiftedRegister { -// reg: 6, -// shift_by: ShiftRegisterBy::ByAmount(5), -// bs_op: BarrelShiftOpCode::LSL, -// added: Some(false) -// }) -// ); - -// assert_eq!(format!("{}", decoded), "ldreq\tr2, [r5, -r6, lsl #5]"); - -// let mut core = Core::new(); -// core.cpsr.set_Z(true); -// core.gpr[5] = 0x34; -// core.gpr[6] = 1; -// core.gpr[2] = 0; - -// #[rustfmt::skip] -// let bytes = vec![ -// /* 00h: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -// /* 10h: */ 0x00, 0x00, 0x00, 0x00, 0x37, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -// /* 20h: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -// /* 30h: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -// ]; -// let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); - -// core.exec_arm(&mut mem, decoded).unwrap(); -// assert_eq!(core.gpr[2], 0x1337); -// } - -// #[test] -// fn str_post_index() { -// // strteq r2, [r4], -r7, asr #8 -// let decoded = ArmInstruction::decode(0x06_24_24_47, 0).unwrap(); -// assert_eq!(decoded.fmt, ArmFormat::SingleDataTransfer); -// assert_eq!(decoded.cond, ArmCond::EQ); -// assert_eq!(decoded.load_flag(), false); -// assert_eq!(decoded.pre_index_flag(), false); -// assert_eq!(decoded.write_back_flag(), true); -// assert_eq!(decoded.rd(), 2); -// assert_eq!(decoded.rn(), 4); -// assert_eq!( -// decoded.ldr_str_offset(), -// BarrelShifterValue::ShiftedRegister(ShiftedRegister { -// reg: 7, -// shift_by: ShiftRegisterBy::ByAmount(8), -// bs_op: BarrelShiftOpCode::ASR, -// added: Some(false) -// }) -// ); -// assert_eq!(format!("{}", decoded), "strteq\tr2, [r4], -r7, asr #8"); - -// let mut core = Core::new(); -// core.cpsr.set_Z(true); -// core.gpr[4] = 0x0; -// core.gpr[7] = 1; -// core.gpr[2] = 0xabababab; - -// #[rustfmt::skip] -// let bytes = vec![ -// /* 00h: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -// /* 10h: */ 0x00, 0x00, 0x00, 0x00, 0x37, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -// /* 20h: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -// /* 30h: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -// ]; -// let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); - -// core.exec_arm(&mut mem, decoded).unwrap(); -// assert_eq!(mem.read_32(0), 0xabababab); -// } - -// #[test] -// fn str_pre_index() { -// // str r4, [sp, 0x10] -// let decoded = ArmInstruction::decode(0xe58d4010, 0).unwrap(); -// assert_eq!(decoded.fmt, ArmFormat::SingleDataTransfer); -// assert_eq!(decoded.cond, ArmCond::AL); - -// let mut core = Core::new(); -// core.set_reg(4, 0x12345678); -// core.set_reg(REG_SP, 0); - -// #[rustfmt::skip] -// let bytes = vec![ -// /* 0: */ 0xaa, 0xbb, 0xcc, 0xdd, -// /* 4: */ 0xaa, 0xbb, 0xcc, 0xdd, -// /* 8: */ 0xaa, 0xbb, 0xcc, 0xdd, -// /* c: */ 0xaa, 0xbb, 0xcc, 0xdd, -// /* 10: */ 0xaa, 0xbb, 0xcc, 0xdd, -// ]; -// let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); - -// assert_ne!(mem.read_32(core.get_reg(REG_SP) + 0x10), 0x12345678); -// core.exec_arm(&mut mem, decoded).unwrap(); -// assert_eq!(mem.read_32(core.get_reg(REG_SP) + 0x10), 0x12345678); -// } -// } diff --git a/a/src/cpu.rs b/a/src/cpu.rs deleted file mode 100644 index 3f4a1d8..0000000 --- a/a/src/cpu.rs +++ /dev/null @@ -1,566 +0,0 @@ -use std::fmt; - -use ansi_term::Style; -use bit::BitIndex; -use log::debug; -use num::FromPrimitive; -use serde::{Deserialize, Serialize}; - -use rustboyadvance_utils::{Shared, WeakPointer}; - -pub use super::exception::Exception; -use super::reg_string; - -use super::{arm::ArmCond, psr::RegPSR, Addr, CpuMode, CpuState}; - -use super::memory::{MemoryAccess, MemoryInterface}; -use MemoryAccess::*; - -use cfg_if::cfg_if; - -#[cfg(feature = "debugger")] -use super::thumb::ThumbFormat; - -#[cfg(feature = "debugger")] -use super::arm::ArmFormat; - -#[cfg_attr(not(feature = "debugger"), repr(transparent))] -pub struct ThumbInstructionInfo { - pub handler_fn: fn(&mut Arm7tdmiCore, insn: u16) -> CpuAction, - #[cfg(feature = "debugger")] - pub fmt: ThumbFormat, -} - -#[cfg_attr(not(feature = "debugger"), repr(transparent))] -pub struct ArmInstructionInfo { - pub handler_fn: fn(&mut Arm7tdmiCore, insn: u32) -> CpuAction, - #[cfg(feature = "debugger")] - pub fmt: ArmFormat, -} - -cfg_if! { - if #[cfg(feature = "debugger")] { - use super::DecodedInstruction; - use super::arm::ArmInstruction; - use super::thumb::ThumbInstruction; - - } else { - - } -} - -pub enum CpuAction { - AdvancePC(MemoryAccess), - PipelineFlushed, -} - -#[derive(Serialize, Deserialize, Clone, Debug, Default)] -pub struct BankedRegisters { - // r13 and r14 are banked for all modes. System&User mode share them - pub gpr_banked_r13: [u32; 6], - pub gpr_banked_r14: [u32; 6], - // r8-r12 are banked for fiq mode - pub gpr_banked_old_r8_12: [u32; 5], - pub gpr_banked_fiq_r8_12: [u32; 5], - pub spsr_bank: [RegPSR; 6], -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct SavedCpuState { - pub pc: u32, - pub gpr: [u32; 15], - next_fetch_access: MemoryAccess, - pipeline: [u32; 2], - - pub cpsr: RegPSR, - pub(super) spsr: RegPSR, - - pub(super) banks: BankedRegisters, -} - -#[derive(Clone, Debug)] -#[cfg(feature = "debugger")] -pub struct DebuggerState { - pub last_executed: Option, - /// store the gpr before executing an instruction to show diff in the Display impl - pub gpr_previous: [u32; 15], - pub breakpoints: Vec, - pub verbose: bool, - pub trace_opcodes: bool, - pub trace_exceptions: bool, -} - -#[cfg(feature = "debugger")] -impl Default for DebuggerState { - fn default() -> DebuggerState { - DebuggerState { - last_executed: None, - gpr_previous: [0; 15], - breakpoints: Vec::new(), - verbose: false, - trace_opcodes: false, - trace_exceptions: false, - } - } -} - -#[derive(Clone)] -pub struct Arm7tdmiCore { - pub pc: u32, - pub bus: Shared, - - next_fetch_access: MemoryAccess, - pipeline: [u32; 2], - pub gpr: [u32; 15], - - pub cpsr: RegPSR, - pub spsr: RegPSR, - - pub banks: BankedRegisters, - - /// Hardware breakpoints for use by gdb - breakpoints: Vec, - - /// Deprecated in-house debugger state - #[cfg(feature = "debugger")] - pub dbg: DebuggerState, -} - -impl Arm7tdmiCore { - pub fn new(bus: Shared) -> Arm7tdmiCore { - let cpsr = RegPSR::new(0x0000_00D3); - Arm7tdmiCore { - bus, - pc: 0, - gpr: [0; 15], - pipeline: [0; 2], - next_fetch_access: MemoryAccess::NonSeq, - cpsr, - spsr: Default::default(), - banks: BankedRegisters::default(), - - breakpoints: Vec::new(), - - #[cfg(feature = "debugger")] - dbg: DebuggerState::default(), - } - } - - pub fn weak_ptr(&mut self) -> WeakPointer> { - WeakPointer::new(self as *mut Arm7tdmiCore) - } - - pub fn from_saved_state(bus: Shared, state: SavedCpuState) -> Arm7tdmiCore { - Arm7tdmiCore { - bus, - - pc: state.pc, - cpsr: state.cpsr, - gpr: state.gpr, - banks: state.banks, - spsr: state.spsr, - - pipeline: state.pipeline, - next_fetch_access: state.next_fetch_access, - - breakpoints: Vec::new(), // TODO include breakpoints in saved state - - // savestate does not keep debugger related information, so just reinitialize to default - #[cfg(feature = "debugger")] - dbg: DebuggerState::default(), - } - } - - pub fn save_state(&self) -> SavedCpuState { - SavedCpuState { - cpsr: self.cpsr, - pc: self.pc, - gpr: self.gpr, - spsr: self.spsr, - banks: self.banks.clone(), - pipeline: self.pipeline, - next_fetch_access: self.next_fetch_access, - } - } - - pub fn restore_state(&mut self, state: SavedCpuState) { - self.pc = state.pc; - self.cpsr = state.cpsr; - self.gpr = state.gpr; - self.spsr = state.spsr; - self.banks = state.banks; - self.pipeline = state.pipeline; - self.next_fetch_access = state.next_fetch_access; - } - - pub fn set_memory_interface(&mut self, i: Shared) { - self.bus = i; - } - - pub fn add_breakpoint(&mut self, addr: Addr) { - debug!("adding breakpoint {:08x}", addr); - self.breakpoints.push(addr); - } - - pub fn del_breakpoint(&mut self, addr: Addr) { - if let Some(pos) = self.breakpoints.iter().position(|x| *x == addr) { - debug!("deleting breakpoint {:08x}", addr); - self.breakpoints.remove(pos); - } - } - - pub fn check_breakpoint(&self) -> Option { - let next_pc = self.get_next_pc(); - for bp in &self.breakpoints { - if (*bp & !1) == next_pc { - return Some(*bp); - } - } - None - } - - #[cfg(feature = "debugger")] - pub fn set_verbose(&mut self, v: bool) { - self.dbg.verbose = v; - } - - pub fn get_reg(&self, r: usize) -> u32 { - match r { - 0..=14 => self.gpr[r], - 15 => self.pc, - _ => panic!("invalid register {}", r), - } - } - - #[inline] - /// Gets PC of the currently executed instruction in arm mode - pub fn pc_arm(&self) -> u32 { - self.pc.wrapping_sub(8) - } - - #[inline] - /// Gets PC of the currently executed instruction in thumb mode - pub fn pc_thumb(&self) -> u32 { - self.pc.wrapping_sub(4) - } - - pub fn get_reg_user(&mut self, r: usize) -> u32 { - match r { - 0..=7 => self.gpr[r], - 8..=12 => { - if self.cpsr.mode() == CpuMode::Fiq { - self.gpr[r] - } else { - self.banks.gpr_banked_old_r8_12[r - 8] - } - } - 13 => self.banks.gpr_banked_r13[0], - 14 => self.banks.gpr_banked_r14[0], - _ => panic!("invalid register"), - } - } - - pub fn set_reg(&mut self, r: usize, val: u32) { - match r { - 0..=14 => self.gpr[r] = val, - 15 => { - self.pc = { - match self.cpsr.state() { - CpuState::THUMB => val & !1, - CpuState::ARM => val & !3, - } - } - } - _ => panic!("invalid register"), - } - } - - pub fn set_reg_user(&mut self, r: usize, val: u32) { - match r { - 0..=7 => self.gpr[r] = val, - 8..=12 => { - if self.cpsr.mode() == CpuMode::Fiq { - self.gpr[r] = val; - } else { - self.banks.gpr_banked_old_r8_12[r - 8] = val; - } - } - 13 => { - self.banks.gpr_banked_r13[0] = val; - } - 14 => { - self.banks.gpr_banked_r14[0] = val; - } - _ => panic!("invalid register"), - } - } - - pub fn copy_registers(&self) -> [u32; 15] { - self.gpr - } - - pub(super) fn change_mode(&mut self, old_mode: CpuMode, new_mode: CpuMode) { - let new_index = new_mode.bank_index(); - let old_index = old_mode.bank_index(); - - if new_index == old_index { - return; - } - - let banks = &mut self.banks; - - banks.spsr_bank[old_index] = self.spsr; - banks.gpr_banked_r13[old_index] = self.gpr[13]; - banks.gpr_banked_r14[old_index] = self.gpr[14]; - - self.spsr = banks.spsr_bank[new_index]; - self.gpr[13] = banks.gpr_banked_r13[new_index]; - self.gpr[14] = banks.gpr_banked_r14[new_index]; - - if new_mode == CpuMode::Fiq { - for r in 0..5 { - banks.gpr_banked_old_r8_12[r] = self.gpr[r + 8]; - self.gpr[r + 8] = banks.gpr_banked_fiq_r8_12[r]; - } - } else if old_mode == CpuMode::Fiq { - for r in 0..5 { - banks.gpr_banked_fiq_r8_12[r] = self.gpr[r + 8]; - self.gpr[r + 8] = banks.gpr_banked_old_r8_12[r]; - } - } - self.cpsr.set_mode(new_mode); - } - - /// Resets the cpu - pub fn reset(&mut self) { - self.exception(Exception::Reset, 0); - } - - pub fn word_size(&self) -> usize { - match self.cpsr.state() { - CpuState::ARM => 4, - CpuState::THUMB => 2, - } - } - - pub(super) fn get_required_multipiler_array_cycles(&self, rs: u32) -> usize { - if rs & 0xff == rs { - 1 - } else if rs & 0xffff == rs { - 2 - } else if rs & 0xffffff == rs { - 3 - } else { - 4 - } - } - - #[inline(always)] - pub(super) fn check_arm_cond(&self, cond: ArmCond) -> bool { - use ArmCond::*; - match cond { - Invalid => { - // TODO - we would normally want to panic here - false - } - EQ => self.cpsr.Z(), - NE => !self.cpsr.Z(), - HS => self.cpsr.C(), - LO => !self.cpsr.C(), - MI => self.cpsr.N(), - PL => !self.cpsr.N(), - VS => self.cpsr.V(), - VC => !self.cpsr.V(), - HI => self.cpsr.C() && !self.cpsr.Z(), - LS => !self.cpsr.C() || self.cpsr.Z(), - GE => self.cpsr.N() == self.cpsr.V(), - LT => self.cpsr.N() != self.cpsr.V(), - GT => !self.cpsr.Z() && (self.cpsr.N() == self.cpsr.V()), - LE => self.cpsr.Z() || (self.cpsr.N() != self.cpsr.V()), - AL => true, - } - } - - #[cfg(feature = "debugger")] - fn debugger_record_step(&mut self, d: DecodedInstruction) { - self.dbg.gpr_previous = self.copy_registers(); - self.dbg.last_executed = Some(d); - } - - fn step_arm_exec(&mut self, insn: u32) -> CpuAction { - let hash = (((insn >> 16) & 0xff0) | ((insn >> 4) & 0xf)) as usize; - let arm_info = &Self::ARM_LUT[hash]; - #[cfg(feature = "debugger")] - self.debugger_record_step(DecodedInstruction::Arm(ArmInstruction::new( - insn, - self.pc.wrapping_sub(8), - arm_info.fmt, - ))); - (arm_info.handler_fn)(self, insn) - } - - fn step_thumb_exec(&mut self, insn: u16) -> CpuAction { - let thumb_info = &Self::THUMB_LUT[(insn >> 6) as usize]; - #[cfg(feature = "debugger")] - self.debugger_record_step(DecodedInstruction::Thumb(ThumbInstruction::new( - insn, - self.pc.wrapping_sub(4), - thumb_info.fmt, - ))); - (thumb_info.handler_fn)(self, insn) - } - - /// 2S + 1N - #[inline(always)] - pub fn reload_pipeline16(&mut self) { - self.pipeline[0] = self.load_16(self.pc, NonSeq) as u32; - self.advance_thumb(); - self.pipeline[1] = self.load_16(self.pc, Seq) as u32; - self.advance_thumb(); - self.next_fetch_access = Seq; - } - - /// 2S + 1N - #[inline(always)] - pub fn reload_pipeline32(&mut self) { - self.pipeline[0] = self.load_32(self.pc, NonSeq); - self.advance_arm(); - self.pipeline[1] = self.load_32(self.pc, Seq); - self.advance_arm(); - self.next_fetch_access = Seq; - } - - #[inline] - pub(super) fn advance_thumb(&mut self) { - self.pc = self.pc.wrapping_add(2) - } - - #[inline] - pub(super) fn advance_arm(&mut self) { - self.pc = self.pc.wrapping_add(4) - } - - #[inline] - pub fn get_decoded_opcode(&self) -> u32 { - self.pipeline[0] - } - - #[inline] - pub fn get_prefetched_opcode(&self) -> u32 { - self.pipeline[1] - } - - /// Perform a pipeline step - /// If an instruction was executed in this step, return it. - #[inline] - pub fn step(&mut self) { - match self.cpsr.state() { - CpuState::ARM => { - let pc = self.pc & !3; - - let fetched_now = self.load_32(pc, self.next_fetch_access); - let insn = self.pipeline[0]; - self.pipeline[0] = self.pipeline[1]; - self.pipeline[1] = fetched_now; - let cond = ArmCond::from_u8(insn.bit_range(28..32) as u8) - .unwrap_or_else(|| unsafe { std::hint::unreachable_unchecked() }); - if cond != ArmCond::AL && !self.check_arm_cond(cond) { - self.advance_arm(); - self.next_fetch_access = MemoryAccess::NonSeq; - return; - } - match self.step_arm_exec(insn) { - CpuAction::AdvancePC(access) => { - self.next_fetch_access = access; - self.advance_arm(); - } - CpuAction::PipelineFlushed => {} - } - } - CpuState::THUMB => { - let pc = self.pc & !1; - - let fetched_now = self.load_16(pc, self.next_fetch_access); - let insn = self.pipeline[0]; - self.pipeline[0] = self.pipeline[1]; - self.pipeline[1] = fetched_now as u32; - match self.step_thumb_exec(insn as u16) { - CpuAction::AdvancePC(access) => { - self.advance_thumb(); - self.next_fetch_access = access; - } - CpuAction::PipelineFlushed => {} - } - } - } - } - - /// Get's the address of the next instruction that is going to be executed - pub fn get_next_pc(&self) -> Addr { - let insn_size = self.word_size() as u32; - self.pc - 2 * insn_size - } - - pub fn get_cpu_state(&self) -> CpuState { - self.cpsr.state() - } -} - -impl fmt::Debug for Arm7tdmiCore { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "ARM7TDMI Core Status:")?; - writeln!(f, "\tCPSR: {}", self.cpsr)?; - writeln!(f, "\tGeneral Purpose Registers:")?; - let reg_normal_style = Style::new().bold(); - let gpr = self.copy_registers(); - for i in 0..15 { - let mut reg_name = reg_string(i).to_string(); - reg_name.make_ascii_uppercase(); - let entry = format!("\t{:-3} = 0x{:08x}", reg_name, gpr[i]); - write!( - f, - "{}{}", - reg_normal_style.paint(entry), - if (i + 1) % 4 == 0 { "\n" } else { "" } - )?; - } - let pc = format!("\tPC = 0x{:08x}", self.get_next_pc()); - writeln!(f, "{}", reg_normal_style.paint(pc)) - } -} - -#[cfg(feature = "debugger")] -impl fmt::Display for Core { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "ARM7TDMI Core Status:")?; - writeln!(f, "\tCPSR: {}", self.cpsr)?; - writeln!(f, "\tGeneral Purpose Registers:")?; - let reg_normal_style = Style::new().bold(); - let reg_dirty_style = Colour::Black.bold().on(Colour::Yellow); - let gpr = self.copy_registers(); - for i in 0..15 { - let mut reg_name = reg_string(i).to_string(); - reg_name.make_ascii_uppercase(); - - let style = if gpr[i] != self.dbg.gpr_previous[i] { - ®_dirty_style - } else { - ®_normal_style - }; - - let entry = format!("\t{:-3} = 0x{:08x}", reg_name, gpr[i]); - - write!( - f, - "{}{}", - style.paint(entry), - if (i + 1) % 4 == 0 { "\n" } else { "" } - )?; - } - let pc = format!("\tPC = 0x{:08x}", self.get_next_pc()); - writeln!(f, "{}", reg_normal_style.paint(pc)) - } -} - -include!(concat!(env!("OUT_DIR"), "/arm_lut.rs")); -include!(concat!(env!("OUT_DIR"), "/thumb_lut.rs")); diff --git a/a/src/disass.rs b/a/src/disass.rs deleted file mode 100644 index c7e85fe..0000000 --- a/a/src/disass.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::fmt; -use std::fmt::Write; -use std::marker::PhantomData; - -use super::Addr; -use super::InstructionDecoder; - -pub struct Disassembler<'a, D> -where - D: InstructionDecoder, -{ - base: Addr, - pos: usize, - bytes: &'a [u8], - pub word_size: usize, - instruction_decoder: PhantomData, -} - -impl<'a, D> Disassembler<'a, D> -where - D: InstructionDecoder, -{ - pub fn new(base: Addr, bytes: &'a [u8]) -> Disassembler<'_, D> { - Disassembler { - base: base as Addr, - pos: 0, - bytes, - word_size: std::mem::size_of::(), - instruction_decoder: PhantomData, - } - } -} - -impl<'a, D> Iterator for Disassembler<'a, D> -where - D: InstructionDecoder + fmt::Display, - ::IntType: std::fmt::LowerHex, -{ - type Item = (Addr, String); - - fn next(&mut self) -> Option { - let mut line = String::new(); - - let addr = self.base + self.pos as Addr; - let decoded: D = D::decode_from_bytes(&self.bytes[(self.pos)..], addr); - let decoded_raw = decoded.get_raw(); - self.pos += self.word_size; - write!(&mut line, "{addr:8x}:\t{decoded_raw:08x} \t{decoded}").unwrap(); - Some((self.pos as Addr, line)) - } -} diff --git a/a/src/exception.rs b/a/src/exception.rs deleted file mode 100644 index 30d316b..0000000 --- a/a/src/exception.rs +++ /dev/null @@ -1,72 +0,0 @@ -use super::memory::MemoryInterface; -use super::Arm7tdmiCore; -use super::{CpuMode, CpuState}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[allow(dead_code)] -/// Models a CPU exception, and maps to the relavnt entry in the exception vector -pub enum Exception { - Reset = 0x00, - UndefinedInstruction = 0x04, - SoftwareInterrupt = 0x08, - PrefatchAbort = 0x0c, - DataAbort = 0x10, - Reserved = 0x14, - Irq = 0x18, - Fiq = 0x1c, -} - -impl Arm7tdmiCore { - pub fn exception(&mut self, e: Exception, lr: u32) { - use Exception::*; - let (new_mode, irq_disable, fiq_disable) = match e { - Reset => (CpuMode::Supervisor, true, true), - UndefinedInstruction => (CpuMode::Undefined, false, false), - SoftwareInterrupt => (CpuMode::Supervisor, true, false), - DataAbort => (CpuMode::Abort, false, false), - PrefatchAbort => (CpuMode::Abort, false, false), - Reserved => panic!("Cpu reserved exception"), - Irq => (CpuMode::Irq, true, false), - Fiq => (CpuMode::Fiq, true, true), - }; - - #[cfg(feature = "debugger")] - { - if self.dbg.trace_exceptions { - trace!("exception {:?} lr={:x} new_mode={:?}", e, lr, new_mode); - } - } - - let new_bank = new_mode.bank_index(); - self.banks.spsr_bank[new_bank] = self.cpsr; - self.banks.gpr_banked_r14[new_bank] = lr; - self.change_mode(self.cpsr.mode(), new_mode); - - // Set appropriate CPSR bits - self.cpsr.set_state(CpuState::ARM); - self.cpsr.set_mode(new_mode); - if irq_disable { - self.cpsr.set_irq_disabled(true); - } - if fiq_disable { - self.cpsr.set_fiq_disabled(true); - } - - // Set PC to vector address - self.pc = e as u32; - self.reload_pipeline32(); - } - - #[inline] - pub fn irq(&mut self) { - if !self.cpsr.irq_disabled() { - let lr = self.get_next_pc() + 4; - self.exception(Exception::Irq, lr); - } - } - - #[inline] - pub fn software_interrupt(&mut self, lr: u32, _cmt: u32) { - self.exception(Exception::SoftwareInterrupt, lr); - } -} diff --git a/a/src/gdb/breakpoints.rs b/a/src/gdb/breakpoints.rs deleted file mode 100644 index 4fd896b..0000000 --- a/a/src/gdb/breakpoints.rs +++ /dev/null @@ -1,36 +0,0 @@ -use gdbstub::target; -use gdbstub::target::TargetResult; - -use crate::Arm7tdmiCore; - -use super::target::MemoryGdbInterface; - -impl target::ext::breakpoints::Breakpoints for Arm7tdmiCore { - // there are several kinds of breakpoints - this target uses software breakpoints - #[inline(always)] - fn support_sw_breakpoint( - &mut self, - ) -> Option> { - Some(self) - } -} - -impl target::ext::breakpoints::SwBreakpoint for Arm7tdmiCore { - fn add_sw_breakpoint( - &mut self, - addr: u32, - _kind: gdbstub_arch::arm::ArmBreakpointKind, - ) -> TargetResult { - self.add_breakpoint(addr); - Ok(true) - } - - fn remove_sw_breakpoint( - &mut self, - addr: u32, - _kind: gdbstub_arch::arm::ArmBreakpointKind, - ) -> TargetResult { - self.del_breakpoint(addr); - Ok(true) - } -} diff --git a/a/src/gdb/mod.rs b/a/src/gdb/mod.rs deleted file mode 100644 index fd0743d..0000000 --- a/a/src/gdb/mod.rs +++ /dev/null @@ -1,50 +0,0 @@ -use std::io; -use std::net::{TcpListener, TcpStream}; - -use log::info; - -mod breakpoints; -pub mod target; - -// Re-export the gdbstub crate -pub extern crate gdbstub; -pub extern crate gdbstub_arch; - -/// Wait for tcp connection on port -pub fn wait_for_connection(port: u16) -> io::Result { - let bind_addr = format!("0.0.0.0:{port}"); - info!("waiting for connection on {:?}", bind_addr); - - let sock = TcpListener::bind(bind_addr)?; - - // Blocks until a GDB client connects via TCP. - // i.e: Running `target remote localhost:` from the GDB prompt. - let (stream, addr) = sock.accept()?; - - info!("gdb connected from {:?}", addr); - - Ok(stream) -} - -/// Copy all bytes of `data` to `buf`. -/// Return the size of data copied. -pub fn copy_to_buf(data: &[u8], buf: &mut [u8]) -> usize { - let len = buf.len().min(data.len()); - buf[..len].copy_from_slice(&data[..len]); - len -} - -/// Copy a range of `data` (start at `offset` with a size of `length`) to `buf`. -/// Return the size of data copied. Returns 0 if `offset >= buf.len()`. -/// -/// Mainly used by qXfer:_object_:read commands. -pub fn copy_range_to_buf(data: &[u8], offset: u64, length: usize, buf: &mut [u8]) -> usize { - let offset = offset as usize; - if offset > data.len() { - return 0; - } - - let start = offset; - let end = (offset + length).min(data.len()); - copy_to_buf(&data[start..end], buf) -} diff --git a/a/src/gdb/target.rs b/a/src/gdb/target.rs deleted file mode 100644 index 0b0885c..0000000 --- a/a/src/gdb/target.rs +++ /dev/null @@ -1,113 +0,0 @@ -/// Implementing the Target trait for gdbstub -use gdbstub::common::Signal; -use gdbstub::target::ext::base::singlethread::{ - SingleThreadBase, SingleThreadResume, SingleThreadSingleStep, -}; -use gdbstub::target::ext::base::singlethread::{SingleThreadResumeOps, SingleThreadSingleStepOps}; -use gdbstub::target::ext::base::BaseOps; -use gdbstub::target::ext::breakpoints::BreakpointsOps; -use gdbstub::target::{self, Target, TargetError, TargetResult}; - -use crate::memory::{DebugRead, MemoryInterface}; -use crate::registers_consts::*; -use crate::Arm7tdmiCore; - -pub trait MemoryGdbInterface: MemoryInterface + DebugRead { - fn memory_map_xml(&self, offset: u64, length: usize, buf: &mut [u8]) -> usize; -} - -impl Target for Arm7tdmiCore { - type Error = (); - type Arch = gdbstub_arch::arm::Armv4t; - - #[inline(always)] - fn base_ops(&mut self) -> BaseOps { - BaseOps::SingleThread(self) - } - - // opt-in to support for setting/removing breakpoints - #[inline(always)] - fn support_breakpoints(&mut self) -> Option> { - Some(self) - } - - fn support_memory_map(&mut self) -> Option> { - Some(self) - } -} - -impl SingleThreadBase for Arm7tdmiCore { - fn read_registers( - &mut self, - regs: &mut gdbstub_arch::arm::reg::ArmCoreRegs, - ) -> TargetResult<(), Self> { - regs.pc = self.get_next_pc(); - regs.lr = self.get_reg(REG_LR); - regs.sp = self.get_reg(REG_SP); - regs.r[..].copy_from_slice(&self.gpr[..13]); - regs.cpsr = self.cpsr.get(); - Ok(()) - } - - fn write_registers( - &mut self, - regs: &gdbstub_arch::arm::reg::ArmCoreRegs, - ) -> TargetResult<(), Self> { - self.set_reg(REG_PC, regs.pc); - self.set_reg(REG_LR, regs.lr); - self.set_reg(REG_SP, regs.sp); - self.gpr[..13].copy_from_slice(®s.r); - self.cpsr.set(regs.cpsr); - Ok(()) - } - - fn read_addrs(&mut self, start_addr: u32, data: &mut [u8]) -> TargetResult<(), Self> { - self.bus.debug_get_into_bytes(start_addr, data); - Ok(()) - } - - fn write_addrs(&mut self, _start_addr: u32, _data: &[u8]) -> TargetResult<(), Self> { - // todo!("implement DebugWrite bus extention") - Err(TargetError::NonFatal) - } - - // most targets will want to support at resumption as well... - - #[inline(always)] - fn support_resume(&mut self) -> Option> { - Some(self) - } -} - -impl SingleThreadResume for Arm7tdmiCore { - fn resume(&mut self, _signal: Option) -> Result<(), Self::Error> { - // do nothing - Ok(()) - } - - // ...and if the target supports resumption, it'll likely want to support - // single-step resume as well - - #[inline(always)] - fn support_single_step(&mut self) -> Option> { - Some(self) - } -} - -impl SingleThreadSingleStep for Arm7tdmiCore { - fn step(&mut self, _signal: Option) -> Result<(), Self::Error> { - self.step(); - Ok(()) - } -} - -impl target::ext::memory_map::MemoryMap for Arm7tdmiCore { - fn memory_map_xml( - &self, - offset: u64, - length: usize, - buf: &mut [u8], - ) -> TargetResult { - Ok(self.bus.memory_map_xml(offset, length, buf)) - } -} diff --git a/a/src/lib.rs b/a/src/lib.rs deleted file mode 100644 index 0e69b30..0000000 --- a/a/src/lib.rs +++ /dev/null @@ -1,146 +0,0 @@ -#[macro_use] -extern crate serde; - -#[macro_use] -extern crate enum_primitive_derive; - -use std::fmt; - -use num::Num; -use serde::{Deserialize, Serialize}; - -pub mod arm; -pub mod thumb; - -use arm::ArmInstruction; -use thumb::ThumbInstruction; - -pub mod cpu; -pub use cpu::*; -pub mod alu; -pub mod memory; -pub use alu::*; -use memory::Addr; -pub mod disass; -pub mod exception; -pub mod gdb; -pub use gdb::{gdbstub, gdbstub_arch}; -pub mod psr; -mod simple_memory; -pub use simple_memory::SimpleMemory; - -pub mod registers_consts { - pub const REG_PC: usize = 15; - pub const REG_LR: usize = 14; - pub const REG_SP: usize = 13; -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub enum DecodedInstruction { - Arm(ArmInstruction), - Thumb(ThumbInstruction), -} - -impl DecodedInstruction { - pub fn get_pc(&self) -> Addr { - match self { - DecodedInstruction::Arm(a) => a.pc, - DecodedInstruction::Thumb(t) => t.pc, - } - } -} - -#[cfg(feature = "debugger")] -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), - } - } -} - -pub trait InstructionDecoder: Sized { - type IntType: Num; - - fn decode(n: Self::IntType, addr: Addr) -> Self; - /// Helper functions for the Disassembler - fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Self; - fn get_raw(&self) -> Self::IntType; -} - -pub fn reg_string>(reg: T) -> &'static str { - let reg_names = &[ - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "fp", "ip", "sp", "lr", - "pc", - ]; - reg_names[reg.into()] -} - -#[derive(Debug, PartialEq, Eq, Primitive, Copy, Clone)] -#[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"), - } - } -} - -#[derive(Debug, Primitive, Copy, Clone, PartialEq, Eq)] -#[repr(u8)] -pub enum CpuMode { - User = 0b10000, - Fiq = 0b10001, - Irq = 0b10010, - Supervisor = 0b10011, - Abort = 0b10111, - Undefined = 0b11011, - System = 0b11111, -} - -impl CpuMode { - pub fn spsr_index(&self) -> Option { - match self { - CpuMode::Fiq => Some(0), - CpuMode::Irq => Some(1), - CpuMode::Supervisor => Some(2), - CpuMode::Abort => Some(3), - CpuMode::Undefined => Some(4), - _ => None, - } - } - - pub fn bank_index(&self) -> usize { - match self { - CpuMode::User | CpuMode::System => 0, - CpuMode::Fiq => 1, - CpuMode::Irq => 2, - CpuMode::Supervisor => 3, - CpuMode::Abort => 4, - CpuMode::Undefined => 5, - } - } -} - -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"), - } - } -} diff --git a/a/src/memory.rs b/a/src/memory.rs deleted file mode 100644 index d39cac2..0000000 --- a/a/src/memory.rs +++ /dev/null @@ -1,265 +0,0 @@ -use super::Arm7tdmiCore; -use std::fmt; - -pub type Addr = u32; - -#[derive(Serialize, Deserialize, Debug, Copy, Clone)] -pub enum MemoryAccess { - NonSeq = 0, - Seq, -} - -impl Default for MemoryAccess { - fn default() -> MemoryAccess { - MemoryAccess::NonSeq - } -} - -impl fmt::Display for MemoryAccess { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match self { - MemoryAccess::NonSeq => "N", - MemoryAccess::Seq => "S", - } - ) - } -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -#[repr(u8)] -pub enum MemoryAccessWidth { - MemoryAccess8 = 0, - MemoryAccess16, - MemoryAccess32, -} - -/// A trait meant to abstract memory accesses and report the access type back to the user of the arm7tdmi::Arm7tdmiCore -/// -/// struct Memory { -/// data: [u8; 0x4000] -/// } -/// -/// impl MemoryInterface for Memory { -/// fn load_8(&mut self, addr: u32, access: MemoryAccess) { -/// debug!("CPU read {:?} cycle", access); -/// self.data[addr & 0x3fff] -/// } -/// -/// fn store_8(&mut self, addr: u32, value: u8, access: MemoryAccess) { -/// debug!("CPU write {:?} cycle", access); -/// self.data[addr & 0x3fff] = value; -/// } -/// -/// fn idle_cycle(&mut self) { -/// debug!("CPU idle cycle"); -/// } -/// -/// // implement rest of trait methods -/// } -/// -/// let mem = Shared::new(Memory { ... }); -/// let cpu = arm7tdmi::Arm7tdmiCore::new(mem.clone()) -/// -pub trait MemoryInterface { - /// Read a byte - fn load_8(&mut self, addr: u32, access: MemoryAccess) -> u8; - /// Read a halfword - fn load_16(&mut self, addr: u32, access: MemoryAccess) -> u16; - /// Read a word - fn load_32(&mut self, addr: u32, access: MemoryAccess) -> u32; - - /// Write a byte - fn store_8(&mut self, addr: u32, value: u8, access: MemoryAccess); - /// Write a halfword - fn store_16(&mut self, addr: u32, value: u16, access: MemoryAccess); - /// Write a word - fn store_32(&mut self, addr: u32, value: u32, access: MemoryAccess); - - fn idle_cycle(&mut self); -} - -impl MemoryInterface for Arm7tdmiCore { - #[inline] - fn load_8(&mut self, addr: u32, access: MemoryAccess) -> u8 { - self.bus.load_8(addr, access) - } - - #[inline] - fn load_16(&mut self, addr: u32, access: MemoryAccess) -> u16 { - self.bus.load_16(addr & !1, access) - } - - #[inline] - fn load_32(&mut self, addr: u32, access: MemoryAccess) -> u32 { - self.bus.load_32(addr & !3, access) - } - - #[inline] - fn store_8(&mut self, addr: u32, value: u8, access: MemoryAccess) { - self.bus.store_8(addr, value, access); - } - #[inline] - fn store_16(&mut self, addr: u32, value: u16, access: MemoryAccess) { - self.bus.store_16(addr & !1, value, access); - } - - #[inline] - fn store_32(&mut self, addr: u32, value: u32, access: MemoryAccess) { - self.bus.store_32(addr & !3, value, access); - } - - #[inline] - fn idle_cycle(&mut self) { - self.bus.idle_cycle(); - } -} - -/// Implementation of memory access helpers -impl Arm7tdmiCore { - #[inline] - pub(super) fn store_aligned_32(&mut self, addr: Addr, value: u32, access: MemoryAccess) { - self.store_32(addr & !0x3, value, access); - } - - #[inline] - pub(super) fn store_aligned_16(&mut self, addr: Addr, value: u16, access: MemoryAccess) { - self.store_16(addr & !0x1, value, access); - } - - /// Helper function for "ldr" instruction that handles misaligned addresses - #[inline] - pub(super) fn ldr_word(&mut self, addr: Addr, access: MemoryAccess) -> u32 { - if addr & 0x3 != 0 { - let rotation = (addr & 0x3) << 3; - let value = self.load_32(addr & !0x3, access); - let mut carry = self.cpsr.C(); - let v = self.ror(value, rotation, &mut carry, false, false); - self.cpsr.set_C(carry); - v - } else { - self.load_32(addr, access) - } - } - - /// Helper function for "ldrh" instruction that handles misaligned addresses - #[inline] - pub(super) fn ldr_half(&mut self, addr: Addr, access: MemoryAccess) -> u32 { - if addr & 0x1 != 0 { - let rotation = (addr & 0x1) << 3; - let value = self.load_16(addr & !0x1, access); - let mut carry = self.cpsr.C(); - let v = self.ror(value as u32, rotation, &mut carry, false, false); - self.cpsr.set_C(carry); - v - } else { - self.load_16(addr, access) as u32 - } - } - - /// Helper function for "ldrsh" instruction that handles misaligned addresses - #[inline] - pub(super) fn ldr_sign_half(&mut self, addr: Addr, access: MemoryAccess) -> u32 { - if addr & 0x1 != 0 { - self.load_8(addr, access) as i8 as i32 as u32 - } else { - self.load_16(addr, access) as i16 as i32 as u32 - } - } -} - -/// Simple trait for accessing bus peripherals (higher level API than the low-level MemoryInterface) -pub trait BusIO { - fn read_32(&mut self, addr: Addr) -> u32 { - self.read_16(addr) as u32 | (self.read_16(addr + 2) as u32) << 16 - } - - fn read_16(&mut self, addr: Addr) -> u16 { - self.default_read_16(addr) - } - - #[inline(always)] - fn default_read_16(&mut self, addr: Addr) -> u16 { - self.read_8(addr) as u16 | (self.read_8(addr + 1) as u16) << 8 - } - - fn read_8(&mut self, addr: Addr) -> u8; - - fn write_32(&mut self, addr: Addr, value: u32) { - self.write_16(addr, (value & 0xffff) as u16); - self.write_16(addr + 2, (value >> 16) as u16); - } - - fn write_16(&mut self, addr: Addr, value: u16) { - self.default_write_16(addr, value) - } - - #[inline(always)] - fn default_write_16(&mut self, addr: Addr, value: u16) { - self.write_8(addr, (value & 0xff) as u8); - self.write_8(addr + 1, ((value >> 8) & 0xff) as u8); - } - - fn write_8(&mut self, addr: Addr, value: u8); - - fn get_bytes(&mut self, range: std::ops::Range) -> Vec { - let mut bytes = Vec::new(); - for b in range { - bytes.push(self.read_8(b)); - } - bytes - } -} - -/// Helper trait for reading memory as if we were an all-powerfull debugger -pub trait DebugRead: BusIO { - fn debug_read_32(&mut self, addr: Addr) -> u32 { - self.debug_read_16(addr) as u32 | (self.debug_read_16(addr + 2) as u32) << 16 - } - - fn debug_read_16(&mut self, addr: Addr) -> u16 { - self.debug_read_8(addr) as u16 | (self.debug_read_8(addr + 1) as u16) << 8 - } - - fn debug_read_8(&mut self, addr: Addr) -> u8; - - fn debug_get_bytes(&mut self, range: std::ops::Range) -> Vec { - let mut bytes = Vec::new(); - for b in range { - bytes.push(self.debug_read_8(b)); - } - bytes - } - - fn debug_get_into_bytes(&mut self, start_addr: Addr, bytes: &mut [u8]) { - bytes - .iter_mut() - .enumerate() - .for_each(|(idx, byte)| *byte = self.debug_read_8(start_addr + (idx as Addr))); - } -} - -/// The caller is assumed to handle out of bound accesses, -/// For performance reasons, this impl trusts that 'addr' is within the array range. -impl BusIO for Box<[u8]> { - #[inline] - fn read_8(&mut self, addr: Addr) -> u8 { - unsafe { *self.get_unchecked(addr as usize) } - } - - #[inline] - fn write_8(&mut self, addr: Addr, value: u8) { - unsafe { - *self.get_unchecked_mut(addr as usize) = value; - } - } -} - -impl DebugRead for Box<[u8]> { - #[inline] - fn debug_read_8(&mut self, addr: Addr) -> u8 { - self[addr as usize] - } -} diff --git a/a/src/psr.rs b/a/src/psr.rs deleted file mode 100644 index 61eee4b..0000000 --- a/a/src/psr.rs +++ /dev/null @@ -1,161 +0,0 @@ -/// The program status register -use std::fmt; - -use serde::{Deserialize, Serialize}; - -use bit::BitIndex; -use num::FromPrimitive; - -use super::{CpuMode, CpuState}; - -use colored::*; - -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(Serialize, Deserialize, Debug, Clone, Copy, Default)] -#[repr(transparent)] -pub struct RegPSR { - raw: u32, -} - -const RESERVED_BIT_MASK: u32 = 0x0fffff00; -fn clear_reserved(n: u32) -> u32 { - n & !RESERVED_BIT_MASK -} - -impl RegPSR { - pub const FLAG_BITMASK: u32 = 0xf000_0000; - - pub fn new(u: u32) -> RegPSR { - RegPSR { - raw: clear_reserved(u), - } - } - - pub fn get(&self) -> u32 { - self.raw - } - - pub fn set(&mut self, psr: u32) { - self.raw = clear_reserved(psr); - } - - pub fn set_flag_bits(&mut self, value: u32) { - self.raw &= !Self::FLAG_BITMASK; - self.raw |= Self::FLAG_BITMASK & value; - } - - 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.bit_range(0..5)).unwrap() - } - - pub fn set_mode(&mut self, mode: CpuMode) { - self.raw.set_bit_range(0..5, (mode as u32) & 0b1_1111); - } - - 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, - "{{ [{raw:#010x}] mode: {mode}, state: {state}, irq: {irq}, fiq: {fiq}, condition_flags: (N={N} Z={Z} C={C} V={V}) }}", - raw = self.raw, - 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, - ) - } -} diff --git a/a/src/simple_memory.rs b/a/src/simple_memory.rs deleted file mode 100644 index 4d5d986..0000000 --- a/a/src/simple_memory.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::gdb::{copy_range_to_buf, target::MemoryGdbInterface}; -use crate::memory::{Addr, BusIO, DebugRead, MemoryAccess, MemoryInterface}; - -/// Simple wrapper around a bytearray for memory access -/// For use by tests and examples of this crate. -pub struct SimpleMemory { - data: Box<[u8]>, -} - -impl SimpleMemory { - pub fn new(capacity: usize) -> SimpleMemory { - SimpleMemory { - data: vec![0; capacity].into_boxed_slice(), - } - } - pub fn load_program(&mut self, program: &[u8]) { - self.data[..program.len()].copy_from_slice(program); - } -} - -impl MemoryInterface for SimpleMemory { - #[inline] - fn load_8(&mut self, addr: u32, _access: MemoryAccess) -> u8 { - self.read_8(addr) - } - - #[inline] - fn load_16(&mut self, addr: u32, _access: MemoryAccess) -> u16 { - self.read_16(addr & !1) - } - - #[inline] - fn load_32(&mut self, addr: u32, _access: MemoryAccess) -> u32 { - self.read_32(addr & !3) - } - - fn store_8(&mut self, addr: u32, value: u8, _access: MemoryAccess) { - self.write_8(addr, value); - } - - fn store_16(&mut self, addr: u32, value: u16, _access: MemoryAccess) { - self.write_16(addr & !1, value); - } - - fn store_32(&mut self, addr: u32, value: u32, _access: MemoryAccess) { - self.write_32(addr & !3, value); - } - - fn idle_cycle(&mut self) {} -} - -impl BusIO for SimpleMemory { - fn read_8(&mut self, addr: Addr) -> u8 { - *self.data.get(addr as usize).unwrap_or(&0) - } - - fn write_8(&mut self, addr: Addr, value: u8) { - if let 0..=0x3FFF = addr { - self.data[addr as usize] = value; - } - } -} - -impl DebugRead for SimpleMemory { - fn debug_read_8(&mut self, addr: Addr) -> u8 { - *self.data.get(addr as usize).unwrap_or(&0) - } -} - -impl MemoryGdbInterface for SimpleMemory { - fn memory_map_xml(&self, offset: u64, length: usize, buf: &mut [u8]) -> usize { - let memory_map = format!( - r#" - - - - "#, - self.data.len() - ); - copy_range_to_buf(memory_map.trim().as_bytes(), offset, length, buf) - } -} diff --git a/a/src/thumb/disass.rs b/a/src/thumb/disass.rs deleted file mode 100644 index aba6c99..0000000 --- a/a/src/thumb/disass.rs +++ /dev/null @@ -1,350 +0,0 @@ -use std::fmt; - -use crate::bit::BitIndex; - -use super::*; -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!( - f, - "{op}\t{Rd}, {Rs}, #{Offset5}", - op = self.raw.format1_op(), - Rd = reg_string(self.raw & 0b111), - Rs = reg_string(self.raw.rs()), - Offset5 = self.raw.offset5() - ) - } - - fn fmt_thumb_data_process_imm(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{op}\t{Rd}, #{Offset8:#x}", - op = self.raw.format3_op(), - Rd = reg_string(self.raw.bit_range(8..11)), - Offset8 = self.raw & 0xff - ) - } - - fn fmt_thumb_alu_ops(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{op}\t{Rd}, {Rs}", - op = self.raw.format4_alu_op(), - Rd = reg_string(self.raw & 0b111), - Rs = reg_string(self.raw.rs()) - ) - } - - fn fmt_thumb_high_reg_op_or_bx(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let op = self.raw.format5_op(); - let dst_reg = if self.raw.flag(consts::flags::FLAG_H1) { - self.raw & 0b111 + 8 - } else { - self.raw & 0b111 - }; - let src_reg = if self.raw.flag(consts::flags::FLAG_H2) { - self.raw.rs() + 8 - } else { - self.raw.rs() - }; - - write!(f, "{}\t", op)?; - match op { - OpFormat5::BX => write!(f, "{}", reg_string(src_reg)), - _ => write!( - f, - "{dst}, {src}", - dst = reg_string(dst_reg), - src = reg_string(src_reg) - ), - } - } - - fn fmt_thumb_ldr_pc(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "ldr\t{Rd}, [pc, #{Imm:#x}] ; = #{effective:#x}", - Rd = reg_string(self.raw.bit_range(8..11)), - Imm = self.raw.word8(), - effective = (self.pc + 4 & !0b10) + (self.raw.word8() as Addr) - ) - } - - fn fmt_thumb_ldr_str_reg_offset(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{op}{b}\t{Rd}, [{Rb}, {Ro}]", - op = if self.raw.is_load() { "ldr" } else { "str" }, - b = if self.raw.bit(10) { "b" } else { "" }, - Rd = reg_string(self.raw & 0b111), - Rb = reg_string(self.raw.rb()), - Ro = reg_string(self.raw.ro()), - ) - } - - fn fmt_thumb_ldr_str_shb(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{op}\t{Rd}, [{Rb}, {Ro}]", - op = { - match ( - self.raw.flag(consts::flags::FLAG_SIGN_EXTEND), - self.raw.flag(consts::flags::FLAG_HALFWORD), - ) { - (false, false) => "strh", - (false, true) => "ldrh", - (true, false) => "ldsb", - (true, true) => "ldsh", - } - }, - Rd = reg_string(self.raw & 0b111), - Rb = reg_string(self.raw.rb()), - Ro = reg_string(self.raw.ro()), - ) - } - - fn fmt_thumb_ldr_str_imm_offset(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let is_transferring_bytes = self.raw.bit(12); - write!( - f, - "{op}{b}\t{Rd}, [{Rb}, #{imm:#x}]", - op = if self.raw.is_load() { "ldr" } else { "str" }, - b = if is_transferring_bytes { "b" } else { "" }, - Rd = reg_string(self.raw & 0b111), - Rb = reg_string(self.raw.rb()), - imm = { - let offset5 = self.raw.offset5(); - if is_transferring_bytes { - offset5 - } else { - (offset5 << 3) >> 1 - } - }, - ) - } - - fn fmt_thumb_ldr_str_halfword(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{op}\t{Rd}, [{Rb}, #{imm:#x}]", - op = if self.raw.is_load() { "ldrh" } else { "strh" }, - Rd = reg_string(self.raw & 0b111), - Rb = reg_string(self.raw.rb()), - imm = self.raw.offset5() << 1 - ) - } - - fn fmt_thumb_ldr_str_sp(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{op}\t{Rd}, [sp, #{Imm:#x}]", - op = if self.raw.is_load() { "ldr" } else { "str" }, - Rd = reg_string(self.raw.bit_range(8..11)), - Imm = self.raw.word8(), - ) - } - - fn fmt_thumb_load_address(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "add\t{Rd}, {r}, #{Imm:#x}", - Rd = reg_string(self.raw.bit_range(8..11)), - r = if self.raw.flag(consts::flags::FLAG_SP) { - "sp" - } else { - "pc" - }, - Imm = self.raw.word8(), - ) - } - - fn fmt_thumb_add_sub(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let operand = if self.raw.is_immediate_operand() { - format!("#{:x}", self.raw.bit_range(6..9)) - } else { - String::from(reg_string(self.raw.rn())) - }; - - write!( - f, - "{op}\t{Rd}, {Rs}, {operand}", - op = if self.raw.is_subtract() { "sub" } else { "add" }, - Rd = reg_string(self.raw & 0b111), - Rs = reg_string(self.raw.rs()), - operand = operand - ) - } - - fn fmt_thumb_add_sp(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "add\tsp, #{imm:x}", imm = self.raw.sword7()) - } - - fn fmt_register_list(&self, f: &mut fmt::Formatter<'_>, rlist: u8) -> fmt::Result { - let mut has_first = false; - for i in 0..8 { - if rlist.bit(i) { - if has_first { - write!(f, ", {}", reg_string(i))?; - } else { - has_first = true; - write!(f, "{}", reg_string(i))?; - } - } - } - Ok(()) - } - - fn fmt_thumb_push_pop(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}\t{{", if self.raw.is_load() { "pop" } else { "push" })?; - let rlist = self.raw.register_list(); - self.fmt_register_list(f, rlist)?; - if self.raw.flag(consts::flags::FLAG_R) { - let r = if self.raw.is_load() { "pc" } else { "lr" }; - if rlist != 0 { - write!(f, ", {}", r)?; - } else { - write!(f, "{}", r)?; - } - } - write!(f, "}}") - } - - fn fmt_thumb_ldm_stm(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{op}\t{Rb}!, {{", - op = if self.raw.is_load() { "ldm" } else { "stm" }, - Rb = reg_string(self.raw.rb()), - )?; - self.fmt_register_list(f, self.raw.register_list())?; - write!(f, "}}") - } - - fn fmt_thumb_branch_with_cond(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "b{cond}\t{addr:#x}", - cond = self.raw.cond(), - addr = { - let offset = self.raw.bcond_offset(); - (self.pc as i32 + 4).wrapping_add(offset) as Addr - } - ) - } - - fn fmt_thumb_swi(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "swi\t{value:#x}", value = self.raw & 0xff,) - } - - fn fmt_thumb_branch(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "b\t{addr:#x}", - addr = { - let offset = (self.raw.offset11() << 21) >> 20; - (self.pc as i32 + 4).wrapping_add(offset) as Addr - } - ) - } - - fn fmt_thumb_branch_long_with_link(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "bl\t#0x{:08x}", { - let offset11 = self.raw.offset11(); - if self.raw.flag(consts::flags::FLAG_LOW_OFFSET) { - (offset11 << 1) as i32 - } else { - ((offset11 << 21) >> 9) as i32 - } - }) - } -} - -#[cfg(feature = "debugger")] -impl fmt::Display for ThumbInstruction { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.fmt { - ThumbFormat::MoveShiftedReg => self.fmt_thumb_move_shifted_reg(f), - ThumbFormat::AddSub => self.fmt_thumb_add_sub(f), - ThumbFormat::DataProcessImm => self.fmt_thumb_data_process_imm(f), - ThumbFormat::AluOps => self.fmt_thumb_alu_ops(f), - ThumbFormat::HiRegOpOrBranchExchange => self.fmt_thumb_high_reg_op_or_bx(f), - ThumbFormat::LdrPc => self.fmt_thumb_ldr_pc(f), - ThumbFormat::LdrStrRegOffset => self.fmt_thumb_ldr_str_reg_offset(f), - ThumbFormat::LdrStrSHB => self.fmt_thumb_ldr_str_shb(f), - ThumbFormat::LdrStrImmOffset => self.fmt_thumb_ldr_str_imm_offset(f), - ThumbFormat::LdrStrHalfWord => self.fmt_thumb_ldr_str_halfword(f), - ThumbFormat::LdrStrSp => self.fmt_thumb_ldr_str_sp(f), - ThumbFormat::LoadAddress => self.fmt_thumb_load_address(f), - ThumbFormat::AddSp => self.fmt_thumb_add_sp(f), - ThumbFormat::PushPop => self.fmt_thumb_push_pop(f), - ThumbFormat::LdmStm => self.fmt_thumb_ldm_stm(f), - ThumbFormat::BranchConditional => self.fmt_thumb_branch_with_cond(f), - ThumbFormat::Swi => self.fmt_thumb_swi(f), - ThumbFormat::Branch => self.fmt_thumb_branch(f), - ThumbFormat::BranchLongWithLink => self.fmt_thumb_branch_long_with_link(f), - ThumbFormat::Undefined => write!(f, ""), - } - } -} - -impl fmt::Display for OpFormat3 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - OpFormat3::MOV => write!(f, "mov"), - OpFormat3::CMP => write!(f, "cmp"), - OpFormat3::ADD => write!(f, "add"), - OpFormat3::SUB => write!(f, "sub"), - } - } -} - -impl fmt::Display for OpFormat5 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - OpFormat5::ADD => write!(f, "add"), - OpFormat5::CMP => write!(f, "cmp"), - OpFormat5::MOV => write!(f, "mov"), - OpFormat5::BX => write!(f, "bx"), - } - } -} - -impl fmt::Display for ThumbAluOps { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use ThumbAluOps::*; - match self { - AND => write!(f, "and"), - EOR => write!(f, "eor"), - LSL => write!(f, "lsl"), - LSR => write!(f, "lsr"), - ASR => write!(f, "asr"), - ADC => write!(f, "adc"), - SBC => write!(f, "sbc"), - ROR => write!(f, "ror"), - TST => write!(f, "tst"), - NEG => write!(f, "neg"), - CMP => write!(f, "cmp"), - CMN => write!(f, "cmn"), - ORR => write!(f, "orr"), - MUL => write!(f, "mul"), - BIC => write!(f, "bic"), - MVN => write!(f, "mvn"), - } - } -} diff --git a/a/src/thumb/exec.rs b/a/src/thumb/exec.rs deleted file mode 100644 index 8e988b0..0000000 --- a/a/src/thumb/exec.rs +++ /dev/null @@ -1,575 +0,0 @@ -use crate::{ - exception::Exception, - memory::{MemoryAccess, MemoryInterface}, - registers_consts::*, - Arm7tdmiCore, CpuAction, -}; - -use super::*; -use MemoryAccess::*; - -impl Arm7tdmiCore { - /// Format 1 - /// Execution Time: 1S - 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 = IMM as u32; - let mut carry = self.cpsr.C(); - let bsop = match BS_OP { - 0 => BarrelShiftOpCode::LSL, - 1 => BarrelShiftOpCode::LSR, - 2 => BarrelShiftOpCode::ASR, - 3 => BarrelShiftOpCode::ROR, - _ => unsafe { std::hint::unreachable_unchecked() }, - }; - let op2 = self.barrel_shift_op(bsop, self.gpr[rs], shift_amount, &mut carry, true); - self.gpr[rd] = op2; - self.alu_update_flags(op2, false, carry, self.cpsr.V()); - - CpuAction::AdvancePC(Seq) - } - - /// Format 2 - /// Execution Time: 1S - pub(in super::super) fn exec_thumb_add_sub< - const SUB: bool, - const IMM: bool, - const RN: usize, - >( - &mut self, - insn: u16, - ) -> CpuAction { - let rd = (insn & 0b111) as usize; - let op1 = self.get_reg(insn.rs()); - let op2 = if IMM { RN as u32 } else { self.get_reg(RN) }; - - let mut carry = self.cpsr.C(); - let mut overflow = self.cpsr.V(); - let result = if SUB { - self.alu_sub_flags(op1, op2, &mut carry, &mut overflow) - } else { - self.alu_add_flags(op1, op2, &mut carry, &mut overflow) - }; - self.alu_update_flags(result, true, carry, overflow); - self.set_reg(rd, result); - - CpuAction::AdvancePC(Seq) - } - - /// Format 3 - /// Execution Time: 1S - pub(in super::super) fn exec_thumb_data_process_imm( - &mut self, - insn: u16, - ) -> CpuAction { - use OpFormat3::*; - let op = OpFormat3::from_u8(OP).unwrap(); - let op1 = self.gpr[RD]; - let op2_imm = (insn & 0xff) as u32; - let mut carry = self.cpsr.C(); - let mut overflow = self.cpsr.V(); - let result = match op { - MOV => op2_imm, - CMP | SUB => self.alu_sub_flags(op1, op2_imm, &mut carry, &mut overflow), - ADD => self.alu_add_flags(op1, op2_imm, &mut carry, &mut overflow), - }; - let arithmetic = op == ADD || op == SUB; - self.alu_update_flags(result, arithmetic, carry, overflow); - if op != CMP { - self.gpr[RD] = result; - } - - CpuAction::AdvancePC(Seq) - } - - /// Format 4 - /// Execution Time: - /// 1S for AND,EOR,ADC,SBC,TST,NEG,CMP,CMN,ORR,BIC,MVN - /// 1S+1I for LSL,LSR,ASR,ROR - /// 1S+mI for MUL on ARMv4 (m=1..4; depending on MSBs of incoming Rd value) - pub(in super::super) fn exec_thumb_alu_ops(&mut self, insn: u16) -> CpuAction { - let rd = (insn & 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 mut overflow = self.cpsr.V(); - - use ThumbAluOps::*; - let op = ThumbAluOps::from_u16(OP).unwrap(); - - macro_rules! shifter_op { - ($bs_op:expr) => {{ - let result = self.shift_by_register($bs_op, rd, rs, &mut carry); - self.idle_cycle(); - result - }}; - } - - let result = match op { - AND | TST => dst & src, - EOR => dst ^ src, - LSL => shifter_op!(BarrelShiftOpCode::LSL), - LSR => shifter_op!(BarrelShiftOpCode::LSR), - ASR => shifter_op!(BarrelShiftOpCode::ASR), - ROR => shifter_op!(BarrelShiftOpCode::ROR), - ADC => self.alu_adc_flags(dst, src, &mut carry, &mut overflow), - SBC => self.alu_sbc_flags(dst, src, &mut carry, &mut overflow), - NEG => self.alu_sub_flags(0, src, &mut carry, &mut overflow), - CMP => self.alu_sub_flags(dst, src, &mut carry, &mut overflow), - CMN => self.alu_add_flags(dst, src, &mut carry, &mut overflow), - ORR => dst | src, - MUL => { - let m = self.get_required_multipiler_array_cycles(src); - for _ in 0..m { - self.idle_cycle(); - } - // TODO - meaningless values? - carry = false; - overflow = false; - dst.wrapping_mul(src) - } - BIC => dst & (!src), - MVN => !src, - }; - self.alu_update_flags(result, op.is_arithmetic(), carry, overflow); - - if !op.is_setting_flags() { - self.set_reg(rd, result); - } - - CpuAction::AdvancePC(Seq) - } - - /// Format 5 - /// Execution Time: - /// 1S for ADD/MOV/CMP - /// 2S+1N for ADD/MOV with Rd=R15, and for BX - pub(in super::super) fn exec_thumb_hi_reg_op_or_bx< - const OP: u8, - const FLAG_H1: bool, - const FLAG_H2: bool, - >( - &mut self, - insn: u16, - ) -> CpuAction { - let op = OpFormat5::from_u8(OP).unwrap(); - let rd = (insn & 0b111) as usize; - let rs = insn.rs(); - let dst_reg = if FLAG_H1 { rd + 8 } else { rd }; - let src_reg = if FLAG_H2 { rs + 8 } else { rs }; - let op1 = self.get_reg(dst_reg); - let op2 = self.get_reg(src_reg); - - let mut result = CpuAction::AdvancePC(Seq); - match op { - OpFormat5::BX => { - return self.branch_exchange(self.get_reg(src_reg)); - } - OpFormat5::ADD => { - self.set_reg(dst_reg, op1.wrapping_add(op2)); - if dst_reg == REG_PC { - self.reload_pipeline16(); - result = CpuAction::PipelineFlushed; - } - } - OpFormat5::CMP => { - let mut carry = self.cpsr.C(); - let mut overflow = self.cpsr.V(); - let result = self.alu_sub_flags(op1, op2, &mut carry, &mut overflow); - self.alu_update_flags(result, true, carry, overflow); - } - OpFormat5::MOV => { - self.set_reg(dst_reg, op2); - if dst_reg == REG_PC { - self.reload_pipeline16(); - result = CpuAction::PipelineFlushed; - } - } - } - - result - } - - /// Format 6 load PC-relative (for loading immediates from literal pool) - /// Execution Time: 1S+1N+1I - pub(in super::super) fn exec_thumb_ldr_pc(&mut self, insn: u16) -> CpuAction { - let ofs = insn.word8() as Addr; - let addr = (self.pc & !3) + ofs; - - self.gpr[RD] = self.load_32(addr, NonSeq); - - // +1I - self.idle_cycle(); - - CpuAction::AdvancePC(NonSeq) - } - - /// Helper function for various ldr/str handler - /// Execution Time: 1S+1N+1I for LDR, or 2N for STR - fn do_exec_thumb_ldr_str( - &mut self, - insn: u16, - addr: Addr, - ) -> CpuAction { - let rd = (insn & 0b111) as usize; - if LOAD { - let data = if BYTE { - self.load_8(addr, NonSeq) as u32 - } else { - self.ldr_word(addr, NonSeq) - }; - - self.gpr[rd] = data; - - // +1I - self.idle_cycle(); - CpuAction::AdvancePC(Seq) - } else { - let value = self.get_reg(rd); - if BYTE { - self.store_8(addr, value as u8, NonSeq); - } else { - self.store_aligned_32(addr, value, NonSeq); - }; - CpuAction::AdvancePC(NonSeq) - } - } - - /// Format 7 load/store with register offset - /// Execution Time: 1S+1N+1I for LDR, or 2N for STR - pub(in super::super) fn exec_thumb_ldr_str_reg_offset< - const LOAD: bool, - const RO: usize, - const BYTE: bool, - >( - &mut self, - insn: u16, - ) -> CpuAction { - let rb = insn.bit_range(3..6) as usize; - let addr = self.gpr[rb].wrapping_add(self.gpr[RO]); - self.do_exec_thumb_ldr_str::(insn, addr) - } - - /// 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< - 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[RO]); - match (SIGN_EXTEND, HALFWORD) { - (false, false) => - /* strh */ - { - self.store_aligned_16(addr, self.gpr[rd] as u16, NonSeq); - } - (false, true) => - /* ldrh */ - { - self.gpr[rd] = self.ldr_half(addr, NonSeq); - self.idle_cycle(); - } - (true, false) => - /* ldself */ - { - let val = self.load_8(addr, NonSeq) as i8 as i32 as u32; - self.gpr[rd] = val; - self.idle_cycle(); - } - (true, true) => - /* ldsh */ - { - let val = self.ldr_sign_half(addr, NonSeq); - self.gpr[rd] = val; - self.idle_cycle(); - } - } - - CpuAction::AdvancePC(NonSeq) - } - - /// Format 9 - /// Execution Time: 1S+1N+1I for LDR, or 2N for STR - pub(in super::super) fn exec_thumb_ldr_str_imm_offset< - const LOAD: bool, - const BYTE: bool, - const OFFSET: u8, - >( - &mut self, - insn: u16, - ) -> CpuAction { - let rb = insn.bit_range(3..6) as usize; - let addr = self.gpr[rb].wrapping_add(OFFSET as u32); - self.do_exec_thumb_ldr_str::(insn, addr) - } - - /// 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 { - 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(OFFSET) as Addr; - if LOAD { - let data = self.ldr_half(addr, NonSeq); - self.idle_cycle(); - self.gpr[rd] = data; - CpuAction::AdvancePC(Seq) - } else { - self.store_aligned_16(addr, self.gpr[rd] as u16, NonSeq); - CpuAction::AdvancePC(NonSeq) - } - } - - /// 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 { - let addr = self.gpr[REG_SP] + (insn.word8() as Addr); - if LOAD { - let data = self.ldr_word(addr, NonSeq); - self.idle_cycle(); - self.gpr[RD] = data; - CpuAction::AdvancePC(Seq) - } else { - 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 { - self.gpr[RD] = if SP { - self.gpr[REG_SP] + (insn.word8() as Addr) - } else { - (self.pc_thumb() & !0b10) + 4 + (insn.word8() as Addr) - }; - - CpuAction::AdvancePC(Seq) - } - - /// Format 13 - /// Execution Time: 1S - pub(in super::super) fn exec_thumb_add_sp( - &mut self, - insn: u16, - ) -> CpuAction { - let op1 = self.gpr[REG_SP] as i32; - 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 { - macro_rules! push { - ($r:expr, $access:ident) => { - self.gpr[REG_SP] -= 4; - let stack_addr = self.gpr[REG_SP] & !3; - self.store_32(stack_addr, self.get_reg($r), $access); - $access = Seq; - }; - } - macro_rules! pop { - ($r:expr) => { - let val = self.load_32(self.gpr[REG_SP] & !3, Seq); - self.set_reg($r, val); - self.gpr[REG_SP] += 4; - }; - ($r:expr, $access:ident) => { - let val = self.load_32(self.gpr[REG_SP] & !3, $access); - $access = Seq; - self.set_reg($r, val); - self.gpr[REG_SP] += 4; - }; - } - let mut result = CpuAction::AdvancePC(NonSeq); - let rlist = insn.register_list(); - let mut access = MemoryAccess::NonSeq; - if POP { - for r in 0..8 { - if rlist.bit(r) { - pop!(r, access); - } - } - if FLAG_R { - pop!(REG_PC); - self.pc &= !1; - result = CpuAction::PipelineFlushed; - self.reload_pipeline16(); - } - // Idle 1 cycle - self.idle_cycle(); - } else { - if FLAG_R { - push!(REG_LR, access); - } - for r in (0..8).rev() { - if rlist.bit(r) { - push!(r, access); - } - } - } - - result - } - - /// 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 { - let mut result = CpuAction::AdvancePC(NonSeq); - - 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 LOAD { - let mut access = NonSeq; - for r in 0..8 { - if rlist.bit(r) { - let val = self.load_32(addr, access); - access = Seq; - addr += 4; - self.set_reg(r, val); - } - } - self.idle_cycle(); - 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 != RB { - self.gpr[r] - } else if first { - first = false; - addr - } else { - addr + (rlist.count_ones() - 1) * 4 - }; - self.store_32(addr, v, access); - access = Seq; - addr += 4; - } - self.gpr[RB] = addr + align_preserve; - } - } - } else { - // From gbatek.htm: Empty Rlist: R15 loaded/stored (ARMv4 only), and Rb=Rb+40h (ARMv4-v5). - if LOAD { - let val = self.load_32(addr, NonSeq); - self.pc = val & !1; - result = CpuAction::PipelineFlushed; - self.reload_pipeline16(); - } else { - self.store_32(addr, self.pc + 2, NonSeq); - } - addr += 0x40; - self.gpr[RB] = addr + align_preserve; - } - - result - } - - /// Format 16 - /// 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 { - let cond = ArmCond::from_u8(COND).expect("bad cond"); - if !self.check_arm_cond(cond) { - CpuAction::AdvancePC(Seq) - } else { - let offset = insn.bcond_offset(); - self.pc = (self.pc as i32).wrapping_add(offset) as u32; - self.reload_pipeline16(); - CpuAction::PipelineFlushed - } - } - - /// Format 17 - /// Execution Time: 2S+1N - pub(in super::super) fn exec_thumb_swi(&mut self, _insn: u16) -> CpuAction { - self.exception(Exception::SoftwareInterrupt, self.pc - 2); // implies pipeline reload - CpuAction::PipelineFlushed - } - - /// Format 18 - /// Execution Time: 2S+1N - pub(in super::super) fn exec_thumb_branch(&mut self, insn: u16) -> CpuAction { - let offset = (insn.offset11() << 21) >> 20; - self.pc = (self.pc as i32).wrapping_add(offset) as u32; - self.reload_pipeline16(); // 2S + 1N - CpuAction::PipelineFlushed - } - - /// 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 { - let mut off = insn.offset11(); - if FLAG_LOW_OFFSET { - off <<= 1; - let next_pc = (self.pc - 2) | 1; - self.pc = ((self.gpr[REG_LR] & !1) as i32).wrapping_add(off) as u32; - self.gpr[REG_LR] = next_pc; - self.reload_pipeline16(); // implies 2S + 1N - CpuAction::PipelineFlushed - } else { - off = (off << 21) >> 9; - self.gpr[REG_LR] = (self.pc as i32).wrapping_add(off) as u32; - CpuAction::AdvancePC(Seq) // 1S - } - } - - pub fn thumb_undefined(&mut self, insn: u16) -> CpuAction { - panic!( - "executing undefind thumb instruction {:04x} at @{:08x}", - insn, - self.pc_thumb() - ) - } -} diff --git a/a/src/thumb/mod.rs b/a/src/thumb/mod.rs deleted file mode 100644 index 227620b..0000000 --- a/a/src/thumb/mod.rs +++ /dev/null @@ -1,485 +0,0 @@ -use super::alu::*; -use super::arm::*; -use super::memory::Addr; -use super::InstructionDecoder; -use bit::BitIndex; -use byteorder::{LittleEndian, ReadBytesExt}; -use num::FromPrimitive; - -#[cfg(feature = "debugger")] -pub mod disass; -pub mod exec; - -#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)] -pub enum ThumbFormat { - /// Format 1 - MoveShiftedReg, - /// Format 2 - AddSub, - /// Format 3 - DataProcessImm, - /// Format 4 - AluOps, - /// Format 5 - HiRegOpOrBranchExchange, - /// Format 6 - LdrPc, - /// Format 7 - LdrStrRegOffset, - /// Format 8 - LdrStrSHB, - /// Format 9 - LdrStrImmOffset, - /// Format 10 - LdrStrHalfWord, - /// Format 11 - LdrStrSp, - /// Format 12 - LoadAddress, - /// Format 13 - AddSp, - /// Format 14 - PushPop, - /// Format 15 - LdmStm, - /// Format 16 - BranchConditional, - /// Format 17 - Swi, - /// Format 18 - Branch, - /// Format 19 - BranchLongWithLink, - - /// Not an actual thumb format - Undefined, -} - -impl From for ThumbFormat { - fn from(raw: u16) -> ThumbFormat { - use ThumbFormat::*; - if raw & 0xf800 == 0x1800 { - AddSub - } else if raw & 0xe000 == 0x0000 { - MoveShiftedReg - } else if raw & 0xe000 == 0x2000 { - DataProcessImm - } else if raw & 0xfc00 == 0x4000 { - AluOps - } else if raw & 0xfc00 == 0x4400 { - HiRegOpOrBranchExchange - } else if raw & 0xf800 == 0x4800 { - LdrPc - } else if raw & 0xf200 == 0x5000 { - LdrStrRegOffset - } else if raw & 0xf200 == 0x5200 { - LdrStrSHB - } else if raw & 0xe000 == 0x6000 { - LdrStrImmOffset - } else if raw & 0xf000 == 0x8000 { - LdrStrHalfWord - } else if raw & 0xf000 == 0x9000 { - LdrStrSp - } else if raw & 0xf000 == 0xa000 { - LoadAddress - } else if raw & 0xff00 == 0xb000 { - AddSp - } else if raw & 0xf600 == 0xb400 { - PushPop - } else if raw & 0xf000 == 0xc000 { - LdmStm - } else if raw & 0xff00 == 0xdf00 { - Swi - } else if raw & 0xf000 == 0xd000 { - BranchConditional - } else if raw & 0xf800 == 0xe000 { - Branch - } else if raw & 0xf000 == 0xf000 { - BranchLongWithLink - } else { - Undefined - } - } -} - -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] -pub struct ThumbInstruction { - pub fmt: ThumbFormat, - pub raw: u16, - pub pc: Addr, -} - -impl ThumbInstruction { - pub fn new(raw: u16, pc: Addr, fmt: ThumbFormat) -> ThumbInstruction { - ThumbInstruction { fmt, raw, pc } - } -} - -impl InstructionDecoder for ThumbInstruction { - type IntType = u16; - - fn decode(raw: u16, addr: Addr) -> Self { - let fmt = ThumbFormat::from(raw); - ThumbInstruction::new(raw, addr, fmt) - } - - fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Self { - let mut rdr = std::io::Cursor::new(bytes); - let raw = rdr.read_u16::().unwrap(); - Self::decode(raw, addr) - } - - fn get_raw(&self) -> u16 { - self.raw - } -} - -#[derive(Debug, Primitive, PartialEq, Eq)] -pub enum OpFormat3 { - MOV = 0, - CMP = 1, - ADD = 2, - SUB = 3, -} - -impl From for AluOpCode { - fn from(op: OpFormat3) -> AluOpCode { - match op { - OpFormat3::MOV => AluOpCode::MOV, - OpFormat3::CMP => AluOpCode::CMP, - OpFormat3::ADD => AluOpCode::ADD, - OpFormat3::SUB => AluOpCode::SUB, - } - } -} - -#[derive(Debug, Primitive, PartialEq, Eq)] -pub enum OpFormat5 { - ADD = 0, - CMP = 1, - MOV = 2, - BX = 3, -} - -#[derive(Debug, Primitive, PartialEq, Eq)] -pub enum ThumbAluOps { - AND = 0b0000, - EOR = 0b0001, - LSL = 0b0010, - LSR = 0b0011, - ASR = 0b0100, - ADC = 0b0101, - SBC = 0b0110, - ROR = 0b0111, - TST = 0b1000, - NEG = 0b1001, - CMP = 0b1010, - CMN = 0b1011, - ORR = 0b1100, - MUL = 0b1101, - BIC = 0b1110, - MVN = 0b1111, -} - -impl ThumbAluOps { - pub fn is_setting_flags(&self) -> bool { - use ThumbAluOps::*; - matches!(self, TST | CMP | CMN) - } - pub fn is_arithmetic(&self) -> bool { - use ThumbAluOps::*; - matches!(self, ADC | SBC | NEG | CMP | CMN) - } -} - -impl From for AluOpCode { - fn from(op: OpFormat5) -> AluOpCode { - match op { - OpFormat5::ADD => AluOpCode::ADD, - OpFormat5::CMP => AluOpCode::CMP, - OpFormat5::MOV => AluOpCode::MOV, - OpFormat5::BX => panic!("this should not be called if op = BX"), - } - } -} - -/// A trait which provides methods to extract thumb instruction fields -pub trait ThumbDecodeHelper { - // Consts - - // Methods - - fn rs(&self) -> usize; - - fn rb(&self) -> usize; - - fn ro(&self) -> usize; - - fn rn(&self) -> usize; - - fn format1_op(&self) -> BarrelShiftOpCode; - - fn format3_op(&self) -> OpFormat3; - - fn format5_op(&self) -> OpFormat5; - - fn format4_alu_op(&self) -> ThumbAluOps; - - fn offset5(&self) -> u8; - - fn bcond_offset(&self) -> i32; - - fn offset11(&self) -> i32; - - fn word8(&self) -> u16; - - fn is_load(&self) -> bool; - - fn is_subtract(&self) -> bool; - - fn is_immediate_operand(&self) -> bool; - - fn cond(&self) -> ArmCond; - - fn flag(self, bit: usize) -> bool; - - fn register_list(&self) -> u8; - - fn sword7(&self) -> i32; -} - -macro_rules! thumb_decode_helper_impl { - ($($t:ty),*) => {$( - - impl ThumbDecodeHelper for $t { - - #[inline] - fn rs(&self) -> usize { - self.bit_range(3..6) as usize - } - - #[inline] - /// Note: not true for LdmStm - fn rb(&self) -> usize { - self.bit_range(3..6) as usize - } - - #[inline] - fn ro(&self) -> usize { - self.bit_range(6..9) as usize - } - - #[inline] - fn rn(&self) -> usize { - self.bit_range(6..9) as usize - } - - #[inline] - fn format1_op(&self) -> BarrelShiftOpCode { - BarrelShiftOpCode::from_u8(self.bit_range(11..13) as u8).unwrap() - } - - #[inline] - fn format3_op(&self) -> OpFormat3 { - OpFormat3::from_u8(self.bit_range(11..13) as u8).unwrap() - } - - #[inline] - fn format5_op(&self) -> OpFormat5 { - OpFormat5::from_u8(self.bit_range(8..10) as u8).unwrap() - } - - #[inline] - fn format4_alu_op(&self) -> ThumbAluOps { - ThumbAluOps::from_u16(self.bit_range(6..10)).unwrap() - } - - #[inline] - fn offset5(&self) -> u8 { - self.bit_range(6..11) as u8 - } - - #[inline] - fn bcond_offset(&self) -> i32 { - ((((*self & 0xff) as u32) << 24) as i32) >> 23 - } - - #[inline] - fn offset11(&self) -> i32 { - (*self & 0x7FF) as i32 - } - - #[inline] - fn word8(&self) -> u16 { - (*self & 0xff) << 2 - } - - #[inline] - fn is_load(&self) -> bool { - self.bit(11) - } - - #[inline] - fn is_subtract(&self) -> bool { - self.bit(9) - } - - #[inline] - fn is_immediate_operand(&self) -> bool { - self.bit(10) - } - - #[inline] - fn cond(&self) -> ArmCond { - ArmCond::from_u8(self.bit_range(8..12) as u8).expect("bad condition") - } - - #[inline] - fn flag(self, bit: usize) -> bool { - self.bit(bit) - } - - #[inline] - fn register_list(&self) -> u8 { - (*self & 0xff) as u8 - } - - #[inline] - fn sword7(&self) -> i32 { - let imm7 = *self & 0x7f; - if self.bit(7) { - -((imm7 << 2) as i32) - } else { - (imm7 << 2) as i32 - } - } - } - - )*} -} - -thumb_decode_helper_impl!(u16); - -// #[cfg(test)] -// /// All instructions constants were generated using an ARM assembler. -// mod tests { -// use super::super::Core; -// use super::*; -// use crate::sysbus::BoxedMemory; -// use crate::Bus; - -// #[test] -// fn mov_low_reg() { -// let bytes = vec![]; -// let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); -// 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"); -// core.exec_thumb(&mut mem, insn).unwrap(); -// assert_eq!(core.get_reg(0), 0x27); -// } - -// // #[test] -// // fn decode_add_sub() { -// // let insn = ThumbInstruction::decode(0xac19, 0).unwrap(); -// // assert!(format!("add\tr4, r4")) -// // } - -// #[test] -// fn ldr_pc() { -// // ldr r0, [pc, #4] -// let insn = ThumbInstruction::decode(0x4801, 0x6).unwrap(); - -// #[rustfmt::skip] -// let bytes = vec![ -// /* 0: */ 0x00, 0x00, -// /* 2: */ 0x00, 0x00, -// /* 4: */ 0x00, 0x00, -// /* 6: */ 0x00, 0x00, -// /* 8: */ 0x00, 0x00, 0x00, 0x00, -// /* c: */ 0x78, 0x56, 0x34, 0x12, -// ]; -// let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); -// let mut core = Core::new(); -// core.set_reg(0, 0); - -// assert_eq!(format!("{}", insn), "ldr\tr0, [pc, #0x4] ; = #0xc"); -// core.exec_thumb(&mut mem, insn).unwrap(); -// assert_eq!(core.get_reg(0), 0x12345678); -// } - -// #[test] -// fn ldr_str_reg_offset() { -// // str r0, [r4, r1] -// let str_insn = ThumbInstruction::decode(0x5060, 0x6).unwrap(); -// // ldrb r2, [r4, r1] -// let ldr_insn = ThumbInstruction::decode(0x5c62, 0x6).unwrap(); - -// let mut core = Core::new(); -// core.set_reg(0, 0x12345678); -// core.set_reg(2, 0); -// core.set_reg(1, 0x4); -// core.set_reg(4, 0xc); - -// #[rustfmt::skip] -// let bytes = vec![ -// /* 00h: */ 0xaa, 0xbb, 0xcc, 0xdd, -// /* 04h: */ 0xaa, 0xbb, 0xcc, 0xdd, -// /* 08h: */ 0xaa, 0xbb, 0xcc, 0xdd, -// /* 0ch: */ 0xaa, 0xbb, 0xcc, 0xdd, -// /* 10h: */ 0xaa, 0xbb, 0xcc, 0xdd, -// ]; -// let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); - -// assert_eq!(format!("{}", str_insn), "str\tr0, [r4, r1]"); -// assert_eq!(format!("{}", ldr_insn), "ldrb\tr2, [r4, r1]"); -// core.exec_thumb(&mut mem, str_insn).unwrap(); -// assert_eq!(mem.read_32(0x10), 0x12345678); -// core.exec_thumb(&mut mem, ldr_insn).unwrap(); -// assert_eq!(core.get_reg(2), 0x78); -// } - -// #[allow(overflowing_literals)] -// #[test] -// fn format8() { -// let mut core = Core::new(); -// #[rustfmt::skip] -// let bytes = vec![ -// /* 00h: */ 0xaa, 0xbb, 0xcc, 0xdd, 0xaa, 0xbb, 0xcc, 0xdd, -// /* 08h: */ 0xaa, 0xbb, 0xcc, 0xdd, 0xaa, 0xbb, 0xcc, 0xdd, -// /* 10h: */ 0xaa, 0xbb, 0xcc, 0xdd, 0xaa, 0xbb, 0xcc, 0xdd, -// ]; -// let mut mem = BoxedMemory::new(bytes.into_boxed_slice(), 0xffff_ffff); - -// core.gpr[4] = 0x12345678; -// core.gpr[3] = 0x2; -// core.gpr[0] = 0x4; -// // strh r4, [r3, r0] -// let decoded = ThumbInstruction::decode(0x521c, 0).unwrap(); -// assert_eq!(format!("{}", decoded), "strh\tr4, [r3, r0]"); -// core.exec_thumb(&mut mem, decoded).unwrap(); -// assert_eq!(&mem.get_bytes(0x6)[..4], [0x78, 0x56, 0xaa, 0xbb]); - -// // ldsb r2, [r7, r1] -// core.gpr[2] = 0; -// core.gpr[7] = 0x10; -// core.gpr[1] = 0x5; -// let decoded = ThumbInstruction::decode(0x567a, 0).unwrap(); -// assert_eq!(format!("{}", decoded), "ldsb\tr2, [r7, r1]"); -// core.exec_thumb(&mut mem, decoded).unwrap(); -// assert_eq!(core.gpr[2], mem.read_8(0x15) as i8 as u32); - -// // ldsh r3, [r4, r2] -// core.gpr[3] = 0x0; -// core.gpr[4] = 0x0; -// core.gpr[2] = 0x6; -// let decoded = ThumbInstruction::decode(0x5ea3, 0).unwrap(); -// assert_eq!(format!("{}", decoded), "ldsh\tr3, [r4, r2]"); -// core.exec_thumb(&mut mem, decoded).unwrap(); -// assert_eq!(core.gpr[3], 0x5678); -// } -// }