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