Skip to main content

ab_riscv_interpreter/v/
vector_registers.rs

1//! Vector registers
2
3use crate::v::private::SupportedElenVlen;
4use crate::{Csrs, CustomErrorPlaceholder};
5use ab_riscv_primitives::prelude::*;
6use core::fmt;
7
8/// Alignment wrapper for vector registers
9#[derive(Debug, Clone, Copy)]
10// Aligned to 128 bytes, which is u32 * 32 registers, the minimum reasonable value to use in most
11// cases
12#[repr(align(128))]
13pub struct VectorRegisterFile<const VLENB: usize>([[u8; VLENB]; 32]);
14
15impl<const VLENB: usize> const Default for VectorRegisterFile<VLENB> {
16    #[inline(always)]
17    fn default() -> Self {
18        Self([[0; VLENB]; 32])
19    }
20}
21
22impl<const VLENB: usize> VectorRegisterFile<VLENB> {
23    /// Get reference to a vector register
24    #[inline(always)]
25    pub fn get(&self, index: VReg) -> &[u8; VLENB] {
26        // SAFETY: Always in-range
27        unsafe { self.0.get_unchecked(usize::from(index.to_bits())) }
28    }
29
30    /// Get mutable reference to a vector register
31    #[inline(always)]
32    pub fn get_mut(&mut self, index: VReg) -> &mut [u8; VLENB] {
33        // SAFETY: Always in-range
34        unsafe { self.0.get_unchecked_mut(usize::from(index.to_bits())) }
35    }
36}
37
38/// Base for [`VectorRegisters`].
39///
40/// This is primarily a workaround for type system cycles.
41pub trait VectorRegistersBase {
42    /// Maximum vector element width `ELEN` in bits
43    const ELEN: u32;
44    /// Vector register width `VLEN` in bits
45    const VLEN: u32;
46    /// Vector register width in bytes (`vlenb = VLEN / 8`)
47    const VLENB: u32 = Self::VLEN / u8::BITS;
48}
49
50// TODO: Figure out a way to make `VectorRegisters + VectorRegistersExt` trait bounds work without
51//  type system cycles
52/// Vector register state.
53///
54/// This trait contains only methods that implementations genuinely need to provide. Derived
55/// accessors for simpler CSRs are in [`VectorRegistersExt`].
56///
57/// Note that due to Rust type system limitations, you should use [`VectorRegistersExt`] in trait
58/// bounds instead of this trait directly or else the solver will fail.
59///
60/// Methods for `vtype` and `vl` live here (not in the ext trait) because they have non-trivial
61/// update semantics: `vtype` must maintain a cached decoded form and handle the XLEN-dependent vill
62/// bit, and `vl` is read-only via CSR instructions but writable by `vsetvl{i}` and fault-only-first
63/// loads.
64///
65/// `ELEN` is the maximum element width in bits.
66pub trait VectorRegisters<CustomError = CustomErrorPlaceholder>
67where
68    Self: VectorRegistersBase + SupportedElenVlen<{ Self::ELEN }, { Self::VLEN }>,
69{
70    /// Read the vector register file
71    fn read_vregs(&self) -> &VectorRegisterFile<{ Self::VLENB as usize }>;
72
73    /// Mutable access to the vector register file
74    fn write_vregs(&mut self) -> &mut VectorRegisterFile<{ Self::VLENB as usize }>;
75
76    /// Check whether vector instructions are currently permitted.
77    ///
78    /// Returns `false` when `mstatus.VS == Off` (or equivalent like `sstatus`/`vstatus`). In
79    /// environments without these status registers, returns `true` always.
80    fn vector_instructions_allowed(&self) -> bool;
81
82    /// Mark the vector state as dirty.
83    ///
84    /// Must set VS to Dirty in `mstatus` (and `sstatus`/`vsstatus` shadows) when those registers
85    /// exist. No-op otherwise.
86    fn mark_vs_dirty(&mut self);
87
88    /// Compute `vl` from `AVL` and `VLMAX` per spec constraints.
89    ///
90    /// The simplest compliant implementation (which is used by default) is `min(AVL, VLMAX)`. More
91    /// sophisticated implementations may return values in `[ceil(AVL/2), VLMAX]` for
92    /// `AVL < 2*VLMAX`, but this simple strategy satisfies all three spec requirements.
93    #[inline(always)]
94    fn compute_vl(&self, avl: u32, vlmax: u32) -> u32 {
95        avl.min(vlmax)
96    }
97
98    /// Compute `VLMAX` for a given vtype
99    #[inline(always)]
100    fn vlmax_for_vtype(&self, vtype: Vtype<{ Self::ELEN }, { Self::VLEN }>) -> u32 {
101        vtype.vlmul().vlmax::<{ Self::VLEN }>(vtype.vsew())
102    }
103}
104
105/// Derived convenience accessors for vector CSRs that are simple read/write fields (vstart, vxrm,
106/// vxsat, vcsr).
107///
108/// Intended for types that implement both [`VectorRegisters`] and [`Csrs`].
109///
110/// NOTE: While the default methods implemented via the [`Csrs`] trait are correct, custom
111/// higher-performance implementations are often possible by overriding them and, for example,
112/// caching various CSRs as separate pre-decoded values rather than going through a generic code
113/// path with XLEN-sized raw CSR values during reads.
114pub trait VectorRegistersExt<Reg, CustomError = CustomErrorPlaceholder>
115where
116    Self: Csrs<Reg, CustomError> + VectorRegisters<CustomError>,
117    [(); Self::ELEN as usize]:,
118    [(); Self::VLEN as usize]:,
119    Reg: Register,
120    CustomError: fmt::Debug,
121{
122    /// Initialize the vector state to the recommended default configuration.
123    ///
124    /// Per spec: `vtype.vill` = 1, remaining `vtype` bits = `0`, `vl` = 0.
125    /// `vstart`, `vxrm`, `vxsat` may have arbitrary values at reset but are zeroed here for
126    /// deterministic behavior.
127    fn initialize_vector_state(&mut self) {
128        self.set_vtype(None);
129        self.set_vl(0);
130        self.set_vstart(0);
131        self.set_vxrm(Vxrm::default());
132        self.set_vxsat(false);
133    }
134
135    /// Get current `vstart`
136    #[inline(always)]
137    fn vstart(&self) -> u16 {
138        let raw = self
139            .read_csr(VectorCsr::Vstart.to_csr_index())
140            .unwrap_or_default()
141            .as_u64();
142        raw as u16
143    }
144
145    /// Set `vstart`
146    #[inline(always)]
147    fn set_vstart(&mut self, vstart: u16) {
148        self.write_csr(VectorCsr::Vstart.to_csr_index(), Reg::Type::from(vstart))
149            .expect("Implementation didn't initialize `vstart` CSR");
150    }
151
152    /// Reset `vstart` to zero.
153    ///
154    /// Per spec, all vector instructions reset `vstart` to zero at the end of execution.
155    #[inline(always)]
156    fn reset_vstart(&mut self) {
157        self.set_vstart(0);
158    }
159
160    /// Get `vxsat` (single bit)
161    #[inline(always)]
162    fn vxsat(&self) -> bool {
163        let raw = self
164            .read_csr(VectorCsr::Vxsat.to_csr_index())
165            .unwrap_or_default()
166            .as_u64();
167        (raw & 1) == 1
168    }
169
170    /// Set `vxsat`
171    #[inline(always)]
172    fn set_vxsat(&mut self, vxsat: bool) {
173        let masked = Reg::Type::from(u8::from(vxsat));
174        self.write_csr(VectorCsr::Vxsat.to_csr_index(), masked)
175            .expect("Implementation didn't initialize `vxsat` CSR");
176        // Mirror `vxsat` into `vcsr[0]`, preserving `vcsr[2:1]` (`vxrm`)
177        let old_vcsr = self
178            .read_csr(VectorCsr::Vcsr.to_csr_index())
179            .unwrap_or_default();
180        let new_vcsr = (old_vcsr & !Reg::Type::from(1u8)) | masked;
181        self.write_csr(VectorCsr::Vcsr.to_csr_index(), new_vcsr)
182            .expect("Implementation didn't initialize `vcsr` CSR");
183    }
184
185    /// Get `vxrm`
186    #[inline(always)]
187    fn vxrm(&self) -> Vxrm {
188        let raw = self
189            .read_csr(VectorCsr::Vxrm.to_csr_index())
190            .unwrap_or_default()
191            .as_u64();
192        Vxrm::from_bits(raw as u8)
193    }
194
195    /// Set `vxrm`
196    #[inline(always)]
197    fn set_vxrm(&mut self, vxrm: Vxrm) {
198        let masked = Reg::Type::from(vxrm.to_bits());
199        self.write_csr(VectorCsr::Vxrm.to_csr_index(), masked)
200            .expect("Implementation didn't initialize `vxrm` CSR");
201        // Mirror `vxrm` into `vcsr[2:1]`, preserving `vcsr[0]` (`vxsat`)
202        let old_vcsr = self
203            .read_csr(VectorCsr::Vcsr.to_csr_index())
204            .unwrap_or_default();
205        let new_vcsr = (old_vcsr & !Reg::Type::from(0b110u8)) | (masked << 1u8);
206        self.write_csr(VectorCsr::Vcsr.to_csr_index(), new_vcsr)
207            .expect("Implementation didn't initialize `vcsr` CSR");
208    }
209
210    // TODO: Consider new type for `vl`. It is guaranteed to be `at most u16::MAX + 1`, so can be a
211    //  wrapper around `u16`, which will make things nicer in some places like when iterating over
212    //  `vstart..vl`
213    /// Get the current vl
214    #[inline(always)]
215    fn vl(&self) -> u32 {
216        self.read_csr(VectorCsr::Vl.to_csr_index())
217            .unwrap_or_default()
218            .as_u64() as u32
219    }
220
221    /// Set vl.
222    ///
223    /// The implementation must update both its internal decoded cache and the raw CSR value (for
224    /// reads via Zicsr, writes via Zicsr are not allowed).
225    fn set_vl(&mut self, vl: u32) {
226        self.write_csr(VectorCsr::Vl.to_csr_index(), Reg::Type::from(vl))
227            .expect("Implementation didn't initialize `vl` CSR");
228    }
229
230    /// Get the current decoded vtype
231    #[inline(always)]
232    fn vtype(&self) -> Option<Vtype<{ Self::ELEN }, { Self::VLEN }>> {
233        self.read_csr(VectorCsr::Vtype.to_csr_index())
234            .ok()
235            .and_then(Vtype::from_raw::<Reg>)
236    }
237
238    /// Set the vtype register from a decoded `Vtype`.
239    ///
240    /// The implementation must update both its internal decoded cache and the raw CSR value (for
241    /// reads via Zicsr, writes via Zicsr are not allowed).
242    #[inline(always)]
243    fn set_vtype(&mut self, vtype: Option<Vtype<{ Self::ELEN }, { Self::VLEN }>>) {
244        let vtype_raw = if let Some(vt) = vtype {
245            vt.to_raw::<Reg>()
246        } else {
247            Vtype::<{ Self::ELEN }, { Self::VLEN }>::illegal_raw::<Reg>()
248        };
249
250        self.write_csr(VectorCsr::Vtype.to_csr_index(), vtype_raw)
251            .expect("Implementation didn't initialize `vtype` CSR");
252    }
253}