#[cfg(test)]
mod tests;
use crate::instructions::Instruction;
use crate::instructions::rv32::zce::zcmp::{ZcmpRegister, ZcmpUrlist};
use crate::registers::general_purpose::Register;
use ab_riscv_macros::instruction;
use core::fmt;
#[instruction]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Rv64ZcmpInstruction<Reg> {
CmPush {
urlist: ZcmpUrlist<Reg>,
stack_adj: u32,
},
CmPop {
urlist: ZcmpUrlist<Reg>,
stack_adj: u32,
},
CmPopretz {
urlist: ZcmpUrlist<Reg>,
stack_adj: u32,
},
CmPopret {
urlist: ZcmpUrlist<Reg>,
stack_adj: u32,
},
CmMva01s { r1s: Reg, r2s: Reg },
CmMvsa01 { r1s: Reg, r2s: Reg },
}
#[instruction]
impl<Reg> const Instruction for Rv64ZcmpInstruction<Reg>
where
Reg: [const] ZcmpRegister<Type = u64>,
{
type Reg = Reg;
#[inline(always)]
fn try_decode(instruction: u32) -> Option<Self> {
#[inline(always)]
const fn sreg_bits(field: u8) -> u8 {
match field {
0 => 8,
1 => 9,
f => f + 16,
}
}
let inst = instruction as u16;
let quadrant = inst & 0b11;
let funct3 = ((inst >> 13) & 0b111) as u8;
if quadrant != 0b10 || funct3 != 0b101 {
None?;
}
let funct2_12_11 = ((inst >> 11) & 0b11) as u8;
match funct2_12_11 {
0b11 => {
let op_sel = ((inst >> 9) & 0b11) as u8;
let urlist = ZcmpUrlist::try_from_raw(((inst >> 4) & 0xf) as u8)?;
let spimm = ((inst >> 2) & 0b11) as u32;
let stack_adj = urlist.stack_adj_base() + spimm * 16;
match op_sel {
0b00 => Some(Self::CmPush { urlist, stack_adj }),
0b01 => Some(Self::CmPop { urlist, stack_adj }),
0b10 => Some(Self::CmPopretz { urlist, stack_adj }),
0b11 => Some(Self::CmPopret { urlist, stack_adj }),
_ => None,
}
}
0b01 => {
if (inst >> 10) & 1 != 1 {
None?;
}
let r1s_bits = ((inst >> 7) & 0b111) as u8;
let funct2 = ((inst >> 5) & 0b11) as u8;
let r2s_bits = ((inst >> 2) & 0b111) as u8;
let r1s = Reg::from_bits(sreg_bits(r1s_bits))?;
let r2s = Reg::from_bits(sreg_bits(r2s_bits))?;
match funct2 {
0b11 => Some(Self::CmMva01s { r1s, r2s }),
0b01 => {
if r1s_bits == r2s_bits {
None?;
}
Some(Self::CmMvsa01 { r1s, r2s })
}
_ => None,
}
}
_ => None,
}
}
#[inline(always)]
fn alignment() -> u8 {
align_of::<u16>() as u8
}
#[inline(always)]
fn size(&self) -> u8 {
size_of::<u16>() as u8
}
}
impl<Reg> fmt::Display for Rv64ZcmpInstruction<Reg>
where
Reg: Register,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::CmPush { urlist, stack_adj } => {
write!(f, "cm.push {urlist}, -{stack_adj}")
}
Self::CmPop { urlist, stack_adj } => {
write!(f, "cm.pop {urlist}, {stack_adj}")
}
Self::CmPopretz { urlist, stack_adj } => {
write!(f, "cm.popretz {urlist}, {stack_adj}")
}
Self::CmPopret { urlist, stack_adj } => {
write!(f, "cm.popret {urlist}, {stack_adj}")
}
Self::CmMva01s { r1s, r2s } => write!(f, "cm.mva01s {r1s}, {r2s}"),
Self::CmMvsa01 { r1s, r2s } => write!(f, "cm.mvsa01 {r1s}, {r2s}"),
}
}
}