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 ExecutionResult, FetchInstructionResult, InstructionFetcher, OpaqueThreadedExecutionResult,
13 PackedAddress, ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands,
14 ThreadedExecutableInstruction, ThreadedExecutionResult, VirtualMemory,
15};
16use ab_riscv_macros::instruction_execution;
17use ab_riscv_primitives::prelude::*;
18
19#[instruction_execution]
20const impl<Reg> ExecutableInstructionOperands for ZveXxStoreInstruction<Reg> where Reg: Register {}
21
22#[instruction_execution]
23const impl<Reg, Env> ExecutableInstructionCsr<Env> for ZveXxStoreInstruction<Reg> where Reg: Register
24{}
25
26#[instruction_execution]
27impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
28 for ZveXxStoreInstruction<Reg>
29where
30 Reg: Register,
31 Regs: RegisterFile<Reg>,
32 Env: VectorRegistersExt<Reg>,
33 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
34 Memory: VirtualMemory,
35 PC: ProgramCounter<Reg::Type, Memory>,
36{
37 #[inline(always)]
38 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
39 fn execute(
40 self,
41 Rs1Rs2OperandValues {
42 rs1_value,
43 rs2_value,
44 }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
45 _regs: &mut Regs,
46 env: &mut Env,
47 memory: &mut Memory,
48 program_counter: &mut PC,
49 ) -> ExecutionResult<Self::Reg> {
50 match self {
51 Self::Vsr { vs3, rs1: _, nreg } => {
57 let nreg = nreg.num_registers();
58 if !env.vector_instructions_allowed() {
59 ::core::hint::cold_path();
60 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
61 address: PackedAddress::new(
62 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
63 ),
64 });
65 }
66 if !vs3.to_bits().is_multiple_of(nreg) {
67 ::core::hint::cold_path();
68 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
69 address: PackedAddress::new(
70 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
71 ),
72 });
73 }
74 let vlenb = u64::from(Env::VLEN.bytes());
75 let evl = u64::from(nreg) * vlenb;
76 let vstart = env.vstart();
77 if u64::from(u16::from(vstart)) < evl {
78 let base = rs1_value.as_u64();
79 let mut byte_off = u64::from(u16::from(vstart));
80 while byte_off < evl {
81 let reg_off = byte_off / vlenb;
82 let in_reg = (byte_off % vlenb) as usize;
83 let reg = unsafe {
86 VReg::from_bits(vs3.to_bits() + reg_off as u8).unwrap_unchecked()
87 };
88 let src = unsafe { env.read_vregs().get(reg).get_unchecked(in_reg..) };
90 if let Err(error) = memory.write_slice(base + byte_off, src) {
91 env.set_vstart(Vstart::from(byte_off as u16));
92 return ExecutionResult::Err(ExecutionError::from(error));
93 }
94 byte_off += src.len() as u64;
95 }
96 }
97 env.reset_vstart();
98 }
99 Self::Vsm { vs3, rs1: _ } => {
103 if !env.vector_instructions_allowed() {
104 ::core::hint::cold_path();
105 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
106 address: PackedAddress::new(
107 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
108 ),
109 });
110 }
111 let vl = env.vl();
112 let evl_bytes = vl.bytes();
113 let start_byte = env.vstart();
114 if u16::from(start_byte) < evl_bytes {
115 let base = rs1_value.as_u64();
116 let src = unsafe {
120 env.read_vregs().get(vs3).get_unchecked(
121 usize::from(u16::from(start_byte))..usize::from(evl_bytes),
122 )
123 };
124 memory
125 .write_slice(base + u64::from(u16::from(start_byte)), src)
126 .map_err(ExecutionError::from)?;
127 }
128 env.reset_vstart();
129 }
130 Self::Vse {
136 vs3,
137 rs1: _,
138 vm,
139 eew,
140 } => {
141 if !env.vector_instructions_allowed() {
142 ::core::hint::cold_path();
143 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
144 address: PackedAddress::new(
145 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
146 ),
147 });
148 }
149 let Some(vtype) = env.vtype() else {
150 ::core::hint::cold_path();
151 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
152 address: PackedAddress::new(
153 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
154 ),
155 });
156 };
157 let group_regs = vtype.vlmul().data_register_count(eew, vtype.vsew()).ok_or(
158 ExecutionError::IllegalInstruction {
159 address: PackedAddress::new(
160 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
161 ),
162 },
163 )?;
164 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _>(
165 program_counter,
166 vs3,
167 group_regs,
168 )?;
169 unsafe {
178 zvexx_store_helpers::execute_unit_stride_store(
179 env,
180 memory,
181 vs3,
182 vm,
183 rs1_value.as_u64(),
184 eew,
185 group_regs,
186 Nf::N1,
187 )?;
188 }
189 }
190 Self::Vsse {
192 vs3,
193 rs1: _,
194 rs2: _,
195 vm,
196 eew,
197 } => {
198 if !env.vector_instructions_allowed() {
199 ::core::hint::cold_path();
200 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
201 address: PackedAddress::new(
202 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
203 ),
204 });
205 }
206 let Some(vtype) = env.vtype() else {
207 ::core::hint::cold_path();
208 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
209 address: PackedAddress::new(
210 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
211 ),
212 });
213 };
214 let group_regs = vtype.vlmul().data_register_count(eew, vtype.vsew()).ok_or(
215 ExecutionError::IllegalInstruction {
216 address: PackedAddress::new(
217 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
218 ),
219 },
220 )?;
221 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _>(
222 program_counter,
223 vs3,
224 group_regs,
225 )?;
226 let stride = rs2_value.as_i64();
227 unsafe {
229 zvexx_store_helpers::execute_strided_store(
230 env,
231 memory,
232 vs3,
233 vm,
234 rs1_value.as_u64(),
235 stride,
236 eew,
237 group_regs,
238 Nf::N1,
239 )?;
240 }
241 }
242 Self::Vsuxei {
244 vs3,
245 rs1: _,
246 vs2,
247 vm,
248 eew: index_eew,
249 } => {
250 if !env.vector_instructions_allowed() {
251 ::core::hint::cold_path();
252 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
253 address: PackedAddress::new(
254 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
255 ),
256 });
257 }
258 let Some(vtype) = env.vtype() else {
259 ::core::hint::cold_path();
260 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
261 address: PackedAddress::new(
262 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
263 ),
264 });
265 };
266 let data_eew = vtype.vsew().as_eew();
267 let data_group_regs = vtype.vlmul().register_count();
268 let index_group_regs = vtype
269 .vlmul()
270 .index_register_count(index_eew, vtype.vsew())
271 .ok_or(ExecutionError::IllegalInstruction {
272 address: PackedAddress::new(
273 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
274 ),
275 })?;
276 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _>(
277 program_counter,
278 vs3,
279 data_group_regs,
280 )?;
281 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _>(
282 program_counter,
283 vs2,
284 index_group_regs,
285 )?;
286 unsafe {
296 zvexx_store_helpers::execute_indexed_store(
297 env,
298 memory,
299 vs3,
300 vs2,
301 vm,
302 rs1_value.as_u64(),
303 data_eew,
304 index_eew,
305 data_group_regs,
306 Nf::N1,
307 )?;
308 }
309 }
310 Self::Vsoxei {
314 vs3,
315 rs1: _,
316 vs2,
317 vm,
318 eew: index_eew,
319 } => {
320 if !env.vector_instructions_allowed() {
321 ::core::hint::cold_path();
322 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
323 address: PackedAddress::new(
324 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
325 ),
326 });
327 }
328 let Some(vtype) = env.vtype() else {
329 ::core::hint::cold_path();
330 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
331 address: PackedAddress::new(
332 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
333 ),
334 });
335 };
336 let data_eew = vtype.vsew().as_eew();
337 let data_group_regs = vtype.vlmul().register_count();
338 let index_group_regs = vtype
339 .vlmul()
340 .index_register_count(index_eew, vtype.vsew())
341 .ok_or(ExecutionError::IllegalInstruction {
342 address: PackedAddress::new(
343 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
344 ),
345 })?;
346 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _>(
347 program_counter,
348 vs3,
349 data_group_regs,
350 )?;
351 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _>(
352 program_counter,
353 vs2,
354 index_group_regs,
355 )?;
356 unsafe {
358 zvexx_store_helpers::execute_indexed_store(
359 env,
360 memory,
361 vs3,
362 vs2,
363 vm,
364 rs1_value.as_u64(),
365 data_eew,
366 index_eew,
367 data_group_regs,
368 Nf::N1,
369 )?;
370 }
371 }
372 Self::Vsseg {
374 vs3,
375 rs1: _,
376 eew,
377 vm_nf,
378 } => {
379 let vm = vm_nf.vm();
380 let nf = vm_nf.nf();
381 if !env.vector_instructions_allowed() {
382 ::core::hint::cold_path();
383 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
384 address: PackedAddress::new(
385 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
386 ),
387 });
388 }
389 let Some(vtype) = env.vtype() else {
390 ::core::hint::cold_path();
391 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
392 address: PackedAddress::new(
393 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
394 ),
395 });
396 };
397 let group_regs = vtype.vlmul().data_register_count(eew, vtype.vsew()).ok_or(
398 ExecutionError::IllegalInstruction {
399 address: PackedAddress::new(
400 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
401 ),
402 },
403 )?;
404 zvexx_store_helpers::validate_segment_store_registers::<Reg, _, _>(
405 program_counter,
406 vs3,
407 group_regs,
408 nf,
409 )?;
410 unsafe {
416 zvexx_store_helpers::execute_unit_stride_store(
417 env,
418 memory,
419 vs3,
420 vm,
421 rs1_value.as_u64(),
422 eew,
423 group_regs,
424 nf,
425 )?;
426 }
427 }
428 Self::Vssseg {
430 vs3,
431 rs1: _,
432 rs2: _,
433 eew,
434 vm_nf,
435 } => {
436 let vm = vm_nf.vm();
437 let nf = vm_nf.nf();
438 if !env.vector_instructions_allowed() {
439 ::core::hint::cold_path();
440 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
441 address: PackedAddress::new(
442 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
443 ),
444 });
445 }
446 let Some(vtype) = env.vtype() else {
447 ::core::hint::cold_path();
448 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
449 address: PackedAddress::new(
450 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
451 ),
452 });
453 };
454 let group_regs = vtype.vlmul().data_register_count(eew, vtype.vsew()).ok_or(
455 ExecutionError::IllegalInstruction {
456 address: PackedAddress::new(
457 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
458 ),
459 },
460 )?;
461 zvexx_store_helpers::validate_segment_store_registers::<Reg, _, _>(
462 program_counter,
463 vs3,
464 group_regs,
465 nf,
466 )?;
467 let stride = rs2_value.as_i64();
468 unsafe {
470 zvexx_store_helpers::execute_strided_store(
471 env,
472 memory,
473 vs3,
474 vm,
475 rs1_value.as_u64(),
476 stride,
477 eew,
478 group_regs,
479 nf,
480 )?;
481 }
482 }
483 Self::Vsuxseg {
485 vs3,
486 rs1: _,
487 vs2,
488 eew: index_eew,
489 vm_nf,
490 } => {
491 let vm = vm_nf.vm();
492 let nf = vm_nf.nf();
493 if !env.vector_instructions_allowed() {
494 ::core::hint::cold_path();
495 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
496 address: PackedAddress::new(
497 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
498 ),
499 });
500 }
501 let Some(vtype) = env.vtype() else {
502 ::core::hint::cold_path();
503 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
504 address: PackedAddress::new(
505 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
506 ),
507 });
508 };
509 let data_eew = vtype.vsew().as_eew();
510 let data_group_regs = vtype.vlmul().register_count();
511 let index_group_regs = vtype
512 .vlmul()
513 .index_register_count(index_eew, vtype.vsew())
514 .ok_or(ExecutionError::IllegalInstruction {
515 address: PackedAddress::new(
516 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
517 ),
518 })?;
519 zvexx_store_helpers::validate_segment_store_registers::<Reg, _, _>(
520 program_counter,
521 vs3,
522 data_group_regs,
523 nf,
524 )?;
525 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _>(
526 program_counter,
527 vs2,
528 index_group_regs,
529 )?;
530 unsafe {
536 zvexx_store_helpers::execute_indexed_store(
537 env,
538 memory,
539 vs3,
540 vs2,
541 vm,
542 rs1_value.as_u64(),
543 data_eew,
544 index_eew,
545 data_group_regs,
546 nf,
547 )?;
548 }
549 }
550 Self::Vsoxseg {
553 vs3,
554 rs1: _,
555 vs2,
556 eew: index_eew,
557 vm_nf,
558 } => {
559 let vm = vm_nf.vm();
560 let nf = vm_nf.nf();
561 if !env.vector_instructions_allowed() {
562 ::core::hint::cold_path();
563 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
564 address: PackedAddress::new(
565 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
566 ),
567 });
568 }
569 let Some(vtype) = env.vtype() else {
570 ::core::hint::cold_path();
571 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
572 address: PackedAddress::new(
573 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
574 ),
575 });
576 };
577 let data_eew = vtype.vsew().as_eew();
578 let data_group_regs = vtype.vlmul().register_count();
579 let index_group_regs = vtype
580 .vlmul()
581 .index_register_count(index_eew, vtype.vsew())
582 .ok_or(ExecutionError::IllegalInstruction {
583 address: PackedAddress::new(
584 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
585 ),
586 })?;
587 zvexx_store_helpers::validate_segment_store_registers::<Reg, _, _>(
588 program_counter,
589 vs3,
590 data_group_regs,
591 nf,
592 )?;
593 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _>(
594 program_counter,
595 vs2,
596 index_group_regs,
597 )?;
598 unsafe {
600 zvexx_store_helpers::execute_indexed_store(
601 env,
602 memory,
603 vs3,
604 vs2,
605 vm,
606 rs1_value.as_u64(),
607 data_eew,
608 index_eew,
609 data_group_regs,
610 nf,
611 )?;
612 }
613 }
614 }
615
616 ExecutionResult::ContinueNoWrite
617 }
618}