From be97f60c41ff46e8b7a894cf5faf67109c3d4288 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 4 Aug 2019 19:12:54 -0700 Subject: decode blx --- src/armv7.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- test/armv7.rs | 4 +++ 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/src/armv7.rs b/src/armv7.rs index a5467e5..4a806f2 100644 --- a/src/armv7.rs +++ b/src/armv7.rs @@ -119,6 +119,9 @@ impl ShowContextual], T> for Instructi write!(out, " ")?; format_reg_list(out, list, colors)?; }, + Operands::OneOperand(a) => { + write!(out, " {}", reg_name_colorize(a, colors))?; + }, Operands::TwoOperand(a, b) => { write!(out, " {}, {}", reg_name_colorize(a, colors), reg_name_colorize(b, colors))?; }, @@ -409,6 +412,7 @@ pub enum ShiftSpec { #[derive(Debug, PartialEq, Eq)] pub enum Operands { RegisterList(u16), + OneOperand(u8), TwoOperand(u8, u8), RegImm(u8, u32), RegRegList(u8, u16), @@ -697,7 +701,34 @@ impl Decodable for Instruction { if cond == 0b1111 { // do unconditional instruction stuff self.condition = ConditionCode::AL; - self.opcode = Opcode::Incomplete(word); + let op1 = (word >> 20) as u8; + if op1 > 0x80 { + match (op1 >> 5) & 0b11 { + 0b00 => { + self.opcode = Opcode::Incomplete(word); + } + 0b01 => { + self.opcode = Opcode::BLX; + let operand = ((word & 0xffffff) as i32) << 8 >> 6; + self.operands = Operands::BranchOffset( + operand | ( + ((word >> 23) & 0b10) as i32 + ) + ); + } + 0b10 => { + self.opcode = Opcode::Incomplete(word); + } + 0b11 => { + self.opcode = Opcode::Incomplete(word); + } + _ => { + unreachable!(); + } + } + } else { + self.opcode = Opcode::Incomplete(word); + } return Some(()); } else { self.condition = ConditionCode::build(cond); @@ -915,11 +946,54 @@ impl Decodable for Instruction { // misc instructions in Figure A3-4 if s == false && opcode >= 0b1000 && opcode < 0b1100 { + let op2 = ((word >> 4) & 0x0f) as u8; // the instruction looks like // |c o n d|0 0 0|1 0 x x|0|x x x x|x x x x|x x x x x|x x|x|x x x x| - // misc instructions (page A5-194) - self.opcode = Opcode::Incomplete(word); - return Some(()); + if op2 & 0x08 == 0x00 { + let op2 = op2 & 0x07; + // |c o n d|0 0 0|1 0 x x|0|x x x x|x x x x|x x x x|0|x x|x|x x x x| + // misc instructions (page A5-194) + match op2 { + 0b000 => { + + }, + 0b001 => { + + }, + 0b010 => { + + }, + 0b011 => { + if opcode & 0b11 == 0b01 { + self.opcode = Opcode::BLX; + self.operands = Operands::OneOperand((word & 0x0f) as u8); + return Some(()); + } else { + return None; + } + }, + 0b100 => { + self.opcode = Opcode::Incomplete(word); + return Some(()); + }, + 0b101 => { + + } + 0b110 => { + }, + 0b111 => { + + }, + _ => { + unreachable!(); + } + } + } else { + // |c o n d|0 0 0|1 0 x x|0|x x x x|x x x x|x x x x|1|x x|x|x x x x| + // multiply and multiply-accumulate + self.opcode = Opcode::Incomplete(word); + return Some(()); + } } else { if opcode >= 16 { unreachable!(); diff --git a/test/armv7.rs b/test/armv7.rs index 7715585..13c986e 100644 --- a/test/armv7.rs +++ b/test/armv7.rs @@ -86,6 +86,10 @@ fn test_decode_str_ldr() { #[test] fn test_decode_misc() { test_display( + [0x32, 0xff, 0x2f, 0xe1], + "blx r2" + ); + test_display( [0x02, 0x00, 0xa0, 0xe3], "mov r0, 0x2" ); -- cgit v1.1