charm 0.0.1

ARM assembler & disassembler generated from the ARM exploration tools.
Documentation
//! # MLA, MLAS
//!
//! Multiply Accumulate multiplies two register values, and adds a third register value. The least significant 32 bits of the result are written to the destination register. These 32 bits do not depend on whether the source register values are considered to be signed values or unsigned values.

#![allow(non_snake_case)]
#![allow(unused)]
use crate::error::Result;
use crate::utils::*;
use super::super::formatter::*;
use super::super::instruction::*;
use super::super::operand::*;
use super::super::consts::*;
use super::super::config::*;
use super::super::decoder::*;

// ---------------------------------------------------------------------------
// Iclass IclassMlaT1
// ---------------------------------------------------------------------------

/// Type that represents the IclassMlaT1 instruction class.
pub(crate) struct IclassMlaT1;

impl IclassMlaT1 {
    /// Tries to decode the instruction in `data`.
    pub(crate) fn decode(data: u32, decoder: &mut Decoder) -> Result<Instruction> {
        let op1 = (data >> 20) & 7;
        let op1_post = op1;
        let Rm = (data >> 0) & 15;
        let Rm_post = Rm;
        let op2 = (data >> 4) & 3;
        let op2_post = op2;
        let field_31 = (data >> 29) & 7;
        let field_31_post = field_31;
        let Ra = (data >> 12) & 15;
        let Ra_post = Ra;
        let Rn = (data >> 16) & 15;
        let Rn_post = Rn;
        let field_28 = (data >> 23) & 63;
        let field_28_post = field_28;
        let Rd = (data >> 8) & 15;
        let Rd_post = Rd;
        let field_7 = (data >> 6) & 3;
        let field_7_post = field_7;


        return MlaT1::decode(data as u32, decoder);

        unreachable!()
    }
}

/// MLA T1 encoding.
///
/// # Encoding
///
/// <table style="font-family: courier, monospace">
///     <tr>
///         <td style="border: none">31</td>
///         <td style="border: none">30</td>
///         <td style="border: none">29</td>
///         <td style="border: none">28</td>
///         <td style="border: none">27</td>
///         <td style="border: none">26</td>
///         <td style="border: none">25</td>
///         <td style="border: none">24</td>
///         <td style="border: none">23</td>
///         <td style="border: none">22</td>
///         <td style="border: none">21</td>
///         <td style="border: none">20</td>
///         <td style="border: none">19</td>
///         <td style="border: none">18</td>
///         <td style="border: none">17</td>
///         <td style="border: none">16</td>
///         <td style="border: none">15</td>
///         <td style="border: none">14</td>
///         <td style="border: none">13</td>
///         <td style="border: none">12</td>
///         <td style="border: none">11</td>
///         <td style="border: none">10</td>
///         <td style="border: none">9</td>
///         <td style="border: none">8</td>
///         <td style="border: none">7</td>
///         <td style="border: none">6</td>
///         <td style="border: none">5</td>
///         <td style="border: none">4</td>
///         <td style="border: none">3</td>
///         <td style="border: none">2</td>
///         <td style="border: none">1</td>
///         <td style="border: none">0</td>
///     </tr>
///     <tr>
///          <td style="text-align: center; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-left: none; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-left: none" colspan="1">1</td>
///          <td style="text-align: center; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-left: none; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-left: none; border-right: none" colspan="1">0</td>
///          <td style="text-align: center; border-left: none; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-left: none; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-left: none" colspan="1">0</td>
///          <td style="text-align: center; border-right: none" colspan="1">0</td>
///          <td style="text-align: center; border-left: none; border-right: none" colspan="1">0</td>
///          <td style="text-align: center; border-left: none" colspan="1">0</td>
/// <td style="text-align: center" colspan="4">Rn</td>
///          <td style="text-align: center; border-right: none" colspan="4">!= 1111</td>
/// <td style="text-align: center" colspan="4">Rd</td>
///          <td style="text-align: center; border-right: none" colspan="1">0</td>
///          <td style="text-align: center; border-left: none" colspan="1">0</td>
///          <td style="text-align: center; border-right: none" colspan="1">0</td>
///          <td style="text-align: center; border-left: none" colspan="1">0</td>
/// <td style="text-align: center" colspan="4">Rm</td>
///     </tr>
///     <tr>
/// <td style="text-align: center; border: none" colspan="3"></td>
/// <td style="text-align: center; border: none" colspan="6"></td>
/// <td style="text-align: center; border: none" colspan="3">op1</td>
/// <td style="text-align: center; border: none" colspan="4"></td>
/// <td style="text-align: center; border: none" colspan="4">Ra</td>
/// <td style="text-align: center; border: none" colspan="4"></td>
/// <td style="text-align: center; border: none" colspan="2"></td>
/// <td style="text-align: center; border: none" colspan="2">op2</td>
/// <td style="text-align: center; border: none" colspan="4"></td>
///     </tr>
/// </table>
pub struct MlaT1;

impl MlaT1 {
    /// Returns the instruction mnemonic.
    pub fn mnemonic(_instr: &Instruction) -> Mnemonic {
        Mnemonic::MLA
    }

    /// Returns the instruction condition information.
    pub fn condition(instr: &Instruction) -> ConditionalInstruction {
        ConditionalInstruction::Condition(0, false, false)
    }

    /// Returns the instruction size.
    pub fn size(_instr: &Instruction) -> usize {4}

