diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/armv8/a64.rs | 248 | 
1 files changed, 122 insertions, 126 deletions
| diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs index 648703e..cc86ea5 100644 --- a/src/armv8/a64.rs +++ b/src/armv8/a64.rs @@ -4119,7 +4119,7 @@ impl Decoder<ARMv8> for InstDecoder {                                          return Err(DecodeError::InvalidOpcode);                                      } -                                    if size == 0b01 && Q == 1 { +                                    if size == 0b10 && Q == 0 {                                          return Err(DecodeError::InvalidOperand);                                      } @@ -4483,21 +4483,28 @@ impl Decoder<ARMv8> for InstDecoder {                                      Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand),                                  ]; +                                const TABLE_K: &'static OperandSizeTable = &[ +                                    Ok((D, B, D, B)), Ok((Q, B, Q, B)), +                                    Ok((D, H, D, H)), Ok((Q, H, Q, H)), +                                    Ok((D, S, D, S)), Ok((Q, S, Q, S)), +                                    Err(DecodeError::InvalidOperand), Ok((Q, D, Q, D)), +                                ]; +                                  if op2 & 0b0111 == 0b0100 {                                      // `Advanced SIMD two-register miscellaneous`                                      const OPCODES_U0_LOW: &[Result<(Opcode, &'static OperandSizeTable), DecodeError>; 20] = &[                                          Ok((Opcode::REV64, TABLE_A)),                                          Ok((Opcode::REV16, TABLE_B)),                                          Ok((Opcode::SADDLP, TABLE_C)), -                                        Ok((Opcode::SUQADD, TABLE_A)), +                                        Ok((Opcode::SUQADD, TABLE_K)),                                          Ok((Opcode::CLS, TABLE_A)),                                          Ok((Opcode::CNT, TABLE_B)),                                          Ok((Opcode::SADALP, TABLE_C)), -                                        Ok((Opcode::SQABS, TABLE_A)), -                                        Ok((Opcode::CMGT, TABLE_A)), -                                        Ok((Opcode::CMEQ, TABLE_A)), -                                        Ok((Opcode::CMLT, TABLE_A)), -                                        Ok((Opcode::ABS, TABLE_A)), +                                        Ok((Opcode::SQABS, TABLE_K)), +                                        Ok((Opcode::CMGT, TABLE_K)), +                                        Ok((Opcode::CMEQ, TABLE_K)), +                                        Ok((Opcode::CMLT, TABLE_K)), +                                        Ok((Opcode::ABS, TABLE_K)),                                          // 0b01100, all four size=1x                                          Ok((Opcode::FCMGT, TABLE_I)),                                          Ok((Opcode::FCMEQ, TABLE_I)), @@ -4545,15 +4552,15 @@ impl Decoder<ARMv8> for InstDecoder {                                          Ok((Opcode::REV32, TABLE_A)),                                          Err(DecodeError::InvalidOpcode),                                          Ok((Opcode::UADDLP, TABLE_C)), -                                        Ok((Opcode::USQADD, TABLE_A)), +                                        Ok((Opcode::USQADD, TABLE_K)),                                          Ok((Opcode::CLZ, TABLE_A)),                                          Err(DecodeError::InvalidOpcode),                                          Ok((Opcode::UADALP, TABLE_C)), -                                        Ok((Opcode::SQNEG, TABLE_A)), -                                        Ok((Opcode::CMGE, TABLE_A)), -                                        Ok((Opcode::CMLE, TABLE_A)), +                                        Ok((Opcode::SQNEG, TABLE_K)), +                                        Ok((Opcode::CMGE, TABLE_K)), +                                        Ok((Opcode::CMLE, TABLE_K)),                                          Err(DecodeError::InvalidOpcode), -                                        Ok((Opcode::NEG, TABLE_A)), +                                        Ok((Opcode::NEG, TABLE_K)),                                          // 0b01100, all four size=1x                                          Ok((Opcode::FCMGE, TABLE_I)),                                          Ok((Opcode::FCMLE, TABLE_I)), @@ -5985,8 +5992,8 @@ impl Decoder<ARMv8> for InstDecoder {                                          Err(DecodeError::InvalidOpcode),                                          Err(DecodeError::InvalidOpcode),                                          Err(DecodeError::InvalidOpcode), -                                        Err(DecodeError::InvalidOpcode), -                                        Err(DecodeError::InvalidOpcode), +                                        Ok((Opcode::FRECPS, TABLE_C)), +                                        Ok((Opcode::FRSQRTS, TABLE_C)),                                      ];                                      const OPCODES_U1_HIGH: &[Result<(Opcode, &'static OperandSizeTable), DecodeError>; 16] = &[                                          Err(DecodeError::InvalidOpcode), @@ -6305,7 +6312,7 @@ impl Decoder<ARMv8> for InstDecoder {                                                  (SIMDSizeCode::Q, SIMDSizeCode::D)                                              }; -                                            let opcode = match opcode | ((size & 0b10) << 5) { +                                            let opcode = match opcode | ((size & 0b10) << 4) {                                                  0b001100 => Opcode::FMAXNMP,                                                  0b001101 => Opcode::FADDP,                                                  0b001111 => Opcode::FMAXP, @@ -6468,14 +6475,19 @@ impl Decoder<ARMv8> for InstDecoder {                                  let a = (word >> 23) & 1;                                  let U = (word >> 29) & 1; -                                if opcode < 0b011 { +                                if opcode < 0b010 {                                      return Err(DecodeError::InvalidOpcode);                                  } -                                let opcode = opcode - 0b011; +                                let opcode = opcode - 0b010;                                  let index = (opcode << 2) | (U << 1) | a;                                  inst.opcode = [ +                                    // opcode == 0b010 +                                    Err(DecodeError::InvalidOpcode), +                                    Err(DecodeError::InvalidOpcode), +                                    Err(DecodeError::InvalidOpcode), +                                    Ok(Opcode::FABD),                                      // opcode == 0b011                                      Ok(Opcode::FMULX),                                      Err(DecodeError::InvalidOpcode), @@ -6485,7 +6497,7 @@ impl Decoder<ARMv8> for InstDecoder {                                      Ok(Opcode::FCMEQ),                                      Err(DecodeError::InvalidOpcode),                                      Ok(Opcode::FCMGE), -                                    Err(DecodeError::InvalidOpcode), +                                    Ok(Opcode::FCMGT),                                      // opcode == 0b101                                      Err(DecodeError::InvalidOpcode),                                      Err(DecodeError::InvalidOpcode), @@ -6635,11 +6647,19 @@ impl Decoder<ARMv8> for InstDecoder {                              // size=0b01.                              match operands_kind {                                  OperandKind::SameSizes => { -                                    let size = match size { -                                        0b00 => SIMDSizeCode::H, -                                        0b01 => { return Err(DecodeError::InvalidOperand); } -                                        0b10 => SIMDSizeCode::S, -                                        _ => SIMDSizeCode::D, +                                    let size = if opcode == Opcode::SQDMULH || opcode == Opcode::SQRDMULH || opcode == Opcode::SQRDMLAH || opcode == Opcode::SQRDMLSH { +                                        match size { +                                            0b01 => SIMDSizeCode::H, +                                            0b10 => SIMDSizeCode::S, +                                            _ => SIMDSizeCode::D, +                                        } +                                    } else { +                                        match size { +                                            0b00 => SIMDSizeCode::H, +                                            0b01 => { return Err(DecodeError::InvalidOperand); } +                                            0b10 => SIMDSizeCode::S, +                                            _ => SIMDSizeCode::D, +                                        }                                      };                                      let (Rm, index) = match size { @@ -6697,124 +6717,100 @@ impl Decoder<ARMv8> for InstDecoder {                              let immb = (word >> 16) & 0b111;                              let immh = (word >> 19) & 0b1111;                              let U = (word >> 29) & 1; -                            let Q = (word >> 30) & 1 == 1;                              if immh == 0 {                                  return Err(DecodeError::InvalidOperand);                              } +                            #[allow(non_camel_case_types)] +                            #[derive(Debug)]                              enum OperandsKind { -                                SameSizes, -                                DifferentSizes, +                                D_After, +                                D_Before, +                                BHSD_After, +                                HSD_Before, +                                BHS_HSD_Before,                              }                              let (opcode, operands_kind) = match (opcode << 1) + U { -                                0b00000_0 => (Opcode::SSHR, OperandsKind::SameSizes), -                                0b00010_0 => (Opcode::SSRA, OperandsKind::SameSizes), -                                0b00100_0 => (Opcode::SRSHR, OperandsKind::SameSizes), -                                0b00110_0 => (Opcode::SRSRA, OperandsKind::SameSizes), -                                0b01010_0 => (Opcode::SHL, OperandsKind::SameSizes), -                                0b01110_0 => (Opcode::SQSHL, OperandsKind::SameSizes), -                                0b10010_0 => (Opcode::SQSHRN, OperandsKind::DifferentSizes), -                                0b10011_0 => (Opcode::SQRSHRN, OperandsKind::DifferentSizes), -                                0b11100_0 => (Opcode::SCVTF, OperandsKind::SameSizes), -                                0b11111_0 => (Opcode::FCVTZS, OperandsKind::SameSizes), -                                0b00000_1 => (Opcode::USHR, OperandsKind::SameSizes), -                                0b00010_1 => (Opcode::USRA, OperandsKind::SameSizes), -                                0b00100_1 => (Opcode::URSHR, OperandsKind::SameSizes), -                                0b00110_1 => (Opcode::URSRA, OperandsKind::SameSizes), -                                0b01000_1 => (Opcode::SRI, OperandsKind::SameSizes), -                                0b01010_1 => (Opcode::SLI, OperandsKind::SameSizes), -                                0b01100_1 => (Opcode::SQSHLU, OperandsKind::SameSizes), -                                0b01110_1 => (Opcode::UQSHL, OperandsKind::SameSizes), -                                0b10000_1 => (Opcode::SQSHRUN, OperandsKind::DifferentSizes), -                                0b10001_1 => (Opcode::SQRSHRUN, OperandsKind::DifferentSizes), -                                0b10010_1 => (Opcode::UQSHRN, OperandsKind::DifferentSizes), -                                0b10011_1 => (Opcode::UQRSHRN, OperandsKind::DifferentSizes), -                                0b11100_1 => (Opcode::UCVTF, OperandsKind::SameSizes), -                                0b11111_1 => (Opcode::FCVTZU, OperandsKind::SameSizes), +                                0b00000_0 => (Opcode::SSHR, OperandsKind::D_Before), +                                0b00010_0 => (Opcode::SSRA, OperandsKind::D_Before), +                                0b00100_0 => (Opcode::SRSHR, OperandsKind::D_Before), +                                0b00110_0 => (Opcode::SRSRA, OperandsKind::D_Before), +                                0b01010_0 => (Opcode::SHL, OperandsKind::D_After), +                                0b01110_0 => (Opcode::SQSHL, OperandsKind::BHSD_After), +                                0b10010_0 => (Opcode::SQSHRN, OperandsKind::BHS_HSD_Before), +                                0b10011_0 => (Opcode::SQRSHRN, OperandsKind::BHS_HSD_Before), +                                0b11100_0 => (Opcode::SCVTF, OperandsKind::HSD_Before), +                                0b11111_0 => (Opcode::FCVTZS, OperandsKind::HSD_Before), +                                0b00000_1 => (Opcode::USHR, OperandsKind::D_Before), +                                0b00010_1 => (Opcode::USRA, OperandsKind::D_Before), +                                0b00100_1 => (Opcode::URSHR, OperandsKind::D_Before), +                                0b00110_1 => (Opcode::URSRA, OperandsKind::D_Before), +                                0b01000_1 => (Opcode::SRI, OperandsKind::D_Before), +                                0b01010_1 => (Opcode::SLI, OperandsKind::D_After), +                                0b01100_1 => (Opcode::SQSHLU, OperandsKind::BHSD_After), +                                0b01110_1 => (Opcode::UQSHL, OperandsKind::BHSD_After), +                                0b10000_1 => (Opcode::SQSHRUN, OperandsKind::BHS_HSD_Before), +                                0b10001_1 => (Opcode::SQRSHRUN, OperandsKind::BHS_HSD_Before), +                                0b10010_1 => (Opcode::UQSHRN, OperandsKind::BHS_HSD_Before), +                                0b10011_1 => (Opcode::UQRSHRN, OperandsKind::BHS_HSD_Before), +                                0b11100_1 => (Opcode::UCVTF, OperandsKind::HSD_Before), +                                0b11111_1 => (Opcode::FCVTZU, OperandsKind::HSD_Before),                                  _ => { return Err(DecodeError::InvalidOpcode); },                              }; -                            let opcode = if Q { -                                if opcode == Opcode::SQSHRN { -                                    Opcode::SQSHRN2 -                                } else if opcode == Opcode::SQRSHRN { -                                    Opcode::SQRSHRN2 -                                } else if opcode == Opcode::SQSHRUN { -                                    Opcode::SQSHRUN2 -                                } else if opcode == Opcode::SQRSHRUN { -                                    Opcode::SQRSHRUN2 -                                } else if opcode == Opcode::UQSHRN { -                                    Opcode::UQSHRN2 -                                } else if opcode == Opcode::UQRSHRN { -                                    Opcode::UQRSHRN2 -                                } else { -                                    opcode -                                } -                            } else { -                                opcode -                            }; -                              inst.opcode = opcode; -                            match operands_kind { -                                OperandsKind::SameSizes => { -                                    let vec_size = if Q { -                                        SIMDSizeCode::Q -                                    } else { -                                        SIMDSizeCode::D -                                    }; -                                    let (size, imm) = match immh.leading_zeros() { -                                        3 => { -                                            (SIMDSizeCode::B, immb) -                                        } -                                        2 => { -                                            (SIMDSizeCode::H, ((immh & 0b0001) << 4)| immb) -                                        } -                                        1 => { -                                            (SIMDSizeCode::S, ((immh & 0b0011) << 4)| immb) -                                        } -                                        0 => { -                                            // the +q version of this check would be `Advanced SIMD -                                            // modified immediate`, checked well before we got -                                            // here. so assume q is 0, error. -                                            return Err(DecodeError::InvalidOperand); -                                        } -                                        _ => { -                                            return Err(DecodeError::InvalidOperand); -                                        } -                                    }; -                                    inst.operands = [ -                                        Operand::SIMDRegisterElements(vec_size, Rd as u16, size), -                                        Operand::SIMDRegisterElements(vec_size, Rn as u16, size), -                                        Operand::Imm16(imm as u16), -                                        Operand::Nothing, -                                    ]; +                            let immh = immh as u8; +                            let immb = immb as u8; + +                            let leading_zeros = immh.leading_zeros() - 4; + +                            let shift = immh << 3 | immb; + +                            let (a_sz, b_sz, shift) = match operands_kind { +                                OperandsKind::D_After => { +                                    if leading_zeros != 0 { return Err(DecodeError::InvalidOperand); } +                                    (SIMDSizeCode::D, SIMDSizeCode::D, shift - 64)                                  }, -                                OperandsKind::DifferentSizes => { -                                    let (dest_size, src_size, imm) = match immh.leading_zeros() { -                                        3 => { -                                            (SIMDSizeCode::B, SIMDSizeCode::H, immb) -                                        } -                                        2 => { -                                            (SIMDSizeCode::H, SIMDSizeCode::S, ((immh & 0b0001) << 4)| immb) -                                        } -                                        1 => { -                                            (SIMDSizeCode::S, SIMDSizeCode::D, ((immh & 0b0011) << 4)| immb) -                                        } -                                        _ => { -                                            return Err(DecodeError::InvalidOperand); -                                        } -                                    }; -                                    inst.operands = [ -                                        Operand::SIMDRegister(dest_size, Rd as u16), -                                        Operand::SIMDRegister(src_size, Rn as u16), -                                        Operand::Imm16(imm as u16), -                                        Operand::Nothing, -                                    ]; +                                OperandsKind::D_Before => { +                                    if leading_zeros != 0 { return Err(DecodeError::InvalidOperand); } +                                    (SIMDSizeCode::D, SIMDSizeCode::D, 128 - shift) +                                }, +                                OperandsKind::BHSD_After => { +                                    match leading_zeros { +                                        0 => (SIMDSizeCode::D, SIMDSizeCode::D, shift - 64), +                                        1 => (SIMDSizeCode::S, SIMDSizeCode::S, shift - 32), +                                        2 => (SIMDSizeCode::H, SIMDSizeCode::H, shift - 16), +                                        3 => (SIMDSizeCode::B, SIMDSizeCode::B, shift - 8), +                                        _ => { return Err(DecodeError::InvalidOperand); }, +                                    } +                                }, +                                OperandsKind::HSD_Before => { +                                    match leading_zeros { +                                        0 => (SIMDSizeCode::D, SIMDSizeCode::D, 128 - shift), +                                        1 => (SIMDSizeCode::S, SIMDSizeCode::S, 64 - shift), +                                        2 => (SIMDSizeCode::H, SIMDSizeCode::H, 32 - shift), +                                        _ => { return Err(DecodeError::InvalidOperand); }, +                                    }                                  } -                            } +                                OperandsKind::BHS_HSD_Before => { +                                    match leading_zeros { +                                        1 => (SIMDSizeCode::S, SIMDSizeCode::D, 64 - shift), +                                        2 => (SIMDSizeCode::H, SIMDSizeCode::S, 32 - shift), +                                        3 => (SIMDSizeCode::B, SIMDSizeCode::H, 16 - shift), +                                        _ => { return Err(DecodeError::InvalidOperand); }, +                                    } +                                } +                            }; + +                            inst.operands = [ +                                Operand::SIMDRegister(a_sz, Rd as u16), +                                Operand::SIMDRegister(b_sz, Rn as u16), +                                Operand::Imm16(shift as u16), +                                Operand::Nothing, +                            ];                          }                      }                  } else if op0 == 0b1100 { @@ -8108,7 +8104,7 @@ impl Decoder<ARMv8> for InstDecoder {                          let size = (word >> 30) & 0x3;                          // load/store exclusive                          // o2 == 1 -                        if Lo1 & 1 == 1 && size < 0b10 { +                        if Lo1 & 1 == 1 {                              // o1 == 1                              if Rt2 != 0b11111 {                                  return Err(DecodeError::InvalidOperand); | 
