aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2021-10-21 17:47:46 -0700
committeriximeow <me@iximeow.net>2021-10-21 17:47:46 -0700
commit097888dd845b7292bb107af80d87bc926001a9a1 (patch)
treea1ae941215a682feeffb0931087909aced003aed
parent4a03599767c0ebac12e730a837abe1d15ac800e5 (diff)
data processing (three source)
-rw-r--r--src/armv8/a64.rs92
-rw-r--r--test/armv8/a64.rs23
2 files changed, 113 insertions, 2 deletions
diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs
index 60bbbed..3609103 100644
--- a/src/armv8/a64.rs
+++ b/src/armv8/a64.rs
@@ -134,7 +134,7 @@ mod docs {
}
}
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Copy, Clone)]
pub enum DecodeError {
ExhaustedInput,
InvalidOpcode,
@@ -665,6 +665,30 @@ impl Display for Instruction {
Opcode::CLS => {
write!(fmt, "cls")?;
}
+ Opcode::MADD => {
+ write!(fmt, "madd")?;
+ }
+ Opcode::MSUB => {
+ write!(fmt, "msub")?;
+ }
+ Opcode::SMADDL => {
+ write!(fmt, "smaddl")?;
+ }
+ Opcode::SMSUBL => {
+ write!(fmt, "smsubl")?;
+ }
+ Opcode::SMULH => {
+ write!(fmt, "smulh")?;
+ }
+ Opcode::UMADDL => {
+ write!(fmt, "umaddl")?;
+ }
+ Opcode::UMSUBL => {
+ write!(fmt, "umsubl")?;
+ }
+ Opcode::UMULH => {
+ write!(fmt, "umulh")?;
+ }
};
if self.operands[0] != Operand::Nothing {
@@ -840,6 +864,14 @@ pub enum Opcode {
REV32,
CLZ,
CLS,
+ MADD,
+ MSUB,
+ SMADDL,
+ SMSUBL,
+ SMULH,
+ UMADDL,
+ UMSUBL,
+ UMULH,
}
#[derive(Copy, Clone, Debug, PartialEq)]
@@ -1414,7 +1446,63 @@ impl Decoder<ARMv8> for InstDecoder {
},
_ => {
// Data processing (3 source)
- return Err(DecodeError::IncompleteDecoder);
+ let op0 = ((word >> 15) & 0x01) as u8;
+ let op31 = ((word >> 21) & 0x07) as u8;
+ let op54 = ((word >> 29) & 0x03) as u8;
+ let op = op0 | (op31 << 1) | (op54 << 4);
+ let sf = ((word >> 31) & 0x01) as u8;
+
+ let Rd = ((word >> 0) & 0x1f) as u16;
+ let Rn = ((word >> 5) & 0x1f) as u16;
+ let Ra = ((word >> 10) & 0x1f) as u16;
+ let Rm = ((word >> 16) & 0x1f) as u16;
+
+ const DATA_PROCESSING_3_SOURCE: &[Result<(Opcode, SizeCode, SizeCode), DecodeError>] = &[
+ Ok((Opcode::MADD, SizeCode::W, SizeCode::W)),
+ Ok((Opcode::MADD, SizeCode::X, SizeCode::X)),
+ Ok((Opcode::MSUB, SizeCode::W, SizeCode::W)),
+ Ok((Opcode::MSUB, SizeCode::X, SizeCode::X)),
+ Err(DecodeError::InvalidOpcode),
+ Ok((Opcode::SMADDL, SizeCode::W, SizeCode::X)),
+ Err(DecodeError::InvalidOpcode),
+ Ok((Opcode::SMSUBL, SizeCode::W, SizeCode::X)),
+ Err(DecodeError::InvalidOpcode),
+ Ok((Opcode::SMULH, SizeCode::W, SizeCode::X)),
+ Err(DecodeError::InvalidOpcode),
+ Err(DecodeError::InvalidOpcode),
+ Err(DecodeError::InvalidOpcode),
+ Err(DecodeError::InvalidOpcode),
+ Err(DecodeError::InvalidOpcode),
+ Err(DecodeError::InvalidOpcode),
+ Err(DecodeError::InvalidOpcode),
+ Err(DecodeError::InvalidOpcode),
+ Err(DecodeError::InvalidOpcode),
+ Err(DecodeError::InvalidOpcode),
+ Err(DecodeError::InvalidOpcode),
+ Ok((Opcode::UMADDL, SizeCode::W, SizeCode::X)),
+ Err(DecodeError::InvalidOpcode),
+ Ok((Opcode::UMSUBL, SizeCode::W, SizeCode::X)),
+ Err(DecodeError::InvalidOpcode),
+ Ok((Opcode::UMULH, SizeCode::X, SizeCode::X)),
+ Err(DecodeError::InvalidOpcode),
+ ];
+
+ let compound_idx = (op << 1) | sf;
+ crate::armv8::a64::std::eprintln!("word: {:#08x}, compound_idx: {:x}", word, compound_idx);
+ let (opcode, source_size, dest_size) = DATA_PROCESSING_3_SOURCE.get(compound_idx as usize)
+ .map(std::borrow::ToOwned::to_owned)
+ .unwrap_or(Err(DecodeError::InvalidOpcode))?;
+
+ inst.opcode = opcode;
+ inst.operands = [
+ Operand::Register(dest_size, Rd),
+ Operand::Register(source_size, Rn),
+ Operand::Register(source_size, Rm),
+ Operand::Register(dest_size, Ra), // in practice these match up with the corresponding operand.
+ ];
+ if opcode == Opcode::UMULH {
+ inst.operands[3] = Operand::Nothing;
+ }
}
}
} else {
diff --git a/test/armv8/a64.rs b/test/armv8/a64.rs
index feb878a..c251d4a 100644
--- a/test/armv8/a64.rs
+++ b/test/armv8/a64.rs
@@ -314,6 +314,29 @@ fn test_decode_data_processing_one_source() {
}
#[test]
+fn test_decode_data_processing_three_source() {
+ const TESTS: &[([u8; 4], &'static str)] = &[
+ ([0x11, 0x01, 0x0f, 0x1b], "madd w17, w8, w15, w0"),
+ ([0x11, 0x81, 0x0f, 0x1b], "msub w17, w8, w15, w0"),
+ ([0x11, 0x81, 0x0f, 0x9b], "msub x17, x8, x15, x0"),
+ ([0x11, 0x89, 0x0f, 0x9b], "msub x17, x8, x15, x2"),
+
+ ([0x11, 0x09, 0x2f, 0x9b], "smaddl x17, w8, w15, x2"),
+ ([0x11, 0x89, 0x2f, 0x9b], "smsubl x17, w8, w15, x2"),
+ ([0x11, 0x09, 0x4f, 0x9b], "smulh x17, w8, w15, x2"),
+ ([0x11, 0x09, 0xaf, 0x9b], "umaddl x17, w8, w15, x2"),
+ ([0x11, 0x89, 0xaf, 0x9b], "umsubl x17, w8, w15, x2"),
+ ([0x11, 0x09, 0xcf, 0x9b], "umulh x17, x8, x15"),
+ ];
+
+ for (bytes, instr) in TESTS {
+ test_display(*bytes, instr);
+ }
+
+ test_err([0x11, 0x81, 0x0f, 0x3b], DecodeError::InvalidOpcode);
+}
+
+#[test]
fn test_decode_chrome_entrypoint() {
// 1400 instructions from the entrypoint of a chrome binary, sorted by
// instruction word for no good reason.