Skip to main content

ab_riscv_interpreter/v/zve64x/
muldiv.rs

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