Skip to main content

ab_riscv_interpreter/v/zvexx/
config.rs

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