diff options
author | iximeow <me@iximeow.net> | 2021-12-27 18:19:58 -0800 |
---|---|---|
committer | iximeow <me@iximeow.net> | 2021-12-27 18:19:58 -0800 |
commit | d887643b7a528736fff857c67f1a93afa3d8b2f5 (patch) | |
tree | f5e3ee187470d45716dd0cde0ec0f35988fec252 | |
parent | 56cbef33bfaaa633fbe95b0256ac462024925c2e (diff) |
vector x indexed fmla,fmls,fmul
-rw-r--r-- | src/armv8/a64.rs | 166 | ||||
-rw-r--r-- | test/armv8/a64.rs | 20 |
2 files changed, 177 insertions, 9 deletions
diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs index b698f6c..af52bf4 100644 --- a/src/armv8/a64.rs +++ b/src/armv8/a64.rs @@ -3089,26 +3089,174 @@ impl Decoder<ARMv8> for InstDecoder { return Err(DecodeError::InvalidOpcode); } 0b0_0000 => { - if size < 0b10 { + // FMLAL + if size != 0b10 { return Err(DecodeError::InvalidOpcode); } - // FMLAL + if (word >> 29 & 1) == 0 { + inst.opcode = Opcode::FMLAL; + } else { + inst.opcode = Opcode::FMLAL2; + } + + let index = (H << 2) | (L << 1) | M; + + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, SIMDSizeCode::S), + Operand::SIMDRegisterElements(datasize, Rn as u16, SIMDSizeCode::H), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, SIMDSizeCode::H, index as u8), + Operand::Nothing, + ]; + } + 0b0_0100 => { + // FMLSL + if size != 0b10 { + return Err(DecodeError::InvalidOpcode); + } + if (word >> 29 & 1) == 0 { + inst.opcode = Opcode::FMLSL; + } else { + inst.opcode = Opcode::FMLSL2; + } + + let index = (H << 2) | (L << 1) | M; + + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, SIMDSizeCode::S), + Operand::SIMDRegisterElements(datasize, Rn as u16, SIMDSizeCode::H), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, SIMDSizeCode::H, index as u8), + Operand::Nothing, + ]; } 0b0_0001 => { - // TODO: // FMLA (not size=0b01) - } - 0b0_0100 => { - // TODO: - // FMLSL (not size<0b10) + if size == 0b01 { + return Err(DecodeError::InvalidOpcode); + } + + inst.opcode = Opcode::FMLA; + + let sz = size & 1; + + if sz == 1 && L == 1 { + return Err(DecodeError::InvalidOperand); + } + + if sz == 1 && Q == 0 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm, size) = if size == 0b00 { + let index = (H << 2) | (L << 1) | M; + (index, Rm, SIMDSizeCode::H) + } else if size == 0b10 { + // `sz == 0` + let index = (H << 1) | L; + let Rm = (M << 4) | Rm; + (index, Rm, SIMDSizeCode::S) + } else { + // `sz == 1` + let index = H; + let Rm = (M << 4) | Rm; + (index, Rm, SIMDSizeCode::D) + }; + + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, size), + Operand::SIMDRegisterElements(datasize, Rn as u16, size), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, size, index as u8), + Operand::Nothing, + ]; } 0b0_0101 => { - // TODO: // FMLS (not size=0b01) + if size == 0b01 { + return Err(DecodeError::InvalidOpcode); + } + + inst.opcode = Opcode::FMLS; + + let sz = size & 1; + + if sz == 1 && L == 1 { + return Err(DecodeError::InvalidOperand); + } + + if sz == 1 && Q == 0 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm, size) = if size == 0b00 { + let index = (H << 2) | (L << 1) | M; + (index, Rm, SIMDSizeCode::H) + } else if size == 0b10 { + // `sz == 0` + let index = (H << 1) | L; + let Rm = (M << 4) | Rm; + (index, Rm, SIMDSizeCode::S) + } else { + // `sz == 1` + let index = H; + let Rm = (M << 4) | Rm; + (index, Rm, SIMDSizeCode::D) + }; + + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, size), + Operand::SIMDRegisterElements(datasize, Rn as u16, size), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, size, index as u8), + Operand::Nothing, + ]; } 0b0_1001 => { - // TODO: // FMUL (not size=0b01) + if size == 0b01 { + return Err(DecodeError::InvalidOpcode); + } + + inst.opcode = Opcode::FMUL; + + let sz = size & 1; + + if sz == 1 && L == 1 { + return Err(DecodeError::InvalidOperand); + } + + if sz == 1 && Q == 0 { + return Err(DecodeError::InvalidOperand); + } + + let (index, Rm, size) = if size == 0b00 { + let index = (H << 2) | (L << 1) | M; + (index, Rm, SIMDSizeCode::H) + } else if size == 0b10 { + // `sz == 0` + let index = (H << 1) | L; + let Rm = (M << 4) | Rm; + (index, Rm, SIMDSizeCode::S) + } else { + // `sz == 1` + let index = H; + let Rm = (M << 4) | Rm; + (index, Rm, SIMDSizeCode::D) + }; + + let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; + + inst.operands = [ + Operand::SIMDRegisterElements(datasize, Rd as u16, size), + Operand::SIMDRegisterElements(datasize, Rn as u16, size), + Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, size, index as u8), + Operand::Nothing, + ]; } 0b1_0000 => { if size == 0b00 || size == 0b11 { diff --git a/test/armv8/a64.rs b/test/armv8/a64.rs index 6f43c22..593dcbf 100644 --- a/test/armv8/a64.rs +++ b/test/armv8/a64.rs @@ -4283,3 +4283,23 @@ fn test_ext() { assert!(errs.is_empty()); } + +#[test] +fn test_indexed() { + const TESTS: &[([u8; 4], &'static str)] = &[ + ([0x10, 0x11, 0x80, 0x0f], "fmla v16.2s, v8.2s, v0.s[0]"), + ([0x39, 0x58, 0x88, 0x0f], "fmls v25.2s, v1.2s, v8.s[2]"), + ([0x08, 0x92, 0x8a, 0x0f], "fmul v8.2s, v16.2s, v10.s[0]"), + ([0x01, 0x12, 0x8b, 0x0f], "fmla v1.2s, v16.2s, v11.s[0]"), + ([0x8c, 0x12, 0x8e, 0x0f], "fmla v12.2s, v20.2s, v14.s[0]"), + ([0xc6, 0x12, 0x8e, 0x0f], "fmla v6.2s, v22.2s, v14.s[0]"), + ([0x3c, 0x58, 0xa9, 0x0f], "fmls v28.2s, v1.2s, v9.s[3]"), + ]; + let errs = run_tests(TESTS); + + for err in errs.iter() { + println!("{}", err); + } + + assert!(errs.is_empty()); +} |