aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjam1garner <jam@jam1.re>2023-01-31 00:53:05 -0500
committerjam1garner <jam@jam1.re>2023-01-31 00:57:03 -0500
commitaf8fcdb3d748b130919e60c1d3a6172d27e487cd (patch)
treef3a71b187fb1074bbb6dbf82d0d7c8a40e327ed2
parentefbdb28824acc2a94b5910a13da34866da300d20 (diff)
fix 24-bit branch immediate decoding
-rw-r--r--src/armv7.rs14
-rw-r--r--tests/armv7/mod.rs3
2 files changed, 13 insertions, 4 deletions
diff --git a/src/armv7.rs b/src/armv7.rs
index c2254a5..276b807 100644
--- a/src/armv7.rs
+++ b/src/armv7.rs
@@ -3815,20 +3815,26 @@ impl Decoder<ARMv7> for InstDecoder {
];
} else if op < 0b110000 {
// 10xxxx
- // the + 1 is to compensate for an architecturally-defined initial offset
inst.opcode = Opcode::B;
+
+ // the + 2 is to compensate for an architecturally-defined initial offset
+ let imm24 = ((((word & 0x00ff_ffff) + 2) << 8) as i32) >> 8;
+
inst.operands = [
- Operand::BranchOffset(((word & 0x00ffff) + 1) as i16 as i32),
+ Operand::BranchOffset(imm24),
Operand::Nothing,
Operand::Nothing,
Operand::Nothing,
];
} else {
// 11xxxx
- // the + 1 is to compensate for an architecturally-defined initial offset
+
+ // the + 2 is to compensate for an architecturally-defined initial offset
+ let imm24 = ((((word & 0x00ff_ffff) + 2) << 8) as i32) >> 8;
+
inst.opcode = Opcode::BL;
inst.operands = [
- Operand::BranchOffset(((word & 0x00ffff) + 1) as i16 as i32),
+ Operand::BranchOffset(imm24),
Operand::Nothing,
Operand::Nothing,
Operand::Nothing,
diff --git a/tests/armv7/mod.rs b/tests/armv7/mod.rs
index a60b50a..59dea7c 100644
--- a/tests/armv7/mod.rs
+++ b/tests/armv7/mod.rs
@@ -298,6 +298,9 @@ fn test_data_imm() {
#[test]
fn test_decode_misc() {
+ test_display([0xfe, 0xff, 0xff, 0xea], "b $+0x0");
+ test_display([0xfd, 0xff, 0xff, 0xeb], "bl $-0x4");
+ test_display([0x13, 0x8d, 0x04, 0xea], "b $+0x123454");
test_armv5([0x32, 0xff, 0x2f, 0xe1], "blx r2");
test_display(
[0x13, 0x5f, 0x6f, 0xe1],