1#[cfg(test)]
4mod tests;
5pub mod zvexx_muldiv_helpers;
6
7use crate::v::vector_registers::VectorRegistersExt;
8use crate::v::zvexx::zvexx_helpers;
9use crate::{
10 ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands, ExecutionError,
11 ExecutionResult, FetchInstructionResult, InstructionFetcher, OpaqueThreadedExecutionResult,
12 PackedAddress, ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands,
13 ThreadedExecutableInstruction, ThreadedExecutionResult, VirtualMemory,
14};
15use ab_riscv_macros::instruction_execution;
16use ab_riscv_primitives::prelude::*;
17
18#[instruction_execution]
19const impl<Reg> ExecutableInstructionOperands for ZveXxMulDivInstruction<Reg> where Reg: Register {}
20
21#[instruction_execution]
22const impl<Reg, Env> ExecutableInstructionCsr<Env> for ZveXxMulDivInstruction<Reg> where
23 Reg: Register
24{
25}
26
27#[instruction_execution]
28impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
29 for ZveXxMulDivInstruction<Reg>
30where
31 Reg: Register,
32 Regs: RegisterFile<Reg>,
33 Env: VectorRegistersExt<Reg>,
34 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
35 Memory: VirtualMemory,
36 PC: ProgramCounter<Reg::Type, Memory>,
37{
38 #[inline(always)]
39 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
40 fn execute(
41 self,
42 Rs1Rs2OperandValues {
43 rs1_value,
44 rs2_value: _,
45 }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
46 _regs: &mut Regs,
47 env: &mut Env,
48 _memory: &mut Memory,
49 program_counter: &mut PC,
50 ) -> ExecutionResult<Self::Reg> {
51 match self {
52 Self::VmulVv { vd, vs2, vs1, vm } => {
54 if !env.vector_instructions_allowed() {
55 ::core::hint::cold_path();
56 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
57 address: PackedAddress::new(
58 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
59 ),
60 });
61 }
62 let Some(vtype) = env.vtype() else {
63 ::core::hint::cold_path();
64 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
65 address: PackedAddress::new(
66 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
67 ),
68 });
69 };
70 let group_regs = vtype.vlmul().register_count();
71 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
72 program_counter,
73 vd,
74 group_regs,
75 )?;
76 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
77 program_counter,
78 vs2,
79 group_regs,
80 )?;
81 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
82 program_counter,
83 vs1,
84 group_regs,
85 )?;
86 if !vm && vd == VReg::V0 {
87 ::core::hint::cold_path();
88 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
89 address: PackedAddress::new(
90 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
91 ),
92 });
93 }
94 let sew = vtype.vsew();
95 unsafe {
97 zvexx_muldiv_helpers::execute_arith_op(
98 env,
99 vd,
100 vs2,
101 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
102 vm,
103 sew,
104 |a, b, _| a.wrapping_mul(b),
105 );
106 }
107 }
108 Self::VmulVx {
109 vd,
110 vs2,
111 rs1: _,
112 vm,
113 } => {
114 if !env.vector_instructions_allowed() {
115 ::core::hint::cold_path();
116 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
117 address: PackedAddress::new(
118 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
119 ),
120 });
121 }
122 let Some(vtype) = env.vtype() else {
123 ::core::hint::cold_path();
124 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
125 address: PackedAddress::new(
126 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
127 ),
128 });
129 };
130 let group_regs = vtype.vlmul().register_count();
131 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
132 program_counter,
133 vd,
134 group_regs,
135 )?;
136 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
137 program_counter,
138 vs2,
139 group_regs,
140 )?;
141 if !vm && vd == VReg::V0 {
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 sew = vtype.vsew();
150 let scalar = rs1_value.as_i64().cast_unsigned();
151 unsafe {
153 zvexx_muldiv_helpers::execute_arith_op(
154 env,
155 vd,
156 vs2,
157 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
158 vm,
159 sew,
160 |a, b, _| a.wrapping_mul(b),
161 );
162 }
163 }
164 Self::VmulhVv { vd, vs2, vs1, vm } => {
166 if !env.vector_instructions_allowed() {
167 ::core::hint::cold_path();
168 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
169 address: PackedAddress::new(
170 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
171 ),
172 });
173 }
174 let Some(vtype) = env.vtype() else {
175 ::core::hint::cold_path();
176 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
177 address: PackedAddress::new(
178 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
179 ),
180 });
181 };
182 if !Self::implements_extension::<V<_>>() && vtype.vsew() == Vsew::E64 {
186 ::core::hint::cold_path();
187 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
188 address: PackedAddress::new(
189 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
190 ),
191 });
192 }
193 let group_regs = vtype.vlmul().register_count();
194 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
195 program_counter,
196 vd,
197 group_regs,
198 )?;
199 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
200 program_counter,
201 vs2,
202 group_regs,
203 )?;
204 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
205 program_counter,
206 vs1,
207 group_regs,
208 )?;
209 if !vm && vd == VReg::V0 {
210 ::core::hint::cold_path();
211 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
212 address: PackedAddress::new(
213 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
214 ),
215 });
216 }
217 let sew = vtype.vsew();
218 unsafe {
220 zvexx_muldiv_helpers::execute_arith_op(
221 env,
222 vd,
223 vs2,
224 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
225 vm,
226 sew,
227 zvexx_muldiv_helpers::mulh_ss,
228 );
229 }
230 }
231 Self::VmulhVx {
232 vd,
233 vs2,
234 rs1: _,
235 vm,
236 } => {
237 if !env.vector_instructions_allowed() {
238 ::core::hint::cold_path();
239 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
240 address: PackedAddress::new(
241 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
242 ),
243 });
244 }
245 let Some(vtype) = env.vtype() else {
246 ::core::hint::cold_path();
247 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
248 address: PackedAddress::new(
249 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
250 ),
251 });
252 };
253 if !Self::implements_extension::<V<_>>() && vtype.vsew() == Vsew::E64 {
257 ::core::hint::cold_path();
258 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
259 address: PackedAddress::new(
260 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
261 ),
262 });
263 }
264 let group_regs = vtype.vlmul().register_count();
265 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
266 program_counter,
267 vd,
268 group_regs,
269 )?;
270 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
271 program_counter,
272 vs2,
273 group_regs,
274 )?;
275 if !vm && vd == VReg::V0 {
276 ::core::hint::cold_path();
277 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
278 address: PackedAddress::new(
279 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
280 ),
281 });
282 }
283 let sew = vtype.vsew();
284 let scalar = rs1_value.as_u64();
285 unsafe {
287 zvexx_muldiv_helpers::execute_arith_op(
288 env,
289 vd,
290 vs2,
291 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
292 vm,
293 sew,
294 zvexx_muldiv_helpers::mulh_ss,
295 );
296 }
297 }
298 Self::VmulhuVv { vd, vs2, vs1, vm } => {
300 if !env.vector_instructions_allowed() {
301 ::core::hint::cold_path();
302 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
303 address: PackedAddress::new(
304 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
305 ),
306 });
307 }
308 let Some(vtype) = env.vtype() else {
309 ::core::hint::cold_path();
310 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
311 address: PackedAddress::new(
312 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
313 ),
314 });
315 };
316 if !Self::implements_extension::<V<_>>() && vtype.vsew() == Vsew::E64 {
320 ::core::hint::cold_path();
321 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
322 address: PackedAddress::new(
323 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
324 ),
325 });
326 }
327 let group_regs = vtype.vlmul().register_count();
328 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
329 program_counter,
330 vd,
331 group_regs,
332 )?;
333 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
334 program_counter,
335 vs2,
336 group_regs,
337 )?;
338 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
339 program_counter,
340 vs1,
341 group_regs,
342 )?;
343 if !vm && vd == VReg::V0 {
344 ::core::hint::cold_path();
345 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
346 address: PackedAddress::new(
347 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
348 ),
349 });
350 }
351 let sew = vtype.vsew();
352 unsafe {
354 zvexx_muldiv_helpers::execute_arith_op(
355 env,
356 vd,
357 vs2,
358 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
359 vm,
360 sew,
361 zvexx_muldiv_helpers::mulhu_uu,
362 );
363 }
364 }
365 Self::VmulhuVx {
366 vd,
367 vs2,
368 rs1: _,
369 vm,
370 } => {
371 if !env.vector_instructions_allowed() {
372 ::core::hint::cold_path();
373 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
374 address: PackedAddress::new(
375 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
376 ),
377 });
378 }
379 let Some(vtype) = env.vtype() else {
380 ::core::hint::cold_path();
381 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
382 address: PackedAddress::new(
383 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
384 ),
385 });
386 };
387 if !Self::implements_extension::<V<_>>() && vtype.vsew() == Vsew::E64 {
391 ::core::hint::cold_path();
392 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
393 address: PackedAddress::new(
394 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
395 ),
396 });
397 }
398 let group_regs = vtype.vlmul().register_count();
399 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
400 program_counter,
401 vd,
402 group_regs,
403 )?;
404 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
405 program_counter,
406 vs2,
407 group_regs,
408 )?;
409 if !vm && vd == VReg::V0 {
410 ::core::hint::cold_path();
411 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
412 address: PackedAddress::new(
413 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
414 ),
415 });
416 }
417 let sew = vtype.vsew();
418 let scalar = rs1_value.as_u64();
419 unsafe {
421 zvexx_muldiv_helpers::execute_arith_op(
422 env,
423 vd,
424 vs2,
425 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
426 vm,
427 sew,
428 zvexx_muldiv_helpers::mulhu_uu,
429 );
430 }
431 }
432 Self::VmulhsuVv { vd, vs2, vs1, vm } => {
434 if !env.vector_instructions_allowed() {
435 ::core::hint::cold_path();
436 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
437 address: PackedAddress::new(
438 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
439 ),
440 });
441 }
442 let Some(vtype) = env.vtype() else {
443 ::core::hint::cold_path();
444 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
445 address: PackedAddress::new(
446 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
447 ),
448 });
449 };
450 if !Self::implements_extension::<V<_>>() && vtype.vsew() == Vsew::E64 {
454 ::core::hint::cold_path();
455 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
456 address: PackedAddress::new(
457 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
458 ),
459 });
460 }
461 let group_regs = vtype.vlmul().register_count();
462 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
463 program_counter,
464 vd,
465 group_regs,
466 )?;
467 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
468 program_counter,
469 vs2,
470 group_regs,
471 )?;
472 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
473 program_counter,
474 vs1,
475 group_regs,
476 )?;
477 if !vm && vd == VReg::V0 {
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 sew = vtype.vsew();
486 unsafe {
488 zvexx_muldiv_helpers::execute_arith_op(
489 env,
490 vd,
491 vs2,
492 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
493 vm,
494 sew,
495 zvexx_muldiv_helpers::mulhsu_su,
497 );
498 }
499 }
500 Self::VmulhsuVx {
501 vd,
502 vs2,
503 rs1: _,
504 vm,
505 } => {
506 if !env.vector_instructions_allowed() {
507 ::core::hint::cold_path();
508 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
509 address: PackedAddress::new(
510 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
511 ),
512 });
513 }
514 let Some(vtype) = env.vtype() else {
515 ::core::hint::cold_path();
516 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
517 address: PackedAddress::new(
518 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
519 ),
520 });
521 };
522 if !Self::implements_extension::<V<_>>() && vtype.vsew() == Vsew::E64 {
526 ::core::hint::cold_path();
527 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
528 address: PackedAddress::new(
529 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
530 ),
531 });
532 }
533 let group_regs = vtype.vlmul().register_count();
534 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
535 program_counter,
536 vd,
537 group_regs,
538 )?;
539 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
540 program_counter,
541 vs2,
542 group_regs,
543 )?;
544 if !vm && vd == VReg::V0 {
545 ::core::hint::cold_path();
546 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
547 address: PackedAddress::new(
548 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
549 ),
550 });
551 }
552 let sew = vtype.vsew();
553 let scalar = rs1_value.as_u64();
555 unsafe {
557 zvexx_muldiv_helpers::execute_arith_op(
558 env,
559 vd,
560 vs2,
561 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
562 vm,
563 sew,
564 zvexx_muldiv_helpers::mulhsu_su,
566 );
567 }
568 }
569 Self::VdivuVv { vd, vs2, vs1, vm } => {
571 if !env.vector_instructions_allowed() {
572 ::core::hint::cold_path();
573 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
574 address: PackedAddress::new(
575 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
576 ),
577 });
578 }
579 let Some(vtype) = env.vtype() else {
580 ::core::hint::cold_path();
581 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
582 address: PackedAddress::new(
583 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
584 ),
585 });
586 };
587 let group_regs = vtype.vlmul().register_count();
588 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
589 program_counter,
590 vd,
591 group_regs,
592 )?;
593 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
594 program_counter,
595 vs2,
596 group_regs,
597 )?;
598 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
599 program_counter,
600 vs1,
601 group_regs,
602 )?;
603 if !vm && vd == VReg::V0 {
604 ::core::hint::cold_path();
605 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
606 address: PackedAddress::new(
607 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
608 ),
609 });
610 }
611 let sew = vtype.vsew();
612 unsafe {
614 zvexx_muldiv_helpers::execute_arith_op(
615 env,
616 vd,
617 vs2,
618 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
619 vm,
620 sew,
621 |a, b, sew| {
623 let mask = zvexx_muldiv_helpers::sew_mask(sew);
624 let dividend = a & mask;
625 let divisor = b & mask;
626 dividend.checked_div(divisor).unwrap_or(mask)
627 },
628 );
629 }
630 }
631 Self::VdivuVx {
632 vd,
633 vs2,
634 rs1: _,
635 vm,
636 } => {
637 if !env.vector_instructions_allowed() {
638 ::core::hint::cold_path();
639 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
640 address: PackedAddress::new(
641 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
642 ),
643 });
644 }
645 let Some(vtype) = env.vtype() else {
646 ::core::hint::cold_path();
647 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
648 address: PackedAddress::new(
649 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
650 ),
651 });
652 };
653 let group_regs = vtype.vlmul().register_count();
654 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
655 program_counter,
656 vd,
657 group_regs,
658 )?;
659 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
660 program_counter,
661 vs2,
662 group_regs,
663 )?;
664 if !vm && vd == VReg::V0 {
665 ::core::hint::cold_path();
666 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
667 address: PackedAddress::new(
668 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
669 ),
670 });
671 }
672 let sew = vtype.vsew();
673 let scalar = rs1_value.as_i64().cast_unsigned();
674 unsafe {
676 zvexx_muldiv_helpers::execute_arith_op(
677 env,
678 vd,
679 vs2,
680 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
681 vm,
682 sew,
683 |a, b, sew| {
684 let mask = zvexx_muldiv_helpers::sew_mask(sew);
685 let dividend = a & mask;
686 let divisor = b & mask;
687 dividend.checked_div(divisor).unwrap_or(mask)
688 },
689 );
690 }
691 }
692 Self::VdivVv { vd, vs2, vs1, vm } => {
694 if !env.vector_instructions_allowed() {
695 ::core::hint::cold_path();
696 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
697 address: PackedAddress::new(
698 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
699 ),
700 });
701 }
702 let Some(vtype) = env.vtype() else {
703 ::core::hint::cold_path();
704 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
705 address: PackedAddress::new(
706 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
707 ),
708 });
709 };
710 let group_regs = vtype.vlmul().register_count();
711 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
712 program_counter,
713 vd,
714 group_regs,
715 )?;
716 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
717 program_counter,
718 vs2,
719 group_regs,
720 )?;
721 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
722 program_counter,
723 vs1,
724 group_regs,
725 )?;
726 if !vm && vd == VReg::V0 {
727 ::core::hint::cold_path();
728 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
729 address: PackedAddress::new(
730 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
731 ),
732 });
733 }
734 let sew = vtype.vsew();
735 unsafe {
737 zvexx_muldiv_helpers::execute_arith_op(
738 env,
739 vd,
740 vs2,
741 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
742 vm,
743 sew,
744 zvexx_muldiv_helpers::sdiv,
745 );
746 }
747 }
748 Self::VdivVx {
749 vd,
750 vs2,
751 rs1: _,
752 vm,
753 } => {
754 if !env.vector_instructions_allowed() {
755 ::core::hint::cold_path();
756 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
757 address: PackedAddress::new(
758 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
759 ),
760 });
761 }
762 let Some(vtype) = env.vtype() else {
763 ::core::hint::cold_path();
764 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
765 address: PackedAddress::new(
766 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
767 ),
768 });
769 };
770 let group_regs = vtype.vlmul().register_count();
771 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
772 program_counter,
773 vd,
774 group_regs,
775 )?;
776 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
777 program_counter,
778 vs2,
779 group_regs,
780 )?;
781 if !vm && vd == VReg::V0 {
782 ::core::hint::cold_path();
783 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
784 address: PackedAddress::new(
785 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
786 ),
787 });
788 }
789 let sew = vtype.vsew();
790 let scalar = rs1_value.as_i64().cast_unsigned();
791 unsafe {
793 zvexx_muldiv_helpers::execute_arith_op(
794 env,
795 vd,
796 vs2,
797 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
798 vm,
799 sew,
800 zvexx_muldiv_helpers::sdiv,
801 );
802 }
803 }
804 Self::VremuVv { vd, vs2, vs1, vm } => {
806 if !env.vector_instructions_allowed() {
807 ::core::hint::cold_path();
808 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
809 address: PackedAddress::new(
810 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
811 ),
812 });
813 }
814 let Some(vtype) = env.vtype() else {
815 ::core::hint::cold_path();
816 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
817 address: PackedAddress::new(
818 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
819 ),
820 });
821 };
822 let group_regs = vtype.vlmul().register_count();
823 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
824 program_counter,
825 vd,
826 group_regs,
827 )?;
828 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
829 program_counter,
830 vs2,
831 group_regs,
832 )?;
833 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
834 program_counter,
835 vs1,
836 group_regs,
837 )?;
838 if !vm && vd == VReg::V0 {
839 ::core::hint::cold_path();
840 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
841 address: PackedAddress::new(
842 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
843 ),
844 });
845 }
846 let sew = vtype.vsew();
847 unsafe {
849 zvexx_muldiv_helpers::execute_arith_op(
850 env,
851 vd,
852 vs2,
853 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
854 vm,
855 sew,
856 |a, b, sew| {
858 let mask = zvexx_muldiv_helpers::sew_mask(sew);
859 let dividend = a & mask;
860 let divisor = b & mask;
861 if divisor == 0 {
862 dividend
863 } else {
864 dividend % divisor
865 }
866 },
867 );
868 }
869 }
870 Self::VremuVx {
871 vd,
872 vs2,
873 rs1: _,
874 vm,
875 } => {
876 if !env.vector_instructions_allowed() {
877 ::core::hint::cold_path();
878 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
879 address: PackedAddress::new(
880 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
881 ),
882 });
883 }
884 let Some(vtype) = env.vtype() else {
885 ::core::hint::cold_path();
886 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
887 address: PackedAddress::new(
888 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
889 ),
890 });
891 };
892 let group_regs = vtype.vlmul().register_count();
893 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
894 program_counter,
895 vd,
896 group_regs,
897 )?;
898 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
899 program_counter,
900 vs2,
901 group_regs,
902 )?;
903 if !vm && vd == VReg::V0 {
904 ::core::hint::cold_path();
905 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
906 address: PackedAddress::new(
907 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
908 ),
909 });
910 }
911 let sew = vtype.vsew();
912 let scalar = rs1_value.as_i64().cast_unsigned();
913 unsafe {
915 zvexx_muldiv_helpers::execute_arith_op(
916 env,
917 vd,
918 vs2,
919 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
920 vm,
921 sew,
922 |a, b, sew| {
923 let mask = zvexx_muldiv_helpers::sew_mask(sew);
924 let dividend = a & mask;
925 let divisor = b & mask;
926 if divisor == 0 {
927 dividend
928 } else {
929 dividend % divisor
930 }
931 },
932 );
933 }
934 }
935 Self::VremVv { vd, vs2, vs1, vm } => {
937 if !env.vector_instructions_allowed() {
938 ::core::hint::cold_path();
939 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
940 address: PackedAddress::new(
941 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
942 ),
943 });
944 }
945 let Some(vtype) = env.vtype() else {
946 ::core::hint::cold_path();
947 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
948 address: PackedAddress::new(
949 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
950 ),
951 });
952 };
953 let group_regs = vtype.vlmul().register_count();
954 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
955 program_counter,
956 vd,
957 group_regs,
958 )?;
959 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
960 program_counter,
961 vs2,
962 group_regs,
963 )?;
964 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
965 program_counter,
966 vs1,
967 group_regs,
968 )?;
969 if !vm && vd == VReg::V0 {
970 ::core::hint::cold_path();
971 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
972 address: PackedAddress::new(
973 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
974 ),
975 });
976 }
977 let sew = vtype.vsew();
978 unsafe {
980 zvexx_muldiv_helpers::execute_arith_op(
981 env,
982 vd,
983 vs2,
984 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
985 vm,
986 sew,
987 zvexx_muldiv_helpers::srem,
988 );
989 }
990 }
991 Self::VremVx {
992 vd,
993 vs2,
994 rs1: _,
995 vm,
996 } => {
997 if !env.vector_instructions_allowed() {
998 ::core::hint::cold_path();
999 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1000 address: PackedAddress::new(
1001 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1002 ),
1003 });
1004 }
1005 let Some(vtype) = env.vtype() else {
1006 ::core::hint::cold_path();
1007 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1008 address: PackedAddress::new(
1009 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1010 ),
1011 });
1012 };
1013 let group_regs = vtype.vlmul().register_count();
1014 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1015 program_counter,
1016 vd,
1017 group_regs,
1018 )?;
1019 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1020 program_counter,
1021 vs2,
1022 group_regs,
1023 )?;
1024 if !vm && vd == VReg::V0 {
1025 ::core::hint::cold_path();
1026 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1027 address: PackedAddress::new(
1028 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1029 ),
1030 });
1031 }
1032 let sew = vtype.vsew();
1033 let scalar = rs1_value.as_i64().cast_unsigned();
1034 unsafe {
1036 zvexx_muldiv_helpers::execute_arith_op(
1037 env,
1038 vd,
1039 vs2,
1040 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
1041 vm,
1042 sew,
1043 zvexx_muldiv_helpers::srem,
1044 );
1045 }
1046 }
1047 Self::VwmuluVv { vd, vs2, vs1, vm } => {
1049 if !env.vector_instructions_allowed() {
1050 ::core::hint::cold_path();
1051 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1052 address: PackedAddress::new(
1053 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1054 ),
1055 });
1056 }
1057 let Some(vtype) = env.vtype() else {
1058 ::core::hint::cold_path();
1059 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1060 address: PackedAddress::new(
1061 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1062 ),
1063 });
1064 };
1065 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
1068 ::core::hint::cold_path();
1069 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1070 address: PackedAddress::new(
1071 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1072 ),
1073 });
1074 }
1075 let group_regs = vtype.vlmul().register_count();
1076 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
1078 vtype.vlmul(),
1079 )
1080 .ok_or(ExecutionError::IllegalInstruction {
1081 address: PackedAddress::new(
1082 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1083 ),
1084 })?;
1085 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1086 program_counter,
1087 vd,
1088 dest_group_regs,
1089 )?;
1090 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1091 program_counter,
1092 vs2,
1093 group_regs,
1094 )?;
1095 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1096 program_counter,
1097 vs1,
1098 group_regs,
1099 )?;
1100 if !vm && vd == VReg::V0 {
1101 ::core::hint::cold_path();
1102 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1103 address: PackedAddress::new(
1104 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1105 ),
1106 });
1107 }
1108 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1110 program_counter,
1111 vd,
1112 vs2,
1113 dest_group_regs,
1114 group_regs,
1115 )?;
1116 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1117 program_counter,
1118 vd,
1119 vs1,
1120 dest_group_regs,
1121 group_regs,
1122 )?;
1123 let sew = vtype.vsew();
1124 unsafe {
1126 zvexx_muldiv_helpers::execute_widening_op(
1127 env,
1128 vd,
1129 vs2,
1130 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
1131 vm,
1132 sew,
1133 |a, b, sew| {
1134 let mask = zvexx_muldiv_helpers::sew_mask(sew);
1135 (a & mask).wrapping_mul(b & mask)
1136 },
1137 );
1138 }
1139 }
1140 Self::VwmuluVx {
1141 vd,
1142 vs2,
1143 rs1: _,
1144 vm,
1145 } => {
1146 if !env.vector_instructions_allowed() {
1147 ::core::hint::cold_path();
1148 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1149 address: PackedAddress::new(
1150 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1151 ),
1152 });
1153 }
1154 let Some(vtype) = env.vtype() else {
1155 ::core::hint::cold_path();
1156 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1157 address: PackedAddress::new(
1158 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1159 ),
1160 });
1161 };
1162 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
1165 ::core::hint::cold_path();
1166 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1167 address: PackedAddress::new(
1168 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1169 ),
1170 });
1171 }
1172 let group_regs = vtype.vlmul().register_count();
1173 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
1174 vtype.vlmul(),
1175 )
1176 .ok_or(ExecutionError::IllegalInstruction {
1177 address: PackedAddress::new(
1178 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1179 ),
1180 })?;
1181 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1182 program_counter,
1183 vd,
1184 dest_group_regs,
1185 )?;
1186 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1187 program_counter,
1188 vs2,
1189 group_regs,
1190 )?;
1191 if !vm && vd == VReg::V0 {
1192 ::core::hint::cold_path();
1193 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1194 address: PackedAddress::new(
1195 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1196 ),
1197 });
1198 }
1199 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1200 program_counter,
1201 vd,
1202 vs2,
1203 dest_group_regs,
1204 group_regs,
1205 )?;
1206 let sew = vtype.vsew();
1207 let scalar = rs1_value.as_u64();
1208 unsafe {
1210 zvexx_muldiv_helpers::execute_widening_op(
1211 env,
1212 vd,
1213 vs2,
1214 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
1215 vm,
1216 sew,
1217 |a, b, sew| {
1218 let mask = zvexx_muldiv_helpers::sew_mask(sew);
1219 (a & mask).wrapping_mul(b & mask)
1220 },
1221 );
1222 }
1223 }
1224 Self::VwmulsuVv { vd, vs2, vs1, vm } => {
1226 if !env.vector_instructions_allowed() {
1227 ::core::hint::cold_path();
1228 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1229 address: PackedAddress::new(
1230 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1231 ),
1232 });
1233 }
1234 let Some(vtype) = env.vtype() else {
1235 ::core::hint::cold_path();
1236 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1237 address: PackedAddress::new(
1238 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1239 ),
1240 });
1241 };
1242 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
1245 ::core::hint::cold_path();
1246 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1247 address: PackedAddress::new(
1248 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1249 ),
1250 });
1251 }
1252 let group_regs = vtype.vlmul().register_count();
1253 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
1254 vtype.vlmul(),
1255 )
1256 .ok_or(ExecutionError::IllegalInstruction {
1257 address: PackedAddress::new(
1258 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1259 ),
1260 })?;
1261 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1262 program_counter,
1263 vd,
1264 dest_group_regs,
1265 )?;
1266 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1267 program_counter,
1268 vs2,
1269 group_regs,
1270 )?;
1271 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1272 program_counter,
1273 vs1,
1274 group_regs,
1275 )?;
1276 if !vm && vd == VReg::V0 {
1277 ::core::hint::cold_path();
1278 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1279 address: PackedAddress::new(
1280 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1281 ),
1282 });
1283 }
1284 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1285 program_counter,
1286 vd,
1287 vs2,
1288 dest_group_regs,
1289 group_regs,
1290 )?;
1291 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1292 program_counter,
1293 vd,
1294 vs1,
1295 dest_group_regs,
1296 group_regs,
1297 )?;
1298 let sew = vtype.vsew();
1299 unsafe {
1301 zvexx_muldiv_helpers::execute_widening_op(
1302 env,
1303 vd,
1304 vs2,
1305 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
1306 vm,
1307 sew,
1308 |a, b, sew| {
1310 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
1311 let ub = b & zvexx_muldiv_helpers::sew_mask(sew);
1312 sa.cast_unsigned().wrapping_mul(ub)
1313 },
1314 );
1315 }
1316 }
1317 Self::VwmulsuVx {
1318 vd,
1319 vs2,
1320 rs1: _,
1321 vm,
1322 } => {
1323 if !env.vector_instructions_allowed() {
1324 ::core::hint::cold_path();
1325 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1326 address: PackedAddress::new(
1327 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1328 ),
1329 });
1330 }
1331 let Some(vtype) = env.vtype() else {
1332 ::core::hint::cold_path();
1333 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1334 address: PackedAddress::new(
1335 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1336 ),
1337 });
1338 };
1339 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
1342 ::core::hint::cold_path();
1343 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1344 address: PackedAddress::new(
1345 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1346 ),
1347 });
1348 }
1349 let group_regs = vtype.vlmul().register_count();
1350 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
1351 vtype.vlmul(),
1352 )
1353 .ok_or(ExecutionError::IllegalInstruction {
1354 address: PackedAddress::new(
1355 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1356 ),
1357 })?;
1358 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1359 program_counter,
1360 vd,
1361 dest_group_regs,
1362 )?;
1363 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1364 program_counter,
1365 vs2,
1366 group_regs,
1367 )?;
1368 if !vm && vd == VReg::V0 {
1369 ::core::hint::cold_path();
1370 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1371 address: PackedAddress::new(
1372 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1373 ),
1374 });
1375 }
1376 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1377 program_counter,
1378 vd,
1379 vs2,
1380 dest_group_regs,
1381 group_regs,
1382 )?;
1383 let sew = vtype.vsew();
1384 let scalar = rs1_value.as_u64();
1386 unsafe {
1388 zvexx_muldiv_helpers::execute_widening_op(
1389 env,
1390 vd,
1391 vs2,
1392 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
1393 vm,
1394 sew,
1395 |a, b, sew| {
1396 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
1397 let ub = b & zvexx_muldiv_helpers::sew_mask(sew);
1398 sa.cast_unsigned().wrapping_mul(ub)
1399 },
1400 );
1401 }
1402 }
1403 Self::VwmulVv { vd, vs2, vs1, vm } => {
1405 if !env.vector_instructions_allowed() {
1406 ::core::hint::cold_path();
1407 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1408 address: PackedAddress::new(
1409 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1410 ),
1411 });
1412 }
1413 let Some(vtype) = env.vtype() else {
1414 ::core::hint::cold_path();
1415 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1416 address: PackedAddress::new(
1417 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1418 ),
1419 });
1420 };
1421 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
1424 ::core::hint::cold_path();
1425 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1426 address: PackedAddress::new(
1427 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1428 ),
1429 });
1430 }
1431 let group_regs = vtype.vlmul().register_count();
1432 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
1433 vtype.vlmul(),
1434 )
1435 .ok_or(ExecutionError::IllegalInstruction {
1436 address: PackedAddress::new(
1437 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1438 ),
1439 })?;
1440 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1441 program_counter,
1442 vd,
1443 dest_group_regs,
1444 )?;
1445 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1446 program_counter,
1447 vs2,
1448 group_regs,
1449 )?;
1450 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1451 program_counter,
1452 vs1,
1453 group_regs,
1454 )?;
1455 if !vm && vd == VReg::V0 {
1456 ::core::hint::cold_path();
1457 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1458 address: PackedAddress::new(
1459 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1460 ),
1461 });
1462 }
1463 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1464 program_counter,
1465 vd,
1466 vs2,
1467 dest_group_regs,
1468 group_regs,
1469 )?;
1470 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1471 program_counter,
1472 vd,
1473 vs1,
1474 dest_group_regs,
1475 group_regs,
1476 )?;
1477 let sew = vtype.vsew();
1478 unsafe {
1480 zvexx_muldiv_helpers::execute_widening_op(
1481 env,
1482 vd,
1483 vs2,
1484 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
1485 vm,
1486 sew,
1487 |a, b, sew| {
1489 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
1490 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
1491 sa.cast_unsigned().wrapping_mul(sb.cast_unsigned())
1492 },
1493 );
1494 }
1495 }
1496 Self::VwmulVx {
1497 vd,
1498 vs2,
1499 rs1: _,
1500 vm,
1501 } => {
1502 if !env.vector_instructions_allowed() {
1503 ::core::hint::cold_path();
1504 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1505 address: PackedAddress::new(
1506 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1507 ),
1508 });
1509 }
1510 let Some(vtype) = env.vtype() else {
1511 ::core::hint::cold_path();
1512 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1513 address: PackedAddress::new(
1514 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1515 ),
1516 });
1517 };
1518 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
1521 ::core::hint::cold_path();
1522 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1523 address: PackedAddress::new(
1524 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1525 ),
1526 });
1527 }
1528 let group_regs = vtype.vlmul().register_count();
1529 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
1530 vtype.vlmul(),
1531 )
1532 .ok_or(ExecutionError::IllegalInstruction {
1533 address: PackedAddress::new(
1534 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1535 ),
1536 })?;
1537 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1538 program_counter,
1539 vd,
1540 dest_group_regs,
1541 )?;
1542 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1543 program_counter,
1544 vs2,
1545 group_regs,
1546 )?;
1547 if !vm && vd == VReg::V0 {
1548 ::core::hint::cold_path();
1549 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1550 address: PackedAddress::new(
1551 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1552 ),
1553 });
1554 }
1555 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1556 program_counter,
1557 vd,
1558 vs2,
1559 dest_group_regs,
1560 group_regs,
1561 )?;
1562 let sew = vtype.vsew();
1563 let scalar = rs1_value.as_u64();
1565 unsafe {
1567 zvexx_muldiv_helpers::execute_widening_op(
1568 env,
1569 vd,
1570 vs2,
1571 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
1572 vm,
1573 sew,
1574 |a, b, sew| {
1575 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
1576 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
1577 sa.cast_unsigned().wrapping_mul(sb.cast_unsigned())
1578 },
1579 );
1580 }
1581 }
1582 Self::VmaccVv { vd, vs1, vs2, vm } => {
1584 if !env.vector_instructions_allowed() {
1585 ::core::hint::cold_path();
1586 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1587 address: PackedAddress::new(
1588 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1589 ),
1590 });
1591 }
1592 let Some(vtype) = env.vtype() else {
1593 ::core::hint::cold_path();
1594 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1595 address: PackedAddress::new(
1596 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1597 ),
1598 });
1599 };
1600 let group_regs = vtype.vlmul().register_count();
1601 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1602 program_counter,
1603 vd,
1604 group_regs,
1605 )?;
1606 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1607 program_counter,
1608 vs2,
1609 group_regs,
1610 )?;
1611 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1612 program_counter,
1613 vs1,
1614 group_regs,
1615 )?;
1616 if !vm && vd == VReg::V0 {
1617 ::core::hint::cold_path();
1618 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1619 address: PackedAddress::new(
1620 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1621 ),
1622 });
1623 }
1624 let sew = vtype.vsew();
1625 unsafe {
1627 zvexx_muldiv_helpers::execute_muladd_op(
1628 env,
1629 vd,
1630 vs1,
1631 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1632 vm,
1633 sew,
1634 |acc, a, b, _| acc.wrapping_add(a.wrapping_mul(b)),
1636 );
1637 }
1638 }
1639 Self::VmaccVx {
1640 vd,
1641 rs1: _,
1642 vs2,
1643 vm,
1644 } => {
1645 if !env.vector_instructions_allowed() {
1646 ::core::hint::cold_path();
1647 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1648 address: PackedAddress::new(
1649 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1650 ),
1651 });
1652 }
1653 let Some(vtype) = env.vtype() else {
1654 ::core::hint::cold_path();
1655 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1656 address: PackedAddress::new(
1657 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1658 ),
1659 });
1660 };
1661 let group_regs = vtype.vlmul().register_count();
1662 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1663 program_counter,
1664 vd,
1665 group_regs,
1666 )?;
1667 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1668 program_counter,
1669 vs2,
1670 group_regs,
1671 )?;
1672 if !vm && vd == VReg::V0 {
1673 ::core::hint::cold_path();
1674 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1675 address: PackedAddress::new(
1676 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1677 ),
1678 });
1679 }
1680 let sew = vtype.vsew();
1681 let scalar = rs1_value.as_i64().cast_unsigned();
1682 unsafe {
1684 zvexx_muldiv_helpers::execute_muladd_scalar_op(
1685 env,
1686 vd,
1687 scalar,
1688 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1689 vm,
1690 sew,
1691 |acc, a, b, _| acc.wrapping_add(a.wrapping_mul(b)),
1692 );
1693 }
1694 }
1695 Self::VnmsacVv { vd, vs1, vs2, vm } => {
1697 if !env.vector_instructions_allowed() {
1698 ::core::hint::cold_path();
1699 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1700 address: PackedAddress::new(
1701 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1702 ),
1703 });
1704 }
1705 let Some(vtype) = env.vtype() else {
1706 ::core::hint::cold_path();
1707 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1708 address: PackedAddress::new(
1709 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1710 ),
1711 });
1712 };
1713 let group_regs = vtype.vlmul().register_count();
1714 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1715 program_counter,
1716 vd,
1717 group_regs,
1718 )?;
1719 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1720 program_counter,
1721 vs2,
1722 group_regs,
1723 )?;
1724 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1725 program_counter,
1726 vs1,
1727 group_regs,
1728 )?;
1729 if !vm && vd == VReg::V0 {
1730 ::core::hint::cold_path();
1731 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1732 address: PackedAddress::new(
1733 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1734 ),
1735 });
1736 }
1737 let sew = vtype.vsew();
1738 unsafe {
1740 zvexx_muldiv_helpers::execute_muladd_op(
1741 env,
1742 vd,
1743 vs1,
1744 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1745 vm,
1746 sew,
1747 |acc, a, b, _| acc.wrapping_sub(a.wrapping_mul(b)),
1749 );
1750 }
1751 }
1752 Self::VnmsacVx {
1753 vd,
1754 rs1: _,
1755 vs2,
1756 vm,
1757 } => {
1758 if !env.vector_instructions_allowed() {
1759 ::core::hint::cold_path();
1760 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1761 address: PackedAddress::new(
1762 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1763 ),
1764 });
1765 }
1766 let Some(vtype) = env.vtype() else {
1767 ::core::hint::cold_path();
1768 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1769 address: PackedAddress::new(
1770 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1771 ),
1772 });
1773 };
1774 let group_regs = vtype.vlmul().register_count();
1775 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1776 program_counter,
1777 vd,
1778 group_regs,
1779 )?;
1780 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1781 program_counter,
1782 vs2,
1783 group_regs,
1784 )?;
1785 if !vm && vd == VReg::V0 {
1786 ::core::hint::cold_path();
1787 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1788 address: PackedAddress::new(
1789 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1790 ),
1791 });
1792 }
1793 let sew = vtype.vsew();
1794 let scalar = rs1_value.as_i64().cast_unsigned();
1795 unsafe {
1797 zvexx_muldiv_helpers::execute_muladd_scalar_op(
1798 env,
1799 vd,
1800 scalar,
1801 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1802 vm,
1803 sew,
1804 |acc, a, b, _| acc.wrapping_sub(a.wrapping_mul(b)),
1805 );
1806 }
1807 }
1808 Self::VmaddVv { vd, vs1, vs2, vm } => {
1810 if !env.vector_instructions_allowed() {
1811 ::core::hint::cold_path();
1812 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1813 address: PackedAddress::new(
1814 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1815 ),
1816 });
1817 }
1818 let Some(vtype) = env.vtype() else {
1819 ::core::hint::cold_path();
1820 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1821 address: PackedAddress::new(
1822 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1823 ),
1824 });
1825 };
1826 let group_regs = vtype.vlmul().register_count();
1827 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1828 program_counter,
1829 vd,
1830 group_regs,
1831 )?;
1832 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1833 program_counter,
1834 vs2,
1835 group_regs,
1836 )?;
1837 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1838 program_counter,
1839 vs1,
1840 group_regs,
1841 )?;
1842 if !vm && vd == VReg::V0 {
1843 ::core::hint::cold_path();
1844 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1845 address: PackedAddress::new(
1846 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1847 ),
1848 });
1849 }
1850 let sew = vtype.vsew();
1851 unsafe {
1853 zvexx_muldiv_helpers::execute_muladd_op(
1854 env,
1855 vd,
1856 vs1,
1857 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1858 vm,
1859 sew,
1860 |acc, a, b, _| a.wrapping_mul(acc).wrapping_add(b),
1862 );
1863 }
1864 }
1865 Self::VmaddVx {
1866 vd,
1867 rs1: _,
1868 vs2,
1869 vm,
1870 } => {
1871 if !env.vector_instructions_allowed() {
1872 ::core::hint::cold_path();
1873 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1874 address: PackedAddress::new(
1875 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1876 ),
1877 });
1878 }
1879 let Some(vtype) = env.vtype() else {
1880 ::core::hint::cold_path();
1881 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1882 address: PackedAddress::new(
1883 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1884 ),
1885 });
1886 };
1887 let group_regs = vtype.vlmul().register_count();
1888 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1889 program_counter,
1890 vd,
1891 group_regs,
1892 )?;
1893 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1894 program_counter,
1895 vs2,
1896 group_regs,
1897 )?;
1898 if !vm && vd == VReg::V0 {
1899 ::core::hint::cold_path();
1900 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1901 address: PackedAddress::new(
1902 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1903 ),
1904 });
1905 }
1906 let sew = vtype.vsew();
1907 let scalar = rs1_value.as_i64().cast_unsigned();
1908 unsafe {
1910 zvexx_muldiv_helpers::execute_muladd_scalar_op(
1911 env,
1912 vd,
1913 scalar,
1914 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1915 vm,
1916 sew,
1917 |acc, a, b, _| a.wrapping_mul(acc).wrapping_add(b),
1919 );
1920 }
1921 }
1922 Self::VnmsubVv { vd, vs1, vs2, vm } => {
1924 if !env.vector_instructions_allowed() {
1925 ::core::hint::cold_path();
1926 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1927 address: PackedAddress::new(
1928 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1929 ),
1930 });
1931 }
1932 let Some(vtype) = env.vtype() else {
1933 ::core::hint::cold_path();
1934 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1935 address: PackedAddress::new(
1936 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1937 ),
1938 });
1939 };
1940 let group_regs = vtype.vlmul().register_count();
1941 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1942 program_counter,
1943 vd,
1944 group_regs,
1945 )?;
1946 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1947 program_counter,
1948 vs2,
1949 group_regs,
1950 )?;
1951 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1952 program_counter,
1953 vs1,
1954 group_regs,
1955 )?;
1956 if !vm && vd == VReg::V0 {
1957 ::core::hint::cold_path();
1958 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1959 address: PackedAddress::new(
1960 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1961 ),
1962 });
1963 }
1964 let sew = vtype.vsew();
1965 unsafe {
1967 zvexx_muldiv_helpers::execute_muladd_op(
1968 env,
1969 vd,
1970 vs1,
1971 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1972 vm,
1973 sew,
1974 |acc, a, b, _| b.wrapping_sub(a.wrapping_mul(acc)),
1976 );
1977 }
1978 }
1979 Self::VnmsubVx {
1980 vd,
1981 rs1: _,
1982 vs2,
1983 vm,
1984 } => {
1985 if !env.vector_instructions_allowed() {
1986 ::core::hint::cold_path();
1987 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1988 address: PackedAddress::new(
1989 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1990 ),
1991 });
1992 }
1993 let Some(vtype) = env.vtype() else {
1994 ::core::hint::cold_path();
1995 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1996 address: PackedAddress::new(
1997 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1998 ),
1999 });
2000 };
2001 let group_regs = vtype.vlmul().register_count();
2002 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2003 program_counter,
2004 vd,
2005 group_regs,
2006 )?;
2007 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2008 program_counter,
2009 vs2,
2010 group_regs,
2011 )?;
2012 if !vm && vd == VReg::V0 {
2013 ::core::hint::cold_path();
2014 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2015 address: PackedAddress::new(
2016 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2017 ),
2018 });
2019 }
2020 let sew = vtype.vsew();
2021 let scalar = rs1_value.as_i64().cast_unsigned();
2022 unsafe {
2024 zvexx_muldiv_helpers::execute_muladd_scalar_op(
2025 env,
2026 vd,
2027 scalar,
2028 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2029 vm,
2030 sew,
2031 |acc, a, b, _| b.wrapping_sub(a.wrapping_mul(acc)),
2033 );
2034 }
2035 }
2036 Self::VwmaccuVv { vd, vs1, vs2, vm } => {
2038 if !env.vector_instructions_allowed() {
2039 ::core::hint::cold_path();
2040 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2041 address: PackedAddress::new(
2042 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2043 ),
2044 });
2045 }
2046 let Some(vtype) = env.vtype() else {
2047 ::core::hint::cold_path();
2048 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2049 address: PackedAddress::new(
2050 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2051 ),
2052 });
2053 };
2054 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
2057 ::core::hint::cold_path();
2058 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2059 address: PackedAddress::new(
2060 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2061 ),
2062 });
2063 }
2064 let group_regs = vtype.vlmul().register_count();
2065 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
2066 vtype.vlmul(),
2067 )
2068 .ok_or(ExecutionError::IllegalInstruction {
2069 address: PackedAddress::new(
2070 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2071 ),
2072 })?;
2073 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2075 program_counter,
2076 vd,
2077 dest_group_regs,
2078 )?;
2079 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2080 program_counter,
2081 vs2,
2082 group_regs,
2083 )?;
2084 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2085 program_counter,
2086 vs1,
2087 group_regs,
2088 )?;
2089 if !vm && vd == VReg::V0 {
2090 ::core::hint::cold_path();
2091 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2092 address: PackedAddress::new(
2093 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2094 ),
2095 });
2096 }
2097 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2098 program_counter,
2099 vd,
2100 vs2,
2101 dest_group_regs,
2102 group_regs,
2103 )?;
2104 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2105 program_counter,
2106 vd,
2107 vs1,
2108 dest_group_regs,
2109 group_regs,
2110 )?;
2111 let sew = vtype.vsew();
2112 unsafe {
2114 zvexx_muldiv_helpers::execute_widening_muladd_op(
2115 env,
2116 vd,
2117 vs1,
2118 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2119 vm,
2120 sew,
2121 |acc, a, b, sew| {
2123 let mask = zvexx_muldiv_helpers::sew_mask(sew);
2124 acc.wrapping_add((a & mask).wrapping_mul(b & mask))
2125 },
2126 );
2127 }
2128 }
2129 Self::VwmaccuVx {
2130 vd,
2131 rs1: _,
2132 vs2,
2133 vm,
2134 } => {
2135 if !env.vector_instructions_allowed() {
2136 ::core::hint::cold_path();
2137 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2138 address: PackedAddress::new(
2139 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2140 ),
2141 });
2142 }
2143 let Some(vtype) = env.vtype() else {
2144 ::core::hint::cold_path();
2145 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2146 address: PackedAddress::new(
2147 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2148 ),
2149 });
2150 };
2151 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
2154 ::core::hint::cold_path();
2155 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2156 address: PackedAddress::new(
2157 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2158 ),
2159 });
2160 }
2161 let group_regs = vtype.vlmul().register_count();
2162 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
2163 vtype.vlmul(),
2164 )
2165 .ok_or(ExecutionError::IllegalInstruction {
2166 address: PackedAddress::new(
2167 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2168 ),
2169 })?;
2170 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2171 program_counter,
2172 vd,
2173 dest_group_regs,
2174 )?;
2175 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2176 program_counter,
2177 vs2,
2178 group_regs,
2179 )?;
2180 if !vm && vd == VReg::V0 {
2181 ::core::hint::cold_path();
2182 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2183 address: PackedAddress::new(
2184 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2185 ),
2186 });
2187 }
2188 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2189 program_counter,
2190 vd,
2191 vs2,
2192 dest_group_regs,
2193 group_regs,
2194 )?;
2195 let sew = vtype.vsew();
2196 let scalar = rs1_value.as_u64();
2197 unsafe {
2199 zvexx_muldiv_helpers::execute_widening_muladd_scalar_op(
2200 env,
2201 vd,
2202 scalar,
2203 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2204 vm,
2205 sew,
2206 |acc, a, b, sew| {
2207 let mask = zvexx_muldiv_helpers::sew_mask(sew);
2208 acc.wrapping_add((a & mask).wrapping_mul(b & mask))
2209 },
2210 );
2211 }
2212 }
2213 Self::VwmaccVv { vd, vs1, vs2, vm } => {
2215 if !env.vector_instructions_allowed() {
2216 ::core::hint::cold_path();
2217 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2218 address: PackedAddress::new(
2219 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2220 ),
2221 });
2222 }
2223 let Some(vtype) = env.vtype() else {
2224 ::core::hint::cold_path();
2225 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2226 address: PackedAddress::new(
2227 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2228 ),
2229 });
2230 };
2231 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
2234 ::core::hint::cold_path();
2235 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2236 address: PackedAddress::new(
2237 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2238 ),
2239 });
2240 }
2241 let group_regs = vtype.vlmul().register_count();
2242 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
2243 vtype.vlmul(),
2244 )
2245 .ok_or(ExecutionError::IllegalInstruction {
2246 address: PackedAddress::new(
2247 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2248 ),
2249 })?;
2250 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2251 program_counter,
2252 vd,
2253 dest_group_regs,
2254 )?;
2255 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2256 program_counter,
2257 vs2,
2258 group_regs,
2259 )?;
2260 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2261 program_counter,
2262 vs1,
2263 group_regs,
2264 )?;
2265 if !vm && vd == VReg::V0 {
2266 ::core::hint::cold_path();
2267 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2268 address: PackedAddress::new(
2269 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2270 ),
2271 });
2272 }
2273 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2274 program_counter,
2275 vd,
2276 vs2,
2277 dest_group_regs,
2278 group_regs,
2279 )?;
2280 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2281 program_counter,
2282 vd,
2283 vs1,
2284 dest_group_regs,
2285 group_regs,
2286 )?;
2287 let sew = vtype.vsew();
2288 unsafe {
2290 zvexx_muldiv_helpers::execute_widening_muladd_op(
2291 env,
2292 vd,
2293 vs1,
2294 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2295 vm,
2296 sew,
2297 |acc, a, b, sew| {
2299 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
2300 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
2301 acc.wrapping_add(sa.cast_unsigned().wrapping_mul(sb.cast_unsigned()))
2302 },
2303 );
2304 }
2305 }
2306 Self::VwmaccVx {
2307 vd,
2308 rs1: _,
2309 vs2,
2310 vm,
2311 } => {
2312 if !env.vector_instructions_allowed() {
2313 ::core::hint::cold_path();
2314 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2315 address: PackedAddress::new(
2316 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2317 ),
2318 });
2319 }
2320 let Some(vtype) = env.vtype() else {
2321 ::core::hint::cold_path();
2322 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2323 address: PackedAddress::new(
2324 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2325 ),
2326 });
2327 };
2328 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
2331 ::core::hint::cold_path();
2332 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2333 address: PackedAddress::new(
2334 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2335 ),
2336 });
2337 }
2338 let group_regs = vtype.vlmul().register_count();
2339 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
2340 vtype.vlmul(),
2341 )
2342 .ok_or(ExecutionError::IllegalInstruction {
2343 address: PackedAddress::new(
2344 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2345 ),
2346 })?;
2347 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2348 program_counter,
2349 vd,
2350 dest_group_regs,
2351 )?;
2352 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2353 program_counter,
2354 vs2,
2355 group_regs,
2356 )?;
2357 if !vm && vd == VReg::V0 {
2358 ::core::hint::cold_path();
2359 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2360 address: PackedAddress::new(
2361 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2362 ),
2363 });
2364 }
2365 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2366 program_counter,
2367 vd,
2368 vs2,
2369 dest_group_regs,
2370 group_regs,
2371 )?;
2372 let sew = vtype.vsew();
2373 let scalar = rs1_value.as_u64();
2374 unsafe {
2376 zvexx_muldiv_helpers::execute_widening_muladd_scalar_op(
2377 env,
2378 vd,
2379 scalar,
2380 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2381 vm,
2382 sew,
2383 |acc, a, b, sew| {
2384 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
2385 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
2386 acc.wrapping_add(sa.cast_unsigned().wrapping_mul(sb.cast_unsigned()))
2387 },
2388 );
2389 }
2390 }
2391 Self::VwmaccsuVv { vd, vs1, vs2, vm } => {
2393 if !env.vector_instructions_allowed() {
2394 ::core::hint::cold_path();
2395 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2396 address: PackedAddress::new(
2397 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2398 ),
2399 });
2400 }
2401 let Some(vtype) = env.vtype() else {
2402 ::core::hint::cold_path();
2403 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2404 address: PackedAddress::new(
2405 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2406 ),
2407 });
2408 };
2409 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
2412 ::core::hint::cold_path();
2413 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2414 address: PackedAddress::new(
2415 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2416 ),
2417 });
2418 }
2419 let group_regs = vtype.vlmul().register_count();
2420 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
2421 vtype.vlmul(),
2422 )
2423 .ok_or(ExecutionError::IllegalInstruction {
2424 address: PackedAddress::new(
2425 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2426 ),
2427 })?;
2428 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2429 program_counter,
2430 vd,
2431 dest_group_regs,
2432 )?;
2433 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2434 program_counter,
2435 vs2,
2436 group_regs,
2437 )?;
2438 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2439 program_counter,
2440 vs1,
2441 group_regs,
2442 )?;
2443 if !vm && vd == VReg::V0 {
2444 ::core::hint::cold_path();
2445 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2446 address: PackedAddress::new(
2447 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2448 ),
2449 });
2450 }
2451 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2452 program_counter,
2453 vd,
2454 vs2,
2455 dest_group_regs,
2456 group_regs,
2457 )?;
2458 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2459 program_counter,
2460 vd,
2461 vs1,
2462 dest_group_regs,
2463 group_regs,
2464 )?;
2465 let sew = vtype.vsew();
2466 unsafe {
2468 zvexx_muldiv_helpers::execute_widening_muladd_op(
2469 env,
2470 vd,
2471 vs1,
2472 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2473 vm,
2474 sew,
2475 |acc, a, b, sew| {
2477 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
2478 let ub = b & zvexx_muldiv_helpers::sew_mask(sew);
2479 acc.wrapping_add(sa.cast_unsigned().wrapping_mul(ub))
2480 },
2481 );
2482 }
2483 }
2484 Self::VwmaccsuVx {
2485 vd,
2486 rs1: _,
2487 vs2,
2488 vm,
2489 } => {
2490 if !env.vector_instructions_allowed() {
2491 ::core::hint::cold_path();
2492 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2493 address: PackedAddress::new(
2494 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2495 ),
2496 });
2497 }
2498 let Some(vtype) = env.vtype() else {
2499 ::core::hint::cold_path();
2500 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2501 address: PackedAddress::new(
2502 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2503 ),
2504 });
2505 };
2506 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
2509 ::core::hint::cold_path();
2510 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2511 address: PackedAddress::new(
2512 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2513 ),
2514 });
2515 }
2516 let group_regs = vtype.vlmul().register_count();
2517 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
2518 vtype.vlmul(),
2519 )
2520 .ok_or(ExecutionError::IllegalInstruction {
2521 address: PackedAddress::new(
2522 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2523 ),
2524 })?;
2525 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2526 program_counter,
2527 vd,
2528 dest_group_regs,
2529 )?;
2530 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2531 program_counter,
2532 vs2,
2533 group_regs,
2534 )?;
2535 if !vm && vd == VReg::V0 {
2536 ::core::hint::cold_path();
2537 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2538 address: PackedAddress::new(
2539 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2540 ),
2541 });
2542 }
2543 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2544 program_counter,
2545 vd,
2546 vs2,
2547 dest_group_regs,
2548 group_regs,
2549 )?;
2550 let sew = vtype.vsew();
2551 let scalar = rs1_value.as_u64();
2553 unsafe {
2555 zvexx_muldiv_helpers::execute_widening_muladd_scalar_op(
2556 env,
2557 vd,
2558 scalar,
2559 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2560 vm,
2561 sew,
2562 |acc, a, b, sew| {
2566 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
2567 let ub = b & zvexx_muldiv_helpers::sew_mask(sew);
2568 acc.wrapping_add(sa.cast_unsigned().wrapping_mul(ub))
2569 },
2570 );
2571 }
2572 }
2573 Self::VwmaccusVx {
2575 vd,
2576 rs1: _,
2577 vs2,
2578 vm,
2579 } => {
2580 if !env.vector_instructions_allowed() {
2581 ::core::hint::cold_path();
2582 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2583 address: PackedAddress::new(
2584 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2585 ),
2586 });
2587 }
2588 let Some(vtype) = env.vtype() else {
2589 ::core::hint::cold_path();
2590 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2591 address: PackedAddress::new(
2592 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2593 ),
2594 });
2595 };
2596 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
2599 ::core::hint::cold_path();
2600 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2601 address: PackedAddress::new(
2602 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2603 ),
2604 });
2605 }
2606 let group_regs = vtype.vlmul().register_count();
2607 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
2608 vtype.vlmul(),
2609 )
2610 .ok_or(ExecutionError::IllegalInstruction {
2611 address: PackedAddress::new(
2612 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2613 ),
2614 })?;
2615 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2616 program_counter,
2617 vd,
2618 dest_group_regs,
2619 )?;
2620 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2621 program_counter,
2622 vs2,
2623 group_regs,
2624 )?;
2625 if !vm && vd == VReg::V0 {
2626 ::core::hint::cold_path();
2627 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2628 address: PackedAddress::new(
2629 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2630 ),
2631 });
2632 }
2633 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2634 program_counter,
2635 vd,
2636 vs2,
2637 dest_group_regs,
2638 group_regs,
2639 )?;
2640 let sew = vtype.vsew();
2641 let scalar = rs1_value.as_u64();
2643 unsafe {
2645 zvexx_muldiv_helpers::execute_widening_muladd_scalar_op(
2646 env,
2647 vd,
2648 scalar,
2649 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2650 vm,
2651 sew,
2652 |acc, a, b, sew| {
2656 let ua = a & zvexx_muldiv_helpers::sew_mask(sew);
2657 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
2658 acc.wrapping_add(sb.cast_unsigned().wrapping_mul(ua))
2659 },
2660 );
2661 }
2662 }
2663 }
2664
2665 ExecutionResult::ContinueNoWrite
2666 }
2667}