aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2026-09-11 16:57:56 +0000
committeriximeow <me@iximeow.net>2026-09-11 16:57:56 +0000
commit9eebd279e4a523e009150786ca270f0e2330e0c3 (patch)
tree6c8ff475a50518e0a165fbb750ea840b26b79ec0
parent475321a686f346ac51cded60384a903fa8e9fdf8 (diff)
report rounding bit of smmla/smmls
-rw-r--r--CHANGELOG2
-rw-r--r--src/armv7.rs2
-rw-r--r--src/armv7/display.rs4
-rw-r--r--src/armv7/thumb.rs56
-rw-r--r--tests/armv7/thumb.rs8
5 files changed, 58 insertions, 14 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 15a9c15..c19d6f3 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -36,6 +36,8 @@
the field is 1-based rather than 0-based, so for example an instruction which
had that operand as "1" was incorrectly decoded as being "0"
* thumb2: fix `hvc` immediate missing its upper four bits
+* thumb2: report "round" bit of `smmls` and `smmla` (as the new `smmlsr` and
+ `smmlar` opcodes)
* ARMv7: do not try to elide memory offset when 0 in postindex operands.
this makes a post-index (and implied writeback!) ambiguous with a pre-indexed
access with offset zero. that is, `[r1, 0]` may be written as `[r1]`, but
diff --git a/src/armv7.rs b/src/armv7.rs
index 30a8960..537dccd 100644
--- a/src/armv7.rs
+++ b/src/armv7.rs
@@ -257,7 +257,9 @@ pub enum Opcode {
SMLSD,
SMMLA,
+ SMMLAR,
SMMLS,
+ SMMLSR,
USADA8,
USAD8,
SMLAD,
diff --git a/src/armv7/display.rs b/src/armv7/display.rs
index 3f7162b..7b0be82 100644
--- a/src/armv7/display.rs
+++ b/src/armv7/display.rs
@@ -858,7 +858,9 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for ConditionedOpcode {
Opcode::UMLAL |
Opcode::SMLSD |
Opcode::SMMLA |
+ Opcode::SMMLAR |
Opcode::SMMLS |
+ Opcode::SMMLSR |
Opcode::USADA8 |
Opcode::USAD8 |
Opcode::SDIV |
@@ -1185,7 +1187,9 @@ impl Opcode {
Opcode::SMLSLD(false) => { "smlsldb" },
Opcode::SMLSD => { "smlsd" },
Opcode::SMMLA => { "smmla" },
+ Opcode::SMMLAR => { "smmlar" },
Opcode::SMMLS => { "smmls" },
+ Opcode::SMMLSR => { "smmlsr" },
Opcode::USADA8 => { "usada8" },
Opcode::USAD8 => { "usad8" },
Opcode::SMLAD => { "smlad" },
diff --git a/src/armv7/thumb.rs b/src/armv7/thumb.rs
index 96b6b98..b59754c 100644
--- a/src/armv7/thumb.rs
+++ b/src/armv7/thumb.rs
@@ -3228,6 +3228,23 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
Operand::Reg(Reg::from_u8(rm)),
Operand::Nothing,
];
+ } else if op1 == 0b110 {
+ // Ra == 0b1111? unpredictable!
+ decoder.unpredictable()?;
+ if op2 >= 0b10 {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ if op2 == 0b00 {
+ inst.opcode = Opcode::SMMLS;
+ } else {
+ inst.opcode = Opcode::SMMLSR;
+ }
+ inst.operands = [
+ Operand::Reg(Reg::from_u8(rd)),
+ Operand::Reg(Reg::from_u8(rn)),
+ Operand::Reg(Reg::from_u8(rm)),
+ Operand::Reg(Reg::from_u8(ra)),
+ ];
} else {
if op2 >= 0b10 {
return Err(DecodeError::InvalidOpcode);
@@ -3235,9 +3252,6 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
if op1 == 0b111 && op2 == 0b00 {
return Err(DecodeError::InvalidOpcode);
}
- if op1 == 0b110 {
- decoder.unpredictable()?;
- }
inst.opcode = [
Opcode::MUL, // already handled
Opcode::UDF, // already handled
@@ -3245,7 +3259,7 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
Opcode::UDF, // already handled
Opcode::SMUSD,
Opcode::SMMUL,
- Opcode::SMMLS,
+ Opcode::SMMLS, // already handled
Opcode::USAD8,
][op1];
inst.operands = [
@@ -3291,6 +3305,35 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
Operand::Reg(Reg::from_u8(rm)),
Operand::Reg(Reg::from_u8(ra)),
];
+ } else if op1 == 0b110 {
+ if op2 >= 0b10 {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ if op2 == 0b00 {
+ inst.opcode = Opcode::SMMLS;
+ } else {
+ inst.opcode = Opcode::SMMLSR;
+ }
+ inst.operands = [
+ Operand::Reg(Reg::from_u8(rd)),
+ Operand::Reg(Reg::from_u8(rn)),
+ Operand::Reg(Reg::from_u8(rm)),
+ Operand::Reg(Reg::from_u8(ra)),
+ ];
+ } else if op1 == 0b101 {
+ if op2 == 0b00 {
+ inst.opcode = Opcode::SMMLA;
+ } else if op2 == 0b01 {
+ inst.opcode = Opcode::SMMLAR;
+ } else {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ inst.operands = [
+ Operand::Reg(Reg::from_u8(rd)),
+ Operand::Reg(Reg::from_u8(rn)),
+ Operand::Reg(Reg::from_u8(rm)),
+ Operand::Reg(Reg::from_u8(ra)),
+ ];
} else {
if op2 >= 0b10 {
return Err(DecodeError::InvalidOpcode);
@@ -3298,9 +3341,6 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
if op1 == 0b111 && op2 == 0b00 {
return Err(DecodeError::InvalidOpcode);
}
- if op1 == 0b110 {
- decoder.unpredictable()?;
- }
inst.opcode = [
Opcode::MUL, // already handled
Opcode::UDF, // already handled
@@ -3308,7 +3348,7 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
Opcode::UDF, // already handled
Opcode::SMLSD,
Opcode::SMMLA,
- Opcode::SMMLS,
+ Opcode::SMMLS, // already handled
Opcode::USADA8,
][op1];
inst.operands = [
diff --git a/tests/armv7/thumb.rs b/tests/armv7/thumb.rs
index 6b8c891..ed9ae0e 100644
--- a/tests/armv7/thumb.rs
+++ b/tests/armv7/thumb.rs
@@ -4699,15 +4699,11 @@ fn smml() {
// smmla, smmlar, smmls, smmlsr
test_display(
&[0x64, 0xfb, 0x1f, 0x92],
- "smmlsr r2, r4, pc, sb"
+ "smmlsr.w r2, r4, pc, sb"
);
test_display(
&[0x59, 0xfb, 0x1b, 0x66],
- "smmlar r6, sb, fp, r6"
- );
- test_display(
- &[0x20, 0xfb, 0x1d, 0xd1],
- "smladx r1, r0, sp, sp"
+ "smmlar.w r6, sb, fp, r6"
);
}