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 let Some(vs3) = zvexx_load_helpers::VRegGroup::whole_registers(vs3, nreg, Eew::E8)
67 else {
68 ::core::hint::cold_path();
69 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
70 address: PackedAddress::new(
71 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
72 ),
73 });
74 };
75 let vl = vs3.vl().get();
77 if env.vstart() >= vl {
79 ::core::hint::cold_path();
80 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
81 address: PackedAddress::new(
82 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
83 ),
84 });
85 }
86 zvexx_store_helpers::execute_unit_stride_store(
87 env,
88 memory,
89 zvexx_load_helpers::VRegSegmentGroup::single(vs3),
90 true,
91 rs1_value.as_u64(),
92 )?;
93 }
94 Self::Vsm { vs3, rs1: _ } => {
98 if !env.vector_instructions_allowed() {
99 ::core::hint::cold_path();
100 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
101 address: PackedAddress::new(
102 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
103 ),
104 });
105 }
106 let Some(config) = env.vector_config() else {
107 ::core::hint::cold_path();
108 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
109 address: PackedAddress::new(
110 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
111 ),
112 });
113 };
114 let Some(vs3) =
117 zvexx_load_helpers::VRegGroup::whole_registers(vs3, VRegGroupSize::R1, Eew::E8)
118 .and_then(|vs3| vs3.with_vl(Vl::from(config.vl().bytes())))
119 else {
120 ::core::hint::cold_path();
121 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
122 address: PackedAddress::new(
123 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
124 ),
125 });
126 };
127 zvexx_store_helpers::execute_unit_stride_store(
128 env,
129 memory,
130 zvexx_load_helpers::VRegSegmentGroup::single(vs3),
131 true,
132 rs1_value.as_u64(),
133 )?;
134 }
135 Self::Vse {
141 vs3,
142 rs1: _,
143 vm,
144 eew,
145 } => {
146 if !env.vector_instructions_allowed() {
147 ::core::hint::cold_path();
148 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
149 address: PackedAddress::new(
150 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
151 ),
152 });
153 }
154 let Some(config) = env.vector_config() else {
155 ::core::hint::cold_path();
156 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
157 address: PackedAddress::new(
158 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
159 ),
160 });
161 };
162 let vs3 =
163 zvexx_helpers::vreg_group::<Reg, Env, _, _>(program_counter, config, vs3, eew)?;
164 zvexx_store_helpers::execute_unit_stride_store(
165 env,
166 memory,
167 zvexx_load_helpers::VRegSegmentGroup::single(vs3),
168 vm,
169 rs1_value.as_u64(),
170 )?;
171 }
172 Self::Vsse {
174 vs3,
175 rs1: _,
176 rs2: _,
177 vm,
178 eew,
179 } => {
180 if !env.vector_instructions_allowed() {
181 ::core::hint::cold_path();
182 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
183 address: PackedAddress::new(
184 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
185 ),
186 });
187 }
188 let Some(config) = env.vector_config() else {
189 ::core::hint::cold_path();
190 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
191 address: PackedAddress::new(
192 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
193 ),
194 });
195 };
196 let vs3 =
197 zvexx_helpers::vreg_group::<Reg, Env, _, _>(program_counter, config, vs3, eew)?;
198 let stride = rs2_value.as_i64();
199 zvexx_store_helpers::execute_strided_store(
200 env,
201 memory,
202 zvexx_load_helpers::VRegSegmentGroup::single(vs3),
203 vm,
204 rs1_value.as_u64(),
205 stride,
206 )?;
207 }
208 Self::Vsuxei {
210 vs3,
211 rs1: _,
212 vs2,
213 vm,
214 eew: index_eew,
215 } => {
216 if !env.vector_instructions_allowed() {
217 ::core::hint::cold_path();
218 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
219 address: PackedAddress::new(
220 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
221 ),
222 });
223 }
224 let Some(config) = env.vector_config() else {
225 ::core::hint::cold_path();
226 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
227 address: PackedAddress::new(
228 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
229 ),
230 });
231 };
232 let data_eew = config.vtype().vsew().as_eew();
233 let vs3 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
234 program_counter,
235 config,
236 vs3,
237 data_eew,
238 )?;
239 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
240 program_counter,
241 config,
242 vs2,
243 index_eew,
244 )?;
245 if index_eew != data_eew {
248 zvexx_helpers::check_groups_disjoint::<Reg, Env, _, _>(
249 program_counter,
250 vs2,
251 vs3,
252 )?;
253 }
254 zvexx_store_helpers::execute_indexed_store(
255 env,
256 memory,
257 zvexx_load_helpers::VRegSegmentGroup::single(vs3),
258 vs2,
259 vm,
260 rs1_value.as_u64(),
261 )?;
262 }
263 Self::Vsoxei {
267 vs3,
268 rs1: _,
269 vs2,
270 vm,
271 eew: index_eew,
272 } => {
273 if !env.vector_instructions_allowed() {
274 ::core::hint::cold_path();
275 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
276 address: PackedAddress::new(
277 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
278 ),
279 });
280 }
281 let Some(config) = env.vector_config() else {
282 ::core::hint::cold_path();
283 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
284 address: PackedAddress::new(
285 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
286 ),
287 });
288 };
289 let data_eew = config.vtype().vsew().as_eew();
290 let vs3 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
291 program_counter,
292 config,
293 vs3,
294 data_eew,
295 )?;
296 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
297 program_counter,
298 config,
299 vs2,
300 index_eew,
301 )?;
302 if index_eew != data_eew {
305 zvexx_helpers::check_groups_disjoint::<Reg, Env, _, _>(
306 program_counter,
307 vs2,
308 vs3,
309 )?;
310 }
311 zvexx_store_helpers::execute_indexed_store(
312 env,
313 memory,
314 zvexx_load_helpers::VRegSegmentGroup::single(vs3),
315 vs2,
316 vm,
317 rs1_value.as_u64(),
318 )?;
319 }
320 Self::Vsseg {
322 vs3,
323 rs1: _,
324 eew,
325 vm_nf,
326 } => {
327 let vm = vm_nf.vm();
328 let nf = vm_nf.nf();
329 if !env.vector_instructions_allowed() {
330 ::core::hint::cold_path();
331 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
332 address: PackedAddress::new(
333 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
334 ),
335 });
336 }
337 let Some(config) = env.vector_config() else {
338 ::core::hint::cold_path();
339 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
340 address: PackedAddress::new(
341 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
342 ),
343 });
344 };
345 let vs3 =
346 zvexx_helpers::vreg_group::<Reg, Env, _, _>(program_counter, config, vs3, eew)?;
347 let vs3 =
348 zvexx_helpers::vreg_segment_group::<Reg, Env, _, _>(program_counter, vs3, nf)?;
349 zvexx_store_helpers::execute_unit_stride_store(
350 env,
351 memory,
352 vs3,
353 vm,
354 rs1_value.as_u64(),
355 )?;
356 }
357 Self::Vssseg {
359 vs3,
360 rs1: _,
361 rs2: _,
362 eew,
363 vm_nf,
364 } => {
365 let vm = vm_nf.vm();
366 let nf = vm_nf.nf();
367 if !env.vector_instructions_allowed() {
368 ::core::hint::cold_path();
369 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
370 address: PackedAddress::new(
371 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
372 ),
373 });
374 }
375 let Some(config) = env.vector_config() else {
376 ::core::hint::cold_path();
377 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
378 address: PackedAddress::new(
379 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
380 ),
381 });
382 };
383 let vs3 =
384 zvexx_helpers::vreg_group::<Reg, Env, _, _>(program_counter, config, vs3, eew)?;
385 let vs3 =
386 zvexx_helpers::vreg_segment_group::<Reg, Env, _, _>(program_counter, vs3, nf)?;
387 let stride = rs2_value.as_i64();
388 zvexx_store_helpers::execute_strided_store(
389 env,
390 memory,
391 vs3,
392 vm,
393 rs1_value.as_u64(),
394 stride,
395 )?;
396 }
397 Self::Vsuxseg {
399 vs3,
400 rs1: _,
401 vs2,
402 eew: index_eew,
403 vm_nf,
404 } => {
405 let vm = vm_nf.vm();
406 let nf = vm_nf.nf();
407 if !env.vector_instructions_allowed() {
408 ::core::hint::cold_path();
409 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
410 address: PackedAddress::new(
411 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
412 ),
413 });
414 }
415 let Some(config) = env.vector_config() else {
416 ::core::hint::cold_path();
417 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
418 address: PackedAddress::new(
419 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
420 ),
421 });
422 };
423 let data_eew = config.vtype().vsew().as_eew();
424 let vs3 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
425 program_counter,
426 config,
427 vs3,
428 data_eew,
429 )?;
430 let vs3 =
431 zvexx_helpers::vreg_segment_group::<Reg, Env, _, _>(program_counter, vs3, nf)?;
432 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
433 program_counter,
434 config,
435 vs2,
436 index_eew,
437 )?;
438 if index_eew != data_eew && vs3.fields().any(|field| field.overlaps(vs2)) {
441 ::core::hint::cold_path();
442 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
443 address: PackedAddress::new(
444 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
445 ),
446 });
447 }
448 zvexx_store_helpers::execute_indexed_store(
449 env,
450 memory,
451 vs3,
452 vs2,
453 vm,
454 rs1_value.as_u64(),
455 )?;
456 }
457 Self::Vsoxseg {
460 vs3,
461 rs1: _,
462 vs2,
463 eew: index_eew,
464 vm_nf,
465 } => {
466 let vm = vm_nf.vm();
467 let nf = vm_nf.nf();
468 if !env.vector_instructions_allowed() {
469 ::core::hint::cold_path();
470 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
471 address: PackedAddress::new(
472 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
473 ),
474 });
475 }
476 let Some(config) = env.vector_config() else {
477 ::core::hint::cold_path();
478 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
479 address: PackedAddress::new(
480 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
481 ),
482 });
483 };
484 let data_eew = config.vtype().vsew().as_eew();
485 let vs3 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
486 program_counter,
487 config,
488 vs3,
489 data_eew,
490 )?;
491 let vs3 =
492 zvexx_helpers::vreg_segment_group::<Reg, Env, _, _>(program_counter, vs3, nf)?;
493 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
494 program_counter,
495 config,
496 vs2,
497 index_eew,
498 )?;
499 if index_eew != data_eew && vs3.fields().any(|field| field.overlaps(vs2)) {
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 zvexx_store_helpers::execute_indexed_store(
510 env,
511 memory,
512 vs3,
513 vs2,
514 vm,
515 rs1_value.as_u64(),
516 )?;
517 }
518 }
519
520 ExecutionResult::ContinueNoWrite
521 }
522}