charm 0.0.1

ARM assembler & disassembler generated from the ARM exploration tools.
Documentation
//! Default configuration objects and all configuration-related types.

use super::consts::config::ConfigInstructions;

// -----------------------------------------------------------------------------------------------
// Config
// -----------------------------------------------------------------------------------------------

/// Main configuration object.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct Config {
    /// Global configuration.
    ///
    /// This is where the default behavior is set. Values in this structure
    /// act as a fallback if there is no per-instruction settings.
    pub global: ConfigGlobal,
    /// Per-instruction settings that override the default behavior in the global config.
    pub instructions: ConfigInstructions,
}

impl Config {
    /// Creates a new configuration object with default values.
    pub fn new() -> Self {
        Self::default()
    }
}

/// Type that represents the global configuration.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct ConfigGlobal {
    /// Global syntax rules.
    pub syntax: FormatSyntaxGlobal,
    /// Global aliases rules.
    pub aliases: FormatAliasGlobal,
}

impl ConfigGlobal {
    /// Creates a new global configuration object.
    pub fn new() -> Self {
        Self::default()
    }
}

/// Type that represents the configuration of an instruction.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub struct ConfigInstruction<A> {
    /// Per-instruction syntax rules.
    pub syntax: FormatSyntax,
    /// Per-instruction qualifier rules.
    ///
    /// If `None`, defaults to the corresponding global configuration value.
    pub aliases: Option<FormatAliasInstruction<A>>,
}

impl<A> ConfigInstruction<A> {
    pub fn new() -> Self {
        Self::default()
    }
}

impl<A> Default for ConfigInstruction<A> {
    fn default() -> Self {
        Self {
            syntax: FormatSyntax::default(),
            aliases: None,
        }
    }
}

/// Trait to retrieve the syntax and qualifier object.
pub trait HasConfigInstruction {
    fn syntax(&self) -> &FormatSyntax;
}

impl<A> HasConfigInstruction for ConfigInstruction<A> {
    fn syntax(&self) -> &FormatSyntax {
        &self.syntax
    }
}

// -----------------------------------------------------------------------------------------------
// Aliases
// -----------------------------------------------------------------------------------------------

/// Type that represents the global alias settings.
///
/// It specifies Charm's default behavior when using an alias is possible.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub enum FormatAliasGlobal {
    /// Never use the alias, regardless of any condition.
    Never,
    /// Follows ARM's recommendations.
    #[default]
    Recommended,
    /// Always use the alias, regardless of any condition.
    Always,
}

/// Type that represents the per-instruction alias settings.
///
/// It specifies Charm's behavior for a given encoding when using an alias is possible.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub enum FormatAliasInstruction<A> {
    /// Never use the alias, regardless of any condition.
    Never,
    /// Follows ARM's recommendations.
    #[default]
    Recommended,
    /// If multiple aliases are possible, try to use this alias first.
    Preferred(A),
    /// Always use the alias, regardless of any condition.
    Always(A),
}

// -----------------------------------------------------------------------------------------------
// Syntax
// -----------------------------------------------------------------------------------------------

/// Type that represent the integer formatting configuration.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub enum FormatInteger {
    /// Display integers as signed decimal numbers.
    #[default]
    DecimalSigned,
    /// Display integers as unsigned decimal numbers.
    DecimalUnsigned,
    /// Display integers as signed hexdecimal numbers.
    HexadecimalSigned,
    /// Display integers as unsigned hexdecimal numbers.
    HexadecimalUnsigned,
}

/// Type that represents the global syntax settings.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct FormatSyntaxGlobal {
    /// Settings for a register that can be omitted when it is *used* as both the source and the
    /// destination.
    /// For example, in `ADCS{<q>} {<Rdn>, }<Rdn>, <Rm>`, this would control whether or not `<Rdn>`
    /// is displayed.
    pub omit_src_dst_same_reg: bool,
    /// Controls if a register that can be omitted when it *can* be used as both the source and the
    /// destination should be displayed.
    /// For example, in `ADC{<c>}{<q>} {<Rd>, }<Rn>, <Rm>, RRX`, this would control whether or not
    /// `<Rd>` is displayed if `<Rd> == <Rn>`.
    pub omit_src_dst_diff_reg: bool,
    /// Controls if optional null integers in dereferencing groups should be displayed.
    /// For example, in `LDXRB <Wt>, [<Xn|SP>{, #0}]`, this would control whether or not #0 is
    /// displayed.
    pub omit_deref_null_const: bool,
    /// Controls how positive numbers are displayed.
    pub positive_integer_format: FormatInteger,
    /// Controls how negative numbers are displayed.
    pub negative_integer_format: FormatInteger,
}

