aboutsummaryrefslogtreecommitdiff
path: root/src/armv7
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/armv7
parent5e590eba9a1baf8a544f75ec87a58daa4da33726 (diff)
add ldc/sdc instructions and a slew of 32b thumb2 tests
Diffstat (limited to 'src/armv7')
-rw-r--r--src/armv7/thumb.rs193
1 files changed, 188 insertions, 5 deletions
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(())
+}