ab_riscv_interpreter/zicsr/zicsr_helpers.rs
1//! Opaque helpers for Zicsr extension
2
3use crate::{CsrError, Csrs};
4use ab_riscv_primitives::privilege::PrivilegeLevel;
5use ab_riscv_primitives::registers::general_purpose::Register;
6
7/// CSR privilege level check helper.
8///
9/// Returns `Err` if `current` is below the privilege level encoded in `csr_index` bits `[9:8]`.
10/// May return `Ok(())` for invalid CSRs for efficiency reasons since those will be rejected by
11/// extensions anyway.
12#[inline(always)]
13#[doc(hidden)]
14pub fn check_csr_privilege_level<Reg, C, CustomError>(
15 csrs: &C,
16 csr_index: u16,
17) -> Result<(), CsrError<CustomError>>
18where
19 Reg: Register,
20 [(); Reg::N]:,
21 C: Csrs<Reg, CustomError>,
22{
23 let current = csrs.privilege_level();
24 let required_bits = ((csr_index >> 8) & 0b11) as u8;
25 // Privilege level uses two bits. Using machine value as a placeholder (`0b11`) allows the
26 // compiler to optimize this whole function away if `csrs.privilege_level()` returns fixed
27 // `PrivilegeLevel::Machine` value, which is the most common case since `0b11` is larger or
28 // equal than any other 2-bit value. Invalid level will still be rejected at a later stage as
29 // unknown CSR.
30 let required = PrivilegeLevel::from_bits(required_bits).unwrap_or(PrivilegeLevel::Machine);
31
32 if current >= required {
33 Ok(())
34 } else {
35 Err(CsrError::InsufficientPrivilege {
36 csr_index,
37 required,
38 current,
39 })
40 }
41}