#[cfg(feature = "pyo3")]
use pyo3::prelude::*;
use crate::abi::Abi;
use crate::isa::{IsaExtension, IsaVersion};
use crate::opcodes::DecodingFlags;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "pyo3", pyclass(module = "rabbitizer", from_py_object))]
pub struct InstructionFlags {
isa_version: IsaVersion,
isa_extension: Option<IsaExtension>,
decoding_flags: DecodingFlags,
abi: Abi,
j_as_branch: bool,
}
impl InstructionFlags {
#[must_use]
pub(crate) const fn default() -> Self {
Self {
isa_version: IsaVersion::default(),
isa_extension: None,
decoding_flags: DecodingFlags::default(),
abi: Abi::O32,
j_as_branch: true,
}
}
#[must_use]
pub const fn new(isa_version: IsaVersion) -> Self {
Self::new_isa(isa_version, None)
}
#[cfg(any(
feature = "RSP",
feature = "R3000GTE",
feature = "R4000ALLEGREX",
feature = "R5900EE",
))]
#[must_use]
pub const fn new_extension(isa_extension: IsaExtension) -> Self {
Self::new_isa(isa_extension.isa_version(), Some(isa_extension))
}
#[must_use]
pub const fn new_isa(isa_version: IsaVersion, isa_extension: Option<IsaExtension>) -> Self {
Self {
isa_version,
isa_extension,
..Self::default()
}
}
}
impl InstructionFlags {
#[must_use]
pub const fn isa_version(&self) -> IsaVersion {
self.isa_version
}
pub fn isa_version_mut(&mut self) -> &mut IsaVersion {
&mut self.isa_version
}
#[must_use]
pub const fn with_isa_version(self, isa_version: IsaVersion) -> Self {
Self {
isa_version,
..self
}
}
#[must_use]
pub const fn isa_extension(&self) -> Option<IsaExtension> {
self.isa_extension
}
#[cfg(any(
feature = "RSP",
feature = "R3000GTE",
feature = "R4000ALLEGREX",
feature = "R5900EE",
))]
pub fn isa_extension_mut(&mut self) -> &mut Option<IsaExtension> {
&mut self.isa_extension
}
#[cfg(any(
feature = "RSP",
feature = "R3000GTE",
feature = "R4000ALLEGREX",
feature = "R5900EE",
))]
#[must_use]
pub const fn with_isa_extension(self, isa_extension: Option<IsaExtension>) -> Self {
let isa_version = if let Some(isa_extension) = isa_extension {
isa_extension.isa_version()
} else {
self.isa_version
};
Self {
isa_version,
isa_extension,
..self
}
}
#[must_use]
pub(crate) const fn decoding_flags(&self) -> &DecodingFlags {
&self.decoding_flags
}
#[must_use]
pub(crate) const fn with_decoding_flags(self, decoding_flags: DecodingFlags) -> Self {
Self {
decoding_flags,
..self
}
}
#[must_use]
pub const fn enable_pseudos(&self) -> bool {
self.decoding_flags.contains(DecodingFlags::enable_pseudos)
}
pub fn set_enable_pseudos(&mut self, turn_on: bool) {
if turn_on {
self.decoding_flags.insert(DecodingFlags::enable_pseudos);
} else {
self.decoding_flags.remove(DecodingFlags::enable_pseudos);
}
}
#[must_use]
pub const fn with_enable_pseudos(self, turn_on: bool) -> Self {
let other = if turn_on {
self.decoding_flags.union(DecodingFlags::enable_pseudos)
} else {
self.decoding_flags
.intersection(DecodingFlags::enable_pseudos.complement())
};
self.with_decoding_flags(other)
}
#[must_use]
pub const fn pseudo_beqz(&self) -> bool {
self.decoding_flags.contains(DecodingFlags::pseudo_beqz)
}
pub fn set_pseudo_beqz(&mut self, turn_on: bool) {
if turn_on {
self.decoding_flags.insert(DecodingFlags::pseudo_beqz);
} else {
self.decoding_flags.remove(DecodingFlags::pseudo_beqz);
}
}
#[must_use]
pub const fn with_pseudo_beqz(self, turn_on: bool) -> Self {
let other = if turn_on {
self.decoding_flags.union(DecodingFlags::pseudo_beqz)
} else {
self.decoding_flags
.intersection(DecodingFlags::pseudo_beqz.complement())
};
self.with_decoding_flags(other)
}
#[must_use]
pub const fn pseudo_bnez(&self) -> bool {
self.decoding_flags.contains(DecodingFlags::pseudo_bnez)
}
pub fn set_pseudo_bnez(&mut self, turn_on: bool) {
if turn_on {
self.decoding_flags.insert(DecodingFlags::pseudo_bnez);
} else {
self.decoding_flags.remove(DecodingFlags::pseudo_bnez);
}
}
#[must_use]
pub const fn with_pseudo_bnez(self, turn_on: bool) -> Self {
let other = if turn_on {
self.decoding_flags.union(DecodingFlags::pseudo_bnez)
} else {
self.decoding_flags
.intersection(DecodingFlags::pseudo_bnez.complement())
};
self.with_decoding_flags(other)
}
#[must_use]
#[cfg(feature = "MIPS_II")]
pub const fn pseudo_beqzl(&self) -> bool {
self.decoding_flags.contains(DecodingFlags::pseudo_beqzl)
}
#[cfg(feature = "MIPS_II")]
pub fn set_pseudo_beqzl(&mut self, turn_on: bool) {
if turn_on {
self.decoding_flags.insert(DecodingFlags::pseudo_beqzl);
} else {
self.decoding_flags.remove(DecodingFlags::pseudo_beqzl);
}
}
#[must_use]
#[cfg(feature = "MIPS_II")]
pub const fn with_pseudo_beqzl(self, turn_on: bool) -> Self {
let other = if turn_on {
self.decoding_flags.union(DecodingFlags::pseudo_beqzl)
} else {
self.decoding_flags
.intersection(DecodingFlags::pseudo_beqzl.complement())
};
self.with_decoding_flags(other)
}
#[must_use]
#[cfg(feature = "MIPS_II")]
pub const fn pseudo_bnezl(&self) -> bool {
self.decoding_flags.contains(DecodingFlags::pseudo_bnezl)
}
#[cfg(feature = "MIPS_II")]
pub fn set_pseudo_bnezl(&mut self, turn_on: bool) {
if turn_on {
self.decoding_flags.insert(DecodingFlags::pseudo_bnezl);
} else {
self.decoding_flags.remove(DecodingFlags::pseudo_bnezl);
}
}
#[must_use]
#[cfg(feature = "MIPS_II")]
pub const fn with_pseudo_bnezl(self, turn_on: bool) -> Self {
let other = if turn_on {
self.decoding_flags.union(DecodingFlags::pseudo_bnezl)
} else {
self.decoding_flags
.intersection(DecodingFlags::pseudo_bnezl.complement())
};
self.with_decoding_flags(other)
}
#[must_use]
pub const fn pseudo_b(&self) -> bool {
self.decoding_flags.contains(DecodingFlags::pseudo_b)
}
pub fn set_pseudo_b(&mut self, turn_on: bool) {
if turn_on {
self.decoding_flags.insert(DecodingFlags::pseudo_b);
} else {
self.decoding_flags.remove(DecodingFlags::pseudo_b);
}
}
#[must_use]
pub const fn with_pseudo_b(self, turn_on: bool) -> Self {
let other = if turn_on {
self.decoding_flags.union(DecodingFlags::pseudo_b)
} else {
self.decoding_flags
.intersection(DecodingFlags::pseudo_b.complement())
};
self.with_decoding_flags(other)
}
#[must_use]
pub const fn pseudo_bal(&self) -> bool {
self.decoding_flags.contains(DecodingFlags::pseudo_bal)
}
pub fn set_pseudo_bal(&mut self, turn_on: bool) {
if turn_on {
self.decoding_flags.insert(DecodingFlags::pseudo_bal);
} else {
self.decoding_flags.remove(DecodingFlags::pseudo_bal);
}
}
#[must_use]
pub const fn with_pseudo_bal(self, turn_on: bool) -> Self {
let other = if turn_on {
self.decoding_flags.union(DecodingFlags::pseudo_bal)
} else {
self.decoding_flags
.intersection(DecodingFlags::pseudo_bal.complement())
};
self.with_decoding_flags(other)
}
#[must_use]
pub const fn pseudo_not(&self) -> bool {
self.decoding_flags.contains(DecodingFlags::pseudo_not)
}
pub fn set_pseudo_not(&mut self, turn_on: bool) {
if turn_on {
self.decoding_flags.insert(DecodingFlags::pseudo_not);
} else {
self.decoding_flags.remove(DecodingFlags::pseudo_not);
}
}
#[must_use]
pub const fn with_pseudo_not(self, turn_on: bool) -> Self {
let other = if turn_on {
self.decoding_flags.union(DecodingFlags::pseudo_not)
} else {
self.decoding_flags
.intersection(DecodingFlags::pseudo_not.complement())
};
self.with_decoding_flags(other)
}
#[must_use]
pub const fn pseudo_neg(&self) -> bool {
self.decoding_flags.contains(DecodingFlags::pseudo_neg)
}
pub fn set_pseudo_neg(&mut self, turn_on: bool) {
if turn_on {
self.decoding_flags.insert(DecodingFlags::pseudo_neg);
} else {
self.decoding_flags.remove(DecodingFlags::pseudo_neg);
}
}
#[must_use]
pub const fn with_pseudo_neg(self, turn_on: bool) -> Self {
let other = if turn_on {
self.decoding_flags.union(DecodingFlags::pseudo_neg)
} else {
self.decoding_flags
.intersection(DecodingFlags::pseudo_neg.complement())
};
self.with_decoding_flags(other)
}
#[must_use]
pub const fn pseudo_negu(&self) -> bool {
self.decoding_flags.contains(DecodingFlags::pseudo_negu)
}
pub fn set_pseudo_negu(&mut self, turn_on: bool) {
if turn_on {
self.decoding_flags.insert(DecodingFlags::pseudo_negu);
} else {
self.decoding_flags.remove(DecodingFlags::pseudo_negu);
}
}
#[must_use]
pub const fn with_pseudo_negu(self, turn_on: bool) -> Self {
let other = if turn_on {
self.decoding_flags.union(DecodingFlags::pseudo_negu)
} else {
self.decoding_flags
.intersection(DecodingFlags::pseudo_negu.complement())
};
self.with_decoding_flags(other)
}
pub fn set_all_pseudos(&mut self, turn_on: bool) {
self.decoding_flags.set_all_pseudos(turn_on)
}
#[must_use]
pub const fn with_all_pseudos(self, turn_on: bool) -> Self {
self.with_decoding_flags(self.decoding_flags.with_all_pseudos(turn_on))
}
#[must_use]
#[cfg(feature = "RspViceMsp")]
pub const fn gated_rsp_vice_msp(&self) -> bool {
self.decoding_flags
.contains(DecodingFlags::gated_rsp_vice_msp)
}
#[cfg(feature = "RspViceMsp")]
pub fn set_gated_rsp_vice_msp(&mut self, turn_on: bool) {
if turn_on {
self.decoding_flags
.insert(DecodingFlags::gated_rsp_vice_msp);
} else {
self.decoding_flags
.remove(DecodingFlags::gated_rsp_vice_msp);
}
}
#[must_use]
#[cfg(feature = "RspViceMsp")]
pub const fn with_gated_rsp_vice_msp(self, turn_on: bool) -> Self {
let other = if turn_on {
self.decoding_flags.union(DecodingFlags::gated_rsp_vice_msp)
} else {
self.decoding_flags
.intersection(DecodingFlags::gated_rsp_vice_msp.complement())
};
self.with_decoding_flags(other)
}
#[must_use]
pub const fn abi(&self) -> Abi {
self.abi
}
pub fn abi_mut(&mut self) -> &mut Abi {
&mut self.abi
}
#[must_use]
pub const fn with_abi(self, abi: Abi) -> Self {
Self { abi, ..self }
}
#[must_use]
pub const fn j_as_branch(&self) -> bool {
self.j_as_branch
}
pub fn j_as_branch_mut(&mut self) -> &mut bool {
&mut self.j_as_branch
}
#[must_use]
pub const fn with_j_as_branch(self, j_as_branch: bool) -> Self {
Self {
j_as_branch,
..self
}
}
}
#[cfg(feature = "pyo3")]
pub(crate) mod python_bindings {
use super::*;
#[pymethods]
impl InstructionFlags {
#[new]
#[must_use]
pub const fn py_new(isa_version: IsaVersion) -> Self {
Self::new(isa_version)
}
#[pyo3(name = "set_pseudo_beqzl")]
#[cfg(feature = "MIPS_II")]
pub fn py_set_pseudo_beqzl(&mut self, turn_on: bool) {
self.set_pseudo_beqzl(turn_on);
}
#[pyo3(name = "set_pseudo_bnezl")]
#[cfg(feature = "MIPS_II")]
pub fn py_set_pseudo_bnezl(&mut self, turn_on: bool) {
self.set_pseudo_bnezl(turn_on);
}
#[pyo3(name = "new_extension")]
#[staticmethod]
#[must_use]
pub const fn py_new_extension(isa_extension: IsaExtension) -> Self {
Self::new_extension(isa_extension)
}
#[pyo3(name = "set_abi")]
pub fn py_set_abi(&mut self, abi: Abi) {
self.abi = abi;
}
#[pyo3(name = "set_j_as_branch")]
pub fn py_set_j_as_branch(&mut self, j_as_branch: bool) {
self.j_as_branch = j_as_branch;
}
}
}