aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitchell Johnson <ehntoo@ehntoo.org>2022-09-04 19:49:46 -0400
committeriximeow <git@iximeow.net>2022-09-29 15:50:31 -0700
commit9570dae514462f4a823e54de11e6dc86587de1b7 (patch)
treea4b4793490f0aec4ab5d163e7e29c97b530bd6ac
parent4470c5b393817a93854472354d76911cfc9abe6f (diff)
Fix 32-bit conditional thumb branches
Correct the shift used to select condition bits and correctly compute the branch offset.
-rw-r--r--src/armv7/thumb.rs16
-rw-r--r--tests/armv7/thumb.rs4
2 files changed, 18 insertions, 2 deletions
diff --git a/src/armv7/thumb.rs b/src/armv7/thumb.rs
index 2e960b1..45151cd 100644
--- a/src/armv7/thumb.rs
+++ b/src/armv7/thumb.rs
@@ -1491,10 +1491,22 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
if op & 0b0111000 != 0b0111000 {
// `Conditional branch` (`A8-332`)
// v6T2
- inst.condition = ConditionCode::build(((instr >> 8) & 0b1111) as u8);
+ let imm11 = lower2[0..11].load::<u32>();
+ let imm6 = instr2[0..6].load::<u32>();
+ let s = instr2[10..11].load::<u32>();
+ let j1 = lower2[13..14].load::<u32>();
+ let j2 = lower2[11..12].load::<u32>();
+ let imm =
+ (imm11 as i32) |
+ ((imm6 as i32) << 11) |
+ ((j1 as i32) << 17) |
+ ((j2 as i32) << 18) |
+ ((s as i32) << 19);
+ let imm = (imm << 12) >> 12;
+ inst.condition = ConditionCode::build(((instr >> 6) & 0b1111) as u8);
inst.opcode = Opcode::B;
inst.operands = [
- Operand::BranchThumbOffset(((instr & 0b11111111) + 1) as i8 as i32),
+ Operand::BranchThumbOffset(imm),
Operand::Nothing,
Operand::Nothing,
Operand::Nothing,
diff --git a/tests/armv7/thumb.rs b/tests/armv7/thumb.rs
index dc912a6..8e1796d 100644
--- a/tests/armv7/thumb.rs
+++ b/tests/armv7/thumb.rs
@@ -738,6 +738,10 @@ fn test_decode_32b_branch_cases() {
&[0x0c, 0xf0, 0x84, 0xb9],
"b.w $+0xc308"
);
+ test_display(
+ &[0x3f, 0xf4, 0xfe, 0xaf],
+ "b.weq $-0x4"
+ );
}
#[test]
fn test_decode_bkpt_cases() {