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