aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2019-08-04 19:12:54 -0700
committeriximeow <me@iximeow.net>2020-01-12 17:28:07 -0800
commitbe97f60c41ff46e8b7a894cf5faf67109c3d4288 (patch)
tree58ba58588bc646f22ce3509b0c0926520b3036e5
parented2a36de61a295f7c17378598f5a60e7de9d8b8a (diff)
decode blx
-rw-r--r--src/armv7.rs82
-rw-r--r--test/armv7.rs4
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 <T: std::fmt::Write> ShowContextual<u32, [Option<String>], 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"
);