use crate::Imm06;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::FromRepr)]
#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
#[repr(u8)]
#[must_use]
pub enum CompareMode {
EQ = 0,
NE = 1,
LT = 2,
GT = 3,
LTE = 4,
GTE = 5,
LZC = 6,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
#[must_use]
pub struct CompareArgs {
pub mode: CompareMode,
pub indirect_rhs: bool,
}
#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
impl CompareArgs {
pub fn to_imm(self) -> Imm06 {
let mut bits = self.mode as u8;
bits |= (self.indirect_rhs as u8) << 5;
Imm06(bits)
}
pub fn from_imm(bits: Imm06) -> Option<CompareArgs> {
let indirect_rhs = ((bits.0 >> 5) & 1) == 1;
let reserved = (bits.0 >> 3) & 0b11;
if reserved != 0 {
return None
}
let mode = CompareMode::from_repr(bits.0 & 0b111)?;
Some(Self { mode, indirect_rhs })
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::FromRepr)]
#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
#[repr(u8)]
#[must_use]
pub enum MathOp {
ADD = 0,
SUB = 1,
NOT = 2,
OR = 3,
XOR = 4,
AND = 5,
SHL = 6,
SHR = 7,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
#[must_use]
pub struct MathArgs {
pub op: MathOp,
pub indirect_rhs: bool,
}
impl MathArgs {
pub fn to_imm(self) -> Imm06 {
let mut bits = self.op as u8;
bits |= (self.indirect_rhs as u8) << 5;
Imm06(bits)
}
pub fn from_imm(bits: Imm06) -> Option<Self> {
let indirect_rhs = ((bits.0 >> 5) & 1) == 1;
let op = MathOp::from_repr(bits.0 & 0b11111)?;
Some(Self { op, indirect_rhs })
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
#[must_use]
pub struct MulArgs {
pub indirect_lhs: bool,
pub indirect_rhs: bool,
}
impl MulArgs {
pub fn to_imm(self) -> Imm06 {
let mut bits = 0u8;
bits |= (self.indirect_lhs as u8) << 4;
bits |= (self.indirect_rhs as u8) << 5;
Imm06(bits)
}
pub fn from_imm(bits: Imm06) -> Option<Self> {
let indirect_lhs = ((bits.0 >> 4) & 1) == 1;
let indirect_rhs = ((bits.0 >> 5) & 1) == 1;
if (bits.0 & 0b1111) != 0 {
return None
}
Some(Self {
indirect_lhs,
indirect_rhs,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
#[must_use]
pub struct DivArgs {
pub indirect_rhs: bool,
}
impl DivArgs {
pub fn to_imm(self) -> Imm06 {
let mut bits = 0u8;
bits |= (self.indirect_rhs as u8) << 5;
Imm06(bits)
}
pub fn from_imm(bits: Imm06) -> Option<Self> {
let indirect_rhs = ((bits.0 >> 5) & 1) == 1;
if (bits.0 & 0b11111) != 0 {
return None
}
Some(Self { indirect_rhs })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[rstest::rstest]
fn encode_decode_compare(
#[values(CompareMode::EQ, CompareMode::NE, CompareMode::GTE)] mode: CompareMode,
#[values(true, false)] indirect_rhs: bool,
) {
let orig = CompareArgs { mode, indirect_rhs };
let decoded = CompareArgs::from_imm(orig.to_imm()).expect("decode error");
assert_eq!(orig, decoded);
}
#[test]
fn decode_encode_compare() {
for imm in 0..Imm06::MAX.0 {
let bits = Imm06::from(imm);
if let Some(decoded) = CompareArgs::from_imm(bits) {
assert_eq!(decoded.to_imm().0, imm);
}
}
}
#[rstest::rstest]
fn encode_decode_mathop(
#[values(MathOp::ADD, MathOp::SUB, MathOp::SHR)] op: MathOp,
#[values(true, false)] indirect_rhs: bool,
) {
let orig = MathArgs { op, indirect_rhs };
let decoded = MathArgs::from_imm(orig.to_imm()).expect("decode error");
assert_eq!(orig, decoded);
}
#[test]
fn decode_encode_mathop() {
for imm in 0..Imm06::MAX.0 {
let bits = Imm06::from(imm);
if let Some(decoded) = MathArgs::from_imm(bits) {
assert_eq!(decoded.to_imm().0, imm);
}
}
}
#[rstest::rstest]
fn encode_decode_mul(
#[values(true, false)] indirect_lhs: bool,
#[values(true, false)] indirect_rhs: bool,
) {
let orig = MulArgs {
indirect_lhs,
indirect_rhs,
};
let decoded = MulArgs::from_imm(orig.to_imm()).expect("decode error");
assert_eq!(orig, decoded);
}
#[test]
fn decode_encode_mul() {
for imm in 0..Imm06::MAX.0 {
let bits = Imm06::from(imm);
if let Some(decoded) = MulArgs::from_imm(bits) {
assert_eq!(decoded.to_imm().0, imm);
}
}
}
#[rstest::rstest]
fn encode_decode_div(#[values(true, false)] indirect_rhs: bool) {
let orig = DivArgs { indirect_rhs };
let decoded = DivArgs::from_imm(orig.to_imm()).expect("decode error");
assert_eq!(orig, decoded);
}
#[test]
fn decode_encode_div() {
for imm in 0..Imm06::MAX.0 {
let bits = Imm06::from(imm);
if let Some(decoded) = DivArgs::from_imm(bits) {
assert_eq!(decoded.to_imm().0, imm);
}
}
}
}