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