aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG4
-rw-r--r--src/armv7/thumb.rs37
-rw-r--r--tests/armv7/thumb.rs37
3 files changed, 55 insertions, 23 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 20c885d..5566e82 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -41,6 +41,10 @@ as well as thumb2 fixes from @brandonros:
* lsl, lsr, asr, ror were determining opcode from an incorrect bitfield,
* tbh was decoded as an shifted tbb,
* thumb2: (un)signed extend-and-rotate loaded an incorrect field for rotate,
+* thumb2: preload hints (PLD, PLI) were over-eagerly decoded
+ namely, ldrb{t} and ldrh{t} into pc are .. weird .. but just weird.
+* thumb2: preload data reported two operands when it has one
+ (the "first operand" was the Rd=r15 operand which makes them preload in the first place)
thank you for the patches!
diff --git a/src/armv7/thumb.rs b/src/armv7/thumb.rs
index b8d1192..1f0cdf5 100644
--- a/src/armv7/thumb.rs
+++ b/src/armv7/thumb.rs
@@ -2419,19 +2419,11 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
} else if op2 & 0b111100 == 0b111000 {
// `(immediate, Thumb)`
- let opcode = if rt == 0b1111 {
- [
- Opcode::PLD,
- Opcode::PLD,
- Opcode::LDRT,
- ][size]
- } else {
- [
- Opcode::LDRBT,
- Opcode::LDRHT,
- Opcode::LDRT,
- ][size]
- };
+ let opcode = [
+ Opcode::LDRBT,
+ Opcode::LDRHT,
+ Opcode::LDRT,
+ ][size];
let w = lower2[8];
let u = lower2[9];
let p = lower2[10];
@@ -2449,19 +2441,11 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
];
} else if op2 & 0b100100 == 0b100100 {
// `(immediate, Thumb)`
- let opcode = if rt == 0b1111 {
- [
- Opcode::PLD,
- Opcode::PLD,
- Opcode::LDR,
- ][size]
- } else {
- [
+ let opcode = [
Opcode::LDRB,
Opcode::LDRH,
Opcode::LDR,
- ][size]
- };
+ ][size];
let w = lower2[8];
let u = lower2[9];
let p = lower2[10];
@@ -2760,6 +2744,13 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
}
}
}
+
+ // TODO: so, this is gross! the PLD/PLI/PLT handling needs improvement across
+ // the board.
+ if inst.opcode == Opcode::PLD {
+ inst.operands[0] = inst.operands[1];
+ inst.operands[1] = Operand::Nothing;
+ }
} else {
if !op2[4] {
// `Data-processing (register)` (`A6-243`)
diff --git a/tests/armv7/thumb.rs b/tests/armv7/thumb.rs
index e6e1bfb..9ace8d2 100644
--- a/tests/armv7/thumb.rs
+++ b/tests/armv7/thumb.rs
@@ -4573,6 +4573,43 @@ fn msr_mrs() {
}
#[test]
+fn prefetch() {
+ test_display(
+ &[0xb0, 0xf8, 0x03, 0xfe],
+ "pld.w [r0, #0xe03]"
+ );
+ // ldrb with upper word bit 7 clear is just ldrb,
+ // but with it set it would be pld
+ test_display(
+ &[0x11, 0xf8, 0x78, 0xff],
+ "ldrb.w pc, [r1, #0x78]!"
+ );
+ test_display(
+ &[0x91, 0xf8, 0x78, 0xff],
+ "pld.w [r1, #0xf78]"
+ );
+ // likewise, ldrh with bits 7, 8 clear Rt=1111 is only prefetch
+ // for some op2 patterns..
+ test_display(
+ &[0x3b, 0xf8, 0x78, 0xff],
+ "ldrh.w pc, [fp, #0x78]!"
+ );
+ test_display(
+ &[0x3b, 0xf8, 0x78, 0xfc],
+ "pld.w [fp, #-0x78]"
+ );
+ test_display(
+ &[0x3b, 0xf8, 0x38, 0xf0],
+ "pld.w [fp, r8, lsl #3]"
+ );
+ // and ldrbt also does not become pld on rt==1111
+ test_display(
+ &[0x10, 0xf8, 0x7c, 0xfe],
+ "ldrbt.w pc, [r0, #0x7c]"
+ );
+}
+
+#[test]
fn pkh() {
test_display(
&[0xc7, 0xea, 0xe8, 0x77],