#[cfg(test)]
mod tests;
pub mod zicsr_helpers;
use crate::{CsrError, Csrs, ExecutableInstruction, ExecutionError, RegisterFile};
use ab_riscv_macros::instruction_execution;
use ab_riscv_primitives::prelude::*;
use core::ops::ControlFlow;
#[instruction_execution]
impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
for ZicsrInstruction<Reg>
where
Reg: Register,
Regs: RegisterFile<Reg>,
ExtState: Csrs<Reg, CustomError>,
{
#[inline(always)]
fn execute(
self,
regs: &mut Regs,
ext_state: &mut ExtState,
_memory: &mut Memory,
_program_counter: &mut PC,
_system_instruction_handler: &mut InstructionHandler,
) -> Result<ControlFlow<()>, ExecutionError<Reg::Type, CustomError>> {
match self {
Self::Csrrw { rd, rs1, csr } => {
let csr_is_read_only = (csr >> 10) == 0b11;
if csr_is_read_only {
return Err(ExecutionError::CsrError(CsrError::ReadOnly {
csr_index: csr,
}));
}
zicsr_helpers::check_csr_privilege_level(ext_state, csr)?;
let write_value = regs.read(rs1);
if rd != Reg::ZERO {
let raw_value = ext_state.read_csr(csr)?;
let output_value = ext_state.process_csr_read(csr, raw_value)?;
regs.write(rd, output_value);
}
let output_value = ext_state.process_csr_write(csr, write_value)?;
ext_state.write_csr(csr, output_value)?;
}
Self::Csrrs { rd, rs1, csr } => {
let csr_is_read_only = (csr >> 10) == 0b11;
if rs1 != Reg::ZERO && csr_is_read_only {
return Err(ExecutionError::CsrError(CsrError::ReadOnly {
csr_index: csr,
}));
}
zicsr_helpers::check_csr_privilege_level(ext_state, csr)?;
let rs1_value = regs.read(rs1);
let raw_value = ext_state.read_csr(csr)?;
let read_output = ext_state.process_csr_read(csr, raw_value)?;
regs.write(rd, read_output);
if rs1 != Reg::ZERO {
let write_value = raw_value | rs1_value;
let write_output = ext_state.process_csr_write(csr, write_value)?;
ext_state.write_csr(csr, write_output)?;
}
}
Self::Csrrc { rd, rs1, csr } => {
let csr_is_read_only = (csr >> 10) == 0b11;
if rs1 != Reg::ZERO && csr_is_read_only {
return Err(ExecutionError::CsrError(CsrError::ReadOnly {
csr_index: csr,
}));
}
zicsr_helpers::check_csr_privilege_level(ext_state, csr)?;
let rs1_value = regs.read(rs1);
let raw_value = ext_state.read_csr(csr)?;
let read_output = ext_state.process_csr_read(csr, raw_value)?;
regs.write(rd, read_output);
if rs1 != Reg::ZERO {
let write_value = raw_value & !rs1_value;
let write_output = ext_state.process_csr_write(csr, write_value)?;
ext_state.write_csr(csr, write_output)?;
}
}
Self::Csrrwi { rd, zimm, csr } => {
let csr_is_read_only = (csr >> 10) == 0b11;
if csr_is_read_only {
return Err(ExecutionError::CsrError(CsrError::ReadOnly {
csr_index: csr,
}));
}
zicsr_helpers::check_csr_privilege_level(ext_state, csr)?;
if rd != Reg::ZERO {
let raw_value = ext_state.read_csr(csr)?;
let output_value = ext_state.process_csr_read(csr, raw_value)?;
regs.write(rd, output_value);
}
let output_value = ext_state.process_csr_write(csr, zimm.into())?;
ext_state.write_csr(csr, output_value)?;
}
Self::Csrrsi { rd, zimm, csr } => {
let csr_is_read_only = (csr >> 10) == 0b11;
if zimm != 0 && csr_is_read_only {
return Err(ExecutionError::CsrError(CsrError::ReadOnly {
csr_index: csr,
}));
}
zicsr_helpers::check_csr_privilege_level(ext_state, csr)?;
let raw_value = ext_state.read_csr(csr)?;
let read_output = ext_state.process_csr_read(csr, raw_value)?;
regs.write(rd, read_output);
if zimm != 0 {
let write_value = raw_value | Reg::Type::from(zimm);
let write_output = ext_state.process_csr_write(csr, write_value)?;
ext_state.write_csr(csr, write_output)?;
}
}
Self::Csrrci { rd, zimm, csr } => {
let csr_is_read_only = (csr >> 10) == 0b11;
if zimm != 0 && csr_is_read_only {
return Err(ExecutionError::CsrError(CsrError::ReadOnly {
csr_index: csr,
}));
}
zicsr_helpers::check_csr_privilege_level(ext_state, csr)?;
let raw_value = ext_state.read_csr(csr)?;
let read_output = ext_state.process_csr_read(csr, raw_value)?;
regs.write(rd, read_output);
if zimm != 0 {
let write_value = raw_value & !Reg::Type::from(zimm);
let write_output = ext_state.process_csr_write(csr, write_value)?;
ext_state.write_csr(csr, write_output)?;
}
}
}
Ok(ControlFlow::Continue(()))
}
}