diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/armv7.rs | 190 | ||||
| -rw-r--r-- | src/armv7/display.rs | 83 | ||||
| -rw-r--r-- | src/armv7/thumb.rs | 40 |
3 files changed, 222 insertions, 91 deletions
diff --git a/src/armv7.rs b/src/armv7.rs index 06dbecb..cb46d60 100644 --- a/src/armv7.rs +++ b/src/armv7.rs @@ -102,29 +102,23 @@ pub enum Opcode { LDRSBT, STRD, LDRD, - LDC(u8), - LDCL(u8), - LDC2(u8), - LDC2L(u8), - STC(u8), - STCL(u8), - STC2(u8), - STC2L(u8), - MCRR2(u8, u8), + LDC(u8, bool), + LDCL(u8, bool), + STC(u8, bool), + STCL(u8, bool), + MCRR(u8, u8, bool), + MRRC(u8, u8, bool), /// > MCR (Move to Coprocessor from ARM Register) /// /// fields here are `coproc`, `opcode_1`, `opcode_2`, and a bool indicating if the original /// encoding was `MCR` or `MCR2` (`true` means `MCR2`). MCR(u8, u8, u8, bool), - MRRC2(u8, u8), - MCRR(u8, u8), - MRRC(u8, u8), /// > MRC (Move to ARM Register from Coprocessor) /// /// fields here are `coproc`, `opcode_1`, `opcode_2`, and a bool indicating if the original /// encoding was `MRC` or `MRC2` (`true` means `MRC2`). MRC(u8, u8, u8, bool), - CDP2(u8, u8, u8), + CDP(u8, u8, u8, bool), SRS(bool, bool), RFE(bool, bool), LDRT, @@ -1372,9 +1366,9 @@ impl Decoder<ARMv7> for InstDecoder { return Err(DecodeError::InvalidOperand); } if (word >> 20) & 0b00001 != 0 { - inst.opcode = Opcode::MRRC2(coproc, opc1); + inst.opcode = Opcode::MRRC(coproc, opc1, true); } else { - inst.opcode = Opcode::MCRR2(coproc, opc1); + inst.opcode = Opcode::MCRR(coproc, opc1, true); } inst.operands = [ Operand::Reg(Reg::from_u8(Rt)), @@ -1402,18 +1396,18 @@ impl Decoder<ARMv7> for InstDecoder { // page A8-663 if pudw & 0b0010 != 0 { - inst.opcode = Opcode::STC2L(coproc); + inst.opcode = Opcode::STCL(coproc, true); } else { - inst.opcode = Opcode::STC2(coproc); + inst.opcode = Opcode::STC(coproc, true); } } else { // op=110xxxx1, LDC // page A8-393 if pudw & 0b0010 != 0 { - inst.opcode = Opcode::LDC2L(coproc); + inst.opcode = Opcode::LDCL(coproc, true); } else { - inst.opcode = Opcode::LDC2(coproc); + inst.opcode = Opcode::LDC(coproc, true); } } @@ -1458,7 +1452,7 @@ impl Decoder<ARMv7> for InstDecoder { if (word >> 4) & 1 == 0 { // CDP2, page A8-356 let opc1 = (word >> 20) as u8 & 0b1111; - inst.opcode = Opcode::CDP2(coproc, opc1, opc2); + inst.opcode = Opcode::CDP(coproc, opc1, opc2, true); inst.operands = [ Operand::CReg(CReg::from_u8(Rt)), Operand::CReg(CReg::from_u8(CRn)), @@ -2905,12 +2899,164 @@ impl Decoder<ARMv7> for InstDecoder { ]; } }, - 0b110 | 0b111 => { + 0b110 => { // coprocessor instructions and supervisor call // page A5-213 // low bit of 0b110 or 0b111 corresponds to high bit of op1 - return Err(DecodeError::Incomplete); + // + // op1=0b110xxxxx, see table A5-23 + let coproc = (word >> 8) as u8 & 0b1111; + + if coproc & 0b1110 == 0b1010 { + // Advanced SIMD, Floating-point, op1 = 0xxxxx + return Err(DecodeError::Incomplete); + } + + if (word >> 20) & 0b11010 == 0b00000 { + // the `not 11000x0{0,1}` cases in table A5-23, MCRR or MRRC + // but first check that bit 2 of op1 is in fact 1: + if (word >> 20) & 0b00100 != 0 { + // actually MCRR or MRRC + let CRm = word as u8 & 0b1111; + let opc1 = (word >> 4) as u8 & 0b1111; + let Rt = (word >> 12) as u8 & 0b1111; + let Rt2 = (word >> 16) as u8 & 0b1111; + if Rt == 15 || Rt2 == 15 || Rt == Rt2 { + // TODO: actually `UNPREDICTABLE` + return Err(DecodeError::InvalidOperand); + } + if (word >> 20) & 0b00001 != 0 { + inst.opcode = Opcode::MRRC(coproc, opc1, false); + } else { + inst.opcode = Opcode::MCRR(coproc, opc1, false); + } + inst.operands = [ + Operand::Reg(Reg::from_u8(Rt)), + Operand::Reg(Reg::from_u8(Rt2)), + Operand::CReg(CReg::from_u8(CRm)), + Operand::Nothing, + ]; + } else { + return Err(DecodeError::InvalidOpcode); + } + } else { + // STC or LDC + let pudw = (word >> 21) as u8 & 0b1111; + let Rn = (word >> 16) as u8 & 0b1111; + let CRd = (word >> 12) as u8 & 0b1111; + let imm8 = word & 0b11111111; + + if (word >> 20) & 0b00001 == 0 { + // op=110xxxx0, STC + // page A8-663 + + if pudw & 0b0010 != 0 { + inst.opcode = Opcode::STCL(coproc, false); + } else { + inst.opcode = Opcode::STC(coproc, false); + } + } else { + // op=110xxxx1, LDC + // page A8-393 + + if pudw & 0b0010 != 0 { + inst.opcode = Opcode::LDCL(coproc, false); + } else { + inst.opcode = Opcode::LDC(coproc, false); + } + } + + let P = pudw & 0b1000 != 0; + let U = pudw & 0b0100 != 0; + let W = pudw & 0b0001 != 0; + + inst.operands = [ + Operand::CReg(CReg::from_u8(CRd)), + if P { + Operand::RegDerefPreindexOffset(Reg::from_u8(Rn), (imm8 << 2) as u16, U, W) + } else { + if W { + // postindex always has wback + Operand::RegDerefPostindexOffset(Reg::from_u8(Rn), (imm8 << 2) as u16, U, true) + } else { + Operand::RegDeref(Reg::from_u8(Rn)) + } + }, + if !P && !W { + // TODO: not sure what ldc2{l}'s <option> field really means? + // at this point the invalid encoding and mrrc/mcrr forms have + // been tested, so.. + debug_assert!(U); + Operand::CoprocOption(imm8 as u8) + } else { + Operand::Nothing + }, + Operand::Nothing, + ]; + } }, + 0b111 => { + // coprocessor instructions and supervisor call + // page A5-213 + // low bit of 0b110 or 0b111 corresponds to high bit of op1 + // + // op1=0b111xxxxx, see table A5-22 + let op1 = (word >> 20) & 0b111111; + if ((op1 >> 4) & 1) != 0 { + inst.opcode = Opcode::SVC; + let imm = word & 0xff_ff_ff; + inst.operands = [ + Operand::Imm32(imm), + Operand::Nothing, + Operand::Nothing, + Operand::Nothing, + ]; + return Ok(()); + } + + let coproc = (word >> 8) as u8 & 0b1111; + + if coproc & 0b1110 == 0b1010 { + // Advanced SIMD, Floating-point, op1 = 0xxxxx + return Err(DecodeError::Incomplete); + } + + if (word >> 4) & 1 == 0 { + // CDP, page A8-356 + let CRm = word as u8 & 0b1111; + let opc2 = (word >> 5) as u8 & 0b111; + let Rt = (word >> 12) as u8 & 0b1111; + let CRn = (word >> 16) as u8 & 0b1111; + + let opc1 = (word >> 20) as u8 & 0b1111; + inst.opcode = Opcode::CDP(coproc, opc1, opc2, false); + inst.operands = [ + Operand::CReg(CReg::from_u8(Rt)), + Operand::CReg(CReg::from_u8(CRn)), + Operand::CReg(CReg::from_u8(CRm)), + Operand::Nothing, + ]; + } else { + // MCR/MRC, page A8-493 + let CRm = word as u8 & 0b1111; + let opc2 = (word >> 5) as u8 & 0b111; + let Rt = (word >> 12) as u8 & 0b1111; + let CRn = (word >> 16) as u8 & 0b1111; + + let opc1 = (word >> 21) as u8 & 0b111; + if (word >> 20) & 1 == 0 { + inst.opcode = Opcode::MCR(coproc, opc1, opc2, false); + } else { + inst.opcode = Opcode::MRC(coproc, opc1, opc2, false); + } + inst.operands = [ + Operand::Reg(Reg::from_u8(Rt)), + Operand::CReg(CReg::from_u8(CRn)), + Operand::CReg(CReg::from_u8(CRm)), + Operand::Nothing, + ]; + } + } _ => { unreachable!("opc category is three bits"); } } Ok(()) diff --git a/src/armv7/display.rs b/src/armv7/display.rs index f81e2cc..5ceedd6 100644 --- a/src/armv7/display.rs +++ b/src/armv7/display.rs @@ -462,18 +462,20 @@ pub(crate) fn visit_inst<T: DisplaySink>(instr: &Instruction, out: &mut T) -> fm _ => {} } } - Opcode::STCL(coproc) | - Opcode::STC(coproc) | - Opcode::STC2L(coproc) | - Opcode::STC2(coproc) | - Opcode::LDC(coproc) | - Opcode::LDCL(coproc) | - Opcode::LDC2(coproc) | - Opcode::LDC2L(coproc) => { + Opcode::STCL(coproc, _) | + Opcode::STC(coproc, _) | + Opcode::LDC(coproc, _) | + Opcode::LDCL(coproc, _) => { out.span_start_opcode(); unsafe { out.write_lt_8(instr.opcode.name())?; } + if instr.condition != ConditionCode::AL { + let name = instr.condition.name(); + // all condition codes are two characters long + out.write_char(name[0] as char)?; + out.write_char(name[1] as char)?; + } out.span_end_opcode(); out.write_fixed_size(" p")?; if coproc >= 10 { @@ -497,12 +499,18 @@ pub(crate) fn visit_inst<T: DisplaySink>(instr: &Instruction, out: &mut T) -> fm return Ok(()); } - Opcode::MRRC2(coproc, opc) | - Opcode::MCRR2(coproc, opc) => { + Opcode::MRRC(coproc, opc, _) | + Opcode::MCRR(coproc, opc, _) => { out.span_start_opcode(); unsafe { out.write_lt_8(instr.opcode.name())?; } + if instr.condition != ConditionCode::AL { + let name = instr.condition.name(); + // all condition codes are two characters long + out.write_char(name[0] as char)?; + out.write_char(name[1] as char)?; + } out.span_end_opcode(); out.write_char(' ')?; @@ -527,11 +535,17 @@ pub(crate) fn visit_inst<T: DisplaySink>(instr: &Instruction, out: &mut T) -> fm } Opcode::MRC(coproc, opc1, opc2, _) | Opcode::MCR(coproc, opc1, opc2, _) | - Opcode::CDP2(coproc, opc1, opc2) => { + Opcode::CDP(coproc, opc1, opc2, _) => { out.span_start_opcode(); unsafe { out.write_lt_8(instr.opcode.name())?; } + if instr.condition != ConditionCode::AL { + let name = instr.condition.name(); + // all condition codes are two characters long + out.write_char(name[0] as char)?; + out.write_char(name[1] as char)?; + } out.span_end_opcode(); out.write_char(' ')?; @@ -911,21 +925,15 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for ConditionedOpcode { Opcode::HVC | Opcode::SVC | Opcode::SMC | - Opcode::LDC(_) | - Opcode::LDCL(_) | - Opcode::LDC2(_) | - Opcode::LDC2L(_) | - Opcode::STC(_) | - Opcode::STCL(_) | - Opcode::STC2(_) | - Opcode::STC2L(_) | - Opcode::MCRR2(_, _) | + Opcode::LDC(_, _) | + Opcode::LDCL(_, _) | + Opcode::STC(_, _) | + Opcode::STCL(_, _) | + Opcode::MCRR(_, _, _) | Opcode::MCR(_, _, _, _) | - Opcode::MRRC2(_, _) | + Opcode::MRRC(_, _, _) | Opcode::MRC(_, _, _, _) | - Opcode::MCRR(_, _) | - Opcode::MRRC(_, _) | - Opcode::CDP2(_, _, _) => { write!(out, "{}", colors.platform_op(self)) }, + Opcode::CDP(_, _, _, _) => { write!(out, "{}", colors.platform_op(self)) }, } } } @@ -950,23 +958,24 @@ impl Opcode { Opcode::LDRSBT => { "ldrsbt" }, Opcode::STRD => { "strd" }, Opcode::LDRD => { "ldrd" }, - Opcode::LDC(_) => { "ldc" }, - Opcode::LDCL(_) => { "ldcl" }, - Opcode::LDC2(_) => { "ldc2" }, - Opcode::LDC2L(_) => { "ldc2l" }, - Opcode::STC(_) => { "stc" }, - Opcode::STCL(_) => { "stcl" }, - Opcode::STC2(_) => { "stc2" }, - Opcode::STC2L(_) => { "stc2l" }, - Opcode::MCRR2(_, _) => { "mcrr2" }, + Opcode::LDC(_, false) => { "ldc" }, + Opcode::LDC(_, true) => { "ldc2" }, + Opcode::LDCL(_, false) => { "ldcl" }, + Opcode::LDCL(_, true) => { "ldc2l" }, + Opcode::STC(_, false) => { "stc" }, + Opcode::STC(_, true) => { "stc2" }, + Opcode::STCL(_, false) => { "stcl" }, + Opcode::STCL(_, true) => { "stc2l" }, Opcode::MCR(_, _, _, false) => { "mcr" }, Opcode::MCR(_, _, _, true) => { "mcr2" }, - Opcode::MRRC2(_, _) => { "mrrc2" }, Opcode::MRC(_, _, _, false) => { "mrc" }, Opcode::MRC(_, _, _, true) => { "mrc2" }, - Opcode::MCRR(_, _) => { "mcrr" }, - Opcode::MRRC(_, _) => { "mrrc" }, - Opcode::CDP2(_, _, _) => { "cdp2" }, + Opcode::MCRR(_, _, false) => { "mcrr" }, + Opcode::MCRR(_, _, true) => { "mcrr2" }, + Opcode::MRRC(_, _, false) => { "mrrc" }, + Opcode::MRRC(_, _, true) => { "mrrc2" }, + Opcode::CDP(_, _, _, false) => { "cdp" }, + Opcode::CDP(_, _, _, true) => { "cdp2" }, Opcode::SRS(true, true) => { "srsib" }, Opcode::SRS(false, true) => { "srsia" }, Opcode::SRS(true, false) => { "srsdb" }, diff --git a/src/armv7/thumb.rs b/src/armv7/thumb.rs index e18cb38..a2809eb 100644 --- a/src/armv7/thumb.rs +++ b/src/armv7/thumb.rs @@ -4253,11 +4253,7 @@ fn decode_table_a6_30(decoder: &InstDecoder, inst: &mut Instruction, instr2: Bit let opc1 = lower2[4..8].load::<u8>(); let rt = lower2[12..16].load::<u8>(); let rt2 = instr2[0..4].load::<u8>(); - if instr2[12] { - inst.opcode = Opcode::MCRR2(coproc, opc1); - } else { - inst.opcode = Opcode::MCRR(coproc, opc1); - } + inst.opcode = Opcode::MCRR(coproc, opc1, instr2[12]); inst.operands = [ Operand::Reg(Reg::from_u8(rt)), Operand::Reg(Reg::from_u8(rt2)), @@ -4275,11 +4271,7 @@ fn decode_table_a6_30(decoder: &InstDecoder, inst: &mut Instruction, instr2: Bit // but the operand name is `opc1`! // // this is a very uninteresting typo, but fun to spot nonetheless - if instr2[12] { - inst.opcode = Opcode::MRRC2(coproc, opc1); - } else { - inst.opcode = Opcode::MRRC(coproc, opc1); - } + inst.opcode = Opcode::MRRC(coproc, opc1, instr2[12]); inst.operands = [ Operand::Reg(Reg::from_u8(rt)), Operand::Reg(Reg::from_u8(rt2)), @@ -4296,18 +4288,10 @@ fn decode_table_a6_30(decoder: &InstDecoder, inst: &mut Instruction, instr2: Bit let crd = lower2[12..16].load::<u8>(); let imm8 = lower2[0..8].load::<u16>(); - if instr2[12] { - if instr2[6] { - inst.opcode = Opcode::STC2L(coproc); - } else { - inst.opcode = Opcode::STC2(coproc); - } + if instr2[6] { + inst.opcode = Opcode::STCL(coproc, instr2[12]); } else { - if instr2[6] { - inst.opcode = Opcode::STCL(coproc); - } else { - inst.opcode = Opcode::STC(coproc); - } + inst.opcode = Opcode::STC(coproc, instr2[12]); } inst.operands = [ Operand::CReg(CReg::from_u8(crd)), @@ -4356,18 +4340,10 @@ fn decode_table_a6_30(decoder: &InstDecoder, inst: &mut Instruction, instr2: Bit // `LDC, LDC2 (immediate) on A8-393` } - if instr2[12] { - if instr2[6] { - inst.opcode = Opcode::LDC2L(coproc); - } else { - inst.opcode = Opcode::LDC2(coproc); - } + if instr2[6] { + inst.opcode = Opcode::LDCL(coproc, instr2[12]); } else { - if instr2[6] { - inst.opcode = Opcode::LDCL(coproc); - } else { - inst.opcode = Opcode::LDC(coproc); - } + inst.opcode = Opcode::LDC(coproc, instr2[12]); } inst.operands = [ Operand::CReg(CReg::from_u8(crd)), |
