charm 0.0.1

ARM assembler & disassembler generated from the ARM exploration tools.
Documentation
//! # STM (User registers)
//!
//! In an EL1 mode other than System mode, Store Multiple (User registers) stores multiple User mode registers to consecutive memory locations using an address from a base register. The PE reads the base register value normally, using the current mode to determine the correct Banked version of the register. This instruction cannot writeback to the base register.

#![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 IclassStmUA1As
// ---------------------------------------------------------------------------

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

impl IclassStmUA1As {
    /// Tries to decode the instruction in `data`.
    pub(crate) fn decode(data: u32, decoder: &mut Decoder) -> Result<Instruction> {
        let U = (data >> 23) & 1;
        let U_post = U;
        let op = (data >> 22) & 1;
        let op_post = op;
        let register_list = (data >> 0) & 65535;
        let register_list_post = register_list;
        let P = (data >> 24) & 1;
        let P_post = P;
        let Rn = (data >> 16) & 15;
        let Rn_post = Rn;
        let field_25 = (data >> 25) & 1;
        let field_25_post = field_25;
        let field_27 = (data >> 26) & 3;
        let field_27_post = field_27;
        let cond = (data >> 28) & 15;
        let cond_post = cond;
        let L = (data >> 20) & 1;
        let L_post = L;
        let W = (data >> 21) & 1;
        let W_post = W;


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

        unreachable!()
    }
}

/// STM A1 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="4">!= 1111</td>
///          <td style="text-align: center; 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" colspan="1">P</td>
/// <td style="text-align: center" colspan="1">U</td>
///          <td style="text-align: center; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-right: none" colspan="3">(0)</td>
///          <td style="text-align: center; border-right: none" colspan="1">0</td>
/// <td style="text-align: center" colspan="4">Rn</td>
/// <td style="text-align: center" colspan="16">register_list</td>
///     </tr>
///     <tr>
/// <td style="text-align: center; border: none" colspan="4">cond</td>
/// <td style="text-align: center; border: none" colspan="2"></td>
/// <td style="text-align: center; border: none" colspan="1"></td>
/// <td style="text-align: center; border: none" colspan="1"></td>
/// <td style="text-align: center; border: none" colspan="1"></td>
/// <td style="text-align: center; border: none" colspan="1">op</td>
/// <td style="text-align: center; border: none" colspan="1">W</td>
/// <td style="text-align: center; border: none" colspan="1">L</td>
/// <td style="text-align: center; border: none" colspan="4"></td>
/// <td style="text-align: center; border: none" colspan="16"></td>
///     </tr>
/// </table>
pub struct StmUA1As;

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

    /// Returns the instruction condition information.
    pub fn condition(_instr: &Instruction) -> ConditionalInstruction {
        ConditionalInstruction::Condition(1, 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 cond = (data >> 28) & 15;
        let cond_post = cond;
        let P = (data >> 24) & 1;
        let P_post = P;
        let U = (data >> 23) & 1;
        let U_post = U;
        let Rn = (data >> 16) & 15;
        let Rn_post = Rn;
        let register_list = (data >> 0) & 65535;
        let register_list_post = register_list;

        

        // Operand values are computed from the base fields.
        let P_U_post = (U << 1) | P;
        let op_0 = AddressMode::decode(P_U_post);
        let cond_post = cond;
        let op_1 = MnemonicCondition::decode(cond_post)?;
        let Rn_post = Rn;
        let op_2 = Register::decode(Rn_post)?;
        let register_list_post = register_list;
        let op_3 = RegisterList::decode(register_list_post);

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

    /// Encodes the instruction into `buf`.
    pub fn encode(instr: &Instruction, buf: &mut Vec<u8>) -> Result<usize> {
        // Retrieve all operand values.
        let P_U_pre = instr.op0().as_address_mode()?.encode();
        let cond_pre = instr.op1().as_mnemonic_condition()?.encode();
        let Rn_pre = instr.op2().as_register()?.encode();
        let register_list_pre = instr.op3().as_register_list()?.encode();

        // Compute all instruction fields from the operand values.
        let P = (P_U_pre & 1);
        let U = (P_U_pre >> 1) & 1;
        let cond = (cond_pre & 15);
        let Rn = (Rn_pre & 15);
        let register_list = (register_list_pre & 65535);

        // Add all fields to the base instruction encoding.
        let mut instr: u32 = 0b00001000010000000000000000000000;
        instr |= (P & 1) << 24;
        instr |= (U & 1) << 23;
        instr |= (cond & 15) << 28;
        instr |= (Rn & 15) << 16;
        instr |= (register_list & 65535) << 0;

        let bytes = instr.to_le_bytes();
        let len = bytes.len();
        buf.extend(bytes);
        Ok(len)
    }

    /// 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::AddressMode(_) = op {
            return Ok(())
        }
        todo!()
    }
    
    /// Verifies that operand #1 is valid.
    pub fn check_op1(instr: &Instruction, op: &Operand) -> Result<()> {
        if let Operand::MnemonicCondition(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::RegisterList(RegisterList(value)) = op {
            return Ok(())
        }
        todo!()
    }
    
    /// Verifies that operand #4 is valid.
    pub fn check_op4(instr: &Instruction, op: &Operand) -> Result<()> {
        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.stm_u_a1_as, &instr)?;
        fmt.format_operand(output, &config.global, &config.instructions.stm_u_a1_as, &instr, 0)?;
        fmt.format_operand(output, &config.global, &config.instructions.stm_u_a1_as, &instr, 1)?;
        fmt.format_qualifier(output, &config.global, &config.instructions.stm_u_a1_as, &instr, FormatterQualifier::Wide, false, false)?;
        fmt.format_punctuation(output, &config.global, &config.instructions.stm_u_a1_as, &instr, FormatterTextKind::Space)?;
        fmt.format_operand(output, &config.global, &config.instructions.stm_u_a1_as, &instr, 2)?;
        fmt.format_punctuation(output, &config.global, &config.instructions.stm_u_a1_as, &instr, FormatterTextKind::Comma)?;
        fmt.format_operand(output, &config.global, &config.instructions.stm_u_a1_as, &instr, 3)?;
        fmt.format_punctuation(output, &config.global, &config.instructions.stm_u_a1_as, &instr, FormatterTextKind::Hat)?;
        Ok(())
    }
}

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

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