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 [(); SUPPORTED_ELEN_VLEN::<{ ExtState::ELEN }, { ExtState::VLEN }>]:,
39 Memory: VirtualMemory,
40 PC: ProgramCounter<Reg::Type, Memory, CustomError>,
41 CustomError: fmt::Debug,
42{
43 #[inline(always)]
44 fn execute(
45 self,
46 Rs1Rs2OperandValues {
47 rs1_value,
48 rs2_value,
49 }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
50 _regs: &mut Regs,
51 ext_state: &mut ExtState,
52 memory: &mut Memory,
53 program_counter: &mut PC,
54 _system_instruction_handler: &mut InstructionHandler,
55 ) -> Result<
56 ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
57 ExecutionError<Reg::Type, CustomError>,
58 > {
59 match self {
60 Self::Vsr { vs3, rs1: _, nreg } => {
66 let nreg = nreg.num_registers();
67 if !ext_state.vector_instructions_allowed() {
68 ::core::hint::cold_path();
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 ::core::hint::cold_path();
75 return Err(ExecutionError::IllegalInstruction {
76 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
77 });
78 }
79 let vlenb = u64::from(ExtState::VLEN.bytes());
80 let evl = u64::from(nreg) * vlenb;
81 let vstart = ext_state.vstart();
82 if u64::from(u16::from(vstart)) < evl {
83 let base = rs1_value.as_u64();
84 let mut byte_off = u64::from(u16::from(vstart));
85 while byte_off < evl {
86 let reg_off = byte_off / vlenb;
87 let in_reg = (byte_off % vlenb) as usize;
88 let reg = unsafe {
91 VReg::from_bits(vs3.to_bits() + reg_off as u8).unwrap_unchecked()
92 };
93 let src =
95 unsafe { ext_state.read_vregs().get(reg).get_unchecked(in_reg..) };
96 if let Err(error) = memory.write_slice(base + byte_off, src) {
97 ext_state.set_vstart(Vstart::from(byte_off as u16));
98 return Err(ExecutionError::MemoryAccess(error));
99 }
100 byte_off += src.len() as u64;
101 }
102 }
103 ext_state.reset_vstart();
104 }
105 Self::Vsm { vs3, rs1: _ } => {
109 if !ext_state.vector_instructions_allowed() {
110 ::core::hint::cold_path();
111 return Err(ExecutionError::IllegalInstruction {
112 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
113 });
114 }
115 let vl = ext_state.vl();
116 let evl_bytes = vl.bytes();
117 let start_byte = ext_state.vstart();
118 if u16::from(start_byte) < evl_bytes {
119 let base = rs1_value.as_u64();
120 let src = unsafe {
124 ext_state.read_vregs().get(vs3).get_unchecked(
125 usize::from(u16::from(start_byte))..usize::from(evl_bytes),
126 )
127 };
128 memory
129 .write_slice(base + u64::from(u16::from(start_byte)), src)
130 .map_err(ExecutionError::MemoryAccess)?;
131 }
132 ext_state.reset_vstart();
133 }
134 Self::Vse {
140 vs3,
141 rs1: _,
142 vm,
143 eew,
144 } => {
145 if !ext_state.vector_instructions_allowed() {
146 ::core::hint::cold_path();
147 return Err(ExecutionError::IllegalInstruction {
148 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
149 });
150 }
151 let Some(vtype) = ext_state.vtype() else {
152 ::core::hint::cold_path();
153 return Err(ExecutionError::IllegalInstruction {
154 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
155 });
156 };
157 let group_regs = vtype.vlmul().data_register_count(eew, vtype.vsew()).ok_or(
158 ExecutionError::IllegalInstruction {
159 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
160 },
161 )?;
162 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
163 program_counter,
164 vs3,
165 group_regs,
166 )?;
167 unsafe {
176 zvexx_store_helpers::execute_unit_stride_store(
177 ext_state,
178 memory,
179 vs3,
180 vm,
181 rs1_value.as_u64(),
182 eew,
183 group_regs,
184 Nf::N1,
185 )?;
186 }
187 }
188 Self::Vsse {
190 vs3,
191 rs1: _,
192 rs2: _,
193 vm,
194 eew,
195 } => {
196 if !ext_state.vector_instructions_allowed() {
197 ::core::hint::cold_path();
198 return Err(ExecutionError::IllegalInstruction {
199 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
200 });
201 }
202 let Some(vtype) = ext_state.vtype() else {
203 ::core::hint::cold_path();
204 return Err(ExecutionError::IllegalInstruction {
205 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
206 });
207 };
208 let group_regs = vtype.vlmul().data_register_count(eew, vtype.vsew()).ok_or(
209 ExecutionError::IllegalInstruction {
210 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
211 },
212 )?;
213 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
214 program_counter,
215 vs3,
216 group_regs,
217 )?;
218 let stride = rs2_value.as_i64();
219 unsafe {
221 zvexx_store_helpers::execute_strided_store(
222 ext_state,
223 memory,
224 vs3,
225 vm,
226 rs1_value.as_u64(),
227 stride,
228 eew,
229 group_regs,
230 Nf::N1,
231 )?;
232 }
233 }
234 Self::Vsuxei {
236 vs3,
237 rs1: _,
238 vs2,
239 vm,
240 eew: index_eew,
241 } => {
242 if !ext_state.vector_instructions_allowed() {
243 ::core::hint::cold_path();
244 return Err(ExecutionError::IllegalInstruction {
245 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
246 });
247 }
248 let Some(vtype) = ext_state.vtype() else {
249 ::core::hint::cold_path();
250 return Err(ExecutionError::IllegalInstruction {
251 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
252 });
253 };
254 let data_eew = vtype.vsew().as_eew();
255 let data_group_regs = vtype.vlmul().register_count();
256 let index_group_regs = vtype
257 .vlmul()
258 .index_register_count(index_eew, vtype.vsew())
259 .ok_or(ExecutionError::IllegalInstruction {
260 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
261 })?;
262 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
263 program_counter,
264 vs3,
265 data_group_regs,
266 )?;
267 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
268 program_counter,
269 vs2,
270 index_group_regs,
271 )?;
272 unsafe {
282 zvexx_store_helpers::execute_indexed_store(
283 ext_state,
284 memory,
285 vs3,
286 vs2,
287 vm,
288 rs1_value.as_u64(),
289 data_eew,
290 index_eew,
291 data_group_regs,
292 Nf::N1,
293 )?;
294 }
295 }
296 Self::Vsoxei {
300 vs3,
301 rs1: _,
302 vs2,
303 vm,
304 eew: index_eew,
305 } => {
306 if !ext_state.vector_instructions_allowed() {
307 ::core::hint::cold_path();
308 return Err(ExecutionError::IllegalInstruction {
309 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
310 });
311 }
312 let Some(vtype) = ext_state.vtype() else {
313 ::core::hint::cold_path();
314 return Err(ExecutionError::IllegalInstruction {
315 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
316 });
317 };
318 let data_eew = vtype.vsew().as_eew();
319 let data_group_regs = vtype.vlmul().register_count();
320 let index_group_regs = vtype
321 .vlmul()
322 .index_register_count(index_eew, vtype.vsew())
323 .ok_or(ExecutionError::IllegalInstruction {
324 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
325 })?;
326 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
327 program_counter,
328 vs3,
329 data_group_regs,
330 )?;
331 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
332 program_counter,
333 vs2,
334 index_group_regs,
335 )?;
336 unsafe {
338 zvexx_store_helpers::execute_indexed_store(
339 ext_state,
340 memory,
341 vs3,
342 vs2,
343 vm,
344 rs1_value.as_u64(),
345 data_eew,
346 index_eew,
347 data_group_regs,
348 Nf::N1,
349 )?;
350 }
351 }
352 Self::Vsseg {
354 vs3,
355 rs1: _,
356 eew,
357 vm_nf,
358 } => {
359 let vm = vm_nf.vm();
360 let nf = vm_nf.nf();
361 if !ext_state.vector_instructions_allowed() {
362 ::core::hint::cold_path();
363 return Err(ExecutionError::IllegalInstruction {
364 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
365 });
366 }
367 let Some(vtype) = ext_state.vtype() else {
368 ::core::hint::cold_path();
369 return Err(ExecutionError::IllegalInstruction {
370 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
371 });
372 };
373 let group_regs = vtype.vlmul().data_register_count(eew, vtype.vsew()).ok_or(
374 ExecutionError::IllegalInstruction {
375 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
376 },
377 )?;
378 zvexx_store_helpers::validate_segment_store_registers::<Reg, _, _, _>(
379 program_counter,
380 vs3,
381 group_regs,
382 nf,
383 )?;
384 unsafe {
390 zvexx_store_helpers::execute_unit_stride_store(
391 ext_state,
392 memory,
393 vs3,
394 vm,
395 rs1_value.as_u64(),
396 eew,
397 group_regs,
398 nf,
399 )?;
400 }
401 }
402 Self::Vssseg {
404 vs3,
405 rs1: _,
406 rs2: _,
407 eew,
408 vm_nf,
409 } => {
410 let vm = vm_nf.vm();
411 let nf = vm_nf.nf();
412 if !ext_state.vector_instructions_allowed() {
413 ::core::hint::cold_path();
414 return Err(ExecutionError::IllegalInstruction {
415 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
416 });
417 }
418 let Some(vtype) = ext_state.vtype() else {
419 ::core::hint::cold_path();
420 return Err(ExecutionError::IllegalInstruction {
421 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
422 });
423 };
424 let group_regs = vtype.vlmul().data_register_count(eew, vtype.vsew()).ok_or(
425 ExecutionError::IllegalInstruction {
426 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
427 },
428 )?;
429 zvexx_store_helpers::validate_segment_store_registers::<Reg, _, _, _>(
430 program_counter,
431 vs3,
432 group_regs,
433 nf,
434 )?;
435 let stride = rs2_value.as_i64();
436 unsafe {
438 zvexx_store_helpers::execute_strided_store(
439 ext_state,
440 memory,
441 vs3,
442 vm,
443 rs1_value.as_u64(),
444 stride,
445 eew,
446 group_regs,
447 nf,
448 )?;
449 }
450 }
451 Self::Vsuxseg {
453 vs3,
454 rs1: _,
455 vs2,
456 eew: index_eew,
457 vm_nf,
458 } => {
459 let vm = vm_nf.vm();
460 let nf = vm_nf.nf();
461 if !ext_state.vector_instructions_allowed() {
462 ::core::hint::cold_path();
463 return Err(ExecutionError::IllegalInstruction {
464 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
465 });
466 }
467 let Some(vtype) = ext_state.vtype() else {
468 ::core::hint::cold_path();
469 return Err(ExecutionError::IllegalInstruction {
470 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
471 });
472 };
473 let data_eew = vtype.vsew().as_eew();
474 let data_group_regs = vtype.vlmul().register_count();
475 let index_group_regs = vtype
476 .vlmul()
477 .index_register_count(index_eew, vtype.vsew())
478 .ok_or(ExecutionError::IllegalInstruction {
479 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
480 })?;
481 zvexx_store_helpers::validate_segment_store_registers::<Reg, _, _, _>(
482 program_counter,
483 vs3,
484 data_group_regs,
485 nf,
486 )?;
487 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
488 program_counter,
489 vs2,
490 index_group_regs,
491 )?;
492 unsafe {
498 zvexx_store_helpers::execute_indexed_store(
499 ext_state,
500 memory,
501 vs3,
502 vs2,
503 vm,
504 rs1_value.as_u64(),
505 data_eew,
506 index_eew,
507 data_group_regs,
508 nf,
509 )?;
510 }
511 }
512 Self::Vsoxseg {
515 vs3,
516 rs1: _,
517 vs2,
518 eew: index_eew,
519 vm_nf,
520 } => {
521 let vm = vm_nf.vm();
522 let nf = vm_nf.nf();
523 if !ext_state.vector_instructions_allowed() {
524 ::core::hint::cold_path();
525 return Err(ExecutionError::IllegalInstruction {
526 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
527 });
528 }
529 let Some(vtype) = ext_state.vtype() else {
530 ::core::hint::cold_path();
531 return Err(ExecutionError::IllegalInstruction {
532 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
533 });
534 };
535 let data_eew = vtype.vsew().as_eew();
536 let data_group_regs = vtype.vlmul().register_count();
537 let index_group_regs = vtype
538 .vlmul()
539 .index_register_count(index_eew, vtype.vsew())
540 .ok_or(ExecutionError::IllegalInstruction {
541 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
542 })?;
543 zvexx_store_helpers::validate_segment_store_registers::<Reg, _, _, _>(
544 program_counter,
545 vs3,
546 data_group_regs,
547 nf,
548 )?;
549 zvexx_load_helpers::check_register_group_alignment::<Reg, _, _, _>(
550 program_counter,
551 vs2,
552 index_group_regs,
553 )?;
554 unsafe {
556 zvexx_store_helpers::execute_indexed_store(
557 ext_state,
558 memory,
559 vs3,
560 vs2,
561 vm,
562 rs1_value.as_u64(),
563 data_eew,
564 index_eew,
565 data_group_regs,
566 nf,
567 )?;
568 }
569 }
570 }
571
572 Ok(ControlFlow::Continue(Default::default()))
573 }
574}