use crate::arch::csr::{CboInvalAction, Csrs, cbo_inval_action, cbocf_allowed, cboz_allowed};
use crate::common::AccessType;
use crate::isa::encoding::zicboz::CBOZ_BLOCK_SIZE;
use crate::isa::op::SystemOp;
use crate::isa::privileged::{PrivilegeMode, Trap};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CboEffect {
Zero,
Clean,
Flush,
Invalidate,
}
impl CboEffect {
#[must_use]
pub const fn access(self) -> AccessType {
match self {
Self::Zero => AccessType::Write,
Self::Clean | Self::Flush | Self::Invalidate => AccessType::Read,
}
}
}
#[must_use]
pub const fn fault_address(op: SystemOp, rs1: u64) -> u64 {
if matches!(op, SystemOp::CboZero) { block_address(rs1) } else { rs1 }
}
#[must_use]
pub const fn block_address(addr: u64) -> u64 {
addr & !(CBOZ_BLOCK_SIZE - 1)
}
pub const fn gate(
csrs: &Csrs,
privilege: PrivilegeMode,
op: SystemOp,
inst: u32,
) -> Result<CboEffect, Trap> {
let (menvcfg, senvcfg) = (csrs.menvcfg, csrs.senvcfg);
let allowed = match op {
SystemOp::CboZero if cboz_allowed(menvcfg, senvcfg, privilege) => Some(CboEffect::Zero),
SystemOp::CboClean if cbocf_allowed(menvcfg, senvcfg, privilege) => Some(CboEffect::Clean),
SystemOp::CboFlush if cbocf_allowed(menvcfg, senvcfg, privilege) => Some(CboEffect::Flush),
SystemOp::CboInval => match cbo_inval_action(menvcfg, senvcfg, privilege) {
CboInvalAction::Illegal => None,
CboInvalAction::Flush => Some(CboEffect::Flush),
CboInvalAction::Invalidate => Some(CboEffect::Invalidate),
},
_ => None,
};
match allowed {
Some(effect) => Ok(effect),
None => Err(Trap::IllegalInstruction(inst)),
}
}
#[must_use]
pub const fn as_store_fault(trap: Trap, tval: u64) -> Trap {
match trap {
Trap::LoadPageFault(_) | Trap::StorePageFault(_) => Trap::StorePageFault(tval),
Trap::LoadAccessFault(_) | Trap::StoreAccessFault(_) => Trap::StoreAccessFault(tval),
other => other,
}
}