aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2020-12-06 15:17:52 -0800
committeriximeow <me@iximeow.net>2020-12-06 15:17:52 -0800
commit1572e928b41b5c0765d7f47b346110da14e58b9e (patch)
tree697d0217c29abdd505b5693e6c1c648c3587816d /src
parent5e590eba9a1baf8a544f75ec87a58daa4da33726 (diff)
add ldc/sdc instructions and a slew of 32b thumb2 tests
Diffstat (limited to 'src')
-rw-r--r--src/armv7.rs70
-rw-r--r--src/armv7/thumb.rs193
2 files changed, 258 insertions, 5 deletions
diff --git a/src/armv7.rs b/src/armv7.rs
index 4cfbc77..d98cfb0 100644
--- a/src/armv7.rs
+++ b/src/armv7.rs
@@ -175,6 +175,32 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> ShowContextual<u3
_ => { unreachable!(); }
}
},
+ Opcode::STCL(coproc) => {
+ write!(out, "stcl p{}", coproc)?;
+ let ops = self.operands.iter();
+ for op in ops {
+ if let Operand::Nothing = op {
+ break;
+ }
+ write!(out, ", ")?;
+ op.colorize(colors, out)?;
+ }
+
+ Ok(())
+ }
+ Opcode::STC(coproc) => {
+ write!(out, "stc p{}", coproc)?;
+ let ops = self.operands.iter();
+ for op in ops {
+ if let Operand::Nothing = op {
+ break;
+ }
+ write!(out, ", ")?;
+ op.colorize(colors, out)?;
+ }
+
+ Ok(())
+ }
Opcode::STC2L(coproc) => {
write!(out, "stc2l p{}", coproc)?;
let ops = self.operands.iter();
@@ -201,6 +227,32 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> ShowContextual<u3
Ok(())
}
+ Opcode::LDC(coproc) => {
+ write!(out, "ldc p{}", coproc)?;
+ let ops = self.operands.iter();
+ for op in ops {
+ if let Operand::Nothing = op {
+ break;
+ }
+ write!(out, ", ")?;
+ op.colorize(colors, out)?;
+ }
+
+ Ok(())
+ }
+ Opcode::LDCL(coproc) => {
+ write!(out, "ldcl p{}", coproc)?;
+ let ops = self.operands.iter();
+ for op in ops {
+ if let Operand::Nothing = op {
+ break;
+ }
+ write!(out, ", ")?;
+ op.colorize(colors, out)?;
+ }
+
+ Ok(())
+ }
Opcode::LDC2(coproc) => {
write!(out, "ldc2 p{}", coproc)?;
let ops = self.operands.iter();
@@ -535,14 +587,20 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
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::MCR2(_, _, _) |
Opcode::MRRC2(_, _) |
Opcode::MRC2(_, _, _) |
+ Opcode::MCRR(_, _) |
+ Opcode::MRRC(_, _) |
Opcode::CDP2(_, _, _) => { write!(out, "{}", colors.platform_op(self)) },
}
}
@@ -557,14 +615,20 @@ impl Display for Opcode {
Opcode::LDRSBT => { write!(f, "ldrsbt") },
Opcode::STRD => { write!(f, "strd") },
Opcode::LDRD => { write!(f, "ldrd") },
+ Opcode::LDC(_) => { write!(f, "ldc") },
+ Opcode::LDCL(_) => { write!(f, "ldcl") },
Opcode::LDC2(_) => { write!(f, "ldc2") },
Opcode::LDC2L(_) => { write!(f, "ldc2l") },
+ Opcode::STC(_) => { write!(f, "stc") },
+ Opcode::STCL(_) => { write!(f, "stcl") },
Opcode::STC2(_) => { write!(f, "stc2") },
Opcode::STC2L(_) => { write!(f, "stc2l") },
Opcode::MCRR2(_, _) => { write!(f, "mcrr2") },
Opcode::MCR2(_, _, _) => { write!(f, "mcr2") },
Opcode::MRRC2(_, _) => { write!(f, "mrrc2") },
Opcode::MRC2(_, _, _) => { write!(f, "mrc2") },
+ Opcode::MCRR(_, _) => { write!(f, "mcrr") },
+ Opcode::MRRC(_, _) => { write!(f, "mrrc") },
Opcode::CDP2(_, _, _) => { write!(f, "cdp2") },
Opcode::SRS(p, u) => { write!(f, "srs{}{}", if *u { "i" } else { "d" }, if *p { "b" } else { "a" }) },
Opcode::RFE(p, u) => { write!(f, "rfe{}{}", if *u { "i" } else { "d" }, if *p { "b" } else { "a" }) },
@@ -842,13 +906,19 @@ 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),
MCR2(u8, u8, u8),
MRRC2(u8, u8),
+ MCRR(u8, u8),
+ MRRC(u8, u8),
MRC2(u8, u8, u8),
CDP2(u8, u8, u8),
SRS(bool, bool),
diff --git a/src/armv7/thumb.rs b/src/armv7/thumb.rs
index 2743c13..ab28be8 100644
--- a/src/armv7/thumb.rs
+++ b/src/armv7/thumb.rs
@@ -4,6 +4,7 @@ use std::fmt;
use armv7::ConditionCode;
use armv7::DecodeError;
+use armv7::CReg;
use armv7::Reg;
use armv7::RegShift;
use armv7::Operand;
@@ -1025,8 +1026,9 @@ pub fn decode_into<T: IntoIterator<Item=u8>>(decoder: &InstDecoder, inst: &mut I
} else {
// `Coprocessor, Advanced SIMD, and Floating-point instructions` (`A6-249`)
// v6T2
- eprintln!("TODO: coproc/simd/fp");
- return Err(DecodeError::Incomplete);
+ // op1 == 01, op2 == 1xxxxxx
+ // this means `assert!(instr2[10])`
+ return decode_table_a6_30(decoder, inst, instr2, lower2);
}
} else if opword < 0b11111 {
// op1 == 0b10
@@ -1253,6 +1255,7 @@ pub fn decode_into<T: IntoIterator<Item=u8>>(decoder: &InstDecoder, inst: &mut I
} else {
// `Data-processing (plain binary immediate)` (`A6-232`)
// v6T2
+ // aka table `A6-12`
let op = instr2[4..9].load::<u8>();
let i = instr2[10..11].load::<u16>();
inst.s = false;
@@ -3028,7 +3031,6 @@ pub fn decode_into<T: IntoIterator<Item=u8>>(decoder: &InstDecoder, inst: &mut I
} else {
if op2[3] {
// `Long multiply, long multiply accumulate, and divide` (`A6-248`)
- return Err(DecodeError::Incomplete);
let op1 = instr2[4..7].load::<usize>();
let op2 = lower2[4..8].load::<usize>();
@@ -3302,13 +3304,15 @@ pub fn decode_into<T: IntoIterator<Item=u8>>(decoder: &InstDecoder, inst: &mut I
}
}
- return Err(DecodeError::Incomplete);
}
}
}
} else {
// `Coprocessor, Advanced SIMD, and Floating-point instructions` (`A6-249`)
- return Err(DecodeError::Incomplete);
+ // v6T2
+ // op1 == 11, op2 == 1xxxxxx
+ // this means `assert!(instr2[10])`
+ return decode_table_a6_30(decoder, inst, instr2, lower2);
}
}
} else {
@@ -4180,3 +4184,182 @@ pub fn decode_into<T: IntoIterator<Item=u8>>(decoder: &InstDecoder, inst: &mut I
}
Ok(())
}
+
+fn decode_table_a6_30(decoder: &InstDecoder, inst: &mut Instruction, instr2: BitArray<Lsb0, [u16; 1]>, lower2: BitArray<Lsb0, [u16; 1]>) -> Result<(), DecodeError> {
+ // implementation of table `A6-30 Coprocessor, Advanced SIMD, and Floating-point instructions`
+ let op1 = instr2[4..10].load::<usize>();
+ if op1 & 0b11_1110 == 0b00_0000 {
+ inst.opcode = Opcode::UDF;
+ inst.operands = [
+ Operand::Nothing,
+ Operand::Nothing,
+ Operand::Nothing,
+ Operand::Nothing,
+ ];
+ return Err(DecodeError::InvalidOpcode);
+ } else if op1 & 0b110000 == 0b110000 {
+ // TODO: `Advanced SIMD data-processing instructions on A7-259`
+ return Err(DecodeError::Incomplete);
+ } else {
+ let coproc = lower2[8..12].load::<u8>();
+ if coproc & 0b1110 != 0b1010 {
+ // `not 101x` rows
+ if op1 == 0b000100 {
+ // `MCRR, MCRR2 on page A8-479`
+ let crm = lower2[0..4].load::<u8>();
+ 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.operands = [
+ Operand::Reg(Reg::from_u8(rt)),
+ Operand::Reg(Reg::from_u8(rt2)),
+ Operand::CReg(CReg::from_u8(crm)),
+ Operand::Nothing,
+ ];
+ } else if op1 == 0b000101 {
+ // `MRRC, MRRC2 on page A8-495`
+ let crm = lower2[0..4].load::<u8>();
+ let opc1 = lower2[4..8].load::<u8>();
+ let rt = lower2[12..16].load::<u8>();
+ let rt2 = instr2[0..4].load::<u8>();
+ // manual typo!! the manual spells the operands
+ // `<coproc>, <opc>, <Rt>, <Rt2>, <CRm>`
+ // 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.operands = [
+ Operand::Reg(Reg::from_u8(rt)),
+ Operand::Reg(Reg::from_u8(rt2)),
+ Operand::CReg(CReg::from_u8(crm)),
+ Operand::Nothing,
+ ];
+ } else {
+ if op1 & 1 == 0 {
+ // `STC, STC2 on page A8-663`
+ let p = instr2[8];
+ let u = instr2[7];
+ let w = instr2[5];
+ let rn = instr2[0..4].load::<u8>();
+ 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);
+ }
+ } else {
+ if instr2[6] {
+ inst.opcode = Opcode::STCL(coproc);
+ } else {
+ inst.opcode = Opcode::STC(coproc);
+ }
+ }
+ inst.operands = [
+ Operand::CReg(CReg::from_u8(crd)),
+ if p {
+ Operand::RegDerefPreindexOffset(
+ Reg::from_u8(rn),
+ imm8 << 2,
+ u,
+ w,
+ )
+ } else {
+ if w {
+ Operand::RegDerefPostindexOffset(
+ Reg::from_u8(rn),
+ imm8 << 2,
+ u,
+ false, // TODO: wback? this is true? not true?
+ )
+ } else {
+ Operand::RegDeref(Reg::from_u8(rn))
+ }
+ },
+ if !p && !w {
+ Operand::CoprocOption(imm8 as u8)
+ } else {
+ Operand::Nothing
+ },
+ Operand::Nothing,
+ ];
+ } else {
+ // `LDC, LDC2 (immediate or literal) on A8-393 or A8-395`
+ let p = instr2[8];
+ let u = instr2[7];
+ let w = instr2[5];
+ let rn = instr2[0..4].load::<u8>();
+ let crd = lower2[12..16].load::<u8>();
+ let imm8 = lower2[0..8].load::<u16>();
+
+ if rn == 0b1111 {
+ // `LDC, LDC2 (literal) on A8-395`
+ // notable for rejecting writeback
+ if w {
+ decoder.unpredictable()?;
+ }
+ } else {
+ // `LDC, LDC2 (immediate) on A8-393`
+ }
+
+ if instr2[12] {
+ if instr2[6] {
+ inst.opcode = Opcode::LDC2L(coproc);
+ } else {
+ inst.opcode = Opcode::LDC2(coproc);
+ }
+ } else {
+ if instr2[6] {
+ inst.opcode = Opcode::LDCL(coproc);
+ } else {
+ inst.opcode = Opcode::LDC(coproc);
+ }
+ }
+ inst.operands = [
+ Operand::CReg(CReg::from_u8(crd)),
+ if p {
+ Operand::RegDerefPreindexOffset(
+ Reg::from_u8(rn),
+ imm8 << 2,
+ u,
+ w,
+ )
+ } else {
+ if w {
+ Operand::RegDerefPostindexOffset(
+ Reg::from_u8(rn),
+ imm8 << 2,
+ u,
+ false, // TODO: wback? this is true? not true?
+ )
+ } else {
+ Operand::RegDeref(Reg::from_u8(rn))
+ }
+ },
+ if !p && !w {
+ Operand::CoprocOption(imm8 as u8)
+ } else {
+ Operand::Nothing
+ },
+ Operand::Nothing,
+ ];
+ }
+ }
+ } else {
+ // `101x` rows
+ return Err(DecodeError::Incomplete);
+ }
+ }
+ Ok(())
+}