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