/// Type that represents the per-instruction syntax settings.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct FormatSyntax {
    /// Settings for a register that can be omitted when it is *used* as both the source and the
    /// destination.
    /// For example, in `ADCS{<q>} {<Rdn>, }<Rdn>, <Rm>`, this would control whether or not `<Rdn>`
    /// is displayed.
    ///
    /// If `None`, defaults to the corresponding global configuration value.
    pub omit_src_dst_same_reg: Option<bool>,
    /// Controls if a register that can be omitted when it *can* be used as both the source and the
    /// destination should be displayed.
    /// For example, in `ADC{<c>}{<q>} {<Rd>, }<Rn>, <Rm>, RRX`, this would control whether or not
    /// `<Rd>` is displayed if `<Rd> == <Rn>`.
    ///
    /// If `None`, defaults to the corresponding global configuration value.
    pub omit_src_dst_diff_reg: Option<bool>,
    /// Controls if optional null integers in dereferencing groups should be displayed.
    /// For example, in `LDXRB <Wt>, [<Xn|SP>{, #0}]`, this would control whether or not #0 is
    /// displayed.
    ///
    /// If `None`, defaults to the corresponding global configuration value.
    pub omit_deref_null_const: Option<bool>,
    /// Controls how positive numbers are displayed.
    ///
    /// If `None`, defaults to the corresponding global configuration value.
    pub positive_integer_format: Option<FormatInteger>,
    /// Controls how negative numbers are displayed.
    ///
    /// If `None`, defaults to the corresponding global configuration value.
    pub negative_integer_format: Option<FormatInteger>,
}

impl FormatSyntax {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn get_omit_src_dst_same_reg(&self, global: &FormatSyntaxGlobal) -> bool {
        if let Some(value) = self.omit_src_dst_same_reg {
            return value;
        }
        global.omit_src_dst_same_reg
    }

    pub fn get_omit_src_dst_diff_reg(&self, global: &FormatSyntaxGlobal) -> bool {
        if let Some(value) = self.omit_src_dst_diff_reg {
            return value;
        }
        global.omit_src_dst_diff_reg
    }

    pub fn get_positive_integer_format(&self, global: &FormatSyntaxGlobal) -> FormatInteger {
        if let Some(value) = self.positive_integer_format {
            return value;
        }
        global.positive_integer_format
    }

    pub fn get_negative_integer_format(&self, global: &FormatSyntaxGlobal) -> FormatInteger {
        if let Some(value) = self.negative_integer_format {
            return value;
        }
        global.negative_integer_format
    }
}

// -----------------------------------------------------------------------------------------------
// LLVM Config
// -----------------------------------------------------------------------------------------------

/// Configuration making Charm behave similarly to LLVM.
pub struct ConfigLLVM {}

impl ConfigLLVM {
    /// Creates a new LLVM configuration.
    pub fn new() -> Config {
        let mut config = Config::default();

        // ---------------------------------------------------------------------------------------
        // Global - Syntax
        config.global.syntax.omit_src_dst_same_reg = true;
        config.global.syntax.omit_src_dst_diff_reg = false;
        config.global.syntax.omit_deref_null_const = true;

        // ---------------------------------------------------------------------------------------
        // Per-instruction - Syntax
        config
            .instructions
            .and_32_log_imm
            .syntax
            .positive_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .and_32_log_imm
            .syntax
            .negative_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .and_64_log_imm
            .syntax
            .positive_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .and_64_log_imm
            .syntax
            .negative_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .ands_32s_log_imm
            .syntax
            .positive_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .ands_32s_log_imm
            .syntax
            .negative_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .ands_64s_log_imm
            .syntax
            .positive_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .ands_64s_log_imm
            .syntax
            .negative_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .eor_32_log_imm
            .syntax
            .positive_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .eor_32_log_imm
            .syntax
            .negative_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .eor_64_log_imm
            .syntax
            .positive_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .eor_64_log_imm
            .syntax
            .negative_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .orr_32_log_imm
            .syntax
            .positive_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .orr_32_log_imm
            .syntax
            .negative_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .orr_64_log_imm
            .syntax
            .positive_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .orr_64_log_imm
            .syntax
            .negative_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .tst_ands_32s_log_imm
            .syntax
            .positive_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .tst_ands_32s_log_imm
            .syntax
            .negative_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .tst_ands_64s_log_imm
            .syntax
            .positive_integer_format = Some(FormatInteger::HexadecimalUnsigned);
        config
            .instructions
            .tst_ands_64s_log_imm
            .syntax
            .negative_integer_format = Some(FormatInteger::HexadecimalUnsigned);

        // ---------------------------------------------------------------------------------------
        // Per-instruction - Aliases
        config.instructions.ldtadd_32_memop_unpriv.aliases = Some(FormatAliasInstruction::Never);
        config.instructions.ldtadd_64_memop_unpriv.aliases = Some(FormatAliasInstruction::Never);
        config.instructions.ldtaddl_32_memop_unpriv.aliases = Some(FormatAliasInstruction::Never);
        config.instructions.ldtaddl_64_memop_unpriv.aliases = Some(FormatAliasInstruction::Never);
        config.instructions.ldtclr_32_memop_unpriv.aliases = Some(FormatAliasInstruction::Never);
        config.instructions.ldtclr_64_memop_unpriv.aliases = Some(FormatAliasInstruction::Never);
        config.instructions.ldtclrl_32_memop_unpriv.aliases = Some(FormatAliasInstruction::Never);
        config.instructions.ldtclrl_64_memop_unpriv.aliases = Some(FormatAliasInstruction::Never);
        config.instructions.ldtset_32_memop_unpriv.aliases = Some(FormatAliasInstruction::Never);
        config.instructions.ldtset_64_memop_unpriv.aliases = Some(FormatAliasInstruction::Never);
        config.instructions.ldtsetl_32_memop_unpriv.aliases = Some(FormatAliasInstruction::Never);
        config.instructions.ldtsetl_64_memop_unpriv.aliases = Some(FormatAliasInstruction::Never);
        config.instructions.subps_64s_dp_2src.aliases = Some(FormatAliasInstruction::Never);

        config
    }
}