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 ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands, VirtualMemory,
12};
13use ab_riscv_macros::instruction_execution;
14use ab_riscv_primitives::prelude::*;
15use core::fmt;
16use core::ops::ControlFlow;
17
18#[instruction_execution]
19impl<Reg> ExecutableInstructionOperands for ZveXxMulDivInstruction<Reg> where Reg: Register {}
20
21#[instruction_execution]
22impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
23 for ZveXxMulDivInstruction<Reg>
24where
25 Reg: Register,
26{
27}
28
29#[instruction_execution]
30impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
31 ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
32 for ZveXxMulDivInstruction<Reg>
33where
34 Reg: Register,
35 Regs: RegisterFile<Reg>,
36 ExtState: VectorRegistersExt<Reg, CustomError>,
37 [(); ExtState::ELEN as usize]:,
38 [(); ExtState::VLEN as usize]:,
39 [(); ExtState::VLENB as usize]:,
40 Memory: VirtualMemory,
41 PC: ProgramCounter<Reg::Type, Memory, CustomError>,
42 CustomError: fmt::Debug,
43{
44 #[inline(always)]
45 fn execute(
46 self,
47 Rs1Rs2OperandValues {
48 rs1_value,
49 rs2_value: _,
50 }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
51 _regs: &mut Regs,
52 ext_state: &mut ExtState,
53 _memory: &mut Memory,
54 program_counter: &mut PC,
55 _system_instruction_handler: &mut InstructionHandler,
56 ) -> Result<
57 ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
58 ExecutionError<Reg::Type, CustomError>,
59 > {
60 match self {
61 Self::VmulVv { vd, vs2, vs1, vm } => {
63 if !ext_state.vector_instructions_allowed() {
64 ::core::hint::cold_path();
65 return Err(ExecutionError::IllegalInstruction {
66 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
67 });
68 }
69 let Some(vtype) = ext_state.vtype() else {
70 ::core::hint::cold_path();
71 return Err(ExecutionError::IllegalInstruction {
72 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
73 });
74 };
75 let group_regs = vtype.vlmul().register_count();
76 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
77 program_counter,
78 vd,
79 group_regs,
80 )?;
81 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
82 program_counter,
83 vs2,
84 group_regs,
85 )?;
86 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
87 program_counter,
88 vs1,
89 group_regs,
90 )?;
91 if !vm && vd == VReg::V0 {
92 ::core::hint::cold_path();
93 return Err(ExecutionError::IllegalInstruction {
94 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
95 });
96 }
97 let sew = vtype.vsew();
98 unsafe {
100 zvexx_muldiv_helpers::execute_arith_op(
101 ext_state,
102 vd,
103 vs2,
104 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
105 vm,
106 sew,
107 |a, b, _| a.wrapping_mul(b),
108 );
109 }
110 }
111 Self::VmulVx {
112 vd,
113 vs2,
114 rs1: _,
115 vm,
116 } => {
117 if !ext_state.vector_instructions_allowed() {
118 ::core::hint::cold_path();
119 return Err(ExecutionError::IllegalInstruction {
120 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
121 });
122 }
123 let Some(vtype) = ext_state.vtype() else {
124 ::core::hint::cold_path();
125 return Err(ExecutionError::IllegalInstruction {
126 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
127 });
128 };
129 let group_regs = vtype.vlmul().register_count();
130 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
131 program_counter,
132 vd,
133 group_regs,
134 )?;
135 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
136 program_counter,
137 vs2,
138 group_regs,
139 )?;
140 if !vm && vd == VReg::V0 {
141 ::core::hint::cold_path();
142 return Err(ExecutionError::IllegalInstruction {
143 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
144 });
145 }
146 let sew = vtype.vsew();
147 let scalar = rs1_value.as_i64().cast_unsigned();
148 unsafe {
150 zvexx_muldiv_helpers::execute_arith_op(
151 ext_state,
152 vd,
153 vs2,
154 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
155 vm,
156 sew,
157 |a, b, _| a.wrapping_mul(b),
158 );
159 }
160 }
161 Self::VmulhVv { vd, vs2, vs1, vm } => {
163 if !ext_state.vector_instructions_allowed() {
164 ::core::hint::cold_path();
165 return Err(ExecutionError::IllegalInstruction {
166 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
167 });
168 }
169 let Some(vtype) = ext_state.vtype() else {
170 ::core::hint::cold_path();
171 return Err(ExecutionError::IllegalInstruction {
172 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
173 });
174 };
175 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
177 ::core::hint::cold_path();
178 return Err(ExecutionError::IllegalInstruction {
179 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
180 });
181 }
182 let group_regs = vtype.vlmul().register_count();
183 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
184 program_counter,
185 vd,
186 group_regs,
187 )?;
188 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
189 program_counter,
190 vs2,
191 group_regs,
192 )?;
193 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
194 program_counter,
195 vs1,
196 group_regs,
197 )?;
198 if !vm && vd == VReg::V0 {
199 ::core::hint::cold_path();
200 return Err(ExecutionError::IllegalInstruction {
201 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
202 });
203 }
204 let sew = vtype.vsew();
205 unsafe {
207 zvexx_muldiv_helpers::execute_arith_op(
208 ext_state,
209 vd,
210 vs2,
211 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
212 vm,
213 sew,
214 zvexx_muldiv_helpers::mulh_ss,
215 );
216 }
217 }
218 Self::VmulhVx {
219 vd,
220 vs2,
221 rs1: _,
222 vm,
223 } => {
224 if !ext_state.vector_instructions_allowed() {
225 ::core::hint::cold_path();
226 return Err(ExecutionError::IllegalInstruction {
227 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
228 });
229 }
230 let Some(vtype) = ext_state.vtype() else {
231 ::core::hint::cold_path();
232 return Err(ExecutionError::IllegalInstruction {
233 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
234 });
235 };
236 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
237 ::core::hint::cold_path();
238 return Err(ExecutionError::IllegalInstruction {
239 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
240 });
241 }
242 let group_regs = vtype.vlmul().register_count();
243 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
244 program_counter,
245 vd,
246 group_regs,
247 )?;
248 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
249 program_counter,
250 vs2,
251 group_regs,
252 )?;
253 if !vm && vd == VReg::V0 {
254 ::core::hint::cold_path();
255 return Err(ExecutionError::IllegalInstruction {
256 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
257 });
258 }
259 let sew = vtype.vsew();
260 let scalar = rs1_value.as_u64();
261 unsafe {
263 zvexx_muldiv_helpers::execute_arith_op(
264 ext_state,
265 vd,
266 vs2,
267 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
268 vm,
269 sew,
270 zvexx_muldiv_helpers::mulh_ss,
271 );
272 }
273 }
274 Self::VmulhuVv { vd, vs2, vs1, vm } => {
276 if !ext_state.vector_instructions_allowed() {
277 ::core::hint::cold_path();
278 return Err(ExecutionError::IllegalInstruction {
279 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
280 });
281 }
282 let Some(vtype) = ext_state.vtype() else {
283 ::core::hint::cold_path();
284 return Err(ExecutionError::IllegalInstruction {
285 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
286 });
287 };
288 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
289 ::core::hint::cold_path();
290 return Err(ExecutionError::IllegalInstruction {
291 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
292 });
293 }
294 let group_regs = vtype.vlmul().register_count();
295 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
296 program_counter,
297 vd,
298 group_regs,
299 )?;
300 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
301 program_counter,
302 vs2,
303 group_regs,
304 )?;
305 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
306 program_counter,
307 vs1,
308 group_regs,
309 )?;
310 if !vm && vd == VReg::V0 {
311 ::core::hint::cold_path();
312 return Err(ExecutionError::IllegalInstruction {
313 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
314 });
315 }
316 let sew = vtype.vsew();
317 unsafe {
319 zvexx_muldiv_helpers::execute_arith_op(
320 ext_state,
321 vd,
322 vs2,
323 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
324 vm,
325 sew,
326 zvexx_muldiv_helpers::mulhu_uu,
327 );
328 }
329 }
330 Self::VmulhuVx {
331 vd,
332 vs2,
333 rs1: _,
334 vm,
335 } => {
336 if !ext_state.vector_instructions_allowed() {
337 ::core::hint::cold_path();
338 return Err(ExecutionError::IllegalInstruction {
339 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
340 });
341 }
342 let Some(vtype) = ext_state.vtype() else {
343 ::core::hint::cold_path();
344 return Err(ExecutionError::IllegalInstruction {
345 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
346 });
347 };
348 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
349 ::core::hint::cold_path();
350 return Err(ExecutionError::IllegalInstruction {
351 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
352 });
353 }
354 let group_regs = vtype.vlmul().register_count();
355 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
356 program_counter,
357 vd,
358 group_regs,
359 )?;
360 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
361 program_counter,
362 vs2,
363 group_regs,
364 )?;
365 if !vm && vd == VReg::V0 {
366 ::core::hint::cold_path();
367 return Err(ExecutionError::IllegalInstruction {
368 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
369 });
370 }
371 let sew = vtype.vsew();
372 let scalar = rs1_value.as_u64();
373 unsafe {
375 zvexx_muldiv_helpers::execute_arith_op(
376 ext_state,
377 vd,
378 vs2,
379 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
380 vm,
381 sew,
382 zvexx_muldiv_helpers::mulhu_uu,
383 );
384 }
385 }
386 Self::VmulhsuVv { vd, vs2, vs1, vm } => {
388 if !ext_state.vector_instructions_allowed() {
389 ::core::hint::cold_path();
390 return Err(ExecutionError::IllegalInstruction {
391 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
392 });
393 }
394 let Some(vtype) = ext_state.vtype() else {
395 ::core::hint::cold_path();
396 return Err(ExecutionError::IllegalInstruction {
397 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
398 });
399 };
400 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
401 ::core::hint::cold_path();
402 return Err(ExecutionError::IllegalInstruction {
403 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
404 });
405 }
406 let group_regs = vtype.vlmul().register_count();
407 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
408 program_counter,
409 vd,
410 group_regs,
411 )?;
412 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
413 program_counter,
414 vs2,
415 group_regs,
416 )?;
417 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
418 program_counter,
419 vs1,
420 group_regs,
421 )?;
422 if !vm && vd == VReg::V0 {
423 ::core::hint::cold_path();
424 return Err(ExecutionError::IllegalInstruction {
425 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
426 });
427 }
428 let sew = vtype.vsew();
429 unsafe {
431 zvexx_muldiv_helpers::execute_arith_op(
432 ext_state,
433 vd,
434 vs2,
435 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
436 vm,
437 sew,
438 zvexx_muldiv_helpers::mulhsu_su,
440 );
441 }
442 }
443 Self::VmulhsuVx {
444 vd,
445 vs2,
446 rs1: _,
447 vm,
448 } => {
449 if !ext_state.vector_instructions_allowed() {
450 ::core::hint::cold_path();
451 return Err(ExecutionError::IllegalInstruction {
452 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
453 });
454 }
455 let Some(vtype) = ext_state.vtype() else {
456 ::core::hint::cold_path();
457 return Err(ExecutionError::IllegalInstruction {
458 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
459 });
460 };
461 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
462 ::core::hint::cold_path();
463 return Err(ExecutionError::IllegalInstruction {
464 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
465 });
466 }
467 let group_regs = vtype.vlmul().register_count();
468 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
469 program_counter,
470 vd,
471 group_regs,
472 )?;
473 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
474 program_counter,
475 vs2,
476 group_regs,
477 )?;
478 if !vm && vd == VReg::V0 {
479 ::core::hint::cold_path();
480 return Err(ExecutionError::IllegalInstruction {
481 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
482 });
483 }
484 let sew = vtype.vsew();
485 let scalar = rs1_value.as_u64();
487 unsafe {
489 zvexx_muldiv_helpers::execute_arith_op(
490 ext_state,
491 vd,
492 vs2,
493 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
494 vm,
495 sew,
496 zvexx_muldiv_helpers::mulhsu_su,
498 );
499 }
500 }
501 Self::VdivuVv { vd, vs2, vs1, vm } => {
503 if !ext_state.vector_instructions_allowed() {
504 ::core::hint::cold_path();
505 return Err(ExecutionError::IllegalInstruction {
506 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
507 });
508 }
509 let Some(vtype) = ext_state.vtype() else {
510 ::core::hint::cold_path();
511 return Err(ExecutionError::IllegalInstruction {
512 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
513 });
514 };
515 let group_regs = vtype.vlmul().register_count();
516 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
517 program_counter,
518 vd,
519 group_regs,
520 )?;
521 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
522 program_counter,
523 vs2,
524 group_regs,
525 )?;
526 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
527 program_counter,
528 vs1,
529 group_regs,
530 )?;
531 if !vm && vd == VReg::V0 {
532 ::core::hint::cold_path();
533 return Err(ExecutionError::IllegalInstruction {
534 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
535 });
536 }
537 let sew = vtype.vsew();
538 unsafe {
540 zvexx_muldiv_helpers::execute_arith_op(
541 ext_state,
542 vd,
543 vs2,
544 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
545 vm,
546 sew,
547 |a, b, sew| {
549 let mask = zvexx_muldiv_helpers::sew_mask(sew);
550 let dividend = a & mask;
551 let divisor = b & mask;
552 dividend.checked_div(divisor).unwrap_or(mask)
553 },
554 );
555 }
556 }
557 Self::VdivuVx {
558 vd,
559 vs2,
560 rs1: _,
561 vm,
562 } => {
563 if !ext_state.vector_instructions_allowed() {
564 ::core::hint::cold_path();
565 return Err(ExecutionError::IllegalInstruction {
566 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
567 });
568 }
569 let Some(vtype) = ext_state.vtype() else {
570 ::core::hint::cold_path();
571 return Err(ExecutionError::IllegalInstruction {
572 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
573 });
574 };
575 let group_regs = vtype.vlmul().register_count();
576 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
577 program_counter,
578 vd,
579 group_regs,
580 )?;
581 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
582 program_counter,
583 vs2,
584 group_regs,
585 )?;
586 if !vm && vd == VReg::V0 {
587 ::core::hint::cold_path();
588 return Err(ExecutionError::IllegalInstruction {
589 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
590 });
591 }
592 let sew = vtype.vsew();
593 let scalar = rs1_value.as_i64().cast_unsigned();
594 unsafe {
596 zvexx_muldiv_helpers::execute_arith_op(
597 ext_state,
598 vd,
599 vs2,
600 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
601 vm,
602 sew,
603 |a, b, sew| {
604 let mask = zvexx_muldiv_helpers::sew_mask(sew);
605 let dividend = a & mask;
606 let divisor = b & mask;
607 dividend.checked_div(divisor).unwrap_or(mask)
608 },
609 );
610 }
611 }
612 Self::VdivVv { vd, vs2, vs1, vm } => {
614 if !ext_state.vector_instructions_allowed() {
615 ::core::hint::cold_path();
616 return Err(ExecutionError::IllegalInstruction {
617 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
618 });
619 }
620 let Some(vtype) = ext_state.vtype() else {
621 ::core::hint::cold_path();
622 return Err(ExecutionError::IllegalInstruction {
623 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
624 });
625 };
626 let group_regs = vtype.vlmul().register_count();
627 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
628 program_counter,
629 vd,
630 group_regs,
631 )?;
632 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
633 program_counter,
634 vs2,
635 group_regs,
636 )?;
637 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
638 program_counter,
639 vs1,
640 group_regs,
641 )?;
642 if !vm && vd == VReg::V0 {
643 ::core::hint::cold_path();
644 return Err(ExecutionError::IllegalInstruction {
645 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
646 });
647 }
648 let sew = vtype.vsew();
649 unsafe {
651 zvexx_muldiv_helpers::execute_arith_op(
652 ext_state,
653 vd,
654 vs2,
655 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
656 vm,
657 sew,
658 zvexx_muldiv_helpers::sdiv,
659 );
660 }
661 }
662 Self::VdivVx {
663 vd,
664 vs2,
665 rs1: _,
666 vm,
667 } => {
668 if !ext_state.vector_instructions_allowed() {
669 ::core::hint::cold_path();
670 return Err(ExecutionError::IllegalInstruction {
671 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
672 });
673 }
674 let Some(vtype) = ext_state.vtype() else {
675 ::core::hint::cold_path();
676 return Err(ExecutionError::IllegalInstruction {
677 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
678 });
679 };
680 let group_regs = vtype.vlmul().register_count();
681 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
682 program_counter,
683 vd,
684 group_regs,
685 )?;
686 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
687 program_counter,
688 vs2,
689 group_regs,
690 )?;
691 if !vm && vd == VReg::V0 {
692 ::core::hint::cold_path();
693 return Err(ExecutionError::IllegalInstruction {
694 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
695 });
696 }
697 let sew = vtype.vsew();
698 let scalar = rs1_value.as_i64().cast_unsigned();
699 unsafe {
701 zvexx_muldiv_helpers::execute_arith_op(
702 ext_state,
703 vd,
704 vs2,
705 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
706 vm,
707 sew,
708 zvexx_muldiv_helpers::sdiv,
709 );
710 }
711 }
712 Self::VremuVv { vd, vs2, vs1, vm } => {
714 if !ext_state.vector_instructions_allowed() {
715 ::core::hint::cold_path();
716 return Err(ExecutionError::IllegalInstruction {
717 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
718 });
719 }
720 let Some(vtype) = ext_state.vtype() else {
721 ::core::hint::cold_path();
722 return Err(ExecutionError::IllegalInstruction {
723 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
724 });
725 };
726 let group_regs = vtype.vlmul().register_count();
727 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
728 program_counter,
729 vd,
730 group_regs,
731 )?;
732 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
733 program_counter,
734 vs2,
735 group_regs,
736 )?;
737 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
738 program_counter,
739 vs1,
740 group_regs,
741 )?;
742 if !vm && vd == VReg::V0 {
743 ::core::hint::cold_path();
744 return Err(ExecutionError::IllegalInstruction {
745 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
746 });
747 }
748 let sew = vtype.vsew();
749 unsafe {
751 zvexx_muldiv_helpers::execute_arith_op(
752 ext_state,
753 vd,
754 vs2,
755 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
756 vm,
757 sew,
758 |a, b, sew| {
760 let mask = zvexx_muldiv_helpers::sew_mask(sew);
761 let dividend = a & mask;
762 let divisor = b & mask;
763 if divisor == 0 {
764 dividend
765 } else {
766 dividend % divisor
767 }
768 },
769 );
770 }
771 }
772 Self::VremuVx {
773 vd,
774 vs2,
775 rs1: _,
776 vm,
777 } => {
778 if !ext_state.vector_instructions_allowed() {
779 ::core::hint::cold_path();
780 return Err(ExecutionError::IllegalInstruction {
781 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
782 });
783 }
784 let Some(vtype) = ext_state.vtype() else {
785 ::core::hint::cold_path();
786 return Err(ExecutionError::IllegalInstruction {
787 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
788 });
789 };
790 let group_regs = vtype.vlmul().register_count();
791 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
792 program_counter,
793 vd,
794 group_regs,
795 )?;
796 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
797 program_counter,
798 vs2,
799 group_regs,
800 )?;
801 if !vm && vd == VReg::V0 {
802 ::core::hint::cold_path();
803 return Err(ExecutionError::IllegalInstruction {
804 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
805 });
806 }
807 let sew = vtype.vsew();
808 let scalar = rs1_value.as_i64().cast_unsigned();
809 unsafe {
811 zvexx_muldiv_helpers::execute_arith_op(
812 ext_state,
813 vd,
814 vs2,
815 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
816 vm,
817 sew,
818 |a, b, sew| {
819 let mask = zvexx_muldiv_helpers::sew_mask(sew);
820 let dividend = a & mask;
821 let divisor = b & mask;
822 if divisor == 0 {
823 dividend
824 } else {
825 dividend % divisor
826 }
827 },
828 );
829 }
830 }
831 Self::VremVv { vd, vs2, vs1, vm } => {
833 if !ext_state.vector_instructions_allowed() {
834 ::core::hint::cold_path();
835 return Err(ExecutionError::IllegalInstruction {
836 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
837 });
838 }
839 let Some(vtype) = ext_state.vtype() else {
840 ::core::hint::cold_path();
841 return Err(ExecutionError::IllegalInstruction {
842 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
843 });
844 };
845 let group_regs = vtype.vlmul().register_count();
846 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
847 program_counter,
848 vd,
849 group_regs,
850 )?;
851 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
852 program_counter,
853 vs2,
854 group_regs,
855 )?;
856 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
857 program_counter,
858 vs1,
859 group_regs,
860 )?;
861 if !vm && vd == VReg::V0 {
862 ::core::hint::cold_path();
863 return Err(ExecutionError::IllegalInstruction {
864 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
865 });
866 }
867 let sew = vtype.vsew();
868 unsafe {
870 zvexx_muldiv_helpers::execute_arith_op(
871 ext_state,
872 vd,
873 vs2,
874 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
875 vm,
876 sew,
877 zvexx_muldiv_helpers::srem,
878 );
879 }
880 }
881 Self::VremVx {
882 vd,
883 vs2,
884 rs1: _,
885 vm,
886 } => {
887 if !ext_state.vector_instructions_allowed() {
888 ::core::hint::cold_path();
889 return Err(ExecutionError::IllegalInstruction {
890 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
891 });
892 }
893 let Some(vtype) = ext_state.vtype() else {
894 ::core::hint::cold_path();
895 return Err(ExecutionError::IllegalInstruction {
896 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
897 });
898 };
899 let group_regs = vtype.vlmul().register_count();
900 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
901 program_counter,
902 vd,
903 group_regs,
904 )?;
905 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
906 program_counter,
907 vs2,
908 group_regs,
909 )?;
910 if !vm && vd == VReg::V0 {
911 ::core::hint::cold_path();
912 return Err(ExecutionError::IllegalInstruction {
913 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
914 });
915 }
916 let sew = vtype.vsew();
917 let scalar = rs1_value.as_i64().cast_unsigned();
918 unsafe {
920 zvexx_muldiv_helpers::execute_arith_op(
921 ext_state,
922 vd,
923 vs2,
924 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
925 vm,
926 sew,
927 zvexx_muldiv_helpers::srem,
928 );
929 }
930 }
931 Self::VwmuluVv { vd, vs2, vs1, vm } => {
933 if !ext_state.vector_instructions_allowed() {
934 ::core::hint::cold_path();
935 return Err(ExecutionError::IllegalInstruction {
936 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
937 });
938 }
939 let Some(vtype) = ext_state.vtype() else {
940 ::core::hint::cold_path();
941 return Err(ExecutionError::IllegalInstruction {
942 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
943 });
944 };
945 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
947 ::core::hint::cold_path();
948 return Err(ExecutionError::IllegalInstruction {
949 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
950 });
951 }
952 let group_regs = vtype.vlmul().register_count();
953 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
955 vtype.vlmul(),
956 )
957 .ok_or(ExecutionError::IllegalInstruction {
958 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
959 })?;
960 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
961 program_counter,
962 vd,
963 dest_group_regs,
964 )?;
965 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
966 program_counter,
967 vs2,
968 group_regs,
969 )?;
970 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
971 program_counter,
972 vs1,
973 group_regs,
974 )?;
975 if !vm && vd == VReg::V0 {
976 ::core::hint::cold_path();
977 return Err(ExecutionError::IllegalInstruction {
978 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
979 });
980 }
981 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
983 program_counter,
984 vd,
985 vs2,
986 dest_group_regs,
987 group_regs,
988 )?;
989 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
990 program_counter,
991 vd,
992 vs1,
993 dest_group_regs,
994 group_regs,
995 )?;
996 let sew = vtype.vsew();
997 unsafe {
999 zvexx_muldiv_helpers::execute_widening_op(
1000 ext_state,
1001 vd,
1002 vs2,
1003 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
1004 vm,
1005 sew,
1006 |a, b, sew| {
1007 let mask = zvexx_muldiv_helpers::sew_mask(sew);
1008 (a & mask).wrapping_mul(b & mask)
1009 },
1010 );
1011 }
1012 }
1013 Self::VwmuluVx {
1014 vd,
1015 vs2,
1016 rs1: _,
1017 vm,
1018 } => {
1019 if !ext_state.vector_instructions_allowed() {
1020 ::core::hint::cold_path();
1021 return Err(ExecutionError::IllegalInstruction {
1022 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1023 });
1024 }
1025 let Some(vtype) = ext_state.vtype() else {
1026 ::core::hint::cold_path();
1027 return Err(ExecutionError::IllegalInstruction {
1028 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1029 });
1030 };
1031 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
1032 ::core::hint::cold_path();
1033 return Err(ExecutionError::IllegalInstruction {
1034 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1035 });
1036 }
1037 let group_regs = vtype.vlmul().register_count();
1038 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
1039 vtype.vlmul(),
1040 )
1041 .ok_or(ExecutionError::IllegalInstruction {
1042 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1043 })?;
1044 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1045 program_counter,
1046 vd,
1047 dest_group_regs,
1048 )?;
1049 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1050 program_counter,
1051 vs2,
1052 group_regs,
1053 )?;
1054 if !vm && vd == VReg::V0 {
1055 ::core::hint::cold_path();
1056 return Err(ExecutionError::IllegalInstruction {
1057 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1058 });
1059 }
1060 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
1061 program_counter,
1062 vd,
1063 vs2,
1064 dest_group_regs,
1065 group_regs,
1066 )?;
1067 let sew = vtype.vsew();
1068 let scalar = rs1_value.as_u64();
1069 unsafe {
1071 zvexx_muldiv_helpers::execute_widening_op(
1072 ext_state,
1073 vd,
1074 vs2,
1075 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
1076 vm,
1077 sew,
1078 |a, b, sew| {
1079 let mask = zvexx_muldiv_helpers::sew_mask(sew);
1080 (a & mask).wrapping_mul(b & mask)
1081 },
1082 );
1083 }
1084 }
1085 Self::VwmulsuVv { vd, vs2, vs1, vm } => {
1087 if !ext_state.vector_instructions_allowed() {
1088 ::core::hint::cold_path();
1089 return Err(ExecutionError::IllegalInstruction {
1090 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1091 });
1092 }
1093 let Some(vtype) = ext_state.vtype() else {
1094 ::core::hint::cold_path();
1095 return Err(ExecutionError::IllegalInstruction {
1096 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1097 });
1098 };
1099 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
1100 ::core::hint::cold_path();
1101 return Err(ExecutionError::IllegalInstruction {
1102 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1103 });
1104 }
1105 let group_regs = vtype.vlmul().register_count();
1106 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
1107 vtype.vlmul(),
1108 )
1109 .ok_or(ExecutionError::IllegalInstruction {
1110 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1111 })?;
1112 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1113 program_counter,
1114 vd,
1115 dest_group_regs,
1116 )?;
1117 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1118 program_counter,
1119 vs2,
1120 group_regs,
1121 )?;
1122 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1123 program_counter,
1124 vs1,
1125 group_regs,
1126 )?;
1127 if !vm && vd == VReg::V0 {
1128 ::core::hint::cold_path();
1129 return Err(ExecutionError::IllegalInstruction {
1130 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1131 });
1132 }
1133 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
1134 program_counter,
1135 vd,
1136 vs2,
1137 dest_group_regs,
1138 group_regs,
1139 )?;
1140 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
1141 program_counter,
1142 vd,
1143 vs1,
1144 dest_group_regs,
1145 group_regs,
1146 )?;
1147 let sew = vtype.vsew();
1148 unsafe {
1150 zvexx_muldiv_helpers::execute_widening_op(
1151 ext_state,
1152 vd,
1153 vs2,
1154 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
1155 vm,
1156 sew,
1157 |a, b, sew| {
1159 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
1160 let ub = b & zvexx_muldiv_helpers::sew_mask(sew);
1161 sa.cast_unsigned().wrapping_mul(ub)
1162 },
1163 );
1164 }
1165 }
1166 Self::VwmulsuVx {
1167 vd,
1168 vs2,
1169 rs1: _,
1170 vm,
1171 } => {
1172 if !ext_state.vector_instructions_allowed() {
1173 ::core::hint::cold_path();
1174 return Err(ExecutionError::IllegalInstruction {
1175 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1176 });
1177 }
1178 let Some(vtype) = ext_state.vtype() else {
1179 ::core::hint::cold_path();
1180 return Err(ExecutionError::IllegalInstruction {
1181 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1182 });
1183 };
1184 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
1185 ::core::hint::cold_path();
1186 return Err(ExecutionError::IllegalInstruction {
1187 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1188 });
1189 }
1190 let group_regs = vtype.vlmul().register_count();
1191 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
1192 vtype.vlmul(),
1193 )
1194 .ok_or(ExecutionError::IllegalInstruction {
1195 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1196 })?;
1197 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1198 program_counter,
1199 vd,
1200 dest_group_regs,
1201 )?;
1202 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1203 program_counter,
1204 vs2,
1205 group_regs,
1206 )?;
1207 if !vm && vd == VReg::V0 {
1208 ::core::hint::cold_path();
1209 return Err(ExecutionError::IllegalInstruction {
1210 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1211 });
1212 }
1213 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
1214 program_counter,
1215 vd,
1216 vs2,
1217 dest_group_regs,
1218 group_regs,
1219 )?;
1220 let sew = vtype.vsew();
1221 let scalar = rs1_value.as_u64();
1223 unsafe {
1225 zvexx_muldiv_helpers::execute_widening_op(
1226 ext_state,
1227 vd,
1228 vs2,
1229 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
1230 vm,
1231 sew,
1232 |a, b, sew| {
1233 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
1234 let ub = b & zvexx_muldiv_helpers::sew_mask(sew);
1235 sa.cast_unsigned().wrapping_mul(ub)
1236 },
1237 );
1238 }
1239 }
1240 Self::VwmulVv { vd, vs2, vs1, vm } => {
1242 if !ext_state.vector_instructions_allowed() {
1243 ::core::hint::cold_path();
1244 return Err(ExecutionError::IllegalInstruction {
1245 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1246 });
1247 }
1248 let Some(vtype) = ext_state.vtype() else {
1249 ::core::hint::cold_path();
1250 return Err(ExecutionError::IllegalInstruction {
1251 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1252 });
1253 };
1254 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
1255 ::core::hint::cold_path();
1256 return Err(ExecutionError::IllegalInstruction {
1257 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1258 });
1259 }
1260 let group_regs = vtype.vlmul().register_count();
1261 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
1262 vtype.vlmul(),
1263 )
1264 .ok_or(ExecutionError::IllegalInstruction {
1265 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1266 })?;
1267 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1268 program_counter,
1269 vd,
1270 dest_group_regs,
1271 )?;
1272 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1273 program_counter,
1274 vs2,
1275 group_regs,
1276 )?;
1277 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1278 program_counter,
1279 vs1,
1280 group_regs,
1281 )?;
1282 if !vm && vd == VReg::V0 {
1283 ::core::hint::cold_path();
1284 return Err(ExecutionError::IllegalInstruction {
1285 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1286 });
1287 }
1288 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
1289 program_counter,
1290 vd,
1291 vs2,
1292 dest_group_regs,
1293 group_regs,
1294 )?;
1295 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
1296 program_counter,
1297 vd,
1298 vs1,
1299 dest_group_regs,
1300 group_regs,
1301 )?;
1302 let sew = vtype.vsew();
1303 unsafe {
1305 zvexx_muldiv_helpers::execute_widening_op(
1306 ext_state,
1307 vd,
1308 vs2,
1309 zvexx_muldiv_helpers::OpSrc::Vreg(vs1),
1310 vm,
1311 sew,
1312 |a, b, sew| {
1314 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
1315 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
1316 sa.cast_unsigned().wrapping_mul(sb.cast_unsigned())
1317 },
1318 );
1319 }
1320 }
1321 Self::VwmulVx {
1322 vd,
1323 vs2,
1324 rs1: _,
1325 vm,
1326 } => {
1327 if !ext_state.vector_instructions_allowed() {
1328 ::core::hint::cold_path();
1329 return Err(ExecutionError::IllegalInstruction {
1330 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1331 });
1332 }
1333 let Some(vtype) = ext_state.vtype() else {
1334 ::core::hint::cold_path();
1335 return Err(ExecutionError::IllegalInstruction {
1336 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1337 });
1338 };
1339 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
1340 ::core::hint::cold_path();
1341 return Err(ExecutionError::IllegalInstruction {
1342 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1343 });
1344 }
1345 let group_regs = vtype.vlmul().register_count();
1346 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
1347 vtype.vlmul(),
1348 )
1349 .ok_or(ExecutionError::IllegalInstruction {
1350 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1351 })?;
1352 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1353 program_counter,
1354 vd,
1355 dest_group_regs,
1356 )?;
1357 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1358 program_counter,
1359 vs2,
1360 group_regs,
1361 )?;
1362 if !vm && vd == VReg::V0 {
1363 ::core::hint::cold_path();
1364 return Err(ExecutionError::IllegalInstruction {
1365 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1366 });
1367 }
1368 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
1369 program_counter,
1370 vd,
1371 vs2,
1372 dest_group_regs,
1373 group_regs,
1374 )?;
1375 let sew = vtype.vsew();
1376 let scalar = rs1_value.as_u64();
1378 unsafe {
1380 zvexx_muldiv_helpers::execute_widening_op(
1381 ext_state,
1382 vd,
1383 vs2,
1384 zvexx_muldiv_helpers::OpSrc::Scalar(scalar),
1385 vm,
1386 sew,
1387 |a, b, sew| {
1388 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
1389 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
1390 sa.cast_unsigned().wrapping_mul(sb.cast_unsigned())
1391 },
1392 );
1393 }
1394 }
1395 Self::VmaccVv { vd, vs1, vs2, vm } => {
1397 if !ext_state.vector_instructions_allowed() {
1398 ::core::hint::cold_path();
1399 return Err(ExecutionError::IllegalInstruction {
1400 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1401 });
1402 }
1403 let Some(vtype) = ext_state.vtype() else {
1404 ::core::hint::cold_path();
1405 return Err(ExecutionError::IllegalInstruction {
1406 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1407 });
1408 };
1409 let group_regs = vtype.vlmul().register_count();
1410 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1411 program_counter,
1412 vd,
1413 group_regs,
1414 )?;
1415 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1416 program_counter,
1417 vs2,
1418 group_regs,
1419 )?;
1420 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1421 program_counter,
1422 vs1,
1423 group_regs,
1424 )?;
1425 if !vm && vd == VReg::V0 {
1426 ::core::hint::cold_path();
1427 return Err(ExecutionError::IllegalInstruction {
1428 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1429 });
1430 }
1431 let sew = vtype.vsew();
1432 unsafe {
1434 zvexx_muldiv_helpers::execute_muladd_op(
1435 ext_state,
1436 vd,
1437 vs1,
1438 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1439 vm,
1440 sew,
1441 |acc, a, b, _| acc.wrapping_add(a.wrapping_mul(b)),
1443 );
1444 }
1445 }
1446 Self::VmaccVx {
1447 vd,
1448 rs1: _,
1449 vs2,
1450 vm,
1451 } => {
1452 if !ext_state.vector_instructions_allowed() {
1453 ::core::hint::cold_path();
1454 return Err(ExecutionError::IllegalInstruction {
1455 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1456 });
1457 }
1458 let Some(vtype) = ext_state.vtype() else {
1459 ::core::hint::cold_path();
1460 return Err(ExecutionError::IllegalInstruction {
1461 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1462 });
1463 };
1464 let group_regs = vtype.vlmul().register_count();
1465 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1466 program_counter,
1467 vd,
1468 group_regs,
1469 )?;
1470 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1471 program_counter,
1472 vs2,
1473 group_regs,
1474 )?;
1475 if !vm && vd == VReg::V0 {
1476 ::core::hint::cold_path();
1477 return Err(ExecutionError::IllegalInstruction {
1478 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1479 });
1480 }
1481 let sew = vtype.vsew();
1482 let scalar = rs1_value.as_i64().cast_unsigned();
1483 unsafe {
1485 zvexx_muldiv_helpers::execute_muladd_scalar_op(
1486 ext_state,
1487 vd,
1488 scalar,
1489 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1490 vm,
1491 sew,
1492 |acc, a, b, _| acc.wrapping_add(a.wrapping_mul(b)),
1493 );
1494 }
1495 }
1496 Self::VnmsacVv { vd, vs1, vs2, vm } => {
1498 if !ext_state.vector_instructions_allowed() {
1499 ::core::hint::cold_path();
1500 return Err(ExecutionError::IllegalInstruction {
1501 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1502 });
1503 }
1504 let Some(vtype) = ext_state.vtype() else {
1505 ::core::hint::cold_path();
1506 return Err(ExecutionError::IllegalInstruction {
1507 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1508 });
1509 };
1510 let group_regs = vtype.vlmul().register_count();
1511 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1512 program_counter,
1513 vd,
1514 group_regs,
1515 )?;
1516 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1517 program_counter,
1518 vs2,
1519 group_regs,
1520 )?;
1521 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1522 program_counter,
1523 vs1,
1524 group_regs,
1525 )?;
1526 if !vm && vd == VReg::V0 {
1527 ::core::hint::cold_path();
1528 return Err(ExecutionError::IllegalInstruction {
1529 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1530 });
1531 }
1532 let sew = vtype.vsew();
1533 unsafe {
1535 zvexx_muldiv_helpers::execute_muladd_op(
1536 ext_state,
1537 vd,
1538 vs1,
1539 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1540 vm,
1541 sew,
1542 |acc, a, b, _| acc.wrapping_sub(a.wrapping_mul(b)),
1544 );
1545 }
1546 }
1547 Self::VnmsacVx {
1548 vd,
1549 rs1: _,
1550 vs2,
1551 vm,
1552 } => {
1553 if !ext_state.vector_instructions_allowed() {
1554 ::core::hint::cold_path();
1555 return Err(ExecutionError::IllegalInstruction {
1556 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1557 });
1558 }
1559 let Some(vtype) = ext_state.vtype() else {
1560 ::core::hint::cold_path();
1561 return Err(ExecutionError::IllegalInstruction {
1562 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1563 });
1564 };
1565 let group_regs = vtype.vlmul().register_count();
1566 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1567 program_counter,
1568 vd,
1569 group_regs,
1570 )?;
1571 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1572 program_counter,
1573 vs2,
1574 group_regs,
1575 )?;
1576 if !vm && vd == VReg::V0 {
1577 ::core::hint::cold_path();
1578 return Err(ExecutionError::IllegalInstruction {
1579 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1580 });
1581 }
1582 let sew = vtype.vsew();
1583 let scalar = rs1_value.as_i64().cast_unsigned();
1584 unsafe {
1586 zvexx_muldiv_helpers::execute_muladd_scalar_op(
1587 ext_state,
1588 vd,
1589 scalar,
1590 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1591 vm,
1592 sew,
1593 |acc, a, b, _| acc.wrapping_sub(a.wrapping_mul(b)),
1594 );
1595 }
1596 }
1597 Self::VmaddVv { vd, vs1, vs2, vm } => {
1599 if !ext_state.vector_instructions_allowed() {
1600 ::core::hint::cold_path();
1601 return Err(ExecutionError::IllegalInstruction {
1602 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1603 });
1604 }
1605 let Some(vtype) = ext_state.vtype() else {
1606 ::core::hint::cold_path();
1607 return Err(ExecutionError::IllegalInstruction {
1608 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1609 });
1610 };
1611 let group_regs = vtype.vlmul().register_count();
1612 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1613 program_counter,
1614 vd,
1615 group_regs,
1616 )?;
1617 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1618 program_counter,
1619 vs2,
1620 group_regs,
1621 )?;
1622 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1623 program_counter,
1624 vs1,
1625 group_regs,
1626 )?;
1627 if !vm && vd == VReg::V0 {
1628 ::core::hint::cold_path();
1629 return Err(ExecutionError::IllegalInstruction {
1630 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1631 });
1632 }
1633 let sew = vtype.vsew();
1634 unsafe {
1636 zvexx_muldiv_helpers::execute_muladd_op(
1637 ext_state,
1638 vd,
1639 vs1,
1640 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1641 vm,
1642 sew,
1643 |acc, a, b, _| a.wrapping_mul(acc).wrapping_add(b),
1645 );
1646 }
1647 }
1648 Self::VmaddVx {
1649 vd,
1650 rs1: _,
1651 vs2,
1652 vm,
1653 } => {
1654 if !ext_state.vector_instructions_allowed() {
1655 ::core::hint::cold_path();
1656 return Err(ExecutionError::IllegalInstruction {
1657 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1658 });
1659 }
1660 let Some(vtype) = ext_state.vtype() else {
1661 ::core::hint::cold_path();
1662 return Err(ExecutionError::IllegalInstruction {
1663 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1664 });
1665 };
1666 let group_regs = vtype.vlmul().register_count();
1667 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1668 program_counter,
1669 vd,
1670 group_regs,
1671 )?;
1672 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1673 program_counter,
1674 vs2,
1675 group_regs,
1676 )?;
1677 if !vm && vd == VReg::V0 {
1678 ::core::hint::cold_path();
1679 return Err(ExecutionError::IllegalInstruction {
1680 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1681 });
1682 }
1683 let sew = vtype.vsew();
1684 let scalar = rs1_value.as_i64().cast_unsigned();
1685 unsafe {
1687 zvexx_muldiv_helpers::execute_muladd_scalar_op(
1688 ext_state,
1689 vd,
1690 scalar,
1691 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1692 vm,
1693 sew,
1694 |acc, a, b, _| a.wrapping_mul(acc).wrapping_add(b),
1696 );
1697 }
1698 }
1699 Self::VnmsubVv { vd, vs1, vs2, vm } => {
1701 if !ext_state.vector_instructions_allowed() {
1702 ::core::hint::cold_path();
1703 return Err(ExecutionError::IllegalInstruction {
1704 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1705 });
1706 }
1707 let Some(vtype) = ext_state.vtype() else {
1708 ::core::hint::cold_path();
1709 return Err(ExecutionError::IllegalInstruction {
1710 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
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 Err(ExecutionError::IllegalInstruction {
1732 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1733 });
1734 }
1735 let sew = vtype.vsew();
1736 unsafe {
1738 zvexx_muldiv_helpers::execute_muladd_op(
1739 ext_state,
1740 vd,
1741 vs1,
1742 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1743 vm,
1744 sew,
1745 |acc, a, b, _| b.wrapping_sub(a.wrapping_mul(acc)),
1747 );
1748 }
1749 }
1750 Self::VnmsubVx {
1751 vd,
1752 rs1: _,
1753 vs2,
1754 vm,
1755 } => {
1756 if !ext_state.vector_instructions_allowed() {
1757 ::core::hint::cold_path();
1758 return Err(ExecutionError::IllegalInstruction {
1759 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1760 });
1761 }
1762 let Some(vtype) = ext_state.vtype() else {
1763 ::core::hint::cold_path();
1764 return Err(ExecutionError::IllegalInstruction {
1765 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
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 Err(ExecutionError::IllegalInstruction {
1782 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1783 });
1784 }
1785 let sew = vtype.vsew();
1786 let scalar = rs1_value.as_i64().cast_unsigned();
1787 unsafe {
1789 zvexx_muldiv_helpers::execute_muladd_scalar_op(
1790 ext_state,
1791 vd,
1792 scalar,
1793 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1794 vm,
1795 sew,
1796 |acc, a, b, _| b.wrapping_sub(a.wrapping_mul(acc)),
1798 );
1799 }
1800 }
1801 Self::VwmaccuVv { vd, vs1, vs2, vm } => {
1803 if !ext_state.vector_instructions_allowed() {
1804 ::core::hint::cold_path();
1805 return Err(ExecutionError::IllegalInstruction {
1806 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1807 });
1808 }
1809 let Some(vtype) = ext_state.vtype() else {
1810 ::core::hint::cold_path();
1811 return Err(ExecutionError::IllegalInstruction {
1812 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1813 });
1814 };
1815 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
1816 ::core::hint::cold_path();
1817 return Err(ExecutionError::IllegalInstruction {
1818 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1819 });
1820 }
1821 let group_regs = vtype.vlmul().register_count();
1822 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
1823 vtype.vlmul(),
1824 )
1825 .ok_or(ExecutionError::IllegalInstruction {
1826 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1827 })?;
1828 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1830 program_counter,
1831 vd,
1832 dest_group_regs,
1833 )?;
1834 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1835 program_counter,
1836 vs2,
1837 group_regs,
1838 )?;
1839 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1840 program_counter,
1841 vs1,
1842 group_regs,
1843 )?;
1844 if !vm && vd == VReg::V0 {
1845 ::core::hint::cold_path();
1846 return Err(ExecutionError::IllegalInstruction {
1847 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1848 });
1849 }
1850 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
1851 program_counter,
1852 vd,
1853 vs2,
1854 dest_group_regs,
1855 group_regs,
1856 )?;
1857 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
1858 program_counter,
1859 vd,
1860 vs1,
1861 dest_group_regs,
1862 group_regs,
1863 )?;
1864 let sew = vtype.vsew();
1865 unsafe {
1867 zvexx_muldiv_helpers::execute_widening_muladd_op(
1868 ext_state,
1869 vd,
1870 vs1,
1871 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1872 vm,
1873 sew,
1874 |acc, a, b, sew| {
1876 let mask = zvexx_muldiv_helpers::sew_mask(sew);
1877 acc.wrapping_add((a & mask).wrapping_mul(b & mask))
1878 },
1879 );
1880 }
1881 }
1882 Self::VwmaccuVx {
1883 vd,
1884 rs1: _,
1885 vs2,
1886 vm,
1887 } => {
1888 if !ext_state.vector_instructions_allowed() {
1889 ::core::hint::cold_path();
1890 return Err(ExecutionError::IllegalInstruction {
1891 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1892 });
1893 }
1894 let Some(vtype) = ext_state.vtype() else {
1895 ::core::hint::cold_path();
1896 return Err(ExecutionError::IllegalInstruction {
1897 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1898 });
1899 };
1900 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
1901 ::core::hint::cold_path();
1902 return Err(ExecutionError::IllegalInstruction {
1903 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1904 });
1905 }
1906 let group_regs = vtype.vlmul().register_count();
1907 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
1908 vtype.vlmul(),
1909 )
1910 .ok_or(ExecutionError::IllegalInstruction {
1911 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1912 })?;
1913 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1914 program_counter,
1915 vd,
1916 dest_group_regs,
1917 )?;
1918 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1919 program_counter,
1920 vs2,
1921 group_regs,
1922 )?;
1923 if !vm && vd == VReg::V0 {
1924 ::core::hint::cold_path();
1925 return Err(ExecutionError::IllegalInstruction {
1926 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1927 });
1928 }
1929 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
1930 program_counter,
1931 vd,
1932 vs2,
1933 dest_group_regs,
1934 group_regs,
1935 )?;
1936 let sew = vtype.vsew();
1937 let scalar = rs1_value.as_u64();
1938 unsafe {
1940 zvexx_muldiv_helpers::execute_widening_muladd_scalar_op(
1941 ext_state,
1942 vd,
1943 scalar,
1944 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
1945 vm,
1946 sew,
1947 |acc, a, b, sew| {
1948 let mask = zvexx_muldiv_helpers::sew_mask(sew);
1949 acc.wrapping_add((a & mask).wrapping_mul(b & mask))
1950 },
1951 );
1952 }
1953 }
1954 Self::VwmaccVv { vd, vs1, vs2, vm } => {
1956 if !ext_state.vector_instructions_allowed() {
1957 ::core::hint::cold_path();
1958 return Err(ExecutionError::IllegalInstruction {
1959 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1960 });
1961 }
1962 let Some(vtype) = ext_state.vtype() else {
1963 ::core::hint::cold_path();
1964 return Err(ExecutionError::IllegalInstruction {
1965 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1966 });
1967 };
1968 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
1969 ::core::hint::cold_path();
1970 return Err(ExecutionError::IllegalInstruction {
1971 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1972 });
1973 }
1974 let group_regs = vtype.vlmul().register_count();
1975 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
1976 vtype.vlmul(),
1977 )
1978 .ok_or(ExecutionError::IllegalInstruction {
1979 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1980 })?;
1981 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1982 program_counter,
1983 vd,
1984 dest_group_regs,
1985 )?;
1986 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1987 program_counter,
1988 vs2,
1989 group_regs,
1990 )?;
1991 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
1992 program_counter,
1993 vs1,
1994 group_regs,
1995 )?;
1996 if !vm && vd == VReg::V0 {
1997 ::core::hint::cold_path();
1998 return Err(ExecutionError::IllegalInstruction {
1999 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2000 });
2001 }
2002 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
2003 program_counter,
2004 vd,
2005 vs2,
2006 dest_group_regs,
2007 group_regs,
2008 )?;
2009 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
2010 program_counter,
2011 vd,
2012 vs1,
2013 dest_group_regs,
2014 group_regs,
2015 )?;
2016 let sew = vtype.vsew();
2017 unsafe {
2019 zvexx_muldiv_helpers::execute_widening_muladd_op(
2020 ext_state,
2021 vd,
2022 vs1,
2023 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2024 vm,
2025 sew,
2026 |acc, a, b, sew| {
2028 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
2029 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
2030 acc.wrapping_add(sa.cast_unsigned().wrapping_mul(sb.cast_unsigned()))
2031 },
2032 );
2033 }
2034 }
2035 Self::VwmaccVx {
2036 vd,
2037 rs1: _,
2038 vs2,
2039 vm,
2040 } => {
2041 if !ext_state.vector_instructions_allowed() {
2042 ::core::hint::cold_path();
2043 return Err(ExecutionError::IllegalInstruction {
2044 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2045 });
2046 }
2047 let Some(vtype) = ext_state.vtype() else {
2048 ::core::hint::cold_path();
2049 return Err(ExecutionError::IllegalInstruction {
2050 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2051 });
2052 };
2053 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
2054 ::core::hint::cold_path();
2055 return Err(ExecutionError::IllegalInstruction {
2056 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2057 });
2058 }
2059 let group_regs = vtype.vlmul().register_count();
2060 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
2061 vtype.vlmul(),
2062 )
2063 .ok_or(ExecutionError::IllegalInstruction {
2064 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2065 })?;
2066 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2067 program_counter,
2068 vd,
2069 dest_group_regs,
2070 )?;
2071 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2072 program_counter,
2073 vs2,
2074 group_regs,
2075 )?;
2076 if !vm && vd == VReg::V0 {
2077 ::core::hint::cold_path();
2078 return Err(ExecutionError::IllegalInstruction {
2079 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2080 });
2081 }
2082 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
2083 program_counter,
2084 vd,
2085 vs2,
2086 dest_group_regs,
2087 group_regs,
2088 )?;
2089 let sew = vtype.vsew();
2090 let scalar = rs1_value.as_u64();
2091 unsafe {
2093 zvexx_muldiv_helpers::execute_widening_muladd_scalar_op(
2094 ext_state,
2095 vd,
2096 scalar,
2097 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2098 vm,
2099 sew,
2100 |acc, a, b, sew| {
2101 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
2102 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
2103 acc.wrapping_add(sa.cast_unsigned().wrapping_mul(sb.cast_unsigned()))
2104 },
2105 );
2106 }
2107 }
2108 Self::VwmaccsuVv { vd, vs1, vs2, vm } => {
2110 if !ext_state.vector_instructions_allowed() {
2111 ::core::hint::cold_path();
2112 return Err(ExecutionError::IllegalInstruction {
2113 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2114 });
2115 }
2116 let Some(vtype) = ext_state.vtype() else {
2117 ::core::hint::cold_path();
2118 return Err(ExecutionError::IllegalInstruction {
2119 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2120 });
2121 };
2122 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
2123 ::core::hint::cold_path();
2124 return Err(ExecutionError::IllegalInstruction {
2125 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2126 });
2127 }
2128 let group_regs = vtype.vlmul().register_count();
2129 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
2130 vtype.vlmul(),
2131 )
2132 .ok_or(ExecutionError::IllegalInstruction {
2133 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2134 })?;
2135 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2136 program_counter,
2137 vd,
2138 dest_group_regs,
2139 )?;
2140 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2141 program_counter,
2142 vs2,
2143 group_regs,
2144 )?;
2145 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2146 program_counter,
2147 vs1,
2148 group_regs,
2149 )?;
2150 if !vm && vd == VReg::V0 {
2151 ::core::hint::cold_path();
2152 return Err(ExecutionError::IllegalInstruction {
2153 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2154 });
2155 }
2156 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
2157 program_counter,
2158 vd,
2159 vs2,
2160 dest_group_regs,
2161 group_regs,
2162 )?;
2163 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
2164 program_counter,
2165 vd,
2166 vs1,
2167 dest_group_regs,
2168 group_regs,
2169 )?;
2170 let sew = vtype.vsew();
2171 unsafe {
2173 zvexx_muldiv_helpers::execute_widening_muladd_op(
2174 ext_state,
2175 vd,
2176 vs1,
2177 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2178 vm,
2179 sew,
2180 |acc, a, b, sew| {
2182 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
2183 let ub = b & zvexx_muldiv_helpers::sew_mask(sew);
2184 acc.wrapping_add(sa.cast_unsigned().wrapping_mul(ub))
2185 },
2186 );
2187 }
2188 }
2189 Self::VwmaccsuVx {
2190 vd,
2191 rs1: _,
2192 vs2,
2193 vm,
2194 } => {
2195 if !ext_state.vector_instructions_allowed() {
2196 ::core::hint::cold_path();
2197 return Err(ExecutionError::IllegalInstruction {
2198 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2199 });
2200 }
2201 let Some(vtype) = ext_state.vtype() else {
2202 ::core::hint::cold_path();
2203 return Err(ExecutionError::IllegalInstruction {
2204 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2205 });
2206 };
2207 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
2208 ::core::hint::cold_path();
2209 return Err(ExecutionError::IllegalInstruction {
2210 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2211 });
2212 }
2213 let group_regs = vtype.vlmul().register_count();
2214 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
2215 vtype.vlmul(),
2216 )
2217 .ok_or(ExecutionError::IllegalInstruction {
2218 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2219 })?;
2220 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2221 program_counter,
2222 vd,
2223 dest_group_regs,
2224 )?;
2225 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2226 program_counter,
2227 vs2,
2228 group_regs,
2229 )?;
2230 if !vm && vd == VReg::V0 {
2231 ::core::hint::cold_path();
2232 return Err(ExecutionError::IllegalInstruction {
2233 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2234 });
2235 }
2236 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
2237 program_counter,
2238 vd,
2239 vs2,
2240 dest_group_regs,
2241 group_regs,
2242 )?;
2243 let sew = vtype.vsew();
2244 let scalar = rs1_value.as_u64();
2246 unsafe {
2248 zvexx_muldiv_helpers::execute_widening_muladd_scalar_op(
2249 ext_state,
2250 vd,
2251 scalar,
2252 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2253 vm,
2254 sew,
2255 |acc, a, b, sew| {
2259 let sa = zvexx_muldiv_helpers::sign_extend(a, sew);
2260 let ub = b & zvexx_muldiv_helpers::sew_mask(sew);
2261 acc.wrapping_add(sa.cast_unsigned().wrapping_mul(ub))
2262 },
2263 );
2264 }
2265 }
2266 Self::VwmaccusVx {
2268 vd,
2269 rs1: _,
2270 vs2,
2271 vm,
2272 } => {
2273 if !ext_state.vector_instructions_allowed() {
2274 ::core::hint::cold_path();
2275 return Err(ExecutionError::IllegalInstruction {
2276 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2277 });
2278 }
2279 let Some(vtype) = ext_state.vtype() else {
2280 ::core::hint::cold_path();
2281 return Err(ExecutionError::IllegalInstruction {
2282 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2283 });
2284 };
2285 if u32::from(vtype.vsew().bits_width()) == u64::BITS {
2286 ::core::hint::cold_path();
2287 return Err(ExecutionError::IllegalInstruction {
2288 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2289 });
2290 }
2291 let group_regs = vtype.vlmul().register_count();
2292 let dest_group_regs = zvexx_muldiv_helpers::widening_dest_register_count(
2293 vtype.vlmul(),
2294 )
2295 .ok_or(ExecutionError::IllegalInstruction {
2296 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2297 })?;
2298 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2299 program_counter,
2300 vd,
2301 dest_group_regs,
2302 )?;
2303 zvexx_muldiv_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
2304 program_counter,
2305 vs2,
2306 group_regs,
2307 )?;
2308 if !vm && vd == VReg::V0 {
2309 ::core::hint::cold_path();
2310 return Err(ExecutionError::IllegalInstruction {
2311 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2312 });
2313 }
2314 zvexx_muldiv_helpers::check_no_widening_overlap::<Reg, _, _, _>(
2315 program_counter,
2316 vd,
2317 vs2,
2318 dest_group_regs,
2319 group_regs,
2320 )?;
2321 let sew = vtype.vsew();
2322 let scalar = rs1_value.as_u64();
2324 unsafe {
2326 zvexx_muldiv_helpers::execute_widening_muladd_scalar_op(
2327 ext_state,
2328 vd,
2329 scalar,
2330 zvexx_muldiv_helpers::OpSrc::Vreg(vs2),
2331 vm,
2332 sew,
2333 |acc, a, b, sew| {
2337 let ua = a & zvexx_muldiv_helpers::sew_mask(sew);
2338 let sb = zvexx_muldiv_helpers::sign_extend(b, sew);
2339 acc.wrapping_add(sb.cast_unsigned().wrapping_mul(ua))
2340 },
2341 );
2342 }
2343 }
2344 }
2345
2346 Ok(ControlFlow::Continue(Default::default()))
2347 }
2348}