Skip to main content

ab_riscv_interpreter/v/zvexx/
widen_narrow.rs

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