From 097888dd845b7292bb107af80d87bc926001a9a1 Mon Sep 17 00:00:00 2001 From: iximeow Date: Thu, 21 Oct 2021 17:47:46 -0700 Subject: data processing (three source) --- src/armv8/a64.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- test/armv8/a64.rs | 23 ++++++++++++++ 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 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. -- cgit v1.1