From 1572e928b41b5c0765d7f47b346110da14e58b9e Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 6 Dec 2020 15:17:52 -0800 Subject: add ldc/sdc instructions and a slew of 32b thumb2 tests --- src/armv7.rs | 70 +++++++++++++++++++ src/armv7/thumb.rs | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 258 insertions(+), 5 deletions(-) (limited to 'src') 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 > ShowContextual { 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 > ShowContextual { + 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 > Colorize { 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>(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>(decoder: &InstDecoder, inst: &mut I } else { // `Data-processing (plain binary immediate)` (`A6-232`) // v6T2 + // aka table `A6-12` let op = instr2[4..9].load::(); let i = instr2[10..11].load::(); inst.s = false; @@ -3028,7 +3031,6 @@ pub fn decode_into>(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::(); let op2 = lower2[4..8].load::(); @@ -3302,13 +3304,15 @@ pub fn decode_into>(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>(decoder: &InstDecoder, inst: &mut I } Ok(()) } + +fn decode_table_a6_30(decoder: &InstDecoder, inst: &mut Instruction, instr2: BitArray, lower2: BitArray) -> Result<(), DecodeError> { + // implementation of table `A6-30 Coprocessor, Advanced SIMD, and Floating-point instructions` + let op1 = instr2[4..10].load::(); + 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::(); + if coproc & 0b1110 != 0b1010 { + // `not 101x` rows + if op1 == 0b000100 { + // `MCRR, MCRR2 on page A8-479` + let crm = lower2[0..4].load::(); + let opc1 = lower2[4..8].load::(); + let rt = lower2[12..16].load::(); + let rt2 = instr2[0..4].load::(); + 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::(); + let opc1 = lower2[4..8].load::(); + let rt = lower2[12..16].load::(); + let rt2 = instr2[0..4].load::(); + // manual typo!! the manual spells the operands + // `, , , , ` + // 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::(); + let crd = lower2[12..16].load::(); + let imm8 = lower2[0..8].load::(); + + 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::(); + let crd = lower2[12..16].load::(); + let imm8 = lower2[0..8].load::(); + + 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(()) +} -- cgit v1.1