aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG1
-rw-r--r--src/armv7/thumb.rs80
-rw-r--r--tests/armv7/thumb.rs25
3 files changed, 58 insertions, 48 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 12bedeb..83594e7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -14,6 +14,7 @@
* thumb2: pkhtb/pkhbt distinction was off by one bit
* thumb2: `mrs` destinations, which should have been a mask of the current (or
saved) program status register, was reported as a banked GPR.
+* thumb2: fixed much confusion about `msr` sources, similar to `mrs`.
* thumb2: some coprocessor instructions were incorrectly decoded as `ldc*/stc*`
* thumb2: fix missing decode of `s` bit for wide lsl/lsr/asr/ror (register)
* thumb2: rfeia and rfedb were decoded backwards. likewise for srsia and srsdb
diff --git a/src/armv7/thumb.rs b/src/armv7/thumb.rs
index d4bef7a..d029221 100644
--- a/src/armv7/thumb.rs
+++ b/src/armv7/thumb.rs
@@ -1619,9 +1619,11 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
// v7VE
let sysm = (((lower >> 4) & 1) << 4) | ((lower >> 8) & 0b1111);
let R = instr2[4];
+ let dest = Reg::from_sysm(R, sysm as u8)
+ .ok_or(DecodeError::InvalidOperand)?;
inst.opcode = Opcode::MSR;
inst.operands = [
- Operand::StatusRegMask(StatusRegMask::from_raw(sysm as u8)?),
+ dest,
Operand::Reg(Reg::from_u8(rn)),
Operand::Nothing,
Operand::Nothing,
@@ -2005,20 +2007,41 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
];
}
} else {
- // `op` is `0b0111110` or `0b0111111`, both are `MRS` but there's
- // some discerning to do still.
+ // `op` is `0b0111110` or `0b0111111`, both are `MRS` (and the
+ // difference is the `R` bit), but there's some more discerning to
+ // do for the source operand still.
let imm8 = lower & 0b11111111;
- if imm8 & 0b00100000 != 0 {
- // `MRS (Banked register)` (`B9-1978`)
+ let r = instr2[4];
+ if imm8 & 0b00100000 == 0 {
+ // `MRS (Banked register)` (`B9-1976`)
// v7VE
- let r = instr & 0b10000;
- let sysm = (lower & 0b10000) | (instr & 0b1111);
+ if lower & 0b0010_0000_1101_1111 != 0 {
+ if decoder.should_is_must {
+ return Err(DecodeError::Nonconforming);
+ }
+ }
+ let rd = ((lower >> 8) & 0b1111) as u8;
+ let source = if r {
+ Operand::SPSR
+ } else {
+ Operand::CPSR
+ };
+ inst.opcode = Opcode::MRS;
+ inst.operands = [
+ Operand::Reg(Reg::from_u8(rd)),
+ source,
+ Operand::Nothing,
+ Operand::Nothing,
+ ];
+ } else {
+ // `MRS` (`B9-1978`)
+ // v6T2
let rd = ((lower >> 8) & 0b1111) as u8;
+ let m = (lower & 0b10000) | (instr & 0b1111);
inst.opcode = Opcode::MRS;
inst.operands = [
Operand::Reg(Reg::from_u8(rd)),
- if let Some(op) = Reg::from_sysm(r != 0, sysm as u8) {
- // TODO: from_sysm should succeed?
+ if let Some(op) = Reg::from_sysm(r, m as u8) {
op
} else {
return Err(DecodeError::InvalidOperand);
@@ -2026,45 +2049,6 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
Operand::Nothing,
Operand::Nothing,
];
- } else {
- if op == 0b0111110 {
- // `MRS` (`A8-497`)
- // v6T2
- inst.opcode = Opcode::MRS;
- let rd = ((lower >> 8) & 0b1111) as u8;
- inst.opcode = Opcode::MRS;
- inst.operands = [
- Operand::Reg(Reg::from_u8(rd)),
- // TODO: "<spec_reg>"?
- if let Some(op) = Reg::from_sysm(false, 0) {
- // TODO: from_sysm should succeed?
- op
- } else {
- return Err(DecodeError::InvalidOperand);
- },
- Operand::Nothing,
- Operand::Nothing,
- ];
- } else {
- // `MRS` (`B9-1976`)
- // v6T2
- inst.opcode = Opcode::MRS;
- let rd = ((lower >> 8) & 0b1111) as u8;
- let r = (instr >> 4) & 1;
- inst.opcode = Opcode::MRS;
- inst.operands = [
- Operand::Reg(Reg::from_u8(rd)),
- // TODO: "<spec_reg>"?
- if let Some(op) = Reg::from_sysm(r != 0, 0) {
- // TODO: from_sysm should succeed?
- op
- } else {
- return Err(DecodeError::InvalidOperand);
- },
- Operand::Nothing,
- Operand::Nothing,
- ];
- }
}
}
} else {
diff --git a/tests/armv7/thumb.rs b/tests/armv7/thumb.rs
index 914b751..bd1a8a2 100644
--- a/tests/armv7/thumb.rs
+++ b/tests/armv7/thumb.rs
@@ -4613,6 +4613,31 @@ fn msr_mrs() {
&[0x9b, 0xf3, 0x00, 0x85],
"msr.w spsr_sc, fp"
);
+
+ test_display(
+ &[0x87, 0xf3, 0x20, 0x80],
+ "msr.w r8_usr, r7"
+ );
+
+ test_display(
+ &[0x87, 0xf3, 0x20, 0x89],
+ "msr.w sb_fiq, r7"
+ );
+
+ test_display(
+ &[0xff, 0xf3, 0x00, 0x86],
+ "mrs.w r6, spsr"
+ );
+
+ test_display(
+ &[0xf2, 0xf3, 0x30, 0x8c],
+ "mrs.w ip, spsr_svc"
+ );
+
+ test_display(
+ &[0xfe, 0xf3, 0x30, 0x8c],
+ "mrs.w ip, spsr_hyp"
+ );
}
#[test]