Skip to main content

ab_riscv_interpreter/zicsr/
zicsr_helpers.rs

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