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 = vtype.vlmul().widening_register_count().ok_or(
1078 ExecutionError::IllegalInstruction {
1079 address: PackedAddress::new(
1080 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1081 ),
1082 },
1083 )?;
1084 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1085 program_counter,
1086 vd,
1087 dest_group_regs,
1088 )?;
1089 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1090 program_counter,
1091 vs2,
1092 group_regs,
1093 )?;
1094 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1095 program_counter,
1096 vs1,
1097 group_regs,
1098 )?;
1099 if !vm && vd == VReg::V0 {
1100 ::core::hint::cold_path();
1101 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1102 address: PackedAddress::new(
1103 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1104 ),
1105 });
1106 }
1107 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1109 program_counter,
1110 vd,
1111 vs2,
1112 dest_group_regs,
1113 group_regs,
1114 )?;
1115 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1116 program_counter,
1117 vd,
1118 vs1,
1119 dest_group_regs,
1120 group_regs,
1121 )?;
1122 let sew = vtype.vsew();
1123 unsafe {
1125 zvexx_muldiv_helpers::execute_widening_op(
1126 env,
1127 vd,
1128 vs2,
1129 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
1130 vm,
1131 sew,
1132 |a, b, sew| {
1133 let mask = zvexx_muldiv_helpers::sew_mask(sew);
1134 (a & mask).wrapping_mul(b & mask)
1135 },
1136 );
1137 }
1138 }
1139 Self::VwmuluVx {
1140 vd,
1141 vs2,
1142 rs1: _,
1143 vm,
1144 } => {
1145 if !env.vector_instructions_allowed() {
1146 ::core::hint::cold_path();
1147 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1148 address: PackedAddress::new(
1149 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1150 ),
1151 });
1152 }
1153 let Some(vtype) = env.vtype() else {
1154 ::core::hint::cold_path();
1155 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1156 address: PackedAddress::new(
1157 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1158 ),
1159 });
1160 };
1161 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
1164 ::core::hint::cold_path();
1165 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1166 address: PackedAddress::new(
1167 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1168 ),
1169 });
1170 }
1171 let group_regs = vtype.vlmul().register_count();
1172 let dest_group_regs = vtype.vlmul().widening_register_count().ok_or(
1173 ExecutionError::IllegalInstruction {
1174 address: PackedAddress::new(
1175 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1176 ),
1177 },
1178 )?;
1179 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1180 program_counter,
1181 vd,
1182 dest_group_regs,
1183 )?;
1184 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1185 program_counter,
1186 vs2,
1187 group_regs,
1188 )?;
1189 if !vm && vd == VReg::V0 {
1190 ::core::hint::cold_path();
1191 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1192 address: PackedAddress::new(
1193 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1194 ),
1195 });
1196 }
1197 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1198 program_counter,
1199 vd,
1200 vs2,
1201 dest_group_regs,
1202 group_regs,
1203 )?;
1204 let sew = vtype.vsew();
1205 let scalar = rs1_value.as_u64();
1206 unsafe {
1208 zvexx_muldiv_helpers::execute_widening_op(
1209 env,
1210 vd,
1211 vs2,
1212 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
1213 vm,
1214 sew,
1215 |a, b, sew| {
1216 let mask = zvexx_muldiv_helpers::sew_mask(sew);
1217 (a & mask).wrapping_mul(b & mask)
1218 },
1219 );
1220 }
1221 }
1222 Self::VwmulsuVv { vd, vs2, vs1, vm } => {
1224 if !env.vector_instructions_allowed() {
1225 ::core::hint::cold_path();
1226 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1227 address: PackedAddress::new(
1228 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1229 ),
1230 });
1231 }
1232 let Some(vtype) = env.vtype() else {
1233 ::core::hint::cold_path();
1234 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1235 address: PackedAddress::new(
1236 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1237 ),
1238 });
1239 };
1240 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
1243 ::core::hint::cold_path();
1244 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1245 address: PackedAddress::new(
1246 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1247 ),
1248 });
1249 }
1250 let group_regs = vtype.vlmul().register_count();
1251 let dest_group_regs = vtype.vlmul().widening_register_count().ok_or(
1252 ExecutionError::IllegalInstruction {
1253 address: PackedAddress::new(
1254 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1255 ),
1256 },
1257 )?;
1258 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1259 program_counter,
1260 vd,
1261 dest_group_regs,
1262 )?;
1263 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1264 program_counter,
1265 vs2,
1266 group_regs,
1267 )?;
1268 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1269 program_counter,
1270 vs1,
1271 group_regs,
1272 )?;
1273 if !vm && vd == VReg::V0 {
1274 ::core::hint::cold_path();
1275 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1276 address: PackedAddress::new(
1277 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1278 ),
1279 });
1280 }
1281 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1282 program_counter,
1283 vd,
1284 vs2,
1285 dest_group_regs,
1286 group_regs,
1287 )?;
1288 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1289 program_counter,
1290 vd,
1291 vs1,
1292 dest_group_regs,
1293 group_regs,
1294 )?;
1295 let sew = vtype.vsew();
1296 unsafe {
1298 zvexx_muldiv_helpers::execute_widening_op(
1299 env,
1300 vd,
1301 vs2,
1302 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
1303 vm,
1304 sew,
1305 |a, b, sew| {
1307 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
1308 let ub = b & zvexx_muldiv_helpers::sew_mask(sew);
1309 sa.cast_unsigned().wrapping_mul(ub)
1310 },
1311 );
1312 }
1313 }
1314 Self::VwmulsuVx {
1315 vd,
1316 vs2,
1317 rs1: _,
1318 vm,
1319 } => {
1320 if !env.vector_instructions_allowed() {
1321 ::core::hint::cold_path();
1322 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1323 address: PackedAddress::new(
1324 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1325 ),
1326 });
1327 }
1328 let Some(vtype) = env.vtype() else {
1329 ::core::hint::cold_path();
1330 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1331 address: PackedAddress::new(
1332 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1333 ),
1334 });
1335 };
1336 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
1339 ::core::hint::cold_path();
1340 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1341 address: PackedAddress::new(
1342 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1343 ),
1344 });
1345 }
1346 let group_regs = vtype.vlmul().register_count();
1347 let dest_group_regs = vtype.vlmul().widening_register_count().ok_or(
1348 ExecutionError::IllegalInstruction {
1349 address: PackedAddress::new(
1350 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1351 ),
1352 },
1353 )?;
1354 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1355 program_counter,
1356 vd,
1357 dest_group_regs,
1358 )?;
1359 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1360 program_counter,
1361 vs2,
1362 group_regs,
1363 )?;
1364 if !vm && vd == VReg::V0 {
1365 ::core::hint::cold_path();
1366 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1367 address: PackedAddress::new(
1368 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1369 ),
1370 });
1371 }
1372 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1373 program_counter,
1374 vd,
1375 vs2,
1376 dest_group_regs,
1377 group_regs,
1378 )?;
1379 let sew = vtype.vsew();
1380 let scalar = rs1_value.as_u64();
1382 unsafe {
1384 zvexx_muldiv_helpers::execute_widening_op(
1385 env,
1386 vd,
1387 vs2,
1388 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
1389 vm,
1390 sew,
1391 |a, b, sew| {
1392 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
1393 let ub = b & zvexx_muldiv_helpers::sew_mask(sew);
1394 sa.cast_unsigned().wrapping_mul(ub)
1395 },
1396 );
1397 }
1398 }
1399 Self::VwmulVv { vd, vs2, vs1, vm } => {
1401 if !env.vector_instructions_allowed() {
1402 ::core::hint::cold_path();
1403 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1404 address: PackedAddress::new(
1405 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1406 ),
1407 });
1408 }
1409 let Some(vtype) = env.vtype() else {
1410 ::core::hint::cold_path();
1411 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1412 address: PackedAddress::new(
1413 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1414 ),
1415 });
1416 };
1417 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
1420 ::core::hint::cold_path();
1421 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1422 address: PackedAddress::new(
1423 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1424 ),
1425 });
1426 }
1427 let group_regs = vtype.vlmul().register_count();
1428 let dest_group_regs = vtype.vlmul().widening_register_count().ok_or(
1429 ExecutionError::IllegalInstruction {
1430 address: PackedAddress::new(
1431 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1432 ),
1433 },
1434 )?;
1435 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1436 program_counter,
1437 vd,
1438 dest_group_regs,
1439 )?;
1440 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1441 program_counter,
1442 vs2,
1443 group_regs,
1444 )?;
1445 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1446 program_counter,
1447 vs1,
1448 group_regs,
1449 )?;
1450 if !vm && vd == VReg::V0 {
1451 ::core::hint::cold_path();
1452 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1453 address: PackedAddress::new(
1454 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1455 ),
1456 });
1457 }
1458 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1459 program_counter,
1460 vd,
1461 vs2,
1462 dest_group_regs,
1463 group_regs,
1464 )?;
1465 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1466 program_counter,
1467 vd,
1468 vs1,
1469 dest_group_regs,
1470 group_regs,
1471 )?;
1472 let sew = vtype.vsew();
1473 unsafe {
1475 zvexx_muldiv_helpers::execute_widening_op(
1476 env,
1477 vd,
1478 vs2,
1479 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
1480 vm,
1481 sew,
1482 |a, b, sew| {
1484 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
1485 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
1486 sa.cast_unsigned().wrapping_mul(sb.cast_unsigned())
1487 },
1488 );
1489 }
1490 }
1491 Self::VwmulVx {
1492 vd,
1493 vs2,
1494 rs1: _,
1495 vm,
1496 } => {
1497 if !env.vector_instructions_allowed() {
1498 ::core::hint::cold_path();
1499 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1500 address: PackedAddress::new(
1501 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1502 ),
1503 });
1504 }
1505 let Some(vtype) = env.vtype() else {
1506 ::core::hint::cold_path();
1507 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1508 address: PackedAddress::new(
1509 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1510 ),
1511 });
1512 };
1513 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
1516 ::core::hint::cold_path();
1517 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1518 address: PackedAddress::new(
1519 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1520 ),
1521 });
1522 }
1523 let group_regs = vtype.vlmul().register_count();
1524 let dest_group_regs = vtype.vlmul().widening_register_count().ok_or(
1525 ExecutionError::IllegalInstruction {
1526 address: PackedAddress::new(
1527 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1528 ),
1529 },
1530 )?;
1531 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1532 program_counter,
1533 vd,
1534 dest_group_regs,
1535 )?;
1536 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1537 program_counter,
1538 vs2,
1539 group_regs,
1540 )?;
1541 if !vm && vd == VReg::V0 {
1542 ::core::hint::cold_path();
1543 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1544 address: PackedAddress::new(
1545 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1546 ),
1547 });
1548 }
1549 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
1550 program_counter,
1551 vd,
1552 vs2,
1553 dest_group_regs,
1554 group_regs,
1555 )?;
1556 let sew = vtype.vsew();
1557 let scalar = rs1_value.as_u64();
1559 unsafe {
1561 zvexx_muldiv_helpers::execute_widening_op(
1562 env,
1563 vd,
1564 vs2,
1565 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
1566 vm,
1567 sew,
1568 |a, b, sew| {
1569 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
1570 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
1571 sa.cast_unsigned().wrapping_mul(sb.cast_unsigned())
1572 },
1573 );
1574 }
1575 }
1576 Self::VmaccVv { vd, vs1, vs2, vm } => {
1578 if !env.vector_instructions_allowed() {
1579 ::core::hint::cold_path();
1580 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1581 address: PackedAddress::new(
1582 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1583 ),
1584 });
1585 }
1586 let Some(vtype) = env.vtype() else {
1587 ::core::hint::cold_path();
1588 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1589 address: PackedAddress::new(
1590 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1591 ),
1592 });
1593 };
1594 let group_regs = vtype.vlmul().register_count();
1595 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1596 program_counter,
1597 vd,
1598 group_regs,
1599 )?;
1600 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1601 program_counter,
1602 vs2,
1603 group_regs,
1604 )?;
1605 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1606 program_counter,
1607 vs1,
1608 group_regs,
1609 )?;
1610 if !vm && vd == VReg::V0 {
1611 ::core::hint::cold_path();
1612 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1613 address: PackedAddress::new(
1614 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1615 ),
1616 });
1617 }
1618 let sew = vtype.vsew();
1619 unsafe {
1621 zvexx_muldiv_helpers::execute_muladd_op(
1622 env,
1623 vd,
1624 vs1,
1625 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1626 vm,
1627 sew,
1628 |acc, a, b, _| acc.wrapping_add(a.wrapping_mul(b)),
1630 );
1631 }
1632 }
1633 Self::VmaccVx {
1634 vd,
1635 rs1: _,
1636 vs2,
1637 vm,
1638 } => {
1639 if !env.vector_instructions_allowed() {
1640 ::core::hint::cold_path();
1641 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1642 address: PackedAddress::new(
1643 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1644 ),
1645 });
1646 }
1647 let Some(vtype) = env.vtype() else {
1648 ::core::hint::cold_path();
1649 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1650 address: PackedAddress::new(
1651 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1652 ),
1653 });
1654 };
1655 let group_regs = vtype.vlmul().register_count();
1656 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1657 program_counter,
1658 vd,
1659 group_regs,
1660 )?;
1661 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1662 program_counter,
1663 vs2,
1664 group_regs,
1665 )?;
1666 if !vm && vd == VReg::V0 {
1667 ::core::hint::cold_path();
1668 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1669 address: PackedAddress::new(
1670 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1671 ),
1672 });
1673 }
1674 let sew = vtype.vsew();
1675 let scalar = rs1_value.as_i64().cast_unsigned();
1676 unsafe {
1678 zvexx_muldiv_helpers::execute_muladd_scalar_op(
1679 env,
1680 vd,
1681 scalar,
1682 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1683 vm,
1684 sew,
1685 |acc, a, b, _| acc.wrapping_add(a.wrapping_mul(b)),
1686 );
1687 }
1688 }
1689 Self::VnmsacVv { vd, vs1, vs2, vm } => {
1691 if !env.vector_instructions_allowed() {
1692 ::core::hint::cold_path();
1693 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1694 address: PackedAddress::new(
1695 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1696 ),
1697 });
1698 }
1699 let Some(vtype) = env.vtype() else {
1700 ::core::hint::cold_path();
1701 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1702 address: PackedAddress::new(
1703 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1704 ),
1705 });
1706 };
1707 let group_regs = vtype.vlmul().register_count();
1708 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1709 program_counter,
1710 vd,
1711 group_regs,
1712 )?;
1713 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1714 program_counter,
1715 vs2,
1716 group_regs,
1717 )?;
1718 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1719 program_counter,
1720 vs1,
1721 group_regs,
1722 )?;
1723 if !vm && vd == VReg::V0 {
1724 ::core::hint::cold_path();
1725 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1726 address: PackedAddress::new(
1727 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1728 ),
1729 });
1730 }
1731 let sew = vtype.vsew();
1732 unsafe {
1734 zvexx_muldiv_helpers::execute_muladd_op(
1735 env,
1736 vd,
1737 vs1,
1738 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1739 vm,
1740 sew,
1741 |acc, a, b, _| acc.wrapping_sub(a.wrapping_mul(b)),
1743 );
1744 }
1745 }
1746 Self::VnmsacVx {
1747 vd,
1748 rs1: _,
1749 vs2,
1750 vm,
1751 } => {
1752 if !env.vector_instructions_allowed() {
1753 ::core::hint::cold_path();
1754 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1755 address: PackedAddress::new(
1756 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1757 ),
1758 });
1759 }
1760 let Some(vtype) = env.vtype() else {
1761 ::core::hint::cold_path();
1762 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1763 address: PackedAddress::new(
1764 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1765 ),
1766 });
1767 };
1768 let group_regs = vtype.vlmul().register_count();
1769 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1770 program_counter,
1771 vd,
1772 group_regs,
1773 )?;
1774 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1775 program_counter,
1776 vs2,
1777 group_regs,
1778 )?;
1779 if !vm && vd == VReg::V0 {
1780 ::core::hint::cold_path();
1781 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1782 address: PackedAddress::new(
1783 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1784 ),
1785 });
1786 }
1787 let sew = vtype.vsew();
1788 let scalar = rs1_value.as_i64().cast_unsigned();
1789 unsafe {
1791 zvexx_muldiv_helpers::execute_muladd_scalar_op(
1792 env,
1793 vd,
1794 scalar,
1795 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1796 vm,
1797 sew,
1798 |acc, a, b, _| acc.wrapping_sub(a.wrapping_mul(b)),
1799 );
1800 }
1801 }
1802 Self::VmaddVv { vd, vs1, vs2, vm } => {
1804 if !env.vector_instructions_allowed() {
1805 ::core::hint::cold_path();
1806 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1807 address: PackedAddress::new(
1808 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1809 ),
1810 });
1811 }
1812 let Some(vtype) = env.vtype() else {
1813 ::core::hint::cold_path();
1814 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1815 address: PackedAddress::new(
1816 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1817 ),
1818 });
1819 };
1820 let group_regs = vtype.vlmul().register_count();
1821 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1822 program_counter,
1823 vd,
1824 group_regs,
1825 )?;
1826 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1827 program_counter,
1828 vs2,
1829 group_regs,
1830 )?;
1831 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1832 program_counter,
1833 vs1,
1834 group_regs,
1835 )?;
1836 if !vm && vd == VReg::V0 {
1837 ::core::hint::cold_path();
1838 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1839 address: PackedAddress::new(
1840 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1841 ),
1842 });
1843 }
1844 let sew = vtype.vsew();
1845 unsafe {
1847 zvexx_muldiv_helpers::execute_muladd_op(
1848 env,
1849 vd,
1850 vs1,
1851 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1852 vm,
1853 sew,
1854 |acc, a, b, _| a.wrapping_mul(acc).wrapping_add(b),
1856 );
1857 }
1858 }
1859 Self::VmaddVx {
1860 vd,
1861 rs1: _,
1862 vs2,
1863 vm,
1864 } => {
1865 if !env.vector_instructions_allowed() {
1866 ::core::hint::cold_path();
1867 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1868 address: PackedAddress::new(
1869 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1870 ),
1871 });
1872 }
1873 let Some(vtype) = env.vtype() else {
1874 ::core::hint::cold_path();
1875 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1876 address: PackedAddress::new(
1877 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1878 ),
1879 });
1880 };
1881 let group_regs = vtype.vlmul().register_count();
1882 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1883 program_counter,
1884 vd,
1885 group_regs,
1886 )?;
1887 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1888 program_counter,
1889 vs2,
1890 group_regs,
1891 )?;
1892 if !vm && vd == VReg::V0 {
1893 ::core::hint::cold_path();
1894 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1895 address: PackedAddress::new(
1896 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1897 ),
1898 });
1899 }
1900 let sew = vtype.vsew();
1901 let scalar = rs1_value.as_i64().cast_unsigned();
1902 unsafe {
1904 zvexx_muldiv_helpers::execute_muladd_scalar_op(
1905 env,
1906 vd,
1907 scalar,
1908 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1909 vm,
1910 sew,
1911 |acc, a, b, _| a.wrapping_mul(acc).wrapping_add(b),
1913 );
1914 }
1915 }
1916 Self::VnmsubVv { vd, vs1, vs2, vm } => {
1918 if !env.vector_instructions_allowed() {
1919 ::core::hint::cold_path();
1920 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1921 address: PackedAddress::new(
1922 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1923 ),
1924 });
1925 }
1926 let Some(vtype) = env.vtype() else {
1927 ::core::hint::cold_path();
1928 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1929 address: PackedAddress::new(
1930 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1931 ),
1932 });
1933 };
1934 let group_regs = vtype.vlmul().register_count();
1935 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1936 program_counter,
1937 vd,
1938 group_regs,
1939 )?;
1940 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1941 program_counter,
1942 vs2,
1943 group_regs,
1944 )?;
1945 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1946 program_counter,
1947 vs1,
1948 group_regs,
1949 )?;
1950 if !vm && vd == VReg::V0 {
1951 ::core::hint::cold_path();
1952 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1953 address: PackedAddress::new(
1954 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1955 ),
1956 });
1957 }
1958 let sew = vtype.vsew();
1959 unsafe {
1961 zvexx_muldiv_helpers::execute_muladd_op(
1962 env,
1963 vd,
1964 vs1,
1965 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1966 vm,
1967 sew,
1968 |acc, a, b, _| b.wrapping_sub(a.wrapping_mul(acc)),
1970 );
1971 }
1972 }
1973 Self::VnmsubVx {
1974 vd,
1975 rs1: _,
1976 vs2,
1977 vm,
1978 } => {
1979 if !env.vector_instructions_allowed() {
1980 ::core::hint::cold_path();
1981 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1982 address: PackedAddress::new(
1983 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1984 ),
1985 });
1986 }
1987 let Some(vtype) = env.vtype() else {
1988 ::core::hint::cold_path();
1989 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1990 address: PackedAddress::new(
1991 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1992 ),
1993 });
1994 };
1995 let group_regs = vtype.vlmul().register_count();
1996 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
1997 program_counter,
1998 vd,
1999 group_regs,
2000 )?;
2001 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2002 program_counter,
2003 vs2,
2004 group_regs,
2005 )?;
2006 if !vm && vd == VReg::V0 {
2007 ::core::hint::cold_path();
2008 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2009 address: PackedAddress::new(
2010 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2011 ),
2012 });
2013 }
2014 let sew = vtype.vsew();
2015 let scalar = rs1_value.as_i64().cast_unsigned();
2016 unsafe {
2018 zvexx_muldiv_helpers::execute_muladd_scalar_op(
2019 env,
2020 vd,
2021 scalar,
2022 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2023 vm,
2024 sew,
2025 |acc, a, b, _| b.wrapping_sub(a.wrapping_mul(acc)),
2027 );
2028 }
2029 }
2030 Self::VwmaccuVv { vd, vs1, vs2, vm } => {
2032 if !env.vector_instructions_allowed() {
2033 ::core::hint::cold_path();
2034 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2035 address: PackedAddress::new(
2036 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2037 ),
2038 });
2039 }
2040 let Some(vtype) = env.vtype() else {
2041 ::core::hint::cold_path();
2042 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2043 address: PackedAddress::new(
2044 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2045 ),
2046 });
2047 };
2048 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
2051 ::core::hint::cold_path();
2052 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2053 address: PackedAddress::new(
2054 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2055 ),
2056 });
2057 }
2058 let group_regs = vtype.vlmul().register_count();
2059 let dest_group_regs = vtype.vlmul().widening_register_count().ok_or(
2060 ExecutionError::IllegalInstruction {
2061 address: PackedAddress::new(
2062 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2063 ),
2064 },
2065 )?;
2066 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2068 program_counter,
2069 vd,
2070 dest_group_regs,
2071 )?;
2072 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2073 program_counter,
2074 vs2,
2075 group_regs,
2076 )?;
2077 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2078 program_counter,
2079 vs1,
2080 group_regs,
2081 )?;
2082 if !vm && vd == VReg::V0 {
2083 ::core::hint::cold_path();
2084 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2085 address: PackedAddress::new(
2086 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2087 ),
2088 });
2089 }
2090 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2091 program_counter,
2092 vd,
2093 vs2,
2094 dest_group_regs,
2095 group_regs,
2096 )?;
2097 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2098 program_counter,
2099 vd,
2100 vs1,
2101 dest_group_regs,
2102 group_regs,
2103 )?;
2104 let sew = vtype.vsew();
2105 unsafe {
2107 zvexx_muldiv_helpers::execute_widening_muladd_op(
2108 env,
2109 vd,
2110 vs1,
2111 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2112 vm,
2113 sew,
2114 |acc, a, b, sew| {
2116 let mask = zvexx_muldiv_helpers::sew_mask(sew);
2117 acc.wrapping_add((a & mask).wrapping_mul(b & mask))
2118 },
2119 );
2120 }
2121 }
2122 Self::VwmaccuVx {
2123 vd,
2124 rs1: _,
2125 vs2,
2126 vm,
2127 } => {
2128 if !env.vector_instructions_allowed() {
2129 ::core::hint::cold_path();
2130 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2131 address: PackedAddress::new(
2132 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2133 ),
2134 });
2135 }
2136 let Some(vtype) = env.vtype() else {
2137 ::core::hint::cold_path();
2138 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2139 address: PackedAddress::new(
2140 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2141 ),
2142 });
2143 };
2144 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
2147 ::core::hint::cold_path();
2148 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2149 address: PackedAddress::new(
2150 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2151 ),
2152 });
2153 }
2154 let group_regs = vtype.vlmul().register_count();
2155 let dest_group_regs = vtype.vlmul().widening_register_count().ok_or(
2156 ExecutionError::IllegalInstruction {
2157 address: PackedAddress::new(
2158 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2159 ),
2160 },
2161 )?;
2162 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2163 program_counter,
2164 vd,
2165 dest_group_regs,
2166 )?;
2167 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2168 program_counter,
2169 vs2,
2170 group_regs,
2171 )?;
2172 if !vm && vd == VReg::V0 {
2173 ::core::hint::cold_path();
2174 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2175 address: PackedAddress::new(
2176 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2177 ),
2178 });
2179 }
2180 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2181 program_counter,
2182 vd,
2183 vs2,
2184 dest_group_regs,
2185 group_regs,
2186 )?;
2187 let sew = vtype.vsew();
2188 let scalar = rs1_value.as_u64();
2189 unsafe {
2191 zvexx_muldiv_helpers::execute_widening_muladd_scalar_op(
2192 env,
2193 vd,
2194 scalar,
2195 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2196 vm,
2197 sew,
2198 |acc, a, b, sew| {
2199 let mask = zvexx_muldiv_helpers::sew_mask(sew);
2200 acc.wrapping_add((a & mask).wrapping_mul(b & mask))
2201 },
2202 );
2203 }
2204 }
2205 Self::VwmaccVv { vd, vs1, vs2, vm } => {
2207 if !env.vector_instructions_allowed() {
2208 ::core::hint::cold_path();
2209 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2210 address: PackedAddress::new(
2211 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2212 ),
2213 });
2214 }
2215 let Some(vtype) = env.vtype() else {
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 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
2226 ::core::hint::cold_path();
2227 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2228 address: PackedAddress::new(
2229 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2230 ),
2231 });
2232 }
2233 let group_regs = vtype.vlmul().register_count();
2234 let dest_group_regs = vtype.vlmul().widening_register_count().ok_or(
2235 ExecutionError::IllegalInstruction {
2236 address: PackedAddress::new(
2237 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2238 ),
2239 },
2240 )?;
2241 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2242 program_counter,
2243 vd,
2244 dest_group_regs,
2245 )?;
2246 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2247 program_counter,
2248 vs2,
2249 group_regs,
2250 )?;
2251 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2252 program_counter,
2253 vs1,
2254 group_regs,
2255 )?;
2256 if !vm && vd == VReg::V0 {
2257 ::core::hint::cold_path();
2258 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2259 address: PackedAddress::new(
2260 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2261 ),
2262 });
2263 }
2264 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2265 program_counter,
2266 vd,
2267 vs2,
2268 dest_group_regs,
2269 group_regs,
2270 )?;
2271 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2272 program_counter,
2273 vd,
2274 vs1,
2275 dest_group_regs,
2276 group_regs,
2277 )?;
2278 let sew = vtype.vsew();
2279 unsafe {
2281 zvexx_muldiv_helpers::execute_widening_muladd_op(
2282 env,
2283 vd,
2284 vs1,
2285 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2286 vm,
2287 sew,
2288 |acc, a, b, sew| {
2290 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
2291 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
2292 acc.wrapping_add(sa.cast_unsigned().wrapping_mul(sb.cast_unsigned()))
2293 },
2294 );
2295 }
2296 }
2297 Self::VwmaccVx {
2298 vd,
2299 rs1: _,
2300 vs2,
2301 vm,
2302 } => {
2303 if !env.vector_instructions_allowed() {
2304 ::core::hint::cold_path();
2305 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2306 address: PackedAddress::new(
2307 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2308 ),
2309 });
2310 }
2311 let Some(vtype) = env.vtype() else {
2312 ::core::hint::cold_path();
2313 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2314 address: PackedAddress::new(
2315 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2316 ),
2317 });
2318 };
2319 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
2322 ::core::hint::cold_path();
2323 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2324 address: PackedAddress::new(
2325 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2326 ),
2327 });
2328 }
2329 let group_regs = vtype.vlmul().register_count();
2330 let dest_group_regs = vtype.vlmul().widening_register_count().ok_or(
2331 ExecutionError::IllegalInstruction {
2332 address: PackedAddress::new(
2333 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2334 ),
2335 },
2336 )?;
2337 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2338 program_counter,
2339 vd,
2340 dest_group_regs,
2341 )?;
2342 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2343 program_counter,
2344 vs2,
2345 group_regs,
2346 )?;
2347 if !vm && vd == VReg::V0 {
2348 ::core::hint::cold_path();
2349 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2350 address: PackedAddress::new(
2351 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2352 ),
2353 });
2354 }
2355 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2356 program_counter,
2357 vd,
2358 vs2,
2359 dest_group_regs,
2360 group_regs,
2361 )?;
2362 let sew = vtype.vsew();
2363 let scalar = rs1_value.as_u64();
2364 unsafe {
2366 zvexx_muldiv_helpers::execute_widening_muladd_scalar_op(
2367 env,
2368 vd,
2369 scalar,
2370 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2371 vm,
2372 sew,
2373 |acc, a, b, sew| {
2374 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
2375 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
2376 acc.wrapping_add(sa.cast_unsigned().wrapping_mul(sb.cast_unsigned()))
2377 },
2378 );
2379 }
2380 }
2381 Self::VwmaccsuVv { vd, vs1, vs2, vm } => {
2383 if !env.vector_instructions_allowed() {
2384 ::core::hint::cold_path();
2385 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2386 address: PackedAddress::new(
2387 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2388 ),
2389 });
2390 }
2391 let Some(vtype) = env.vtype() else {
2392 ::core::hint::cold_path();
2393 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2394 address: PackedAddress::new(
2395 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2396 ),
2397 });
2398 };
2399 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
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 let group_regs = vtype.vlmul().register_count();
2410 let dest_group_regs = vtype.vlmul().widening_register_count().ok_or(
2411 ExecutionError::IllegalInstruction {
2412 address: PackedAddress::new(
2413 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2414 ),
2415 },
2416 )?;
2417 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2418 program_counter,
2419 vd,
2420 dest_group_regs,
2421 )?;
2422 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2423 program_counter,
2424 vs2,
2425 group_regs,
2426 )?;
2427 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2428 program_counter,
2429 vs1,
2430 group_regs,
2431 )?;
2432 if !vm && vd == VReg::V0 {
2433 ::core::hint::cold_path();
2434 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2435 address: PackedAddress::new(
2436 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2437 ),
2438 });
2439 }
2440 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2441 program_counter,
2442 vd,
2443 vs2,
2444 dest_group_regs,
2445 group_regs,
2446 )?;
2447 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2448 program_counter,
2449 vd,
2450 vs1,
2451 dest_group_regs,
2452 group_regs,
2453 )?;
2454 let sew = vtype.vsew();
2455 unsafe {
2457 zvexx_muldiv_helpers::execute_widening_muladd_op(
2458 env,
2459 vd,
2460 vs1,
2461 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2462 vm,
2463 sew,
2464 |acc, a, b, sew| {
2466 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
2467 let ub = b & zvexx_muldiv_helpers::sew_mask(sew);
2468 acc.wrapping_add(sa.cast_unsigned().wrapping_mul(ub))
2469 },
2470 );
2471 }
2472 }
2473 Self::VwmaccsuVx {
2474 vd,
2475 rs1: _,
2476 vs2,
2477 vm,
2478 } => {
2479 if !env.vector_instructions_allowed() {
2480 ::core::hint::cold_path();
2481 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2482 address: PackedAddress::new(
2483 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2484 ),
2485 });
2486 }
2487 let Some(vtype) = env.vtype() else {
2488 ::core::hint::cold_path();
2489 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2490 address: PackedAddress::new(
2491 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2492 ),
2493 });
2494 };
2495 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
2498 ::core::hint::cold_path();
2499 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2500 address: PackedAddress::new(
2501 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2502 ),
2503 });
2504 }
2505 let group_regs = vtype.vlmul().register_count();
2506 let dest_group_regs = vtype.vlmul().widening_register_count().ok_or(
2507 ExecutionError::IllegalInstruction {
2508 address: PackedAddress::new(
2509 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2510 ),
2511 },
2512 )?;
2513 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2514 program_counter,
2515 vd,
2516 dest_group_regs,
2517 )?;
2518 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2519 program_counter,
2520 vs2,
2521 group_regs,
2522 )?;
2523 if !vm && vd == VReg::V0 {
2524 ::core::hint::cold_path();
2525 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2526 address: PackedAddress::new(
2527 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2528 ),
2529 });
2530 }
2531 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2532 program_counter,
2533 vd,
2534 vs2,
2535 dest_group_regs,
2536 group_regs,
2537 )?;
2538 let sew = vtype.vsew();
2539 let scalar = rs1_value.as_u64();
2541 unsafe {
2543 zvexx_muldiv_helpers::execute_widening_muladd_scalar_op(
2544 env,
2545 vd,
2546 scalar,
2547 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2548 vm,
2549 sew,
2550 |acc, a, b, sew| {
2554 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
2555 let ub = b & zvexx_muldiv_helpers::sew_mask(sew);
2556 acc.wrapping_add(sa.cast_unsigned().wrapping_mul(ub))
2557 },
2558 );
2559 }
2560 }
2561 Self::VwmaccusVx {
2563 vd,
2564 rs1: _,
2565 vs2,
2566 vm,
2567 } => {
2568 if !env.vector_instructions_allowed() {
2569 ::core::hint::cold_path();
2570 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2571 address: PackedAddress::new(
2572 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2573 ),
2574 });
2575 }
2576 let Some(vtype) = env.vtype() else {
2577 ::core::hint::cold_path();
2578 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2579 address: PackedAddress::new(
2580 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2581 ),
2582 });
2583 };
2584 if !zvexx_muldiv_helpers::widening_eew_supported(vtype.vsew(), Env::ELEN) {
2587 ::core::hint::cold_path();
2588 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2589 address: PackedAddress::new(
2590 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2591 ),
2592 });
2593 }
2594 let group_regs = vtype.vlmul().register_count();
2595 let dest_group_regs = vtype.vlmul().widening_register_count().ok_or(
2596 ExecutionError::IllegalInstruction {
2597 address: PackedAddress::new(
2598 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2599 ),
2600 },
2601 )?;
2602 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2603 program_counter,
2604 vd,
2605 dest_group_regs,
2606 )?;
2607 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _>(
2608 program_counter,
2609 vs2,
2610 group_regs,
2611 )?;
2612 if !vm && vd == VReg::V0 {
2613 ::core::hint::cold_path();
2614 return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2615 address: PackedAddress::new(
2616 program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2617 ),
2618 });
2619 }
2620 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _>(
2621 program_counter,
2622 vd,
2623 vs2,
2624 dest_group_regs,
2625 group_regs,
2626 )?;
2627 let sew = vtype.vsew();
2628 let scalar = rs1_value.as_u64();
2630 unsafe {
2632 zvexx_muldiv_helpers::execute_widening_muladd_scalar_op(
2633 env,
2634 vd,
2635 scalar,
2636 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2637 vm,
2638 sew,
2639 |acc, a, b, sew| {
2643 let ua = a & zvexx_muldiv_helpers::sew_mask(sew);
2644 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
2645 acc.wrapping_add(sb.cast_unsigned().wrapping_mul(ua))
2646 },
2647 );
2648 }
2649 }
2650 }
2651
2652 ExecutionResult::ContinueNoWrite
2653 }
2654}