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