ab_riscv_interpreter/v/zvexx/
zvexx_helpers.rs1#[cfg(test)]
4mod tests;
5
6use crate::v::vector_config::VectorConfig;
7use crate::v::vector_registers::{VRegGroup, VRegSegmentGroup, VectorRegistersExt};
8use crate::{ExecutionError, PackedAddress, ProgramCounter};
9use ab_riscv_primitives::prelude::*;
10use core::cmp::Ordering;
11use core::hint::cold_path;
12use core::marker::PhantomData;
13
14#[doc(hidden)]
18pub const INSTRUCTION_SIZE: u8 = size_of::<u32>() as u8;
19
20#[inline(always)]
28#[doc(hidden)]
29#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
30pub fn non_memory_instruction_allowed<Reg, Env>(env: &Env) -> bool
31where
32 Reg: Register,
33 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
34{
35 env.vector_instructions_allowed() && env.vstart() == Vstart::ZERO
36}
37
38#[derive(Debug, Clone, Copy)]
45struct InvalidRegisterGroup<Address>
46where
47 Address: Copy,
48{
49 address: PackedAddress<Address>,
50}
51
52const impl<Address> From<InvalidRegisterGroup<Address>> for ExecutionError<Address>
53where
54 Address: Copy,
55{
56 #[inline(always)]
57 fn from(error: InvalidRegisterGroup<Address>) -> Self {
58 Self::IllegalInstruction {
59 address: error.address,
60 }
61 }
62}
63
64#[inline(always)]
68#[doc(hidden)]
69#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
70pub fn vreg_group<Reg, Env, Memory, PC>(
71 program_counter: &PC,
72 config: VectorConfig<Env::Hart>,
73 base: VReg,
74 eew: Eew,
75) -> Result<VRegGroup<Env::Hart>, impl Into<ExecutionError<Reg::Type>>>
76where
77 Reg: Register,
78 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
79 PC: ProgramCounter<Reg::Type, Memory>,
80{
81 let Some(group) = VRegGroup::new(config, base, eew) else {
82 cold_path();
83 return Err(InvalidRegisterGroup {
84 address: PackedAddress::new(program_counter.old_pc(INSTRUCTION_SIZE)),
85 });
86 };
87 Ok(group)
88}
89
90#[inline(always)]
94#[doc(hidden)]
95#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
96pub fn vreg_segment_group<Reg, Env, Memory, PC>(
97 program_counter: &PC,
98 first: VRegGroup<Env::Hart>,
99 nf: Nf,
100) -> Result<VRegSegmentGroup<Env::Hart>, impl Into<ExecutionError<Reg::Type>>>
101where
102 Reg: Register,
103 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
104 PC: ProgramCounter<Reg::Type, Memory>,
105{
106 let Some(group) = VRegSegmentGroup::new(first, nf) else {
107 cold_path();
108 return Err(InvalidRegisterGroup {
109 address: PackedAddress::new(program_counter.old_pc(INSTRUCTION_SIZE)),
110 });
111 };
112 Ok(group)
113}
114
115#[inline(always)]
130#[doc(hidden)]
131#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
132pub fn check_destination_overlap<Reg, Env, Memory, PC>(
133 program_counter: &PC,
134 vd: VRegGroup<Env::Hart>,
135 vs: VRegGroup<Env::Hart>,
136) -> Result<(), ExecutionError<Reg::Type>>
137where
138 Reg: Register,
139 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
140 PC: ProgramCounter<Reg::Type, Memory>,
141{
142 let allowed = !vd.overlaps(vs)
143 || match vd.eew().bytes_width().cmp(&vs.eew().bytes_width()) {
144 Ordering::Equal => true,
145 Ordering::Less => vd.base() == vs.base(),
146 Ordering::Greater => {
147 !vs.emul().is_fractional()
148 && vd.base().to_bits() + vd.group_regs().get()
149 == vs.base().to_bits() + vs.group_regs().get()
150 }
151 };
152 if !allowed {
153 cold_path();
154 return Err(ExecutionError::IllegalInstruction {
155 address: PackedAddress::new(program_counter.old_pc(INSTRUCTION_SIZE)),
156 });
157 }
158 Ok(())
159}
160
161#[inline(always)]
163#[doc(hidden)]
164#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
165pub fn check_groups_disjoint<Reg, Env, Memory, PC>(
166 program_counter: &PC,
167 a: VRegGroup<Env::Hart>,
168 b: VRegGroup<Env::Hart>,
169) -> Result<(), ExecutionError<Reg::Type>>
170where
171 Reg: Register,
172 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
173 PC: ProgramCounter<Reg::Type, Memory>,
174{
175 if a.overlaps(b) {
176 cold_path();
177 return Err(ExecutionError::IllegalInstruction {
178 address: PackedAddress::new(program_counter.old_pc(INSTRUCTION_SIZE)),
179 });
180 }
181 Ok(())
182}
183
184#[inline(always)]
186#[doc(hidden)]
187#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
188pub fn check_register_outside_group<Reg, Env, Memory, PC>(
189 program_counter: &PC,
190 group: VRegGroup<Env::Hart>,
191 reg: VReg,
192) -> Result<(), ExecutionError<Reg::Type>>
193where
194 Reg: Register,
195 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
196 PC: ProgramCounter<Reg::Type, Memory>,
197{
198 if group.contains(reg) {
199 cold_path();
200 return Err(ExecutionError::IllegalInstruction {
201 address: PackedAddress::new(program_counter.old_pc(INSTRUCTION_SIZE)),
202 });
203 }
204 Ok(())
205}
206
207#[derive(Debug, Clone, Copy)]
213#[doc(hidden)]
214pub struct WideningSew<Hart>
215where
216 Hart: VectorHartConfig,
217{
218 narrow: Vsew,
219 wide: Vsew,
220 hart: PhantomData<Hart>,
221}
222
223impl<Hart> WideningSew<Hart>
224where
225 Hart: VectorHartConfig,
226{
227 #[inline(always)]
232 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
233 pub const fn new(sew: Vsew) -> Option<Self> {
234 const {
235 assert!(
236 Hart::VECTOR_LENGTHS.elen <= Elen::L64,
237 "`ELEN` above 64 is not supported by the interpreter"
238 );
239 }
240
241 let Some(wide) = sew.double_width() else {
242 return None;
243 };
244 if !Hart::VECTOR_LENGTHS.elen.supports(wide.as_eew()) {
245 return None;
246 }
247 Some(Self {
248 narrow: sew,
249 wide,
250 hart: PhantomData,
251 })
252 }
253
254 #[inline(always)]
256 pub const fn narrow(self) -> Vsew {
257 self.narrow
258 }
259
260 #[inline(always)]
262 pub const fn wide(self) -> Vsew {
263 self.wide
264 }
265}
266
267#[derive(Debug, Clone, Copy)]
270#[doc(hidden)]
271pub struct ExtensionSew {
272 source: Vsew,
273 dest: Vsew,
274}
275
276impl ExtensionSew {
277 #[inline(always)]
279 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
280 pub const fn new(sew: Vsew, factor: VsewFactor) -> Option<Self> {
281 let Some(source) = sew.divide_by_factor(factor) else {
282 return None;
283 };
284 Some(Self { source, dest: sew })
285 }
286
287 #[inline(always)]
289 pub const fn source(self) -> Vsew {
290 self.source
291 }
292
293 #[inline(always)]
295 pub const fn dest(self) -> Vsew {
296 self.dest
297 }
298}