ab_riscv_interpreter/v/zvexx/store/
zvexx_store_helpers.rs1use crate::v::vector_registers::{VectorRegisterFile, VectorRegistersExt};
4use crate::v::zvexx::load::zvexx_load_helpers::{
5 check_register_group_alignment, mask_bit, snapshot_mask,
6};
7use crate::v::zvexx::zvexx_helpers::INSTRUCTION_SIZE;
8use crate::{ExecutionError, PackedAddress, ProgramCounter, VirtualMemory, VirtualMemoryError};
9use ab_riscv_primitives::prelude::*;
10use core::hint::cold_path;
11
12#[inline(always)]
18#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
19unsafe fn index_buf_to_u64(
20 buf: [u8; const { usize::from(Eew::MAX_BYTES) }],
21 index_eew: Eew,
22) -> u64 {
23 match index_eew {
24 Eew::E8 => u64::from(buf[0]),
25 Eew::E16 => u64::from(u16::from_le_bytes([buf[0], buf[1]])),
26 Eew::E32 => u64::from(u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]])),
27 Eew::E64 => u64::from_le_bytes(buf),
28 }
29}
30
31#[inline(always)]
33#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
34fn write_mem_element(
35 memory: &mut impl VirtualMemory,
36 addr: u64,
37 eew: Eew,
38 buf: [u8; const { usize::from(Eew::MAX_BYTES) }],
39) -> Result<(), VirtualMemoryError> {
40 memory.write_slice(addr, &buf[..usize::from(eew.bytes_width())])
41}
42
43#[inline(always)]
49#[doc(hidden)]
50#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
51pub fn validate_segment_store_registers<Reg, Memory, PC>(
52 program_counter: &PC,
53 vs3: VReg,
54 group_regs: VRegGroupSize,
55 nf: Nf,
56) -> Result<(), ExecutionError<Reg::Type>>
57where
58 Reg: Register,
59 PC: ProgramCounter<Reg::Type, Memory>,
60{
61 if let Err(error) =
62 check_register_group_alignment::<Reg, _, _>(program_counter, vs3, group_regs)
63 {
64 cold_path();
65 return Err(error);
66 }
67 let nf_group_regs = u32::from(nf.fields_per_segment()) * u32::from(group_regs.get());
68 let total = u32::from(vs3.to_bits()) + nf_group_regs;
69 if nf_group_regs > 8 || total > 32 {
72 cold_path();
73 return Err(ExecutionError::IllegalInstruction {
74 address: PackedAddress::new(program_counter.old_pc(INSTRUCTION_SIZE)),
75 });
76 }
77 Ok(())
78}
79
80#[inline(always)]
94#[expect(clippy::too_many_arguments, reason = "Internal API")]
95#[doc(hidden)]
96#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
97pub unsafe fn execute_unit_stride_store<Reg, Env, Memory>(
98 env: &mut Env,
99 memory: &mut Memory,
100 vs3: VReg,
101 vm: bool,
102 base: u64,
103 eew: Eew,
104 group_regs: VRegGroupSize,
105 nf: Nf,
106) -> Result<(), ExecutionError<Reg::Type>>
107where
108 Reg: Register,
109 Env: VectorRegistersExt<Reg>,
110 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
111 Memory: VirtualMemory,
112{
113 let group_regs = group_regs.get();
114 let vl = env.vl();
115 let vstart = env.vstart();
116 let elem_bytes = eew.bytes_width();
117
118 let range = vstart.range_to(vl);
119
120 if vm && nf.fields_per_segment() == 1 && !range.is_empty() {
125 let first = *range.start();
126 let len = range.len() * usize::from(elem_bytes);
127 let addr = base.wrapping_add(u64::from(first) * u64::from(elem_bytes));
128 let offset = VectorRegisterFile::<{ Env::VLEN }>::element_offset(vs3, first, eew);
129 let data = unsafe {
132 env.read_vregs()
133 .as_bytes()
134 .as_flattened()
135 .get_unchecked(offset..offset + len)
136 };
137 if memory.write_slice(addr, data).is_ok() {
138 env.reset_vstart();
139 return Ok(());
140 }
141 cold_path();
142 }
143
144 let segment_stride = u64::from(nf.fields_per_segment() * elem_bytes);
145 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
147 for i in range {
148 if !vm && !mask_bit(&mask_buf, i) {
149 continue;
150 }
151 let elem_base = base.wrapping_add(u64::from(i) * segment_stride);
152 for f in 0..nf.fields_per_segment() {
153 let addr = elem_base.wrapping_add(u64::from(f * elem_bytes));
154 let field_base_reg =
156 unsafe { VReg::from_bits(vs3.to_bits() + f * group_regs).unwrap_unchecked() };
157 let data = unsafe {
171 env.read_vregs()
172 .read_element(field_base_reg, i, eew)
173 .to_le_bytes()
174 };
175 if let Err(error) = write_mem_element(memory, addr, eew, data) {
178 cold_path();
179 env.set_vstart(Vstart::from(i));
180 return Err(ExecutionError::from(error));
181 }
182 }
183 }
184 env.reset_vstart();
185 Ok(())
186}
187
188#[inline(always)]
202#[expect(clippy::too_many_arguments, reason = "Internal API")]
203#[doc(hidden)]
204#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
205pub unsafe fn execute_strided_store<Reg, Env, Memory>(
206 env: &mut Env,
207 memory: &mut Memory,
208 vs3: VReg,
209 vm: bool,
210 base: u64,
211 stride: i64,
212 eew: Eew,
213 group_regs: VRegGroupSize,
214 nf: Nf,
215) -> Result<(), ExecutionError<Reg::Type>>
216where
217 Reg: Register,
218 Env: VectorRegistersExt<Reg>,
219 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
220 Memory: VirtualMemory,
221{
222 let group_regs = group_regs.get();
223 let vl = env.vl();
224 let vstart = env.vstart();
225 let elem_bytes = eew.bytes_width();
226 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
228 for i in vstart.range_to(vl) {
229 if !vm && !mask_bit(&mask_buf, i) {
230 continue;
231 }
232 let elem_base = base.wrapping_add(i64::from(i).wrapping_mul(stride).cast_unsigned());
233 for f in 0..nf.fields_per_segment() {
234 let addr = elem_base.wrapping_add(u64::from(f * elem_bytes));
235 let field_base_reg =
237 unsafe { VReg::from_bits(vs3.to_bits() + f * group_regs).unwrap_unchecked() };
238 let data = unsafe {
242 env.read_vregs()
243 .read_element(field_base_reg, i, eew)
244 .to_le_bytes()
245 };
246 if let Err(error) = write_mem_element(memory, addr, eew, data) {
249 cold_path();
250 env.set_vstart(Vstart::from(i));
251 return Err(ExecutionError::from(error));
252 }
253 }
254 }
255 env.reset_vstart();
256 Ok(())
257}
258
259#[inline(always)]
278#[expect(clippy::too_many_arguments, reason = "Internal API")]
279#[doc(hidden)]
280#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
281pub unsafe fn execute_indexed_store<Reg, Env, Memory>(
282 env: &mut Env,
283 memory: &mut Memory,
284 vs3: VReg,
285 vs2: VReg,
286 vm: bool,
287 base: u64,
288 data_eew: Eew,
289 index_eew: Eew,
290 data_group_regs: VRegGroupSize,
291 nf: Nf,
292) -> Result<(), ExecutionError<Reg::Type>>
293where
294 Reg: Register,
295 Env: VectorRegistersExt<Reg>,
296 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
297 Memory: VirtualMemory,
298{
299 let data_group_regs = data_group_regs.get();
300 let vl = env.vl();
301 let vstart = env.vstart();
302 let data_elem_bytes = data_eew.bytes_width();
303 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
305 for i in vstart.range_to(vl) {
306 if !vm && !mask_bit(&mask_buf, i) {
307 continue;
308 }
309 let index_buf = unsafe {
313 env.read_vregs()
314 .read_element(vs2, i, index_eew)
315 .to_le_bytes()
316 };
317 let offset = unsafe { index_buf_to_u64(index_buf, index_eew) };
319 let elem_base = base.wrapping_add(offset);
320 for f in 0..nf.fields_per_segment() {
321 let addr = elem_base.wrapping_add(u64::from(f) * u64::from(data_elem_bytes));
322 let field_base_reg =
324 unsafe { VReg::from_bits(vs3.to_bits() + f * data_group_regs).unwrap_unchecked() };
325 let data = unsafe {
329 env.read_vregs()
330 .read_element(field_base_reg, i, data_eew)
331 .to_le_bytes()
332 };
333 if let Err(error) = write_mem_element(memory, addr, data_eew, data) {
336 cold_path();
337 env.set_vstart(Vstart::from(i));
338 return Err(ExecutionError::from(error));
339 }
340 }
341 }
342 env.reset_vstart();
343 Ok(())
344}