From 5e590eba9a1baf8a544f75ec87a58daa4da33726 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 6 Dec 2020 13:37:14 -0800 Subject: support more mul/div variants --- src/armv7.rs | 49 ++++++++++ src/armv7/thumb.rs | 271 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 320 insertions(+) (limited to 'src') diff --git a/src/armv7.rs b/src/armv7.rs index be4f0d6..4cfbc77 100644 --- a/src/armv7.rs +++ b/src/armv7.rs @@ -410,6 +410,20 @@ impl > Colorize { write!(f, "strbt") }, Opcode::SWP => { write!(f, "swp") }, Opcode::SWPB => { write!(f, "swpb") }, + Opcode::SDIV => { write!(f, "sdiv") }, + Opcode::UDIV => { write!(f, "udiv") }, Opcode::MUL => { write!(f, "mul") }, Opcode::MLA => { write!(f, "mla") }, Opcode::UMAAL => { write!(f, "umaal") }, @@ -651,6 +667,24 @@ impl Display for Opcode { Opcode::SMLAW(second) => { write!(f, "smlaw{}", if *second { "t" } else { "b" }) }, + Opcode::SMULW(second) => { + write!(f, "smulw{}", if *second { "t" } else { "b" }) + }, + Opcode::SMLALD(second) => { + write!(f, "smlald{}", if *second { "t" } else { "b" }) + }, + Opcode::SMLSLD(second) => { + write!(f, "smlsld{}", if *second { "t" } else { "b" }) + }, + Opcode::SMLSD => { write!(f, "smlsd") }, + Opcode::SMMLA => { write!(f, "smmla") }, + Opcode::SMMLS => { write!(f, "smmls") }, + Opcode::USADA8 => { write!(f, "usada8") }, + Opcode::USAD8 => { write!(f, "usad8") }, + Opcode::SMLAD => { write!(f, "smlad") }, + Opcode::SMUSD => { write!(f, "smusd") }, + Opcode::SMMUL => { write!(f, "smmul") }, + Opcode::SMUAD => { write!(f, "smuad") }, Opcode::TBB => { write!(f, "tbb") }, Opcode::TBH => { write!(f, "tbh") }, Opcode::UDF => { write!(f, "udf") }, @@ -941,6 +975,21 @@ pub enum Opcode { USUB8, UQSUB8, UHSUB8, + + SMLSD, + SMMLA, + SMMLS, + USADA8, + USAD8, + SMLAD, + SMUSD, + SMMUL, + SMULW(bool), + SMUAD, + SDIV, + UDIV, + SMLALD(bool), + SMLSLD(bool), } static DATA_PROCESSING_OPCODES: [Opcode; 16] = [ diff --git a/src/armv7/thumb.rs b/src/armv7/thumb.rs index e65fe05..2743c13 100644 --- a/src/armv7/thumb.rs +++ b/src/armv7/thumb.rs @@ -3029,8 +3029,279 @@ pub fn decode_into>(decoder: &InstDecoder, inst: &mut I 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::(); + + let rn = instr2[0..4].load::(); + let rdlo = lower2[12..16].load::(); + let rd = lower2[8..12].load::(); + let rm = lower2[0..4].load::(); + + match op1 { + 0b000 => { + if op2 == 0b0000 { + inst.opcode = Opcode::SMULL; + inst.operands = [ + Operand::Reg(Reg::from_u8(rdlo)), + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + ]; + } else { + return Err(DecodeError::InvalidOpcode); + } + } + 0b001 => { + if op2 == 0b1111 { + inst.opcode = Opcode::SDIV; + inst.operands = [ + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + Operand::Nothing, + ]; + } else { + return Err(DecodeError::InvalidOpcode); + } + } + 0b010 => { + if op2 == 0b0000 { + inst.opcode = Opcode::UMULL; + inst.operands = [ + Operand::Reg(Reg::from_u8(rdlo)), + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + ]; + } else { + return Err(DecodeError::InvalidOpcode); + } + } + 0b011 => { + if op2 == 0b1111 { + inst.opcode = Opcode::UDIV; + inst.operands = [ + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + Operand::Nothing, + ]; + } else { + return Err(DecodeError::InvalidOpcode); + } + } + 0b100 => { + if op2 == 0b0000 { + inst.opcode = Opcode::SMLAL; + inst.operands = [ + Operand::Reg(Reg::from_u8(rdlo)), + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + ]; + } else if op2 & 0b1100 == 0b1000 { + inst.opcode = Opcode::SMLAL_halfword(lower2[5], lower2[4]); + inst.operands = [ + Operand::Reg(Reg::from_u8(rdlo)), + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + ]; + } else if op2 & 0b1110 == 0b1100 { + inst.opcode = Opcode::SMLALD(lower2[4]); + inst.operands = [ + Operand::Reg(Reg::from_u8(rdlo)), + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + ]; + } else { + return Err(DecodeError::InvalidOpcode); + } + } + 0b101 => { + if op2 == 0b1100 || op2 == 0b1101 { + inst.opcode = Opcode::SMLSLD(lower2[4]); + inst.operands = [ + Operand::Reg(Reg::from_u8(rdlo)), + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + ]; + } else { + return Err(DecodeError::InvalidOpcode); + } + } + 0b110 => { + if op2 == 0b0000 { + inst.opcode = Opcode::UMLAL; + inst.operands = [ + Operand::Reg(Reg::from_u8(rdlo)), + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + ]; + } else if op2 == 0b0110 { + inst.opcode = Opcode::UMAAL; + inst.operands = [ + Operand::Reg(Reg::from_u8(rdlo)), + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + ]; + } else { + return Err(DecodeError::InvalidOpcode); + } + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } } else { // `Multiply, multiply accumulate, and absolute difference` (`A6-247`) + let op1 = instr2[4..7].load::(); + let op2 = lower2[4..6].load::(); + let rm = lower2[0..4].load::(); + let rd = lower2[8..12].load::(); + let ra = lower2[12..16].load::(); + let rn = instr2[0..4].load::(); + + if ra == 0b1111 { + if op1 == 0b000 { + if op2 == 0b00 { + inst.opcode = Opcode::MUL; + inst.operands = [ + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + Operand::Nothing, + ]; + } else if op2 == 0b01{ + inst.opcode = Opcode::MLS; + // a == 15, unpredictable + decoder.unpredictable()?; + inst.operands = [ + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + Operand::Reg(Reg::from_u8(ra)), + ]; + } else { + return Err(DecodeError::InvalidOpcode); + } + + } else if op1 == 0b001 { + // `SMULBB, SMULBT, SMULTB, SMULTT on page A8-645` + inst.opcode = Opcode::SMUL(lower2[5], lower2[4]); + inst.operands = [ + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + Operand::Nothing, + ]; + } else if op1 == 0b011 { + if op2 >= 0b10 { + return Err(DecodeError::InvalidOpcode); + } + inst.opcode = Opcode::SMULW(lower2[4]); + inst.operands = [ + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + Operand::Nothing, + ]; + } else { + if op2 >= 0b10 { + return Err(DecodeError::InvalidOpcode); + } + if op1 == 0b111 && op2 == 0b00 { + return Err(DecodeError::InvalidOpcode); + } + if op1 == 0b110 { + decoder.unpredictable()?; + } + inst.opcode = [ + Opcode::MUL, // already handled + Opcode::UDF, // already handled + Opcode::SMUAD, + Opcode::UDF, // already handled + Opcode::SMUSD, + Opcode::SMMUL, + Opcode::SMMLS, + Opcode::USAD8, + ][op1]; + inst.operands = [ + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + Operand::Nothing, + ]; + } + } else { + if op1 == 0b000 { + if op2 == 0b00 { + inst.opcode = Opcode::MLA; + } else if op2 == 0b01{ + inst.opcode = Opcode::MLS; + } else { + return Err(DecodeError::InvalidOpcode); + } + + inst.operands = [ + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + Operand::Reg(Reg::from_u8(ra)), + ]; + } else if op1 == 0b001 { + // `SMULBB, SMULBT, SMULTB, SMULTT on page A8-645` + inst.opcode = Opcode::SMLA(lower2[5], lower2[4]); + inst.operands = [ + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + Operand::Reg(Reg::from_u8(ra)), + ]; + } else if op1 == 0b011 { + if op2 >= 0b10 { + return Err(DecodeError::InvalidOpcode); + } + inst.opcode = Opcode::SMLAW(lower2[4]); + inst.operands = [ + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + Operand::Reg(Reg::from_u8(ra)), + ]; + } else { + if op2 >= 0b10 { + return Err(DecodeError::InvalidOpcode); + } + if op1 == 0b111 && op2 == 0b00 { + return Err(DecodeError::InvalidOpcode); + } + if op1 == 0b110 { + decoder.unpredictable()?; + } + inst.opcode = [ + Opcode::MUL, // already handled + Opcode::UDF, // already handled + Opcode::SMLAD, + Opcode::UDF, // already handled + Opcode::SMLSD, + Opcode::SMMLA, + Opcode::SMMLS, + Opcode::USADA8, + ][op1]; + inst.operands = [ + Operand::Reg(Reg::from_u8(rd)), + Operand::Reg(Reg::from_u8(rn)), + Operand::Reg(Reg::from_u8(rm)), + Operand::Reg(Reg::from_u8(ra)), + ]; + } + + } return Err(DecodeError::Incomplete); } } -- cgit v1.1