diff options
| -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()); +}  | 
