aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/armv7.rs190
-rw-r--r--src/armv7/display.rs83
-rw-r--r--src/armv7/thumb.rs40
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)),