From e30fee133cd0296bf3d0211e5ce13b5dfba03561 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sat, 5 Dec 2020 16:42:17 -0800 Subject: fix some 32-bit thumb2 instructions, hook up .w, `s`, and a few typos mostly confusion of pre/post-increment, operand widths, immediate widths, things of that nature --- src/armv7.rs | 45 +++++++--- src/armv7/thumb.rs | 240 +++++++++++++++++++++++++++++++---------------------- test/armv7.rs | 57 ++++++++----- 3 files changed, 214 insertions(+), 128 deletions(-) diff --git a/src/armv7.rs b/src/armv7.rs index ac84ad9..bba3510 100644 --- a/src/armv7.rs +++ b/src/armv7.rs @@ -11,11 +11,12 @@ use yaxpeax_arch::{Arch, AddressDiff, Colorize, Decoder, LengthedInstruction, No mod thumb; -pub struct ConditionedOpcode(pub Opcode, pub bool, pub ConditionCode); +// opcode, s, w, cond +pub struct ConditionedOpcode(pub Opcode, pub bool, pub bool, pub ConditionCode); impl Display for ConditionedOpcode { fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { - write!(f, "{}{}{}", self.0, if self.1 { "s" } else { "" }, self.2) + write!(f, "{}{}{}{}", self.0, if self.1 { "s" } else { "" }, if self.2 { ".w" } else { "" }, self.3) } } @@ -116,7 +117,7 @@ impl > ShowContextual { - ConditionedOpcode(Opcode::POP, self.s, self.condition).colorize(colors, out)?; + ConditionedOpcode(Opcode::POP, self.s(), self.w(), self.condition).colorize(colors, out)?; return write!(out, " {{{}}}", reg_name_colorize(Rt, colors)); }, _ => {} @@ -126,7 +127,7 @@ impl > ShowContextual { - ConditionedOpcode(Opcode::PUSH, self.s, self.condition).colorize(colors, out)?; + ConditionedOpcode(Opcode::PUSH, self.s(), self.w(), self.condition).colorize(colors, out)?; return write!(out, " {{{}}}", reg_name_colorize(Rt, colors)); }, _ => {} @@ -136,7 +137,7 @@ impl > ShowContextual { - ConditionedOpcode(Opcode::POP, self.s, self.condition).colorize(colors, out)?; + ConditionedOpcode(Opcode::POP, self.s(), self.w(), self.condition).colorize(colors, out)?; write!(out, " ")?; return format_reg_list(out, list, colors); } @@ -147,7 +148,7 @@ impl > ShowContextual { - ConditionedOpcode(Opcode::PUSH, self.s, self.condition).colorize(colors, out)?; + ConditionedOpcode(Opcode::PUSH, self.s(), self.w(), self.condition).colorize(colors, out)?; write!(out, " ")?; return format_reg_list(out, list, colors); } @@ -163,7 +164,7 @@ impl > ShowContextual { match self.operands { [Operand::RegWBack(Rr, wback), Operand::RegList(list), Operand::Nothing, Operand::Nothing] => { - ConditionedOpcode(self.opcode, self.s, self.condition).colorize(colors, out)?; + ConditionedOpcode(self.opcode, self.s(), self.w(), self.condition).colorize(colors, out)?; write!( out, " {}{}, ", reg_name_colorize(Rr, colors), @@ -301,7 +302,7 @@ impl > ShowContextual { - ConditionedOpcode(self.opcode, self.s, self.condition).colorize(colors, out)?; + ConditionedOpcode(self.opcode, self.s(), self.w(), self.condition).colorize(colors, out)?; let mut ops = self.operands.iter(); if let Some(first_op) = ops.next() { if let Operand::Nothing = first_op { @@ -1313,7 +1314,8 @@ pub struct Instruction { pub condition: ConditionCode, pub opcode: Opcode, pub operands: [Operand; 4], - pub s: bool + pub s: bool, + pub thumb_w: bool, } #[derive(Debug, PartialEq)] @@ -1324,6 +1326,7 @@ pub enum DecodeError { Incomplete, Nonconforming, Undefined, + Unpredictable, } impl fmt::Display for DecodeError { @@ -1335,6 +1338,7 @@ impl fmt::Display for DecodeError { DecodeError::Incomplete => write!(f, "incomplete decoder"), DecodeError::Nonconforming => write!(f, "invalid reserved bits"), DecodeError::Undefined => write!(f, "undefined encoding"), + DecodeError::Unpredictable => write!(f, "unpredictable instruction"), } } } @@ -1342,7 +1346,9 @@ impl fmt::Display for DecodeError { impl yaxpeax_arch::DecodeError for DecodeError { fn data_exhausted(&self) -> bool { self == &DecodeError::ExhaustedInput } fn bad_opcode(&self) -> bool { self == &DecodeError::InvalidOpcode } - fn bad_operand(&self) -> bool { self == &DecodeError::InvalidOperand } + fn bad_operand(&self) -> bool { + self == &DecodeError::InvalidOperand || self == &DecodeError::Unpredictable + } } impl yaxpeax_arch::Instruction for Instruction { @@ -1356,7 +1362,8 @@ impl Default for Instruction { condition: ConditionCode::AL, opcode: Opcode::Invalid, operands: [Operand::Nothing, Operand::Nothing, Operand::Nothing, Operand::Nothing], - s: false + s: false, + thumb_w: false, } } } @@ -1366,6 +1373,10 @@ impl Instruction { self.s = value; } pub fn s(&self) -> bool { self.s } + pub(crate) fn set_w(&mut self, value: bool) { + self.thumb_w = value; + } + pub fn w(&self) -> bool { self.thumb_w } } fn format_reg_list>(f: &mut T, mut list: u16, colors: &Y) -> Result<(), fmt::Error> { @@ -1550,7 +1561,7 @@ impl ConditionCode { } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[allow(dead_code)] enum DecodeMode { User, @@ -1752,6 +1763,14 @@ impl InstDecoder { thumb: false, } } + + fn unpredictable(&self) -> Result<(), DecodeError> { + if self.mode != DecodeMode::Any { + Err(DecodeError::Unpredictable) + } else { + Ok(()) + } + } } #[allow(non_snake_case)] @@ -1761,6 +1780,8 @@ impl Decoder for InstDecoder { fn decode_into>(&self, inst: &mut Instruction, bytes: T) -> Result<(), Self::Error> { if self.thumb { return thumb::decode_into(&self, inst, bytes); + } else { + inst.set_w(false); } fn read_word>(bytes: T) -> Result { diff --git a/src/armv7/thumb.rs b/src/armv7/thumb.rs index d786305..93290a1 100644 --- a/src/armv7/thumb.rs +++ b/src/armv7/thumb.rs @@ -96,7 +96,8 @@ fn DecodeImmShift(reg: u8, ty: u8, imm5: u8) -> RegShift { } #[allow(non_snake_case)] -pub fn decode_into>(_decoder: &InstDecoder, inst: &mut Instruction, bytes: T) -> Result<(), DecodeError> { +pub fn decode_into>(decoder: &InstDecoder, inst: &mut Instruction, bytes: T) -> Result<(), DecodeError> { + inst.set_w(false); let mut iter = bytes.into_iter(); let instr: u16 = ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u16) ) | @@ -106,14 +107,17 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut // `A6.1 Thumb instruction set encoding` if opword >= 0b11101 { + inst.set_w(true); + + // 32b instruction - `A6-228, 32-bit Thumb instruction encoding` + // opword low bits 01, 10, and 11 correspond to `op1` in table `A6-9` + let lower: u16 = ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u16) ) | ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u16) << 8 ); let op2 = (instr >> 5) & 0b1111111; - // 32b instruction - `A6-228, 32-bit Thumb instruction encoding` - // opword low bits 01, 10, and 11 correspond to `op1` in table `A6-9` if opword < 0b11110 { // op1 == 0b01 if op2 < 0b1000000 { @@ -130,15 +134,18 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut let rd = ((lower >> 8) & 0b1111) as u8; let rt = ((lower >> 12) & 0b1111) as u8; + // all only-wide, no w suffix + inst.set_w(false); + match op1op2 { 0b0000 => { // `STREX` (`A8-691`) // v6T2 if rd == 13 || rd == 15 || rt == 13 || rt == 15 || rn == 15 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } if rd == rn || rd == rt { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } inst.opcode = Opcode::STREX; inst.operands = [ @@ -159,7 +166,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut // `LDREX` (`A8-433`) // v6T2 if rt == 13 || rt == 15 || rn == 15 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } // TODO: should_is_must() // rd == 0b1111 @@ -189,7 +196,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut // `if P == '0' && W == '0' then SEE "Related encodings"` -> this // would imply tbb/tbh, should be unreachable if rn == 15 || rt == 13 || rt == 15 || rd == 13 || rd == 15 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } inst.opcode = Opcode::STRD; inst.operands = [ @@ -214,10 +221,10 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut // `if P == '0' && W == '0' then SEE "Related encodings"` -> this // would imply tbb/tbh, should be unreachable if rt == 13 || rt == 15 || rd == 13 || rd == 15 || rd == rt { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } if w && (rn == rt || rn == rd) { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } if rn != 0b1111 { // `LDRD (immediate)` (`A8-427`) @@ -238,7 +245,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut // `LDRD (literal)` (`A8-429`) // v6T2 if w { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } // which because !(p == 0 && w == 0), we know p is true inst.opcode = Opcode::LDRD; @@ -260,10 +267,10 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b0100 => { // `STREXB` (`A8-693`) if rd == 13 || rd == 15 || rt == 13 || rt == 15 || rn == 15 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } if rd == rn || rd == rt { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } // TODO: should_is_must() // rt2 == 0b1111 @@ -278,10 +285,10 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b0101 => { // `STREXH` (`A8-693`) if rd == 13 || rd == 15 || rt == 13 || rt == 15 || rn == 15 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } if rd == rn || rd == rt { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } // TODO: should_is_must() // rt2 == 0b1111 @@ -296,10 +303,10 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b0111 => { // `STREXD` (`A8-693`) if rd == 13 || rd == 15 || rt == 13 || rt == 15 || rt2 == 13 || rt2 == 15 || rn == 15 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } if rd == rn || rd == rt || rd == rt2 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } inst.opcode = Opcode::STREXD; inst.operands = [ @@ -366,7 +373,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b0100 => { // `LDREXB` if rt == 13 || rt == 15 || rn == 15 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } // TODO: should_is_must() // rt2 == 0b1111 @@ -382,7 +389,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b0101 => { // `LDREXH` if rt == 13 || rt == 15 || rn == 15 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } // TODO: should_is_must() // rt2 == 0b1111 @@ -398,7 +405,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b0110 => { // `LDREXD` if rt == 13 || rt == 15 || rt2 == 13 || rt2 == 15 || rn == 15 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } // TODO: should_is_must() // rd == 0b1111 @@ -428,7 +435,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut // `if P == '0' && W == '0' then SEE "Related encodings"` -> this // would imply tbb/tbh, should be unreachable if rn == 15 || rt == 13 || rt == 15 || rd == 13 || rd == 15 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } inst.opcode = Opcode::STRD; inst.operands = [ @@ -456,10 +463,10 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut // `if P == '0' && W == '0' then SEE "Related encodings"` -> this // would imply tbb/tbh, should be unreachable if rt == 13 || rt == 15 || rd == 13 || rd == 15 || rd == rt { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } if w && (rn == rt || rn == rd) { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } if rn != 0b1111 { // `LDRD (immediate)` (`A8-427`) @@ -469,10 +476,10 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut Operand::Reg(Reg::from_u8(rt)), Operand::Reg(Reg::from_u8(rd)), if p { - Operand::RegDerefPreindexOffset(Reg::from_u8(rn), imm8 << 2, u, w) + Operand::RegDerefPostindexOffset(Reg::from_u8(rn), imm8 << 2, u, w) } else { // p == 0 and w == 0 is impossible, would be tbb/tbh - Operand::RegDerefPostindexOffset(Reg::from_u8(rn), imm8 << 2, u, false) + Operand::RegDerefPreindexOffset(Reg::from_u8(rn), imm8 << 2, u, false) }, Operand::Nothing, ]; @@ -480,7 +487,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut // `LDRD (literal)` (`A8-429`) // v6T2 if w { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } // which because !(p == 0 && w == 0), we know p is true inst.opcode = Opcode::LDRD; @@ -517,14 +524,14 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut // `STM (STMIA, STMEA)` (`A8-665`) // v6T2 if rn == 15 || lower.count_ones() < 2 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } if w && (lower & (1 << rn)) != 0 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } inst.opcode = Opcode::STM( true, // add - true, // preincrement + false, // preincrement w, // wback true, // usermode ); @@ -538,11 +545,15 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b10 => { // `STMDB`/`STMFD` (`A8-669`) // or `PUSH` (`A8-539`) + + // implied by instruction? + inst.set_w(false); + if w && rn == 0b1101 { // `PUSH` // v6T2 if lower.count_ones() < 2 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } inst.opcode = Opcode::PUSH; inst.operands = [ @@ -555,10 +566,10 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut // `STMDB` // v6T2 if rn == 15 || lower.count_ones() < 2 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } if w && (lower & (1 << rn)) != 0 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } inst.opcode = Opcode::STM( false, // decrement @@ -596,7 +607,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut // `RFE` (`B9-1986`) // v6T2 if rn == 15 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } inst.opcode = Opcode::RFE(false, true); inst.operands = [ @@ -611,7 +622,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut if w && rn == 0b1101 { // `POP` (`A8-535`) if lower.count_ones() < 2 || (lower & 0xc000) == 0xc000 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } inst.opcode = Opcode::POP; inst.operands = [ @@ -623,12 +634,12 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut } else { // `LDM/LDMIA/LDMFD` if rn == 15 || lower.count_ones() < 2 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } if w && (lower & (1 << rn)) != 0 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } - inst.opcode = Opcode::LDM(true, true, w, true); + inst.opcode = Opcode::LDM(true, false, w, true); inst.operands = [ Operand::RegWBack(Reg::from_u8(rn), w), Operand::RegList(lower), @@ -639,11 +650,15 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut } 0b10 => { // `LDMDB/LDMEA` (`A8-403`) + + // wide is implied + inst.set_w(false); + if rn == 15 || lower.count_ones() < 2 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } if w && (lower & (1 << rn)) != 0 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } inst.opcode = Opcode::LDM(false, true, w, true); inst.operands = [ @@ -657,7 +672,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut // `RFE` (`B9-1986`) // v6T2 if rn == 15 { - todo!("UNPREDICTABLE"); + decoder.unpredictable()?; } inst.opcode = Opcode::RFE(true, false); inst.operands = [ @@ -694,11 +709,14 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut ); let shift = Operand::RegShift(shift); + inst.s = s; + match op { 0b0000 => { if rd == 0b1111 && s { // `TST` (`A8-747`) // v6T2 + inst.s = false; inst.opcode = Opcode::TST; inst.operands = [ Operand::Reg(Reg::from_u8(rn)), @@ -709,7 +727,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut } else { // `AND` (`A8-324`) // v6T2 - // TODO: S inst.opcode = Opcode::AND; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -722,7 +739,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b0001 => { // `BIC` (`A8-340`) // v6T2 - // TODO: S inst.opcode = Opcode::BIC; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -771,7 +787,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut } else { // `ORR` (`A8-519`) // v6T2 - // TODO: S inst.opcode = Opcode::ORR; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -785,7 +800,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut if rn == 0b1111 { // `MVN` (`A8-507`) // v6T2 - // TODO: S inst.opcode = Opcode::MVN; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -796,7 +810,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut } else { // `ORN` (`A8-515`) // v6T2 - // TODO: S inst.opcode = Opcode::ORN; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -810,6 +823,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut if rd == 0b1111 && s { // `TEQ` (`A8-741`) // v6T2 + inst.s = false; inst.opcode = Opcode::TEQ; inst.operands = [ Operand::Reg(Reg::from_u8(rn)), @@ -820,7 +834,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut } else { // `EOR` (`A8-385`) // v6T2 - // TODO: S inst.opcode = Opcode::EOR; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -835,7 +848,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut // v6T2 // TODO: fix shift // TODO: check opcode - // TODO: S + inst.s = false; inst.opcode = if lower & 0b10000 != 0 { Opcode::PKHTB } else { @@ -852,6 +865,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut if rd == 0b1111 && s { // `CMN` (`A8-364`) // v6T2 + inst.s = false; inst.opcode = Opcode::CMN; inst.operands = [ Operand::Reg(Reg::from_u8(rn)), @@ -861,7 +875,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut ]; } else { // `ADD` (`A8-308`) - // TODO: S inst.opcode = Opcode::ADD; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -874,7 +887,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b1010 => { // `ADC` (`A8-300`) // v6T2 - // TODO: S inst.opcode = Opcode::ADC; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -886,7 +898,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b1011 => { // `SBC` (`A8-595`) // v6T2 - // TODO: S inst.opcode = Opcode::SBC; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -899,6 +910,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut if rd == 0b1111 && s { // `CMP` (`A8-370`) // v6T2 + inst.s = false; inst.opcode = Opcode::CMP; inst.operands = [ Operand::Reg(Reg::from_u8(rn)), @@ -909,7 +921,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut } else { // `SUB` (`A8-713`) // v6T2 - // TODO: S inst.opcode = Opcode::SUB; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -959,6 +970,8 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut let imm8 = lower & 0b11111111; let imm = (i << 11) | (imm3 << 8) | imm8; + inst.s = s; + let imm = ThumbExpandImm_C(imm); match op { @@ -966,6 +979,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut if rd == 0b1111 && s { // `TST` (`A8-745`) // v6T2 + inst.s = false; inst.opcode = Opcode::TST; inst.operands = [ Operand::Reg(Reg::from_u8(rn)), @@ -976,7 +990,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut } else { // `AND` (`A8-322`) // v6T2 - // TODO: S inst.opcode = Opcode::AND; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -989,7 +1002,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b0001 => { // `BIC` (`A8-338`) // v6T2 - // TODO: S inst.opcode = Opcode::BIC; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -1002,7 +1014,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut if rn == 0b1111 { // `MOV` (`A8-485`) // v6T2 - // TODO: S inst.opcode = Opcode::MOV; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -1013,7 +1024,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut } else { // `ORR` (`A8-517`) // v6T2 - // TODO: S inst.opcode = Opcode::ORR; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -1027,7 +1037,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut if rn == 0b1111 { // `MVN` (`A8-505`) // v6T2 - // TODO: S inst.opcode = Opcode::MOV; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -1038,7 +1047,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut } else { // `ORN` (`A8-513`) // v6T2 - // TODO: S inst.opcode = Opcode::ORN; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -1052,7 +1060,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut if rd == 0b1111 && s { // `TEQ` (`A8-739`) // v6T2 - // TODO: S + inst.s = false; inst.opcode = Opcode::TEQ; inst.operands = [ Operand::Reg(Reg::from_u8(rn)), @@ -1063,7 +1071,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut } else { // `EOR` (`A8-383`) // v6T2 - // TODO: S inst.opcode = Opcode::EOR; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -1077,7 +1084,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut if rd == 0b1111 && s { // `CMN` (`A8-362`) // v6T2 - // TODO: S + inst.s = false; inst.opcode = Opcode::CMN; inst.operands = [ Operand::Reg(Reg::from_u8(rn)), @@ -1088,7 +1095,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut } else { // `ADD` (`A8-304`) // v6T2 - // TODO: S inst.opcode = Opcode::ADD; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -1101,7 +1107,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b1010 => { // `ADC` (`A8-298`) // v6T2 - // TODO: S inst.opcode = Opcode::ADC; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -1113,7 +1118,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b1011 => { // `SBC` (`A8-593`) // v6T2 - // TODO: S inst.opcode = Opcode::SBC; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -1126,7 +1130,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut if rd == 0b1111 && s { // `CMP` (`A8-368`) // v6T2 - // TODO: S + inst.s = false; inst.opcode = Opcode::CMP; inst.operands = [ Operand::Reg(Reg::from_u8(rn)), @@ -1137,7 +1141,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut } else { // `SUB` (`A8-709`) // v6T2 - // TODO: S inst.opcode = Opcode::SUB; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -1150,7 +1153,6 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b1110 => { // `RSB` (`A8-575`) // v6T2 - // TODO: S inst.opcode = Opcode::RSB; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), @@ -1289,6 +1291,10 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b10100 => { // `SBFX` (`A8-599`) // v6T2 + + // wide is implied + inst.set_w(false); + inst.opcode = Opcode::SBFX; let imm3_2 = ((lower >> 10) & 0b11100) | ((lower >> 6) & 0b11); inst.operands = [ @@ -1334,7 +1340,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut inst.opcode = Opcode::USAT; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), - Operand::Imm32((lower & 0b1111) as u32), + Operand::Imm32((lower & 0b11111) as u32), Operand::RegShift(shift), Operand::Nothing, ]; @@ -1349,7 +1355,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut inst.opcode = Opcode::USAT; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), - Operand::Imm32((lower & 0b1111) as u32), + Operand::Imm32((lower & 0b11111) as u32), Operand::RegShift(shift), Operand::Nothing, ]; @@ -1359,7 +1365,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut inst.opcode = Opcode::USAT16; inst.operands = [ Operand::Reg(Reg::from_u8(rd)), - Operand::Imm32((lower & 0b1111) as u32), + Operand::Imm32((lower & 0b11111) as u32), Operand::Reg(Reg::from_u8(rn)), Operand::Nothing, ]; @@ -1368,6 +1374,10 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut 0b11100 => { // `UBFX` (`A8-757`) // v6T2 + + // wide is implied + inst.set_w(false); + inst.opcode = Opcode::UBFX; let imm3_2 = ((lower >> 10) & 0b11100) | ((lower >> 6) & 0b11); inst.operands = [ @@ -1432,7 +1442,10 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut let mask = (lower >> 10) & 0b11; let spec_reg = match mask { 0b00 => { - todo!("UNPREDICTABLE"); + // TODO: generally "unpredictable" is + // overridden by DecodeMode::Any but there's + // nothing to salvage here? + return Err(DecodeError::Unpredictable); } 0b01 => { StatusRegMask::APSR_G @@ -1920,13 +1933,22 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut ]; } else { // `STRB (immediate, Thumb)` (`A8-679`) - // encoding T3 + // encoding T2/T3 // v6T2 - let imm8 = lower & 0b1111_1111; - let puw = (lower >> 8) & 0b111; - let p = puw & 0b100 != 0; - let u = puw & 0b010 != 0; - let w = puw & 0b001 != 0; + let (imm, p, u, w) = if has_imm12 { + let imm12 = lower & 0b1111_1111_1111; + let p = true; + let u = true; + let w = false; + (imm12, p, u, w) + } else { + let imm8 = lower & 0b1111_1111; + let puw = (lower >> 8) & 0b111; + let p = puw & 0b100 != 0; + let u = puw & 0b010 != 0; + let w = puw & 0b001 != 0; + (imm8, p, u, w) + }; // assert!(puw != 0b110) // would be `strbt` let rt = ((lower >> 12) & 0b1111) as u8; inst.opcode = Opcode::STRB; @@ -1936,14 +1958,14 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut if p { Operand::RegDerefPreindexOffset( Reg::from_u8(rn), - imm8, + imm, u, // add w, // wback ) } else { Operand::RegDerefPostindexOffset( Reg::from_u8(rn), - imm8, + imm, u, // add w, // wback ) @@ -1997,13 +2019,22 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut ]; } else { // `STRH (immediate, Thumb)` (`A8-699`) - // encoding T3 + // encoding T2/T3 // v6T2 - let imm8 = lower & 0b1111_1111; - let puw = (lower >> 8) & 0b111; - let p = puw & 0b100 != 0; - let u = puw & 0b010 != 0; - let w = puw & 0b001 != 0; + let (imm, p, u, w) = if has_imm12 { + let imm12 = lower & 0b1111_1111_1111; + let p = true; + let u = true; + let w = false; + (imm12, p, u, w) + } else { + let imm8 = lower & 0b1111_1111; + let puw = (lower >> 8) & 0b111; + let p = puw & 0b100 != 0; + let u = puw & 0b010 != 0; + let w = puw & 0b001 != 0; + (imm8, p, u, w) + }; // assert!(puw != 0b110) // would be `strbt` let rt = ((lower >> 12) & 0b1111) as u8; inst.opcode = Opcode::STRH; @@ -2013,14 +2044,14 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut if p { Operand::RegDerefPreindexOffset( Reg::from_u8(rn), - imm8, + imm, u, // add w, // wback ) } else { Operand::RegDerefPostindexOffset( Reg::from_u8(rn), - imm8, + imm, u, // add w, // wback ) @@ -2074,13 +2105,22 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut ]; } else { // `STR (immediate, Thumb)` (`A8-673`) - // encoding T4 + // encoding T3/T4 // v6T2 - let imm8 = lower & 0b1111_1111; - let puw = (lower >> 8) & 0b111; - let p = puw & 0b100 != 0; - let u = puw & 0b010 != 0; - let w = puw & 0b001 != 0; + let (imm, p, u, w) = if has_imm12 { + let imm12 = lower & 0b1111_1111_1111; + let p = true; + let u = true; + let w = false; + (imm12, p, u, w) + } else { + let imm8 = lower & 0b1111_1111; + let puw = (lower >> 8) & 0b111; + let p = puw & 0b100 != 0; + let u = puw & 0b010 != 0; + let w = puw & 0b001 != 0; + (imm8, p, u, w) + }; // assert!(puw != 0b110) // would be `strbt` let rt = ((lower >> 12) & 0b1111) as u8; inst.opcode = Opcode::STR; @@ -2090,14 +2130,14 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut if p { Operand::RegDerefPreindexOffset( Reg::from_u8(rn), - imm8, + imm, u, // add w, // wback ) } else { Operand::RegDerefPostindexOffset( Reg::from_u8(rn), - imm8, + imm, u, // add w, // wback ) @@ -2211,24 +2251,30 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut } else { if op2 < 0b0100 { // `Parallel addition and subtraction, signed` + return Err(DecodeError::Incomplete); } else if op2 < 0b1000 { // `Parallel addition and subtraction, unsigned` (`A6-244`) + return Err(DecodeError::Incomplete); } else if op2 < 0b1100 { // `Miscellaneous operations` (`A6-246`) + return Err(DecodeError::Incomplete); } else { return Err(DecodeError::Undefined); } } } else { - if op2 & 0b0001000 == 0 { - // `Multiply, multiply accumulate, and absolute difference` (`A6-247`) - } else { + if op2 & 0b0001000 != 0 { // `Long multiply, long multiply accumulate, and divide` (`A6-248`) + return Err(DecodeError::Incomplete); + } else { + // `Multiply, multiply accumulate, and absolute difference` (`A6-247`) + return Err(DecodeError::Incomplete); } } } } else { // `Coprocessor, Advanced SIMD, and Floating-point instructions` (`A6-249`) + return Err(DecodeError::Incomplete); } } } else { @@ -3040,7 +3086,7 @@ pub fn decode_into>(_decoder: &InstDecoder, inst: &mut let rn = ((instr >> 8) & 0b111) as u8; let reglist = instr & 0b1111_1111; let w = (reglist & (1 << rn)) == 0; - inst.opcode = Opcode::LDM(true, true, false, true); // ldmia, no wback, yes usermode + inst.opcode = Opcode::LDM(true, false, false, true); // ldmia, no wback, yes usermode inst.operands = [ Operand::RegWBack(Reg::from_u8(rn), w), Operand::RegList(reglist as u16), diff --git a/test/armv7.rs b/test/armv7.rs index 09a57e2..c2f3300 100644 --- a/test/armv7.rs +++ b/test/armv7.rs @@ -108,7 +108,8 @@ fn test_decode_str_ldr() { Operand::Nothing, Operand::Nothing, ], - s: false + s: false, + thumb_w: false, } ); test_decode( @@ -122,7 +123,8 @@ fn test_decode_str_ldr() { Operand::Nothing, Operand::Nothing, ], - s: false + s: false, + thumb_w: false, } ); test_decode( @@ -136,7 +138,8 @@ fn test_decode_str_ldr() { Operand::Nothing, Operand::Nothing, ], - s: false + s: false, + thumb_w: false, } ); test_decode( @@ -150,7 +153,8 @@ fn test_decode_str_ldr() { Operand::Nothing, Operand::Nothing, ], - s: false + s: false, + thumb_w: false, } ); test_decode( @@ -164,7 +168,8 @@ fn test_decode_str_ldr() { Operand::Nothing, Operand::Nothing, ], - s: false + s: false, + thumb_w: false, } ); test_decode( @@ -178,7 +183,8 @@ fn test_decode_str_ldr() { Operand::Nothing, Operand::Nothing, ], - s: false + s: false, + thumb_w: false, } ); test_all([0x10, 0x00, 0x7f, 0xe5], "ldrb r0, [pc, -0x10]!"); @@ -342,7 +348,8 @@ fn test_decode_pop() { Operand::Nothing, Operand::Nothing, ], - s: false + s: false, + thumb_w: false, } ); test_display( @@ -360,7 +367,8 @@ fn test_decode_pop() { Operand::Nothing, Operand::Nothing, ], - s: false + s: false, + thumb_w: false, } ); test_display( @@ -378,7 +386,8 @@ fn test_decode_pop() { Operand::Nothing, Operand::Nothing, ], - s: false + s: false, + thumb_w: false, } ); test_display( @@ -400,7 +409,8 @@ fn test_decode_mov() { Operand::Nothing, Operand::Nothing, ], - s: false + s: false, + thumb_w: false, } ); test_display([0x0d, 0x20, 0xa0, 0xe1], "mov r2, sp"); @@ -416,7 +426,8 @@ fn test_decode_mov() { Operand::Nothing, Operand::Nothing, ], - s: false + s: false, + thumb_w: false, } ); } @@ -429,7 +440,8 @@ fn test_decode_arithmetic() { condition: ConditionCode::EQ, opcode: Opcode::AND, operands: [Operand::Reg(Reg::from_u8(1)), Operand::Reg(Reg::from_u8(0)), Operand::RegShift(RegShift::from_raw(0xd18)), Operand::Nothing], - s: false + s: false, + thumb_w: false, } ); test_display( @@ -442,7 +454,8 @@ fn test_decode_arithmetic() { condition: ConditionCode::AL, opcode: Opcode::ADD, operands: [Operand::Reg(Reg::from_u8(3)), Operand::Reg(Reg::from_u8(15)), Operand::Reg(Reg::from_u8(3)), Operand::Nothing], - s: false + s: false, + thumb_w: false, } ); test_decode( @@ -451,7 +464,8 @@ fn test_decode_arithmetic() { condition: ConditionCode::AL, opcode: Opcode::RSB, operands: [Operand::Reg(Reg::from_u8(3)), Operand::Reg(Reg::from_u8(6)), Operand::Reg(Reg::from_u8(3)), Operand::Nothing], - s: false + s: false, + thumb_w: false, } ); test_decode( @@ -460,7 +474,8 @@ fn test_decode_arithmetic() { condition: ConditionCode::AL, opcode: Opcode::MOV, operands: [Operand::Reg(Reg::from_u8(3)), Operand::Reg(Reg::from_u8(0)), Operand::RegShift(RegShift::from_raw(0x143)), Operand::Nothing], - s: false + s: false, + thumb_w: false, } ); test_decode( @@ -469,7 +484,8 @@ fn test_decode_arithmetic() { condition: ConditionCode::AL, opcode: Opcode::SUB, operands: [Operand::Reg(Reg::from_u8(5)), Operand::Reg(Reg::from_u8(3)), Operand::Imm32(1), Operand::Nothing], - s: false + s: false, + thumb_w: false, } ); } @@ -535,7 +551,8 @@ fn test_decode_mul() { Operand::Reg(Reg::from_u8(13)), Operand::Nothing, ], - s: false + s: false, + thumb_w: false, } ); test_decode( @@ -549,7 +566,8 @@ fn test_decode_mul() { Operand::Reg(Reg::from_u8(9)), Operand::Nothing, ], - s: false + s: false, + thumb_w: false, } ); test_decode( @@ -563,7 +581,8 @@ fn test_decode_mul() { Operand::Reg(Reg::from_u8(9)), Operand::Nothing, ], - s: false + s: false, + thumb_w: false, } ); } -- cgit v1.1