    /// Decodes the instruction in `data`.
    pub fn decode(data: u32, decoder: &mut Decoder) -> Result<Instruction> {
        // Fields are extracted from the input value.
        let Rn = (data >> 16) & 15;
        let Rn_post = Rn;
        let Ra = (data >> 12) & 15;
        let Ra_post = Ra;
        let Rd = (data >> 8) & 15;
        let Rd_post = Rd;
        let Rm = (data >> 0) & 15;
        let Rm_post = Rm;
        
        // Compute the dependency values for the operands.
        let Ra_post = Ra;
        let Rd_post = Rd;
        let Rn_post = Rn;
        let Rm_post = Rm;

        // Operand values are computed from the base fields and the dependencies.
        let op_0 = MnemonicCondition::Al;
        let op_1 = Register::decode(Rd_post)?;
        let op_2 = Register::decode(Rn_post)?;
        let op_3 = Register::decode(Rm_post)?;
        let op_4 = Register::decode(Ra_post)?;

        // Instruction creation from the operands.
        let mut instr = Instruction::builder(Code::MLA_T1)
            .operand(0, op_0)?
            .operand(1, op_1)?
            .operand(2, op_2)?
            .operand(3, op_3)?
            .operand(4, op_4)?
            .build();
        
        Ok(instr)
    }

    pub fn encode(instr: &Instruction, buf: &mut Vec<u8>) -> Result<usize> {
        // Retrieve all operand values.
        let Rd_pre = instr.op1().as_register()?.encode();
        let Rn_pre = instr.op2().as_register()?.encode();
        let Rm_pre = instr.op3().as_register()?.encode();
        let Ra_pre = instr.op4().as_register()?.encode();

        // Compute all instruction fields from the operand values.
        let Rd = (Rd_pre & 15);
        let Rn = (Rn_pre & 15);
        let Rm = (Rm_pre & 15);
        let Ra = (Ra_pre & 15);

        // Add all fields to the base instruction encoding.
        let mut instr: u32 = 0b11111011000000000000000000000000;
        instr |= (Rd & 15) << 8;
        instr |= (Rn & 15) << 16;
        instr |= (Rm & 15) << 0;
        instr |= (Ra & 15) << 12;

        let instr_1 = (instr & 0xffff) as u16;
        let instr_2 = ((instr >> 16) & 0xffff) as u16;
        buf.extend(instr_2.to_le_bytes());
        buf.extend(instr_1.to_le_bytes());
        Ok(4)
    }

    /// Encode an instruction part of an instruction block into `buf`.
    pub fn encode_block(instr: &mut Instruction, buf: &mut Vec<u8>, labels: &std::collections::HashMap<u64, u64>) -> Result<usize> {
        Self::encode(instr, buf)
    }
    
    /// Verifies that operand #0 is valid.
    pub fn check_op0(instr: &Instruction, op: &Operand) -> Result<()> {
        if let Operand::MnemonicCondition(r) = op {
            return Ok(())
        }
        todo!()
    }
    
    /// Verifies that operand #1 is valid.
    pub fn check_op1(instr: &Instruction, op: &Operand) -> Result<()> {
        
        if let Operand::Register(r) = op {
            return Ok(())
        }
        todo!()
    }
    
    /// Verifies that operand #2 is valid.
    pub fn check_op2(instr: &Instruction, op: &Operand) -> Result<()> {
        
        if let Operand::Register(r) = op {
            return Ok(())
        }
        todo!()
    }
    
    /// Verifies that operand #3 is valid.
    pub fn check_op3(instr: &Instruction, op: &Operand) -> Result<()> {
        
        if let Operand::Register(r) = op {
            return Ok(())
        }
        todo!()
    }
    
    /// Verifies that operand #4 is valid.
    pub fn check_op4(instr: &Instruction, op: &Operand) -> Result<()> {
        
        if let Operand::Register(r) = op {
            return Ok(())
        }
        todo!()
    }
    
    /// Verifies that operand #5 is valid.
    pub fn check_op5(instr: &Instruction, op: &Operand) -> Result<()> {
        todo!()
    }
    
    /// Verifies that operand #6 is valid.
    pub fn check_op6(instr: &Instruction, op: &Operand) -> Result<()> {
        todo!()
    }

    /// Formats the instruction.
    pub fn format(instr: &Instruction, fmt: &mut impl Formatter, output: &mut impl FormatterOutput, config: &Config) -> Result<()> {
        fmt.format_mnemonic(output, &config.global, &config.instructions.mla_t1, &instr)?;
        fmt.format_operand(output, &config.global, &config.instructions.mla_t1, &instr, 0)?;
        fmt.format_qualifier(output, &config.global, &config.instructions.mla_t1, &instr, FormatterQualifier::Wide, false, false)?;
        fmt.format_punctuation(output, &config.global, &config.instructions.mla_t1, &instr, FormatterTextKind::Space)?;
        fmt.format_operand(output, &config.global, &config.instructions.mla_t1, &instr, 1)?;
        fmt.format_punctuation(output, &config.global, &config.instructions.mla_t1, &instr, FormatterTextKind::Comma)?;
        fmt.format_operand(output, &config.global, &config.instructions.mla_t1, &instr, 2)?;
        fmt.format_punctuation(output, &config.global, &config.instructions.mla_t1, &instr, FormatterTextKind::Comma)?;
        fmt.format_operand(output, &config.global, &config.instructions.mla_t1, &instr, 3)?;
        fmt.format_punctuation(output, &config.global, &config.instructions.mla_t1, &instr, FormatterTextKind::Comma)?;
        fmt.format_operand(output, &config.global, &config.instructions.mla_t1, &instr, 4)?;
        Ok(())
    }
}

/// Type that represents alias identifiers for [`MlaT1`].
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub enum MlaT1Aliases {
    None,
}

/// Type that represents encoding identifiers for [`MlaT1`].
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub enum MlaT1Encodings {
    None
}