1#[cfg(test)]
4mod tests;
5pub mod zvexx_store_helpers;
6
7use crate::v::vector_registers::{VectorRegisters, 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, Hart> ExecutableInstructionOperands for ZveXxStoreInstruction<Hart>
21where
22 Reg: Register,
23 Hart: VectorHartConfig<Reg = Reg>,
24{
25}
26
27#[instruction_execution]
28const impl<Reg, Hart, Env> ExecutableInstructionCsr<Env> for ZveXxStoreInstruction<Hart>
29where
30 Reg: Register,
31 Hart: VectorHartConfig<Reg = Reg>,
32{
33}
34
35#[instruction_execution]
36impl<Reg, Hart, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
37 for ZveXxStoreInstruction<Hart>
38where
39 Reg: Register,
40 Hart: VectorHartConfig<Reg = Reg>,
41 Regs: RegisterFile<Reg>,
42 Env: VectorRegistersExt<Hart = Hart>,
43 Memory: VirtualMemory,
44 PC: ProgramCounter<Reg::Type, Memory>,
45{
46 #[inline(always)]
47 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
48 fn execute(
49 self,
50 Rs1Rs2OperandValues {
51 rs1_value,
52 rs2_value,
53 }: Rs1Rs2OperandValues<Reg::Type>,
54 _regs: &mut Regs,
55 env: &mut Env,
56 memory: &mut Memory,
57 program_counter: &PC,
58 ) -> ExecutionResult<Reg> {
59 match self {
60 Self::Vsr { vs3, rs1: _, nreg } => {
66 let nreg = nreg.num_registers();
67 if !env.vector_instructions_allowed() {
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 Some(vs3) = zvexx_load_helpers::VRegGroup::whole_registers(vs3, nreg, Eew::E8)
76 else {
77 ::core::hint::cold_path();
78 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
79 address: PackedAddress::new(
80 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
81 ),
82 });
83 };
84 let vl = vs3.vl().get();
86 if env.vstart() >= vl {
88 ::core::hint::cold_path();
89 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
90 address: PackedAddress::new(
91 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
92 ),
93 });
94 }
95 zvexx_store_helpers::execute_unit_stride_store(
96 env,
97 memory,
98 zvexx_load_helpers::VRegSegmentGroup::single(vs3),
99 true,
100 rs1_value.as_u64(),
101 )?;
102 }
103 Self::Vsm { vs3, rs1: _ } => {
107 if !env.vector_instructions_allowed() {
108 ::core::hint::cold_path();
109 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
110 address: PackedAddress::new(
111 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
112 ),
113 });
114 }
115 let Some(config) = env.vector_config() else {
116 ::core::hint::cold_path();
117 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
118 address: PackedAddress::new(
119 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
120 ),
121 });
122 };
123 let Some(vs3) =
126 zvexx_load_helpers::VRegGroup::whole_registers(vs3, VRegGroupSize::R1, Eew::E8)
127 .and_then(|vs3| vs3.with_vl(Vl::from(config.vl().bytes())))
128 else {
129 ::core::hint::cold_path();
130 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
131 address: PackedAddress::new(
132 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
133 ),
134 });
135 };
136 zvexx_store_helpers::execute_unit_stride_store(
137 env,
138 memory,
139 zvexx_load_helpers::VRegSegmentGroup::single(vs3),
140 true,
141 rs1_value.as_u64(),
142 )?;
143 }
144 Self::Vse {
150 vs3,
151 rs1: _,
152 vm,
153 eew,
154 } => {
155 if !env.vector_instructions_allowed() {
156 ::core::hint::cold_path();
157 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
158 address: PackedAddress::new(
159 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
160 ),
161 });
162 }
163 let Some(config) = env.vector_config() else {
164 ::core::hint::cold_path();
165 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
166 address: PackedAddress::new(
167 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
168 ),
169 });
170 };
171 let vs3 =
172 zvexx_helpers::vreg_group::<Reg, Env, _, _>(program_counter, config, vs3, eew)?;
173 zvexx_store_helpers::execute_unit_stride_store(
174 env,
175 memory,
176 zvexx_load_helpers::VRegSegmentGroup::single(vs3),
177 vm,
178 rs1_value.as_u64(),
179 )?;
180 }
181 Self::Vsse {
183 vs3,
184 rs1: _,
185 rs2: _,
186 vm,
187 eew,
188 } => {
189 if !env.vector_instructions_allowed() {
190 ::core::hint::cold_path();
191 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
192 address: PackedAddress::new(
193 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
194 ),
195 });
196 }
197 let Some(config) = env.vector_config() else {
198 ::core::hint::cold_path();
199 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
200 address: PackedAddress::new(
201 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
202 ),
203 });
204 };
205 let vs3 =
206 zvexx_helpers::vreg_group::<Reg, Env, _, _>(program_counter, config, vs3, eew)?;
207 let stride = rs2_value.as_i64();
208 zvexx_store_helpers::execute_strided_store(
209 env,
210 memory,
211 zvexx_load_helpers::VRegSegmentGroup::single(vs3),
212 vm,
213 rs1_value.as_u64(),
214 stride,
215 )?;
216 }
217 Self::Vsuxei {
219 vs3,
220 rs1: _,
221 vs2,
222 vm,
223 eew: index_eew,
224 } => {
225 if !env.vector_instructions_allowed() {
226 ::core::hint::cold_path();
227 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
228 address: PackedAddress::new(
229 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
230 ),
231 });
232 }
233 let Some(config) = env.vector_config() else {
234 ::core::hint::cold_path();
235 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
236 address: PackedAddress::new(
237 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
238 ),
239 });
240 };
241 let data_eew = config.vtype().vsew().as_eew();
242 let vs3 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
243 program_counter,
244 config,
245 vs3,
246 data_eew,
247 )?;
248 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
249 program_counter,
250 config,
251 vs2,
252 index_eew,
253 )?;
254 if index_eew != data_eew {
257 zvexx_helpers::check_groups_disjoint::<Reg, Env, _, _>(
258 program_counter,
259 vs2,
260 vs3,
261 )?;
262 }
263 zvexx_store_helpers::execute_indexed_store(
264 env,
265 memory,
266 zvexx_load_helpers::VRegSegmentGroup::single(vs3),
267 vs2,
268 vm,
269 rs1_value.as_u64(),
270 )?;
271 }
272 Self::Vsoxei {
276 vs3,
277 rs1: _,
278 vs2,
279 vm,
280 eew: index_eew,
281 } => {
282 if !env.vector_instructions_allowed() {
283 ::core::hint::cold_path();
284 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
285 address: PackedAddress::new(
286 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
287 ),
288 });
289 }
290 let Some(config) = env.vector_config() else {
291 ::core::hint::cold_path();
292 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
293 address: PackedAddress::new(
294 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
295 ),
296 });
297 };
298 let data_eew = config.vtype().vsew().as_eew();
299 let vs3 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
300 program_counter,
301 config,
302 vs3,
303 data_eew,
304 )?;
305 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
306 program_counter,
307 config,
308 vs2,
309 index_eew,
310 )?;
311 if index_eew != data_eew {
314 zvexx_helpers::check_groups_disjoint::<Reg, Env, _, _>(
315 program_counter,
316 vs2,
317 vs3,
318 )?;
319 }
320 zvexx_store_helpers::execute_indexed_store(
321 env,
322 memory,
323 zvexx_load_helpers::VRegSegmentGroup::single(vs3),
324 vs2,
325 vm,
326 rs1_value.as_u64(),
327 )?;
328 }
329 Self::Vsseg {
331 vs3,
332 rs1: _,
333 eew,
334 vm_nf,
335 } => {
336 let vm = vm_nf.vm();
337 let nf = vm_nf.nf();
338 if !env.vector_instructions_allowed() {
339 ::core::hint::cold_path();
340 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
341 address: PackedAddress::new(
342 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
343 ),
344 });
345 }
346 let Some(config) = env.vector_config() else {
347 ::core::hint::cold_path();
348 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
349 address: PackedAddress::new(
350 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
351 ),
352 });
353 };
354 let vs3 =
355 zvexx_helpers::vreg_group::<Reg, Env, _, _>(program_counter, config, vs3, eew)?;
356 let vs3 =
357 zvexx_helpers::vreg_segment_group::<Reg, Env, _, _>(program_counter, vs3, nf)?;
358 zvexx_store_helpers::execute_unit_stride_store(
359 env,
360 memory,
361 vs3,
362 vm,
363 rs1_value.as_u64(),
364 )?;
365 }
366 Self::Vssseg {
368 vs3,
369 rs1: _,
370 rs2: _,
371 eew,
372 vm_nf,
373 } => {
374 let vm = vm_nf.vm();
375 let nf = vm_nf.nf();
376 if !env.vector_instructions_allowed() {
377 ::core::hint::cold_path();
378 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
379 address: PackedAddress::new(
380 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
381 ),
382 });
383 }
384 let Some(config) = env.vector_config() else {
385 ::core::hint::cold_path();
386 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
387 address: PackedAddress::new(
388 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
389 ),
390 });
391 };
392 let vs3 =
393 zvexx_helpers::vreg_group::<Reg, Env, _, _>(program_counter, config, vs3, eew)?;
394 let vs3 =
395 zvexx_helpers::vreg_segment_group::<Reg, Env, _, _>(program_counter, vs3, nf)?;
396 let stride = rs2_value.as_i64();
397 zvexx_store_helpers::execute_strided_store(
398 env,
399 memory,
400 vs3,
401 vm,
402 rs1_value.as_u64(),
403 stride,
404 )?;
405 }
406 Self::Vsuxseg {
408 vs3,
409 rs1: _,
410 vs2,
411 eew: index_eew,
412 vm_nf,
413 } => {
414 let vm = vm_nf.vm();
415 let nf = vm_nf.nf();
416 if !env.vector_instructions_allowed() {
417 ::core::hint::cold_path();
418 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
419 address: PackedAddress::new(
420 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
421 ),
422 });
423 }
424 let Some(config) = env.vector_config() else {
425 ::core::hint::cold_path();
426 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
427 address: PackedAddress::new(
428 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
429 ),
430 });
431 };
432 let data_eew = config.vtype().vsew().as_eew();
433 let vs3 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
434 program_counter,
435 config,
436 vs3,
437 data_eew,
438 )?;
439 let vs3 =
440 zvexx_helpers::vreg_segment_group::<Reg, Env, _, _>(program_counter, vs3, nf)?;
441 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
442 program_counter,
443 config,
444 vs2,
445 index_eew,
446 )?;
447 if index_eew != data_eew && vs3.fields().any(|field| field.overlaps(vs2)) {
450 ::core::hint::cold_path();
451 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
452 address: PackedAddress::new(
453 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
454 ),
455 });
456 }
457 zvexx_store_helpers::execute_indexed_store(
458 env,
459 memory,
460 vs3,
461 vs2,
462 vm,
463 rs1_value.as_u64(),
464 )?;
465 }
466 Self::Vsoxseg {
469 vs3,
470 rs1: _,
471 vs2,
472 eew: index_eew,
473 vm_nf,
474 } => {
475 let vm = vm_nf.vm();
476 let nf = vm_nf.nf();
477 if !env.vector_instructions_allowed() {
478 ::core::hint::cold_path();
479 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
480 address: PackedAddress::new(
481 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
482 ),
483 });
484 }
485 let Some(config) = env.vector_config() else {
486 ::core::hint::cold_path();
487 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
488 address: PackedAddress::new(
489 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
490 ),
491 });
492 };
493 let data_eew = config.vtype().vsew().as_eew();
494 let vs3 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
495 program_counter,
496 config,
497 vs3,
498 data_eew,
499 )?;
500 let vs3 =
501 zvexx_helpers::vreg_segment_group::<Reg, Env, _, _>(program_counter, vs3, nf)?;
502 let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
503 program_counter,
504 config,
505 vs2,
506 index_eew,
507 )?;
508 if index_eew != data_eew && vs3.fields().any(|field| field.overlaps(vs2)) {
511 ::core::hint::cold_path();
512 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
513 address: PackedAddress::new(
514 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
515 ),
516 });
517 }
518 zvexx_store_helpers::execute_indexed_store(
519 env,
520 memory,
521 vs3,
522 vs2,
523 vm,
524 rs1_value.as_u64(),
525 )?;
526 }
527 }
528
529 ExecutionResult::ContinueNoWrite
530 }
531}