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                )?;
1514                zvexx_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _>(
1515                    program_counter,
1516                    vs2,
1517                    wide_group_regs,
1518                )?;
1519                zvexx_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _>(
1520                    program_counter,
1521                    vs1,
1522                    group_regs,
1523                )?;
1524                if !vm && vd == VReg::V0 {
1525                    ::core::hint::cold_path();
1526                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1527                        address: PackedAddress::new(
1528                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1529                        ),
1530                    });
1531                }
1532                // SAFETY: alignment/overlap/SEW checked above
1533                unsafe {
1534                    zvexx_widen_narrow_helpers::execute_narrow_shift::<false, _, _>(
1535                        env,
1536                        vd,
1537                        vs2,
1538                        zvexx_widen_narrow_helpers::OpSrc::Vreg(vs1),
1539                        vm,
1540                        sew,
1541                    );
1542                }
1543            }
1544            // vnsrl.wx - SEW = (2*SEW) >> rs1 (logical)
1545            Self::VnsrlWx {
1546                vd,
1547                vs2,
1548                rs1: _,
1549                vm,
1550            } => {
1551                if !env.vector_instructions_allowed() {
1552                    ::core::hint::cold_path();
1553                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1554                        address: PackedAddress::new(
1555                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1556                        ),
1557                    });
1558                }
1559                let Some(vtype) = env.vtype() else {
1560                    ::core::hint::cold_path();
1561                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1562                        address: PackedAddress::new(
1563                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1564                        ),
1565                    });
1566                };
1567                let sew = vtype.vsew();
1568                let group_regs = vtype.vlmul().register_count();
1569                let wide_eew = match sew {
1570                    Vsew::E8 => Eew::E16,
1571                    Vsew::E16 => Eew::E32,
1572                    Vsew::E32 => Eew::E64,
1573                    Vsew::E64 => {
1574                        ::core::hint::cold_path();
1575                        return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1576                            address: PackedAddress::new(
1577                                program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1578                            ),
1579                        });
1580                    }
1581                };
1582                if u32::from(wide_eew.bits_width()) > u32::from(Env::ELEN) {
1583                    ::core::hint::cold_path();
1584                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1585                        address: PackedAddress::new(
1586                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1587                        ),
1588                    });
1589                }
1590                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
1591                    ExecutionError::IllegalInstruction {
1592                        address: PackedAddress::new(
1593                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1594                        ),
1595                    },
1596                )?;
1597                zvexx_widen_narrow_helpers::check_vd_narrow_alignment::<Reg, _, _>(
1598                    program_counter,
1599                    vd,
1600                    group_regs,
1601                )?;
1602                zvexx_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _>(
1603                    program_counter,
1604                    vs2,
1605                    wide_group_regs,
1606                )?;
1607                if !vm && vd == VReg::V0 {
1608                    ::core::hint::cold_path();
1609                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1610                        address: PackedAddress::new(
1611                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1612                        ),
1613                    });
1614                }
1615                let scalar = rs1_value.as_u64();
1616                // SAFETY: alignment/overlap/SEW checked above
1617                unsafe {
1618                    zvexx_widen_narrow_helpers::execute_narrow_shift::<false, _, _>(
1619                        env,
1620                        vd,
1621                        vs2,
1622                        zvexx_widen_narrow_helpers::OpSrc::Scalar(scalar),
1623                        vm,
1624                        sew,
1625                    );
1626                }
1627            }
1628            // vnsrl.wi - SEW = (2*SEW) >> uimm (logical)
1629            Self::VnsrlWi { vd, vs2, uimm, vm } => {
1630                if !env.vector_instructions_allowed() {
1631                    ::core::hint::cold_path();
1632                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1633                        address: PackedAddress::new(
1634                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1635                        ),
1636                    });
1637                }
1638                let Some(vtype) = env.vtype() else {
1639                    ::core::hint::cold_path();
1640                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1641                        address: PackedAddress::new(
1642                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1643                        ),
1644                    });
1645                };
1646                let sew = vtype.vsew();
1647                let group_regs = vtype.vlmul().register_count();
1648                let wide_eew = match sew {
1649                    Vsew::E8 => Eew::E16,
1650                    Vsew::E16 => Eew::E32,
1651                    Vsew::E32 => Eew::E64,
1652                    Vsew::E64 => {
1653                        ::core::hint::cold_path();
1654                        return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1655                            address: PackedAddress::new(
1656                                program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1657                            ),
1658                        });
1659                    }
1660                };
1661                if u32::from(wide_eew.bits_width()) > u32::from(Env::ELEN) {
1662                    ::core::hint::cold_path();
1663                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1664                        address: PackedAddress::new(
1665                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1666                        ),
1667                    });
1668                }
1669                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
1670                    ExecutionError::IllegalInstruction {
1671                        address: PackedAddress::new(
1672                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1673                        ),
1674                    },
1675                )?;
1676                zvexx_widen_narrow_helpers::check_vd_narrow_alignment::<Reg, _, _>(
1677                    program_counter,
1678                    vd,
1679                    group_regs,
1680                )?;
1681                zvexx_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _>(
1682                    program_counter,
1683                    vs2,
1684                    wide_group_regs,
1685                )?;
1686                if !vm && vd == VReg::V0 {
1687                    ::core::hint::cold_path();
1688                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1689                        address: PackedAddress::new(
1690                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1691                        ),
1692                    });
1693                }
1694                // SAFETY: alignment/overlap/SEW checked above
1695                unsafe {
1696                    zvexx_widen_narrow_helpers::execute_narrow_shift::<false, _, _>(
1697                        env,
1698                        vd,
1699                        vs2,
1700                        zvexx_widen_narrow_helpers::OpSrc::Scalar(u64::from(uimm)),
1701                        vm,
1702                        sew,
1703                    );
1704                }
1705            }
1706            // vnsra.wv - SEW = (2*SEW) >> SEW (arithmetic)
1707            Self::VnsraWv { vd, vs2, vs1, vm } => {
1708                if !env.vector_instructions_allowed() {
1709                    ::core::hint::cold_path();
1710                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1711                        address: PackedAddress::new(
1712                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1713                        ),
1714                    });
1715                }
1716                let Some(vtype) = env.vtype() else {
1717                    ::core::hint::cold_path();
1718                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1719                        address: PackedAddress::new(
1720                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1721                        ),
1722                    });
1723                };
1724                let sew = vtype.vsew();
1725                let group_regs = vtype.vlmul().register_count();
1726                let wide_eew = match sew {
1727                    Vsew::E8 => Eew::E16,
1728                    Vsew::E16 => Eew::E32,
1729                    Vsew::E32 => Eew::E64,
1730                    Vsew::E64 => {
1731                        ::core::hint::cold_path();
1732                        return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1733                            address: PackedAddress::new(
1734                                program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1735                            ),
1736                        });
1737                    }
1738                };
1739                if u32::from(wide_eew.bits_width()) > u32::from(Env::ELEN) {
1740                    ::core::hint::cold_path();
1741                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1742                        address: PackedAddress::new(
1743                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1744                        ),
1745                    });
1746                }
1747                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
1748                    ExecutionError::IllegalInstruction {
1749                        address: PackedAddress::new(
1750                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1751                        ),
1752                    },
1753                )?;
1754                zvexx_widen_narrow_helpers::check_vd_narrow_alignment::<Reg, _, _>(
1755                    program_counter,
1756                    vd,
1757                    group_regs,
1758                )?;
1759                zvexx_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _>(
1760                    program_counter,
1761                    vs2,
1762                    wide_group_regs,
1763                )?;
1764                zvexx_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _>(
1765                    program_counter,
1766                    vs1,
1767                    group_regs,
1768                )?;
1769                if !vm && vd == VReg::V0 {
1770                    ::core::hint::cold_path();
1771                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1772                        address: PackedAddress::new(
1773                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1774                        ),
1775                    });
1776                }
1777                // SAFETY: alignment/overlap/SEW checked above
1778                unsafe {
1779                    zvexx_widen_narrow_helpers::execute_narrow_shift::<true, _, _>(
1780                        env,
1781                        vd,
1782                        vs2,
1783                        zvexx_widen_narrow_helpers::OpSrc::Vreg(vs1),
1784                        vm,
1785                        sew,
1786                    );
1787                }
1788            }
1789            // vnsra.wx - SEW = (2*SEW) >> rs1 (arithmetic)
1790            Self::VnsraWx {
1791                vd,
1792                vs2,
1793                rs1: _,
1794                vm,
1795            } => {
1796                if !env.vector_instructions_allowed() {
1797                    ::core::hint::cold_path();
1798                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1799                        address: PackedAddress::new(
1800                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1801                        ),
1802                    });
1803                }
1804                let Some(vtype) = env.vtype() else {
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 sew = vtype.vsew();
1813                let group_regs = vtype.vlmul().register_count();
1814                let wide_eew = match sew {
1815                    Vsew::E8 => Eew::E16,
1816                    Vsew::E16 => Eew::E32,
1817                    Vsew::E32 => Eew::E64,
1818                    Vsew::E64 => {
1819                        ::core::hint::cold_path();
1820                        return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1821                            address: PackedAddress::new(
1822                                program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1823                            ),
1824                        });
1825                    }
1826                };
1827                if u32::from(wide_eew.bits_width()) > u32::from(Env::ELEN) {
1828                    ::core::hint::cold_path();
1829                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1830                        address: PackedAddress::new(
1831                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1832                        ),
1833                    });
1834                }
1835                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
1836                    ExecutionError::IllegalInstruction {
1837                        address: PackedAddress::new(
1838                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1839                        ),
1840                    },
1841                )?;
1842                zvexx_widen_narrow_helpers::check_vd_narrow_alignment::<Reg, _, _>(
1843                    program_counter,
1844                    vd,
1845                    group_regs,
1846                )?;
1847                zvexx_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _>(
1848                    program_counter,
1849                    vs2,
1850                    wide_group_regs,
1851                )?;
1852                if !vm && vd == VReg::V0 {
1853                    ::core::hint::cold_path();
1854                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1855                        address: PackedAddress::new(
1856                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1857                        ),
1858                    });
1859                }
1860                let scalar = rs1_value.as_u64();
1861                // SAFETY: alignment/overlap/SEW checked above
1862                unsafe {
1863                    zvexx_widen_narrow_helpers::execute_narrow_shift::<true, _, _>(
1864                        env,
1865                        vd,
1866                        vs2,
1867                        zvexx_widen_narrow_helpers::OpSrc::Scalar(scalar),
1868                        vm,
1869                        sew,
1870                    );
1871                }
1872            }
1873            // vnsra.wi - SEW = (2*SEW) >> uimm (arithmetic)
1874            Self::VnsraWi { vd, vs2, uimm, vm } => {
1875                if !env.vector_instructions_allowed() {
1876                    ::core::hint::cold_path();
1877                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1878                        address: PackedAddress::new(
1879                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1880                        ),
1881                    });
1882                }
1883                let Some(vtype) = env.vtype() else {
1884                    ::core::hint::cold_path();
1885                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1886                        address: PackedAddress::new(
1887                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1888                        ),
1889                    });
1890                };
1891                let sew = vtype.vsew();
1892                let group_regs = vtype.vlmul().register_count();
1893                let wide_eew = match sew {
1894                    Vsew::E8 => Eew::E16,
1895                    Vsew::E16 => Eew::E32,
1896                    Vsew::E32 => Eew::E64,
1897                    Vsew::E64 => {
1898                        ::core::hint::cold_path();
1899                        return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1900                            address: PackedAddress::new(
1901                                program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1902                            ),
1903                        });
1904                    }
1905                };
1906                if u32::from(wide_eew.bits_width()) > u32::from(Env::ELEN) {
1907                    ::core::hint::cold_path();
1908                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1909                        address: PackedAddress::new(
1910                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1911                        ),
1912                    });
1913                }
1914                let wide_group_regs = vtype.vlmul().data_register_count(wide_eew, sew).ok_or(
1915                    ExecutionError::IllegalInstruction {
1916                        address: PackedAddress::new(
1917                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1918                        ),
1919                    },
1920                )?;
1921                zvexx_widen_narrow_helpers::check_vd_narrow_alignment::<Reg, _, _>(
1922                    program_counter,
1923                    vd,
1924                    group_regs,
1925                )?;
1926                zvexx_widen_narrow_helpers::check_vs_wide_alignment::<Reg, _, _>(
1927                    program_counter,
1928                    vs2,
1929                    wide_group_regs,
1930                )?;
1931                if !vm && vd == VReg::V0 {
1932                    ::core::hint::cold_path();
1933                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1934                        address: PackedAddress::new(
1935                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1936                        ),
1937                    });
1938                }
1939                // SAFETY: alignment/overlap/SEW checked above
1940                unsafe {
1941                    zvexx_widen_narrow_helpers::execute_narrow_shift::<true, _, _>(
1942                        env,
1943                        vd,
1944                        vs2,
1945                        zvexx_widen_narrow_helpers::OpSrc::Scalar(u64::from(uimm)),
1946                        vm,
1947                        sew,
1948                    );
1949                }
1950            }
1951            // vzext.vf2 - zero-extend SEW/2 -> SEW
1952            Self::VzextVf2 { vd, vs2, vm } => {
1953                if !env.vector_instructions_allowed() {
1954                    ::core::hint::cold_path();
1955                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1956                        address: PackedAddress::new(
1957                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1958                        ),
1959                    });
1960                }
1961                let Some(vtype) = env.vtype() else {
1962                    ::core::hint::cold_path();
1963                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1964                        address: PackedAddress::new(
1965                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1966                        ),
1967                    });
1968                };
1969                let sew = vtype.vsew();
1970                // SEW must be >= 2*8 = 16
1971                if u32::from(sew.bits_width()) < 16 {
1972                    ::core::hint::cold_path();
1973                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1974                        address: PackedAddress::new(
1975                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1976                        ),
1977                    });
1978                }
1979                let group_regs = vtype.vlmul().register_count();
1980                // EMUL for source = LMUL / 2; src_group = max(1, group_regs / 2)
1981                let src_group = ::core::num::NonZeroU8::new(group_regs.get().max(2) / 2)
1982                    .expect("Not zero; qed");
1983                zvexx_widen_narrow_helpers::check_vs_ext_alignment::<Reg, _, _>(
1984                    program_counter,
1985                    vs2,
1986                    src_group,
1987                    vd,
1988                    group_regs,
1989                )?;
1990                zvexx_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _>(
1991                    program_counter,
1992                    vd,
1993                    group_regs,
1994                )?;
1995                if !vm && vd == VReg::V0 {
1996                    ::core::hint::cold_path();
1997                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1998                        address: PackedAddress::new(
1999                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2000                        ),
2001                    });
2002                }
2003                // SAFETY: alignment/overlap/SEW checked above
2004                unsafe {
2005                    zvexx_widen_narrow_helpers::execute_extension::<false, _, _>(
2006                        env,
2007                        vd,
2008                        vs2,
2009                        vm,
2010                        sew,
2011                        VsewFactor::F2,
2012                    );
2013                }
2014            }
2015            // vzext.vf4 - zero-extend SEW/4 -> SEW
2016            Self::VzextVf4 { vd, vs2, vm } => {
2017                if !env.vector_instructions_allowed() {
2018                    ::core::hint::cold_path();
2019                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2020                        address: PackedAddress::new(
2021                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2022                        ),
2023                    });
2024                }
2025                let Some(vtype) = env.vtype() else {
2026                    ::core::hint::cold_path();
2027                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2028                        address: PackedAddress::new(
2029                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2030                        ),
2031                    });
2032                };
2033                let sew = vtype.vsew();
2034                // SEW must be >= 4*8 = 32
2035                if u32::from(sew.bits_width()) < 32 {
2036                    ::core::hint::cold_path();
2037                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2038                        address: PackedAddress::new(
2039                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2040                        ),
2041                    });
2042                }
2043                let group_regs = vtype.vlmul().register_count();
2044                let src_group = ::core::num::NonZeroU8::new(group_regs.get().max(4) / 4)
2045                    .expect("Not zero; qed");
2046                zvexx_widen_narrow_helpers::check_vs_ext_alignment::<Reg, _, _>(
2047                    program_counter,
2048                    vs2,
2049                    src_group,
2050                    vd,
2051                    group_regs,
2052                )?;
2053                zvexx_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _>(
2054                    program_counter,
2055                    vd,
2056                    group_regs,
2057                )?;
2058                if !vm && vd == VReg::V0 {
2059                    ::core::hint::cold_path();
2060                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2061                        address: PackedAddress::new(
2062                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2063                        ),
2064                    });
2065                }
2066                // SAFETY: alignment/overlap/SEW checked above
2067                unsafe {
2068                    zvexx_widen_narrow_helpers::execute_extension::<false, _, _>(
2069                        env,
2070                        vd,
2071                        vs2,
2072                        vm,
2073                        sew,
2074                        VsewFactor::F4,
2075                    );
2076                }
2077            }
2078            // vzext.vf8 - zero-extend SEW/8 -> SEW
2079            Self::VzextVf8 { vd, vs2, vm } => {
2080                if !env.vector_instructions_allowed() {
2081                    ::core::hint::cold_path();
2082                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2083                        address: PackedAddress::new(
2084                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2085                        ),
2086                    });
2087                }
2088                let Some(vtype) = env.vtype() else {
2089                    ::core::hint::cold_path();
2090                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2091                        address: PackedAddress::new(
2092                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2093                        ),
2094                    });
2095                };
2096                let sew = vtype.vsew();
2097                // SEW must be >= 8*8 = 64; only SEW=64 qualifies in Zve64x
2098                if u32::from(sew.bits_width()) < 64 {
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 group_regs = vtype.vlmul().register_count();
2107                let src_group = ::core::num::NonZeroU8::new(group_regs.get().max(8) / 8)
2108                    .expect("Not zero; qed");
2109                zvexx_widen_narrow_helpers::check_vs_ext_alignment::<Reg, _, _>(
2110                    program_counter,
2111                    vs2,
2112                    src_group,
2113                    vd,
2114                    group_regs,
2115                )?;
2116                zvexx_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _>(
2117                    program_counter,
2118                    vd,
2119                    group_regs,
2120                )?;
2121                if !vm && vd == VReg::V0 {
2122                    ::core::hint::cold_path();
2123                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2124                        address: PackedAddress::new(
2125                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2126                        ),
2127                    });
2128                }
2129                // SAFETY: alignment/overlap/SEW checked above
2130                unsafe {
2131                    zvexx_widen_narrow_helpers::execute_extension::<false, _, _>(
2132                        env,
2133                        vd,
2134                        vs2,
2135                        vm,
2136                        sew,
2137                        VsewFactor::F8,
2138                    );
2139                }
2140            }
2141            // vsext.vf2 - sign-extend SEW/2 -> SEW
2142            Self::VsextVf2 { vd, vs2, vm } => {
2143                if !env.vector_instructions_allowed() {
2144                    ::core::hint::cold_path();
2145                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2146                        address: PackedAddress::new(
2147                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2148                        ),
2149                    });
2150                }
2151                let Some(vtype) = env.vtype() else {
2152                    ::core::hint::cold_path();
2153                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2154                        address: PackedAddress::new(
2155                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2156                        ),
2157                    });
2158                };
2159                let sew = vtype.vsew();
2160                if u32::from(sew.bits_width()) < 16 {
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 group_regs = vtype.vlmul().register_count();
2169                let src_group = ::core::num::NonZeroU8::new(group_regs.get().max(2) / 2)
2170                    .expect("Not zero; qed");
2171                zvexx_widen_narrow_helpers::check_vs_ext_alignment::<Reg, _, _>(
2172                    program_counter,
2173                    vs2,
2174                    src_group,
2175                    vd,
2176                    group_regs,
2177                )?;
2178                zvexx_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _>(
2179                    program_counter,
2180                    vd,
2181                    group_regs,
2182                )?;
2183                if !vm && vd == VReg::V0 {
2184                    ::core::hint::cold_path();
2185                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2186                        address: PackedAddress::new(
2187                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2188                        ),
2189                    });
2190                }
2191                // SAFETY: alignment/overlap/SEW checked above
2192                unsafe {
2193                    zvexx_widen_narrow_helpers::execute_extension::<true, _, _>(
2194                        env,
2195                        vd,
2196                        vs2,
2197                        vm,
2198                        sew,
2199                        VsewFactor::F2,
2200                    );
2201                }
2202            }
2203            // vsext.vf4 - sign-extend SEW/4 -> SEW
2204            Self::VsextVf4 { vd, vs2, vm } => {
2205                if !env.vector_instructions_allowed() {
2206                    ::core::hint::cold_path();
2207                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2208                        address: PackedAddress::new(
2209                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2210                        ),
2211                    });
2212                }
2213                let Some(vtype) = env.vtype() else {
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 sew = vtype.vsew();
2222                if u32::from(sew.bits_width()) < 32 {
2223                    ::core::hint::cold_path();
2224                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2225                        address: PackedAddress::new(
2226                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2227                        ),
2228                    });
2229                }
2230                let group_regs = vtype.vlmul().register_count();
2231                let src_group = ::core::num::NonZeroU8::new(group_regs.get().max(4) / 4)
2232                    .expect("Not zero; qed");
2233                zvexx_widen_narrow_helpers::check_vs_ext_alignment::<Reg, _, _>(
2234                    program_counter,
2235                    vs2,
2236                    src_group,
2237                    vd,
2238                    group_regs,
2239                )?;
2240                zvexx_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _>(
2241                    program_counter,
2242                    vd,
2243                    group_regs,
2244                )?;
2245                if !vm && vd == VReg::V0 {
2246                    ::core::hint::cold_path();
2247                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2248                        address: PackedAddress::new(
2249                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2250                        ),
2251                    });
2252                }
2253                // SAFETY: alignment/overlap/SEW checked above
2254                unsafe {
2255                    zvexx_widen_narrow_helpers::execute_extension::<true, _, _>(
2256                        env,
2257                        vd,
2258                        vs2,
2259                        vm,
2260                        sew,
2261                        VsewFactor::F4,
2262                    );
2263                }
2264            }
2265            // vsext.vf8 - sign-extend SEW/8 -> SEW
2266            Self::VsextVf8 { vd, vs2, vm } => {
2267                if !env.vector_instructions_allowed() {
2268                    ::core::hint::cold_path();
2269                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2270                        address: PackedAddress::new(
2271                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2272                        ),
2273                    });
2274                }
2275                let Some(vtype) = env.vtype() else {
2276                    ::core::hint::cold_path();
2277                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2278                        address: PackedAddress::new(
2279                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2280                        ),
2281                    });
2282                };
2283                let sew = vtype.vsew();
2284                if u32::from(sew.bits_width()) < 64 {
2285                    ::core::hint::cold_path();
2286                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2287                        address: PackedAddress::new(
2288                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2289                        ),
2290                    });
2291                }
2292                let group_regs = vtype.vlmul().register_count();
2293                let src_group = ::core::num::NonZeroU8::new(group_regs.get().max(8) / 8)
2294                    .expect("Not zero; qed");
2295                zvexx_widen_narrow_helpers::check_vs_ext_alignment::<Reg, _, _>(
2296                    program_counter,
2297                    vs2,
2298                    src_group,
2299                    vd,
2300                    group_regs,
2301                )?;
2302                zvexx_widen_narrow_helpers::check_vreg_group_alignment::<Reg, _, _>(
2303                    program_counter,
2304                    vd,
2305                    group_regs,
2306                )?;
2307                if !vm && vd == VReg::V0 {
2308                    ::core::hint::cold_path();
2309                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2310                        address: PackedAddress::new(
2311                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2312                        ),
2313                    });
2314                }
2315                // SAFETY: alignment/overlap/SEW checked above
2316                unsafe {
2317                    zvexx_widen_narrow_helpers::execute_extension::<true, _, _>(
2318                        env,
2319                        vd,
2320                        vs2,
2321                        vm,
2322                        sew,
2323                        VsewFactor::F8,
2324                    );
2325                }
2326            }
2327        }
2328
2329        ExecutionResult::ContinueNoWrite
2330    }
2331}