aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2020-12-06 13:37:14 -0800
committeriximeow <me@iximeow.net>2020-12-06 13:37:14 -0800
commit5e590eba9a1baf8a544f75ec87a58daa4da33726 (patch)
tree6eb47321bb6ef3ee9055c403b9cc0a1e355f7770
parentcf7c141256337dc12f19e98d34efa3aa606af368 (diff)
support more mul/div variants
-rw-r--r--src/armv7.rs49
-rw-r--r--src/armv7/thumb.rs271
2 files changed, 320 insertions, 0 deletions
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 <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::MLS |
Opcode::UMULL |
Opcode::UMLAL |
+ Opcode::SMLSD |
+ Opcode::SMMLA |
+ Opcode::SMMLS |
+ Opcode::USADA8 |
+ Opcode::USAD8 |
+ Opcode::SDIV |
+ Opcode::UDIV |
+ Opcode::SMLALD(_) |
+ Opcode::SMLSLD(_) |
+ Opcode::SMLAD |
+ Opcode::SMUSD |
+ Opcode::SMMUL |
+ Opcode::SMULW(_) |
+ Opcode::SMUAD |
Opcode::SMULL |
Opcode::SMUL(_, _) |
Opcode::SMAL(_, _) |
@@ -628,6 +642,8 @@ impl Display for Opcode {
Opcode::STRBT => { 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<T: IntoIterator<Item=u8>>(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::<usize>();
+ let op2 = lower2[4..8].load::<usize>();
+
+ let rn = instr2[0..4].load::<u8>();
+ let rdlo = lower2[12..16].load::<u8>();
+ let rd = lower2[8..12].load::<u8>();
+ let rm = lower2[0..4].load::<u8>();
+
+ 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::<usize>();
+ let op2 = lower2[4..6].load::<usize>();
+ let rm = lower2[0..4].load::<u8>();
+ let rd = lower2[8..12].load::<u8>();
+ let ra = lower2[12..16].load::<u8>();
+ let rn = instr2[0..4].load::<u8>();
+
+ 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);
}
}