Skip to main content

ab_riscv_interpreter/v/zve64x/
config.rs

1//! Zve64x configuration instructions
2
3#[cfg(test)]
4mod tests;
5pub mod zve64x_config_helpers;
6
7use crate::v::vector_registers::VectorRegistersExt;
8use crate::{
9    CsrError, Csrs, ExecutableInstruction, ExecutionError, InterpreterState, ProgramCounter,
10};
11use ab_riscv_macros::instruction_execution;
12use ab_riscv_primitives::instructions::v::zve64x::config::Zve64xConfigInstruction;
13use ab_riscv_primitives::registers::general_purpose::Register;
14use ab_riscv_primitives::registers::vector::VCsr;
15use core::fmt;
16use core::ops::ControlFlow;
17
18#[instruction_execution]
19impl<Reg, ExtState, Memory, PC, InstructionHandler, CustomError>
20    ExecutableInstruction<
21        InterpreterState<Reg, ExtState, Memory, PC, InstructionHandler, CustomError>,
22        CustomError,
23    > for Zve64xConfigInstruction<Reg>
24where
25    Reg: Register,
26    [(); Reg::N]:,
27    ExtState: VectorRegistersExt<Reg, CustomError>,
28    [(); ExtState::ELEN as usize]:,
29    [(); ExtState::VLEN as usize]:,
30    PC: ProgramCounter<Reg::Type, Memory, CustomError>,
31    CustomError: fmt::Debug,
32{
33    /// Validate reads to vector CSRs from Zicsr instructions.
34    ///
35    /// All vector CSRs are accessible from unprivileged code (U-mode).
36    /// Reads are pass-through: the raw value stored in the CSR is the output value.
37    fn prepare_csr_read<C>(
38        _csrs: &C,
39        csr_index: u16,
40        raw_value: Reg::Type,
41        output_value: &mut Reg::Type,
42    ) -> Result<bool, CsrError<CustomError>>
43    where
44        C: Csrs<Self::Reg, CustomError>,
45    {
46        if VCsr::from_index(csr_index).is_some() {
47            *output_value = raw_value;
48            Ok(true)
49        } else {
50            // Not a vector CSR
51            Ok(false)
52        }
53    }
54
55    /// Validate, sanitize, and mirror writes to vector CSRs from Zicsr instructions.
56    ///
57    /// Enforces WARL semantics and vcsr mirroring:
58    /// - `vl`, `vtype`, `vlenb` are read-only: writes are rejected
59    /// - `vxsat`: only bit 0 is writable; mirrors into `vcsr[0]`
60    /// - `vxrm`: only bits `[1:0]` are writable; mirrors into `vcsr[2:1]`
61    /// - `vcsr`: only bits `[2:0]` are writable; mirrors into `vxsat` and `vxrm`
62    /// - `vstart`: full XLEN write allowed (WARL, implementation may restrict range)
63    fn prepare_csr_write<C>(
64        csrs: &mut C,
65        csr_index: u16,
66        write_value: Reg::Type,
67        output_value: &mut Reg::Type,
68    ) -> Result<bool, CsrError<CustomError>>
69    where
70        C: Csrs<Self::Reg, CustomError>,
71    {
72        if let Some(vcsr) = VCsr::from_index(csr_index) {
73            // WARL: mask to valid bits, zero upper bits
74            *output_value = match vcsr {
75                VCsr::Vstart => {
76                    // WARL: allow full XLEN write, but clamp to implementation-supported range
77                    let max = Reg::Type::from(u16::MAX);
78                    write_value.min(max)
79                }
80                VCsr::Vxsat => {
81                    let masked = write_value & Reg::Type::from(1u8);
82                    // Mirror `vxsat` into `vcsr[0]`, preserving `vcsr[2:1]` (`vxrm`)
83                    let old_vcsr = csrs.read_csr(VCsr::Vcsr as u16)?;
84                    let new_vcsr = (old_vcsr & !Reg::Type::from(1u8)) | masked;
85                    csrs.write_csr(VCsr::Vcsr as u16, new_vcsr)?;
86                    masked
87                }
88                VCsr::Vxrm => {
89                    let masked = write_value & Reg::Type::from(0b11u8);
90                    // Mirror `vxrm` into `vcsr[2:1]`, preserving `vcsr[0]` (`vxsat`)
91                    let old_vcsr = csrs.read_csr(VCsr::Vcsr as u16)?;
92                    let new_vcsr = (old_vcsr & !Reg::Type::from(0b110u8)) | (masked << 1);
93                    csrs.write_csr(VCsr::Vcsr as u16, new_vcsr)?;
94                    masked
95                }
96                VCsr::Vcsr => {
97                    // Mirror `vcsr[0]` -> `vxsat`
98                    let new_vxsat = write_value & Reg::Type::from(1u8);
99                    csrs.write_csr(VCsr::Vxsat as u16, new_vxsat)?;
100
101                    // Mirror `vcsr[2:1]` -> `vxrm`
102                    let new_vxrm = (write_value >> 1) & Reg::Type::from(0b11u8);
103                    csrs.write_csr(VCsr::Vxrm as u16, new_vxrm)?;
104
105                    write_value & Reg::Type::from(0b111u8)
106                }
107                VCsr::Vl | VCsr::Vtype | VCsr::Vlenb => {
108                    // Read-only CSRs (from Zicsr perspective)
109                    Err(CsrError::ReadOnly { csr_index })?
110                }
111            };
112            Ok(true)
113        } else {
114            Ok(false)
115        }
116    }
117
118    #[inline(always)]
119    fn execute(
120        self,
121        state: &mut InterpreterState<Reg, ExtState, Memory, PC, InstructionHandler, CustomError>,
122    ) -> Result<ControlFlow<()>, ExecutionError<Reg::Type, CustomError>> {
123        match self {
124            Self::Vsetvli { rd, rs1, vtypei } => {
125                zve64x_config_helpers::apply_vsetvl(state, rd, rs1, Reg::Type::from(vtypei))?;
126            }
127            Self::Vsetivli { rd, uimm, vtypei } => {
128                zve64x_config_helpers::apply_vsetivli(state, rd, uimm, vtypei)?;
129            }
130            Self::Vsetvl { rd, rs1, rs2 } => {
131                let vtype_raw = state.regs.read(rs2);
132                zve64x_config_helpers::apply_vsetvl(state, rd, rs1, vtype_raw)?;
133            }
134        }
135
136        Ok(ControlFlow::Continue(()))
137    }
138}