diff options
| -rw-r--r-- | CHANGELOG | 1 | ||||
| -rw-r--r-- | src/armv7/thumb.rs | 80 | ||||
| -rw-r--r-- | tests/armv7/thumb.rs | 25 |
3 files changed, 58 insertions, 48 deletions
@@ -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] |
