ab_riscv_interpreter/v/zvexx/store/
zvexx_store_helpers.rs1use crate::v::vector_registers::VectorRegistersExt;
4use crate::v::zvexx::load::zvexx_load_helpers::{
5 check_register_group_alignment, mask_bit, read_group_element, snapshot_mask,
6};
7use crate::v::zvexx::zvexx_helpers::INSTRUCTION_SIZE;
8use crate::{ExecutionError, ProgramCounter, VirtualMemory, VirtualMemoryError};
9use ab_riscv_primitives::prelude::*;
10use core::fmt;
11use core::hint::cold_path;
12
13#[inline(always)]
19unsafe fn index_buf_to_u64(buf: [u8; Eew::MAX_BYTES as usize], index_eew: Eew) -> u64 {
20 match index_eew {
21 Eew::E8 => u64::from(buf[0]),
22 Eew::E16 => u64::from(u16::from_le_bytes([buf[0], buf[1]])),
23 Eew::E32 => u64::from(u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]])),
24 Eew::E64 => u64::from_le_bytes(buf),
25 }
26}
27
28#[inline(always)]
30fn write_mem_element(
31 memory: &mut impl VirtualMemory,
32 addr: u64,
33 eew: Eew,
34 buf: [u8; Eew::MAX_BYTES as usize],
35) -> Result<(), VirtualMemoryError> {
36 memory.write_slice(addr, &buf[..usize::from(eew.bytes_width())])
37}
38
39#[inline(always)]
45#[doc(hidden)]
46pub fn validate_segment_store_registers<Reg, Memory, PC, CustomError>(
47 program_counter: &PC,
48 vs3: VReg,
49 group_regs: u8,
50 nf: Nf,
51) -> Result<(), ExecutionError<Reg::Type, CustomError>>
52where
53 Reg: Register,
54 PC: ProgramCounter<Reg::Type, Memory, CustomError>,
55{
56 if let Err(error) =
57 check_register_group_alignment::<Reg, _, _, _>(program_counter, vs3, group_regs)
58 {
59 cold_path();
60 return Err(error);
61 }
62 let total =
63 u32::from(vs3.to_bits()) + u32::from(nf.fields_per_segment()) * u32::from(group_regs);
64 if total > 32 {
65 cold_path();
66 return Err(ExecutionError::IllegalInstruction {
67 address: program_counter.old_pc(INSTRUCTION_SIZE),
68 });
69 }
70 Ok(())
71}
72
73#[inline(always)]
87#[expect(clippy::too_many_arguments, reason = "Internal API")]
88#[doc(hidden)]
89pub unsafe fn execute_unit_stride_store<Reg, ExtState, Memory, CustomError>(
90 ext_state: &mut ExtState,
91 memory: &mut Memory,
92 vs3: VReg,
93 vm: bool,
94 base: u64,
95 eew: Eew,
96 group_regs: u8,
97 nf: Nf,
98) -> Result<(), ExecutionError<Reg::Type, CustomError>>
99where
100 Reg: Register,
101 ExtState: VectorRegistersExt<Reg, CustomError>,
102 [(); ExtState::ELEN as usize]:,
103 [(); ExtState::VLEN as usize]:,
104 [(); ExtState::VLENB as usize]:,
105 Memory: VirtualMemory,
106 CustomError: fmt::Debug,
107{
108 let vl = ext_state.vl();
109 let vstart = ext_state.vstart();
110 let elem_bytes = eew.bytes_width();
111 let segment_stride = u64::from(nf.fields_per_segment() * elem_bytes);
112 let mask_buf = unsafe { snapshot_mask(ext_state.read_vregs(), vm, vl) };
114 for i in u32::from(vstart)..vl {
115 if !vm && !mask_bit(&mask_buf, i) {
116 continue;
117 }
118 let elem_base = base.wrapping_add(u64::from(i) * segment_stride);
119 for f in 0..nf.fields_per_segment() {
120 let addr = elem_base.wrapping_add(u64::from(f * elem_bytes));
121 let field_base_reg =
123 unsafe { VReg::from_bits(vs3.to_bits() + f * group_regs).unwrap_unchecked() };
124 let data =
138 unsafe { read_group_element(ext_state.read_vregs(), field_base_reg, i, eew) };
139 if let Err(error) = write_mem_element(memory, addr, eew, data) {
142 cold_path();
143 ext_state.set_vstart(i as u16);
144 return Err(ExecutionError::MemoryAccess(error));
145 }
146 }
147 }
148 ext_state.reset_vstart();
149 Ok(())
150}
151
152#[inline(always)]
166#[expect(clippy::too_many_arguments, reason = "Internal API")]
167#[doc(hidden)]
168pub unsafe fn execute_strided_store<Reg, ExtState, Memory, CustomError>(
169 ext_state: &mut ExtState,
170 memory: &mut Memory,
171 vs3: VReg,
172 vm: bool,
173 base: u64,
174 stride: i64,
175 eew: Eew,
176 group_regs: u8,
177 nf: Nf,
178) -> Result<(), ExecutionError<Reg::Type, CustomError>>
179where
180 Reg: Register,
181 ExtState: VectorRegistersExt<Reg, CustomError>,
182 [(); ExtState::ELEN as usize]:,
183 [(); ExtState::VLEN as usize]:,
184 [(); ExtState::VLENB as usize]:,
185 Memory: VirtualMemory,
186 CustomError: fmt::Debug,
187{
188 let vl = ext_state.vl();
189 let vstart = ext_state.vstart();
190 let elem_bytes = eew.bytes_width();
191 let mask_buf = unsafe { snapshot_mask(ext_state.read_vregs(), vm, vl) };
193 for i in u32::from(vstart)..vl {
194 if !vm && !mask_bit(&mask_buf, i) {
195 continue;
196 }
197 let elem_base = base.wrapping_add(i64::from(i).wrapping_mul(stride).cast_unsigned());
198 for f in 0..nf.fields_per_segment() {
199 let addr = elem_base.wrapping_add(u64::from(f * elem_bytes));
200 let field_base_reg =
202 unsafe { VReg::from_bits(vs3.to_bits() + f * group_regs).unwrap_unchecked() };
203 let data =
207 unsafe { read_group_element(ext_state.read_vregs(), field_base_reg, i, eew) };
208 if let Err(error) = write_mem_element(memory, addr, eew, data) {
211 cold_path();
212 ext_state.set_vstart(i as u16);
213 return Err(ExecutionError::MemoryAccess(error));
214 }
215 }
216 }
217 ext_state.reset_vstart();
218 Ok(())
219}
220
221#[inline(always)]
240#[expect(clippy::too_many_arguments, reason = "Internal API")]
241#[doc(hidden)]
242pub unsafe fn execute_indexed_store<Reg, ExtState, Memory, CustomError>(
243 ext_state: &mut ExtState,
244 memory: &mut Memory,
245 vs3: VReg,
246 vs2: VReg,
247 vm: bool,
248 base: u64,
249 data_eew: Eew,
250 index_eew: Eew,
251 data_group_regs: u8,
252 nf: Nf,
253) -> Result<(), ExecutionError<Reg::Type, CustomError>>
254where
255 Reg: Register,
256 ExtState: VectorRegistersExt<Reg, CustomError>,
257 [(); ExtState::ELEN as usize]:,
258 [(); ExtState::VLEN as usize]:,
259 [(); ExtState::VLENB as usize]:,
260 Memory: VirtualMemory,
261 CustomError: fmt::Debug,
262{
263 let vl = ext_state.vl();
264 let vstart = ext_state.vstart();
265 let data_elem_bytes = data_eew.bytes_width();
266 let mask_buf = unsafe { snapshot_mask(ext_state.read_vregs(), vm, vl) };
268 for i in u32::from(vstart)..vl {
269 if !vm && !mask_bit(&mask_buf, i) {
270 continue;
271 }
272 let index_buf = unsafe { read_group_element(ext_state.read_vregs(), vs2, i, index_eew) };
276 let offset = unsafe { index_buf_to_u64(index_buf, index_eew) };
278 let elem_base = base.wrapping_add(offset);
279 for f in 0..nf.fields_per_segment() {
280 let addr = elem_base.wrapping_add(u64::from(f) * u64::from(data_elem_bytes));
281 let field_base_reg =
283 unsafe { VReg::from_bits(vs3.to_bits() + f * data_group_regs).unwrap_unchecked() };
284 let data =
288 unsafe { read_group_element(ext_state.read_vregs(), field_base_reg, i, data_eew) };
289 if let Err(error) = write_mem_element(memory, addr, data_eew, data) {
292 cold_path();
293 ext_state.set_vstart(i as u16);
294 return Err(ExecutionError::MemoryAccess(error));
295 }
296 }
297 }
298 ext_state.reset_vstart();
299 Ok(())
300}