1#[cfg(test)]
4mod tests;
5pub mod zvexx_store_helpers;
6
7use crate::v::vector_registers::VectorRegistersExt;
8use crate::v::zvexx::load::zvexx_load_helpers;
9use crate::v::zvexx::zvexx_helpers;
10use crate::{
11 ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands, ExecutionError,
12 ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands, VirtualMemory,
13};
14use ab_riscv_macros::instruction_execution;
15use ab_riscv_primitives::prelude::*;
16use core::fmt;
17use core::ops::ControlFlow;
18
19#[instruction_execution]
20impl<Reg> ExecutableInstructionOperands for ZveXxStoreInstruction<Reg> where Reg: Register {}
21
22#[instruction_execution]
23impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
24 for ZveXxStoreInstruction<Reg>
25where
26 Reg: Register,
27{
28}
29
30#[instruction_execution]
31impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
32 ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
33 for ZveXxStoreInstruction<Reg>
34where
35 Reg: Register,
36 Regs: RegisterFile<Reg>,
37 ExtState: VectorRegistersExt<Reg, CustomError>,
38 [(); ExtState::ELEN as usize]:,
39 [(); ExtState::VLEN as usize]:,
40 [(); ExtState::VLENB as usize]:,
41 Memory: VirtualMemory,
42 PC: ProgramCounter<Reg::Type, Memory, CustomError>,
43 CustomError: fmt::Debug,
44{
45 #[inline(always)]
46 fn execute(
47 self,
48 Rs1Rs2OperandValues {
49 rs1_value,
50 rs2_value,
51 }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
52 _regs: &mut Regs,
53 ext_state: &mut ExtState,
54 memory: &mut Memory,
55 program_counter: &mut PC,
56 _system_instruction_handler: &mut InstructionHandler,
57 ) -> Result<
58 ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
59 ExecutionError<Reg::Type, CustomError>,
60 > {
61 match self {
62 Self::Vsr { vs3, rs1: _, nreg } => {
67 let nreg = nreg.num_registers();
68 if !ext_state.vector_instructions_allowed() {
69 return Err(ExecutionError::IllegalInstruction {
70 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
71 });
72 }
73 if vs3.to_bits() % nreg != 0 {
74 return Err(ExecutionError::IllegalInstruction {
75 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
76 });
77 }
78 let vlenb = u64::from(ExtState::VLENB);
79 let evl = u64::from(nreg) * vlenb;
80 let vstart = ext_state.vstart();
81 if u64::from(vstart) < evl {
82 let base = rs1_value.as_u64();
83 let mut byte_off = u64::from(vstart);
84 while byte_off < evl {
85 let reg_off = byte_off / vlenb;
86 let in_reg = (byte_off % vlenb) as usize;
87 let reg = unsafe {
90 VReg::from_bits(vs3.to_bits() + reg_off as u8).unwrap_unchecked()
91 };
92 let src =
94 unsafe { ext_state.read_vregs().get(reg).get_unchecked(in_reg..) };
95 if let Err(error) = memory.write_slice(base + byte_off, src) {
96 ext_state.set_vstart(byte_off as u16);
97 return Err(ExecutionError::MemoryAccess(error));
98 }
99 byte_off += src.len() as u64;
100 }
101 }
102 ext_state.reset_vstart();
103 }
104 Self::Vsm { vs3, rs1: _ } => {
108 if !ext_state.vector_instructions_allowed() {
109 return Err(ExecutionError::IllegalInstruction {
110 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
111 });
112 }
113 let vl = ext_state.vl();
114 let evl_bytes = vl.div_ceil(u8::BITS);
115 let start_byte = ext_state.vstart();
116 if u32::from(start_byte) < evl_bytes {
117 let base = rs1_value.as_u64();
118 let src = unsafe {
122 ext_state
123 .read_vregs()
124 .get(vs3)
125 .get_unchecked(usize::from(start_byte)..evl_bytes as usize)
126 };
127 memory
128 .write_slice(base + u64::from(start_byte), src)
129 .map_err(ExecutionError::MemoryAccess)?;
130 }
131 ext_state.reset_vstart();
132 }
133 Self::Vse {
139 vs3,
140 rs1: _,
141 vm,
142 eew,
143 } => {
144 if !ext_state.vector_instructions_allowed() {
145 return Err(ExecutionError::IllegalInstruction {
146 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
147 });
148 }
149 let vtype = ext_state
150 .vtype()
151 .ok_or(ExecutionError::IllegalInstruction {
152 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
153 })?;
154 let group_regs = vtype.vlmul().data_register_count(eew, vtype.vsew()).ok_or(
155 ExecutionError::IllegalInstruction {
156 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
157 },
158 )?;
159 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
160 program_counter,
161 vs3,
162 group_regs,
163 )?;
164 unsafe {
173 zvexx_store_helpers::execute_unit_stride_store(
174 ext_state,
175 memory,
176 vs3,
177 vm,
178 rs1_value.as_u64(),
179 eew,
180 group_regs,
181 Nf::N1,
182 )?;
183 }
184 }
185 Self::Vsse {
187 vs3,
188 rs1: _,
189 rs2: _,
190 vm,
191 eew,
192 } => {
193 if !ext_state.vector_instructions_allowed() {
194 return Err(ExecutionError::IllegalInstruction {
195 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
196 });
197 }
198 let vtype = ext_state
199 .vtype()
200 .ok_or(ExecutionError::IllegalInstruction {
201 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
202 })?;
203 let group_regs = vtype.vlmul().data_register_count(eew, vtype.vsew()).ok_or(
204 ExecutionError::IllegalInstruction {
205 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
206 },
207 )?;
208 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
209 program_counter,
210 vs3,
211 group_regs,
212 )?;
213 let stride = rs2_value.as_i64();
214 unsafe {
216 zvexx_store_helpers::execute_strided_store(
217 ext_state,
218 memory,
219 vs3,
220 vm,
221 rs1_value.as_u64(),
222 stride,
223 eew,
224 group_regs,
225 Nf::N1,
226 )?;
227 }
228 }
229 Self::Vsuxei {
231 vs3,
232 rs1: _,
233 vs2,
234 vm,
235 eew: index_eew,
236 } => {
237 if !ext_state.vector_instructions_allowed() {
238 return Err(ExecutionError::IllegalInstruction {
239 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
240 });
241 }
242 let vtype = ext_state
243 .vtype()
244 .ok_or(ExecutionError::IllegalInstruction {
245 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
246 })?;
247 let data_eew = vtype.vsew().as_eew();
248 let data_group_regs = vtype.vlmul().register_count();
249 let index_group_regs = vtype
250 .vlmul()
251 .index_register_count(index_eew, vtype.vsew())
252 .ok_or(ExecutionError::IllegalInstruction {
253 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
254 })?;
255 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
256 program_counter,
257 vs3,
258 data_group_regs,
259 )?;
260 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
261 program_counter,
262 vs2,
263 index_group_regs,
264 )?;
265 unsafe {
274 zvexx_store_helpers::execute_indexed_store(
275 ext_state,
276 memory,
277 vs3,
278 vs2,
279 vm,
280 rs1_value.as_u64(),
281 data_eew,
282 index_eew,
283 data_group_regs,
284 Nf::N1,
285 )?;
286 }
287 }
288 Self::Vsoxei {
292 vs3,
293 rs1: _,
294 vs2,
295 vm,
296 eew: index_eew,
297 } => {
298 if !ext_state.vector_instructions_allowed() {
299 return Err(ExecutionError::IllegalInstruction {
300 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
301 });
302 }
303 let vtype = ext_state
304 .vtype()
305 .ok_or(ExecutionError::IllegalInstruction {
306 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
307 })?;
308 let data_eew = vtype.vsew().as_eew();
309 let data_group_regs = vtype.vlmul().register_count();
310 let index_group_regs = vtype
311 .vlmul()
312 .index_register_count(index_eew, vtype.vsew())
313 .ok_or(ExecutionError::IllegalInstruction {
314 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
315 })?;
316 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
317 program_counter,
318 vs3,
319 data_group_regs,
320 )?;
321 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
322 program_counter,
323 vs2,
324 index_group_regs,
325 )?;
326 unsafe {
328 zvexx_store_helpers::execute_indexed_store(
329 ext_state,
330 memory,
331 vs3,
332 vs2,
333 vm,
334 rs1_value.as_u64(),
335 data_eew,
336 index_eew,
337 data_group_regs,
338 Nf::N1,
339 )?;
340 }
341 }
342 Self::Vsseg {
344 vs3,
345 rs1: _,
346 eew,
347 vm_nf,
348 } => {
349 let vm = vm_nf.vm();
350 let nf = vm_nf.nf();
351 if !ext_state.vector_instructions_allowed() {
352 return Err(ExecutionError::IllegalInstruction {
353 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
354 });
355 }
356 let vtype = ext_state
357 .vtype()
358 .ok_or(ExecutionError::IllegalInstruction {
359 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
360 })?;
361 let group_regs = vtype.vlmul().data_register_count(eew, vtype.vsew()).ok_or(
362 ExecutionError::IllegalInstruction {
363 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
364 },
365 )?;
366 zvexx_store_helpers::validate_segment_store_registers::<Reg, _, _, _>(
367 program_counter,
368 vs3,
369 group_regs,
370 nf,
371 )?;
372 unsafe {
378 zvexx_store_helpers::execute_unit_stride_store(
379 ext_state,
380 memory,
381 vs3,
382 vm,
383 rs1_value.as_u64(),
384 eew,
385 group_regs,
386 nf,
387 )?;
388 }
389 }
390 Self::Vssseg {
392 vs3,
393 rs1: _,
394 rs2: _,
395 eew,
396 vm_nf,
397 } => {
398 let vm = vm_nf.vm();
399 let nf = vm_nf.nf();
400 if !ext_state.vector_instructions_allowed() {
401 return Err(ExecutionError::IllegalInstruction {
402 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
403 });
404 }
405 let vtype = ext_state
406 .vtype()
407 .ok_or(ExecutionError::IllegalInstruction {
408 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
409 })?;
410 let group_regs = vtype.vlmul().data_register_count(eew, vtype.vsew()).ok_or(
411 ExecutionError::IllegalInstruction {
412 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
413 },
414 )?;
415 zvexx_store_helpers::validate_segment_store_registers::<Reg, _, _, _>(
416 program_counter,
417 vs3,
418 group_regs,
419 nf,
420 )?;
421 let stride = rs2_value.as_i64();
422 unsafe {
424 zvexx_store_helpers::execute_strided_store(
425 ext_state,
426 memory,
427 vs3,
428 vm,
429 rs1_value.as_u64(),
430 stride,
431 eew,
432 group_regs,
433 nf,
434 )?;
435 }
436 }
437 Self::Vsuxseg {
439 vs3,
440 rs1: _,
441 vs2,
442 eew: index_eew,
443 vm_nf,
444 } => {
445 let vm = vm_nf.vm();
446 let nf = vm_nf.nf();
447 if !ext_state.vector_instructions_allowed() {
448 return Err(ExecutionError::IllegalInstruction {
449 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
450 });
451 }
452 let vtype = ext_state
453 .vtype()
454 .ok_or(ExecutionError::IllegalInstruction {
455 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
456 })?;
457 let data_eew = vtype.vsew().as_eew();
458 let data_group_regs = vtype.vlmul().register_count();
459 let index_group_regs = vtype
460 .vlmul()
461 .index_register_count(index_eew, vtype.vsew())
462 .ok_or(ExecutionError::IllegalInstruction {
463 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
464 })?;
465 zvexx_store_helpers::validate_segment_store_registers::<Reg, _, _, _>(
466 program_counter,
467 vs3,
468 data_group_regs,
469 nf,
470 )?;
471 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
472 program_counter,
473 vs2,
474 index_group_regs,
475 )?;
476 unsafe {
482 zvexx_store_helpers::execute_indexed_store(
483 ext_state,
484 memory,
485 vs3,
486 vs2,
487 vm,
488 rs1_value.as_u64(),
489 data_eew,
490 index_eew,
491 data_group_regs,
492 nf,
493 )?;
494 }
495 }
496 Self::Vsoxseg {
499 vs3,
500 rs1: _,
501 vs2,
502 eew: index_eew,
503 vm_nf,
504 } => {
505 let vm = vm_nf.vm();
506 let nf = vm_nf.nf();
507 if !ext_state.vector_instructions_allowed() {
508 return Err(ExecutionError::IllegalInstruction {
509 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
510 });
511 }
512 let vtype = ext_state
513 .vtype()
514 .ok_or(ExecutionError::IllegalInstruction {
515 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
516 })?;
517 let data_eew = vtype.vsew().as_eew();
518 let data_group_regs = vtype.vlmul().register_count();
519 let index_group_regs = vtype
520 .vlmul()
521 .index_register_count(index_eew, vtype.vsew())
522 .ok_or(ExecutionError::IllegalInstruction {
523 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
524 })?;
525 zvexx_store_helpers::validate_segment_store_registers::<Reg, _, _, _>(
526 program_counter,
527 vs3,
528 data_group_regs,
529 nf,
530 )?;
531 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
532 program_counter,
533 vs2,
534 index_group_regs,
535 )?;
536 unsafe {
538 zvexx_store_helpers::execute_indexed_store(
539 ext_state,
540 memory,
541 vs3,
542 vs2,
543 vm,
544 rs1_value.as_u64(),
545 data_eew,
546 index_eew,
547 data_group_regs,
548 nf,
549 )?;
550 }
551 }
552 }
553
554 Ok(ControlFlow::Continue(Default::default()))
555 }
556}