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