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, Hart> ExecutableInstructionOperands for ZveXxWidenNarrowInstruction<Hart>
20where
21    Reg: Register,
22    Hart: VectorHartConfig<Reg = Reg>,
23{
24}
25
26#[instruction_execution]
27const impl<Reg, Hart, Env> ExecutableInstructionCsr<Env> for ZveXxWidenNarrowInstruction<Hart>
28where
29    Reg: Register,
30    Hart: VectorHartConfig<Reg = Reg>,
31{
32}
33
34#[instruction_execution]
35impl<Reg, Hart, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
36    for ZveXxWidenNarrowInstruction<Hart>
37where
38    Reg: Register,
39    Hart: VectorHartConfig<Reg = Reg>,
40    Regs: RegisterFile<Reg>,
41    Env: VectorRegistersExt<Hart = Hart>,
42    Memory: VirtualMemory,
43    PC: ProgramCounter<Reg::Type, Memory>,
44{
45    #[inline(always)]
46    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
47    fn execute(
48        self,
49        Rs1Rs2OperandValues {
50            rs1_value,
51            rs2_value: _,
52        }: Rs1Rs2OperandValues<Reg::Type>,
53        _regs: &mut Regs,
54        env: &mut Env,
55        _memory: &mut Memory,
56        program_counter: &PC,
57    ) -> ExecutionResult<Reg> {
58        match self {
59            // vwaddu.vv - 2*SEW = zext(SEW) + zext(SEW)
60            Self::VwadduVv { vd, vs2, vs1, vm } => {
61                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
62                    ::core::hint::cold_path();
63                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
64                        address: PackedAddress::new(
65                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
66                        ),
67                    });
68                }
69                let Some(config) = env.vector_config() else {
70                    ::core::hint::cold_path();
71                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
72                        address: PackedAddress::new(
73                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
74                        ),
75                    });
76                };
77                let sew = config.vtype().vsew();
78                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
79                    ::core::hint::cold_path();
80                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
81                        address: PackedAddress::new(
82                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
83                        ),
84                    });
85                };
86                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
87                    program_counter,
88                    config,
89                    vd,
90                    widening_sew.wide().as_eew(),
91                )?;
92                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
93                    program_counter,
94                    config,
95                    vs2,
96                    widening_sew.narrow().as_eew(),
97                )?;
98                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
99                    program_counter,
100                    config,
101                    vs1,
102                    widening_sew.narrow().as_eew(),
103                )?;
104                // The wide destination may only overlap narrow sources in its highest-numbered part
105                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
106                    program_counter,
107                    vd,
108                    vs2,
109                )?;
110                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
111                    program_counter,
112                    vd,
113                    vs1,
114                )?;
115                zvexx_widen_narrow_helpers::execute_widen_op::<true, _, _, _>(
116                    env,
117                    vd,
118                    vs2,
119                    zvexx_widen_narrow_helpers::OpSrc::Vreg(vs1),
120                    vm,
121                    widening_sew,
122                    u64::wrapping_add,
123                );
124            }
125            // vwaddu.vx - 2*SEW = zext(SEW) + zext(xlen->SEW)
126            Self::VwadduVx {
127                vd,
128                vs2,
129                rs1: _,
130                vm,
131            } => {
132                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
133                    ::core::hint::cold_path();
134                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
135                        address: PackedAddress::new(
136                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
137                        ),
138                    });
139                }
140                let Some(config) = env.vector_config() else {
141                    ::core::hint::cold_path();
142                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
143                        address: PackedAddress::new(
144                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
145                        ),
146                    });
147                };
148                let sew = config.vtype().vsew();
149                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
150                    ::core::hint::cold_path();
151                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
152                        address: PackedAddress::new(
153                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
154                        ),
155                    });
156                };
157                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
158                    program_counter,
159                    config,
160                    vd,
161                    widening_sew.wide().as_eew(),
162                )?;
163                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
164                    program_counter,
165                    config,
166                    vs2,
167                    widening_sew.narrow().as_eew(),
168                )?;
169                // The wide destination may only overlap narrow sources in its highest-numbered part
170                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
171                    program_counter,
172                    vd,
173                    vs2,
174                )?;
175                // Scalar is zero-extended to 2*SEW; the low SEW bits are what matter
176                let scalar = rs1_value.as_u64();
177                zvexx_widen_narrow_helpers::execute_widen_op::<true, _, _, _>(
178                    env,
179                    vd,
180                    vs2,
181                    zvexx_widen_narrow_helpers::OpSrc::Scalar(scalar),
182                    vm,
183                    widening_sew,
184                    u64::wrapping_add,
185                );
186            }
187            // vwadd.vv - 2*SEW = sext(SEW) + sext(SEW)
188            Self::VwaddVv { vd, vs2, vs1, vm } => {
189                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
190                    ::core::hint::cold_path();
191                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
192                        address: PackedAddress::new(
193                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
194                        ),
195                    });
196                }
197                let Some(config) = env.vector_config() else {
198                    ::core::hint::cold_path();
199                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
200                        address: PackedAddress::new(
201                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
202                        ),
203                    });
204                };
205                let sew = config.vtype().vsew();
206                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
207                    ::core::hint::cold_path();
208                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
209                        address: PackedAddress::new(
210                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
211                        ),
212                    });
213                };
214                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
215                    program_counter,
216                    config,
217                    vd,
218                    widening_sew.wide().as_eew(),
219                )?;
220                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
221                    program_counter,
222                    config,
223                    vs2,
224                    widening_sew.narrow().as_eew(),
225                )?;
226                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
227                    program_counter,
228                    config,
229                    vs1,
230                    widening_sew.narrow().as_eew(),
231                )?;
232                // The wide destination may only overlap narrow sources in its highest-numbered part
233                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
234                    program_counter,
235                    vd,
236                    vs2,
237                )?;
238                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
239                    program_counter,
240                    vd,
241                    vs1,
242                )?;
243                zvexx_widen_narrow_helpers::execute_widen_op::<false, _, _, _>(
244                    env,
245                    vd,
246                    vs2,
247                    zvexx_widen_narrow_helpers::OpSrc::Vreg(vs1),
248                    vm,
249                    widening_sew,
250                    u64::wrapping_add,
251                );
252            }
253            // vwadd.vx - 2*SEW = sext(SEW) + sext(rs1)
254            Self::VwaddVx {
255                vd,
256                vs2,
257                rs1: _,
258                vm,
259            } => {
260                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
261                    ::core::hint::cold_path();
262                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
263                        address: PackedAddress::new(
264                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
265                        ),
266                    });
267                }
268                let Some(config) = env.vector_config() else {
269                    ::core::hint::cold_path();
270                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
271                        address: PackedAddress::new(
272                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
273                        ),
274                    });
275                };
276                let sew = config.vtype().vsew();
277                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
278                    ::core::hint::cold_path();
279                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
280                        address: PackedAddress::new(
281                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
282                        ),
283                    });
284                };
285                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
286                    program_counter,
287                    config,
288                    vd,
289                    widening_sew.wide().as_eew(),
290                )?;
291                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
292                    program_counter,
293                    config,
294                    vs2,
295                    widening_sew.narrow().as_eew(),
296                )?;
297                // The wide destination may only overlap narrow sources in its highest-numbered part
298                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
299                    program_counter,
300                    vd,
301                    vs2,
302                )?;
303                // Scalar is sign-extended from XLEN to 64 bits
304                let scalar = zvexx_widen_narrow_helpers::sign_extend_bits(
305                    rs1_value.as_u64(),
306                    Vsew::from_xlen::<Reg>(),
307                )
308                .cast_unsigned();
309                zvexx_widen_narrow_helpers::execute_widen_op::<false, _, _, _>(
310                    env,
311                    vd,
312                    vs2,
313                    zvexx_widen_narrow_helpers::OpSrc::Scalar(scalar),
314                    vm,
315                    widening_sew,
316                    u64::wrapping_add,
317                );
318            }
319            // vwsubu.vv - 2*SEW = zext(SEW) - zext(SEW)
320            Self::VwsubuVv { vd, vs2, vs1, vm } => {
321                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
322                    ::core::hint::cold_path();
323                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
324                        address: PackedAddress::new(
325                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
326                        ),
327                    });
328                }
329                let Some(config) = env.vector_config() else {
330                    ::core::hint::cold_path();
331                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
332                        address: PackedAddress::new(
333                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
334                        ),
335                    });
336                };
337                let sew = config.vtype().vsew();
338                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
339                    ::core::hint::cold_path();
340                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
341                        address: PackedAddress::new(
342                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
343                        ),
344                    });
345                };
346                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
347                    program_counter,
348                    config,
349                    vd,
350                    widening_sew.wide().as_eew(),
351                )?;
352                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
353                    program_counter,
354                    config,
355                    vs2,
356                    widening_sew.narrow().as_eew(),
357                )?;
358                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
359                    program_counter,
360                    config,
361                    vs1,
362                    widening_sew.narrow().as_eew(),
363                )?;
364                // The wide destination may only overlap narrow sources in its highest-numbered part
365                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
366                    program_counter,
367                    vd,
368                    vs2,
369                )?;
370                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
371                    program_counter,
372                    vd,
373                    vs1,
374                )?;
375                zvexx_widen_narrow_helpers::execute_widen_op::<true, _, _, _>(
376                    env,
377                    vd,
378                    vs2,
379                    zvexx_widen_narrow_helpers::OpSrc::Vreg(vs1),
380                    vm,
381                    widening_sew,
382                    u64::wrapping_sub,
383                );
384            }
385            // vwsubu.vx - 2*SEW = zext(SEW) - zext(rs1)
386            Self::VwsubuVx {
387                vd,
388                vs2,
389                rs1: _,
390                vm,
391            } => {
392                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
393                    ::core::hint::cold_path();
394                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
395                        address: PackedAddress::new(
396                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
397                        ),
398                    });
399                }
400                let Some(config) = env.vector_config() else {
401                    ::core::hint::cold_path();
402                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
403                        address: PackedAddress::new(
404                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
405                        ),
406                    });
407                };
408                let sew = config.vtype().vsew();
409                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
410                    ::core::hint::cold_path();
411                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
412                        address: PackedAddress::new(
413                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
414                        ),
415                    });
416                };
417                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
418                    program_counter,
419                    config,
420                    vd,
421                    widening_sew.wide().as_eew(),
422                )?;
423                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
424                    program_counter,
425                    config,
426                    vs2,
427                    widening_sew.narrow().as_eew(),
428                )?;
429                // The wide destination may only overlap narrow sources in its highest-numbered part
430                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
431                    program_counter,
432                    vd,
433                    vs2,
434                )?;
435                let scalar = rs1_value.as_u64();
436                zvexx_widen_narrow_helpers::execute_widen_op::<true, _, _, _>(
437                    env,
438                    vd,
439                    vs2,
440                    zvexx_widen_narrow_helpers::OpSrc::Scalar(scalar),
441                    vm,
442                    widening_sew,
443                    u64::wrapping_sub,
444                );
445            }
446            // vwsub.vv - 2*SEW = sext(SEW) - sext(SEW)
447            Self::VwsubVv { vd, vs2, vs1, vm } => {
448                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
449                    ::core::hint::cold_path();
450                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
451                        address: PackedAddress::new(
452                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
453                        ),
454                    });
455                }
456                let Some(config) = env.vector_config() else {
457                    ::core::hint::cold_path();
458                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
459                        address: PackedAddress::new(
460                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
461                        ),
462                    });
463                };
464                let sew = config.vtype().vsew();
465                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
466                    ::core::hint::cold_path();
467                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
468                        address: PackedAddress::new(
469                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
470                        ),
471                    });
472                };
473                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
474                    program_counter,
475                    config,
476                    vd,
477                    widening_sew.wide().as_eew(),
478                )?;
479                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
480                    program_counter,
481                    config,
482                    vs2,
483                    widening_sew.narrow().as_eew(),
484                )?;
485                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
486                    program_counter,
487                    config,
488                    vs1,
489                    widening_sew.narrow().as_eew(),
490                )?;
491                // The wide destination may only overlap narrow sources in its highest-numbered part
492                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
493                    program_counter,
494                    vd,
495                    vs2,
496                )?;
497                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
498                    program_counter,
499                    vd,
500                    vs1,
501                )?;
502                zvexx_widen_narrow_helpers::execute_widen_op::<false, _, _, _>(
503                    env,
504                    vd,
505                    vs2,
506                    zvexx_widen_narrow_helpers::OpSrc::Vreg(vs1),
507                    vm,
508                    widening_sew,
509                    u64::wrapping_sub,
510                );
511            }
512            // vwsub.vx - 2*SEW = sext(SEW) - sext(rs1)
513            Self::VwsubVx {
514                vd,
515                vs2,
516                rs1: _,
517                vm,
518            } => {
519                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
520                    ::core::hint::cold_path();
521                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
522                        address: PackedAddress::new(
523                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
524                        ),
525                    });
526                }
527                let Some(config) = env.vector_config() else {
528                    ::core::hint::cold_path();
529                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
530                        address: PackedAddress::new(
531                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
532                        ),
533                    });
534                };
535                let sew = config.vtype().vsew();
536                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
537                    ::core::hint::cold_path();
538                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
539                        address: PackedAddress::new(
540                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
541                        ),
542                    });
543                };
544                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
545                    program_counter,
546                    config,
547                    vd,
548                    widening_sew.wide().as_eew(),
549                )?;
550                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
551                    program_counter,
552                    config,
553                    vs2,
554                    widening_sew.narrow().as_eew(),
555                )?;
556                // The wide destination may only overlap narrow sources in its highest-numbered part
557                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
558                    program_counter,
559                    vd,
560                    vs2,
561                )?;
562                let scalar = zvexx_widen_narrow_helpers::sign_extend_bits(
563                    rs1_value.as_u64(),
564                    Vsew::from_xlen::<Reg>(),
565                )
566                .cast_unsigned();
567                zvexx_widen_narrow_helpers::execute_widen_op::<false, _, _, _>(
568                    env,
569                    vd,
570                    vs2,
571                    zvexx_widen_narrow_helpers::OpSrc::Scalar(scalar),
572                    vm,
573                    widening_sew,
574                    u64::wrapping_sub,
575                );
576            }
577            // vwaddu.wv - 2*SEW = 2*SEW + zext(SEW)
578            Self::VwadduWv { vd, vs2, vs1, vm } => {
579                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
580                    ::core::hint::cold_path();
581                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
582                        address: PackedAddress::new(
583                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
584                        ),
585                    });
586                }
587                let Some(config) = env.vector_config() else {
588                    ::core::hint::cold_path();
589                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
590                        address: PackedAddress::new(
591                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
592                        ),
593                    });
594                };
595                let sew = config.vtype().vsew();
596                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
597                    ::core::hint::cold_path();
598                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
599                        address: PackedAddress::new(
600                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
601                        ),
602                    });
603                };
604                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
605                    program_counter,
606                    config,
607                    vd,
608                    widening_sew.wide().as_eew(),
609                )?;
610                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
611                    program_counter,
612                    config,
613                    vs2,
614                    widening_sew.wide().as_eew(),
615                )?;
616                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
617                    program_counter,
618                    config,
619                    vs1,
620                    widening_sew.narrow().as_eew(),
621                )?;
622                // `vs2` and `vs1` are read with different EEWs
623                zvexx_helpers::check_groups_disjoint::<Reg, Env, _, _>(program_counter, vs2, vs1)?;
624                // The wide destination may only overlap the narrow source in its highest-numbered
625                // part
626                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
627                    program_counter,
628                    vd,
629                    vs1,
630                )?;
631                zvexx_widen_narrow_helpers::execute_widen_w_op::<true, _, _, _>(
632                    env,
633                    vd,
634                    vs2,
635                    zvexx_widen_narrow_helpers::OpSrc::Vreg(vs1),
636                    vm,
637                    widening_sew,
638                    u64::wrapping_add,
639                );
640            }
641            // vwaddu.wx - 2*SEW = 2*SEW + zext(rs1)
642            Self::VwadduWx {
643                vd,
644                vs2,
645                rs1: _,
646                vm,
647            } => {
648                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
649                    ::core::hint::cold_path();
650                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
651                        address: PackedAddress::new(
652                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
653                        ),
654                    });
655                }
656                let Some(config) = env.vector_config() else {
657                    ::core::hint::cold_path();
658                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
659                        address: PackedAddress::new(
660                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
661                        ),
662                    });
663                };
664                let sew = config.vtype().vsew();
665                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
666                    ::core::hint::cold_path();
667                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
668                        address: PackedAddress::new(
669                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
670                        ),
671                    });
672                };
673                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
674                    program_counter,
675                    config,
676                    vd,
677                    widening_sew.wide().as_eew(),
678                )?;
679                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
680                    program_counter,
681                    config,
682                    vs2,
683                    widening_sew.wide().as_eew(),
684                )?;
685                let scalar = rs1_value.as_u64();
686                zvexx_widen_narrow_helpers::execute_widen_w_op::<true, _, _, _>(
687                    env,
688                    vd,
689                    vs2,
690                    zvexx_widen_narrow_helpers::OpSrc::Scalar(scalar),
691                    vm,
692                    widening_sew,
693                    u64::wrapping_add,
694                );
695            }
696            // vwadd.wv - 2*SEW = 2*SEW + sext(SEW)
697            Self::VwaddWv { vd, vs2, vs1, vm } => {
698                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
699                    ::core::hint::cold_path();
700                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
701                        address: PackedAddress::new(
702                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
703                        ),
704                    });
705                }
706                let Some(config) = env.vector_config() else {
707                    ::core::hint::cold_path();
708                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
709                        address: PackedAddress::new(
710                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
711                        ),
712                    });
713                };
714                let sew = config.vtype().vsew();
715                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
716                    ::core::hint::cold_path();
717                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
718                        address: PackedAddress::new(
719                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
720                        ),
721                    });
722                };
723                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
724                    program_counter,
725                    config,
726                    vd,
727                    widening_sew.wide().as_eew(),
728                )?;
729                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
730                    program_counter,
731                    config,
732                    vs2,
733                    widening_sew.wide().as_eew(),
734                )?;
735                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
736                    program_counter,
737                    config,
738                    vs1,
739                    widening_sew.narrow().as_eew(),
740                )?;
741                // `vs2` and `vs1` are read with different EEWs
742                zvexx_helpers::check_groups_disjoint::<Reg, Env, _, _>(program_counter, vs2, vs1)?;
743                // The wide destination may only overlap the narrow source in its highest-numbered
744                // part
745                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
746                    program_counter,
747                    vd,
748                    vs1,
749                )?;
750                zvexx_widen_narrow_helpers::execute_widen_w_op::<false, _, _, _>(
751                    env,
752                    vd,
753                    vs2,
754                    zvexx_widen_narrow_helpers::OpSrc::Vreg(vs1),
755                    vm,
756                    widening_sew,
757                    u64::wrapping_add,
758                );
759            }
760            // vwadd.wx - 2*SEW = 2*SEW + sext(rs1)
761            Self::VwaddWx {
762                vd,
763                vs2,
764                rs1: _,
765                vm,
766            } => {
767                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
768                    ::core::hint::cold_path();
769                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
770                        address: PackedAddress::new(
771                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
772                        ),
773                    });
774                }
775                let Some(config) = env.vector_config() else {
776                    ::core::hint::cold_path();
777                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
778                        address: PackedAddress::new(
779                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
780                        ),
781                    });
782                };
783                let sew = config.vtype().vsew();
784                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
785                    ::core::hint::cold_path();
786                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
787                        address: PackedAddress::new(
788                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
789                        ),
790                    });
791                };
792                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
793                    program_counter,
794                    config,
795                    vd,
796                    widening_sew.wide().as_eew(),
797                )?;
798                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
799                    program_counter,
800                    config,
801                    vs2,
802                    widening_sew.wide().as_eew(),
803                )?;
804                let scalar = zvexx_widen_narrow_helpers::sign_extend_bits(
805                    rs1_value.as_u64(),
806                    Vsew::from_xlen::<Reg>(),
807                )
808                .cast_unsigned();
809                zvexx_widen_narrow_helpers::execute_widen_w_op::<false, _, _, _>(
810                    env,
811                    vd,
812                    vs2,
813                    zvexx_widen_narrow_helpers::OpSrc::Scalar(scalar),
814                    vm,
815                    widening_sew,
816                    u64::wrapping_add,
817                );
818            }
819            // vwsubu.wv - 2*SEW = 2*SEW - zext(SEW)
820            Self::VwsubuWv { vd, vs2, vs1, vm } => {
821                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
822                    ::core::hint::cold_path();
823                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
824                        address: PackedAddress::new(
825                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
826                        ),
827                    });
828                }
829                let Some(config) = env.vector_config() else {
830                    ::core::hint::cold_path();
831                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
832                        address: PackedAddress::new(
833                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
834                        ),
835                    });
836                };
837                let sew = config.vtype().vsew();
838                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
839                    ::core::hint::cold_path();
840                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
841                        address: PackedAddress::new(
842                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
843                        ),
844                    });
845                };
846                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
847                    program_counter,
848                    config,
849                    vd,
850                    widening_sew.wide().as_eew(),
851                )?;
852                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
853                    program_counter,
854                    config,
855                    vs2,
856                    widening_sew.wide().as_eew(),
857                )?;
858                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
859                    program_counter,
860                    config,
861                    vs1,
862                    widening_sew.narrow().as_eew(),
863                )?;
864                // `vs2` and `vs1` are read with different EEWs
865                zvexx_helpers::check_groups_disjoint::<Reg, Env, _, _>(program_counter, vs2, vs1)?;
866                // The wide destination may only overlap the narrow source in its highest-numbered
867                // part
868                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
869                    program_counter,
870                    vd,
871                    vs1,
872                )?;
873                zvexx_widen_narrow_helpers::execute_widen_w_op::<true, _, _, _>(
874                    env,
875                    vd,
876                    vs2,
877                    zvexx_widen_narrow_helpers::OpSrc::Vreg(vs1),
878                    vm,
879                    widening_sew,
880                    u64::wrapping_sub,
881                );
882            }
883            // vwsubu.wx - 2*SEW = 2*SEW - zext(rs1)
884            Self::VwsubuWx {
885                vd,
886                vs2,
887                rs1: _,
888                vm,
889            } => {
890                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
891                    ::core::hint::cold_path();
892                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
893                        address: PackedAddress::new(
894                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
895                        ),
896                    });
897                }
898                let Some(config) = env.vector_config() else {
899                    ::core::hint::cold_path();
900                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
901                        address: PackedAddress::new(
902                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
903                        ),
904                    });
905                };
906                let sew = config.vtype().vsew();
907                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
908                    ::core::hint::cold_path();
909                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
910                        address: PackedAddress::new(
911                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
912                        ),
913                    });
914                };
915                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
916                    program_counter,
917                    config,
918                    vd,
919                    widening_sew.wide().as_eew(),
920                )?;
921                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
922                    program_counter,
923                    config,
924                    vs2,
925                    widening_sew.wide().as_eew(),
926                )?;
927                let scalar = rs1_value.as_u64();
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                    widening_sew,
935                    u64::wrapping_sub,
936                );
937            }
938            // vwsub.wv - 2*SEW = 2*SEW - sext(SEW)
939            Self::VwsubWv { vd, vs2, vs1, vm } => {
940                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
941                    ::core::hint::cold_path();
942                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
943                        address: PackedAddress::new(
944                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
945                        ),
946                    });
947                }
948                let Some(config) = env.vector_config() else {
949                    ::core::hint::cold_path();
950                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
951                        address: PackedAddress::new(
952                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
953                        ),
954                    });
955                };
956                let sew = config.vtype().vsew();
957                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
958                    ::core::hint::cold_path();
959                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
960                        address: PackedAddress::new(
961                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
962                        ),
963                    });
964                };
965                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
966                    program_counter,
967                    config,
968                    vd,
969                    widening_sew.wide().as_eew(),
970                )?;
971                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
972                    program_counter,
973                    config,
974                    vs2,
975                    widening_sew.wide().as_eew(),
976                )?;
977                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
978                    program_counter,
979                    config,
980                    vs1,
981                    widening_sew.narrow().as_eew(),
982                )?;
983                // `vs2` and `vs1` are read with different EEWs
984                zvexx_helpers::check_groups_disjoint::<Reg, Env, _, _>(program_counter, vs2, vs1)?;
985                // The wide destination may only overlap the narrow source in its highest-numbered
986                // part
987                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
988                    program_counter,
989                    vd,
990                    vs1,
991                )?;
992                zvexx_widen_narrow_helpers::execute_widen_w_op::<false, _, _, _>(
993                    env,
994                    vd,
995                    vs2,
996                    zvexx_widen_narrow_helpers::OpSrc::Vreg(vs1),
997                    vm,
998                    widening_sew,
999                    u64::wrapping_sub,
1000                );
1001            }
1002            // vwsub.wx - 2*SEW = 2*SEW - sext(rs1)
1003            Self::VwsubWx {
1004                vd,
1005                vs2,
1006                rs1: _,
1007                vm,
1008            } => {
1009                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1010                    ::core::hint::cold_path();
1011                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1012                        address: PackedAddress::new(
1013                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1014                        ),
1015                    });
1016                }
1017                let Some(config) = env.vector_config() else {
1018                    ::core::hint::cold_path();
1019                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1020                        address: PackedAddress::new(
1021                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1022                        ),
1023                    });
1024                };
1025                let sew = config.vtype().vsew();
1026                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
1027                    ::core::hint::cold_path();
1028                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1029                        address: PackedAddress::new(
1030                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1031                        ),
1032                    });
1033                };
1034                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1035                    program_counter,
1036                    config,
1037                    vd,
1038                    widening_sew.wide().as_eew(),
1039                )?;
1040                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1041                    program_counter,
1042                    config,
1043                    vs2,
1044                    widening_sew.wide().as_eew(),
1045                )?;
1046                let scalar = zvexx_widen_narrow_helpers::sign_extend_bits(
1047                    rs1_value.as_u64(),
1048                    Vsew::from_xlen::<Reg>(),
1049                )
1050                .cast_unsigned();
1051                zvexx_widen_narrow_helpers::execute_widen_w_op::<false, _, _, _>(
1052                    env,
1053                    vd,
1054                    vs2,
1055                    zvexx_widen_narrow_helpers::OpSrc::Scalar(scalar),
1056                    vm,
1057                    widening_sew,
1058                    u64::wrapping_sub,
1059                );
1060            }
1061            // vnsrl.wv - SEW = (2*SEW) >> SEW (logical)
1062            Self::VnsrlWv { vd, vs2, vs1, vm } => {
1063                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
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 Some(config) = env.vector_config() else {
1072                    ::core::hint::cold_path();
1073                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1074                        address: PackedAddress::new(
1075                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1076                        ),
1077                    });
1078                };
1079                let sew = config.vtype().vsew();
1080                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
1081                    ::core::hint::cold_path();
1082                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1083                        address: PackedAddress::new(
1084                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1085                        ),
1086                    });
1087                };
1088                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1089                    program_counter,
1090                    config,
1091                    vd,
1092                    widening_sew.narrow().as_eew(),
1093                )?;
1094                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1095                    program_counter,
1096                    config,
1097                    vs2,
1098                    widening_sew.wide().as_eew(),
1099                )?;
1100                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
1101                    program_counter,
1102                    vd,
1103                    vs2,
1104                )?;
1105                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1106                    program_counter,
1107                    config,
1108                    vs1,
1109                    widening_sew.narrow().as_eew(),
1110                )?;
1111                // `vs2` and `vs1` are read with different EEWs
1112                zvexx_helpers::check_groups_disjoint::<Reg, Env, _, _>(program_counter, vs2, vs1)?;
1113                zvexx_widen_narrow_helpers::execute_narrow_shift::<false, _, _>(
1114                    env,
1115                    vd,
1116                    vs2,
1117                    zvexx_widen_narrow_helpers::OpSrc::Vreg(vs1),
1118                    vm,
1119                    widening_sew,
1120                );
1121            }
1122            // vnsrl.wx - SEW = (2*SEW) >> rs1 (logical)
1123            Self::VnsrlWx {
1124                vd,
1125                vs2,
1126                rs1: _,
1127                vm,
1128            } => {
1129                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1130                    ::core::hint::cold_path();
1131                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1132                        address: PackedAddress::new(
1133                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1134                        ),
1135                    });
1136                }
1137                let Some(config) = env.vector_config() else {
1138                    ::core::hint::cold_path();
1139                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1140                        address: PackedAddress::new(
1141                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1142                        ),
1143                    });
1144                };
1145                let sew = config.vtype().vsew();
1146                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
1147                    ::core::hint::cold_path();
1148                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1149                        address: PackedAddress::new(
1150                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1151                        ),
1152                    });
1153                };
1154                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1155                    program_counter,
1156                    config,
1157                    vd,
1158                    widening_sew.narrow().as_eew(),
1159                )?;
1160                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1161                    program_counter,
1162                    config,
1163                    vs2,
1164                    widening_sew.wide().as_eew(),
1165                )?;
1166                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
1167                    program_counter,
1168                    vd,
1169                    vs2,
1170                )?;
1171                let scalar = rs1_value.as_u64();
1172                zvexx_widen_narrow_helpers::execute_narrow_shift::<false, _, _>(
1173                    env,
1174                    vd,
1175                    vs2,
1176                    zvexx_widen_narrow_helpers::OpSrc::Scalar(scalar),
1177                    vm,
1178                    widening_sew,
1179                );
1180            }
1181            // vnsrl.wi - SEW = (2*SEW) >> uimm (logical)
1182            Self::VnsrlWi { vd, vs2, uimm, vm } => {
1183                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1184                    ::core::hint::cold_path();
1185                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1186                        address: PackedAddress::new(
1187                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1188                        ),
1189                    });
1190                }
1191                let Some(config) = env.vector_config() else {
1192                    ::core::hint::cold_path();
1193                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1194                        address: PackedAddress::new(
1195                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1196                        ),
1197                    });
1198                };
1199                let sew = config.vtype().vsew();
1200                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
1201                    ::core::hint::cold_path();
1202                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1203                        address: PackedAddress::new(
1204                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1205                        ),
1206                    });
1207                };
1208                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1209                    program_counter,
1210                    config,
1211                    vd,
1212                    widening_sew.narrow().as_eew(),
1213                )?;
1214                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1215                    program_counter,
1216                    config,
1217                    vs2,
1218                    widening_sew.wide().as_eew(),
1219                )?;
1220                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
1221                    program_counter,
1222                    vd,
1223                    vs2,
1224                )?;
1225                zvexx_widen_narrow_helpers::execute_narrow_shift::<false, _, _>(
1226                    env,
1227                    vd,
1228                    vs2,
1229                    zvexx_widen_narrow_helpers::OpSrc::Scalar(u64::from(uimm)),
1230                    vm,
1231                    widening_sew,
1232                );
1233            }
1234            // vnsra.wv - SEW = (2*SEW) >> SEW (arithmetic)
1235            Self::VnsraWv { vd, vs2, vs1, vm } => {
1236                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1237                    ::core::hint::cold_path();
1238                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1239                        address: PackedAddress::new(
1240                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1241                        ),
1242                    });
1243                }
1244                let Some(config) = env.vector_config() else {
1245                    ::core::hint::cold_path();
1246                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1247                        address: PackedAddress::new(
1248                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1249                        ),
1250                    });
1251                };
1252                let sew = config.vtype().vsew();
1253                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
1254                    ::core::hint::cold_path();
1255                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1256                        address: PackedAddress::new(
1257                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1258                        ),
1259                    });
1260                };
1261                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1262                    program_counter,
1263                    config,
1264                    vd,
1265                    widening_sew.narrow().as_eew(),
1266                )?;
1267                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1268                    program_counter,
1269                    config,
1270                    vs2,
1271                    widening_sew.wide().as_eew(),
1272                )?;
1273                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
1274                    program_counter,
1275                    vd,
1276                    vs2,
1277                )?;
1278                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1279                    program_counter,
1280                    config,
1281                    vs1,
1282                    widening_sew.narrow().as_eew(),
1283                )?;
1284                // `vs2` and `vs1` are read with different EEWs
1285                zvexx_helpers::check_groups_disjoint::<Reg, Env, _, _>(program_counter, vs2, vs1)?;
1286                zvexx_widen_narrow_helpers::execute_narrow_shift::<true, _, _>(
1287                    env,
1288                    vd,
1289                    vs2,
1290                    zvexx_widen_narrow_helpers::OpSrc::Vreg(vs1),
1291                    vm,
1292                    widening_sew,
1293                );
1294            }
1295            // vnsra.wx - SEW = (2*SEW) >> rs1 (arithmetic)
1296            Self::VnsraWx {
1297                vd,
1298                vs2,
1299                rs1: _,
1300                vm,
1301            } => {
1302                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1303                    ::core::hint::cold_path();
1304                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1305                        address: PackedAddress::new(
1306                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1307                        ),
1308                    });
1309                }
1310                let Some(config) = env.vector_config() else {
1311                    ::core::hint::cold_path();
1312                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1313                        address: PackedAddress::new(
1314                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1315                        ),
1316                    });
1317                };
1318                let sew = config.vtype().vsew();
1319                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
1320                    ::core::hint::cold_path();
1321                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1322                        address: PackedAddress::new(
1323                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1324                        ),
1325                    });
1326                };
1327                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1328                    program_counter,
1329                    config,
1330                    vd,
1331                    widening_sew.narrow().as_eew(),
1332                )?;
1333                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1334                    program_counter,
1335                    config,
1336                    vs2,
1337                    widening_sew.wide().as_eew(),
1338                )?;
1339                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
1340                    program_counter,
1341                    vd,
1342                    vs2,
1343                )?;
1344                let scalar = rs1_value.as_u64();
1345                zvexx_widen_narrow_helpers::execute_narrow_shift::<true, _, _>(
1346                    env,
1347                    vd,
1348                    vs2,
1349                    zvexx_widen_narrow_helpers::OpSrc::Scalar(scalar),
1350                    vm,
1351                    widening_sew,
1352                );
1353            }
1354            // vnsra.wi - SEW = (2*SEW) >> uimm (arithmetic)
1355            Self::VnsraWi { vd, vs2, uimm, vm } => {
1356                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1357                    ::core::hint::cold_path();
1358                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1359                        address: PackedAddress::new(
1360                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1361                        ),
1362                    });
1363                }
1364                let Some(config) = env.vector_config() else {
1365                    ::core::hint::cold_path();
1366                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1367                        address: PackedAddress::new(
1368                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1369                        ),
1370                    });
1371                };
1372                let sew = config.vtype().vsew();
1373                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
1374                    ::core::hint::cold_path();
1375                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1376                        address: PackedAddress::new(
1377                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1378                        ),
1379                    });
1380                };
1381                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1382                    program_counter,
1383                    config,
1384                    vd,
1385                    widening_sew.narrow().as_eew(),
1386                )?;
1387                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1388                    program_counter,
1389                    config,
1390                    vs2,
1391                    widening_sew.wide().as_eew(),
1392                )?;
1393                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
1394                    program_counter,
1395                    vd,
1396                    vs2,
1397                )?;
1398                zvexx_widen_narrow_helpers::execute_narrow_shift::<true, _, _>(
1399                    env,
1400                    vd,
1401                    vs2,
1402                    zvexx_widen_narrow_helpers::OpSrc::Scalar(u64::from(uimm)),
1403                    vm,
1404                    widening_sew,
1405                );
1406            }
1407            // vzext.vf2 - zero-extend SEW/2 -> SEW
1408            Self::VzextVf2 { vd, vs2, vm } => {
1409                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
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 Some(config) = env.vector_config() else {
1418                    ::core::hint::cold_path();
1419                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1420                        address: PackedAddress::new(
1421                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1422                        ),
1423                    });
1424                };
1425                let sew = config.vtype().vsew();
1426                let Some(extension_sew) = zvexx_helpers::ExtensionSew::new(sew, VsewFactor::F2)
1427                else {
1428                    ::core::hint::cold_path();
1429                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1430                        address: PackedAddress::new(
1431                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1432                        ),
1433                    });
1434                };
1435                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1436                    program_counter,
1437                    config,
1438                    vd,
1439                    extension_sew.dest().as_eew(),
1440                )?;
1441                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1442                    program_counter,
1443                    config,
1444                    vs2,
1445                    extension_sew.source().as_eew(),
1446                )?;
1447                // The destination may only overlap the narrow source in its highest-numbered part
1448                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
1449                    program_counter,
1450                    vd,
1451                    vs2,
1452                )?;
1453                zvexx_widen_narrow_helpers::execute_extension::<false, _, _>(
1454                    env,
1455                    vd,
1456                    vs2,
1457                    vm,
1458                    extension_sew,
1459                );
1460            }
1461            // vzext.vf4 - zero-extend SEW/4 -> SEW
1462            Self::VzextVf4 { vd, vs2, vm } => {
1463                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1464                    ::core::hint::cold_path();
1465                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1466                        address: PackedAddress::new(
1467                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1468                        ),
1469                    });
1470                }
1471                let Some(config) = env.vector_config() else {
1472                    ::core::hint::cold_path();
1473                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1474                        address: PackedAddress::new(
1475                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1476                        ),
1477                    });
1478                };
1479                let sew = config.vtype().vsew();
1480                let Some(extension_sew) = zvexx_helpers::ExtensionSew::new(sew, VsewFactor::F4)
1481                else {
1482                    ::core::hint::cold_path();
1483                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1484                        address: PackedAddress::new(
1485                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1486                        ),
1487                    });
1488                };
1489                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1490                    program_counter,
1491                    config,
1492                    vd,
1493                    extension_sew.dest().as_eew(),
1494                )?;
1495                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1496                    program_counter,
1497                    config,
1498                    vs2,
1499                    extension_sew.source().as_eew(),
1500                )?;
1501                // The destination may only overlap the narrow source in its highest-numbered part
1502                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
1503                    program_counter,
1504                    vd,
1505                    vs2,
1506                )?;
1507                zvexx_widen_narrow_helpers::execute_extension::<false, _, _>(
1508                    env,
1509                    vd,
1510                    vs2,
1511                    vm,
1512                    extension_sew,
1513                );
1514            }
1515            // vzext.vf8 - zero-extend SEW/8 -> SEW
1516            Self::VzextVf8 { vd, vs2, vm } => {
1517                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1518                    ::core::hint::cold_path();
1519                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1520                        address: PackedAddress::new(
1521                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1522                        ),
1523                    });
1524                }
1525                let Some(config) = env.vector_config() else {
1526                    ::core::hint::cold_path();
1527                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1528                        address: PackedAddress::new(
1529                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1530                        ),
1531                    });
1532                };
1533                let sew = config.vtype().vsew();
1534                let Some(extension_sew) = zvexx_helpers::ExtensionSew::new(sew, VsewFactor::F8)
1535                else {
1536                    ::core::hint::cold_path();
1537                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1538                        address: PackedAddress::new(
1539                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1540                        ),
1541                    });
1542                };
1543                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1544                    program_counter,
1545                    config,
1546                    vd,
1547                    extension_sew.dest().as_eew(),
1548                )?;
1549                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1550                    program_counter,
1551                    config,
1552                    vs2,
1553                    extension_sew.source().as_eew(),
1554                )?;
1555                // The destination may only overlap the narrow source in its highest-numbered part
1556                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
1557                    program_counter,
1558                    vd,
1559                    vs2,
1560                )?;
1561                zvexx_widen_narrow_helpers::execute_extension::<false, _, _>(
1562                    env,
1563                    vd,
1564                    vs2,
1565                    vm,
1566                    extension_sew,
1567                );
1568            }
1569            // vsext.vf2 - sign-extend SEW/2 -> SEW
1570            Self::VsextVf2 { vd, vs2, vm } => {
1571                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1572                    ::core::hint::cold_path();
1573                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1574                        address: PackedAddress::new(
1575                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1576                        ),
1577                    });
1578                }
1579                let Some(config) = env.vector_config() else {
1580                    ::core::hint::cold_path();
1581                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1582                        address: PackedAddress::new(
1583                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1584                        ),
1585                    });
1586                };
1587                let sew = config.vtype().vsew();
1588                let Some(extension_sew) = zvexx_helpers::ExtensionSew::new(sew, VsewFactor::F2)
1589                else {
1590                    ::core::hint::cold_path();
1591                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1592                        address: PackedAddress::new(
1593                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1594                        ),
1595                    });
1596                };
1597                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1598                    program_counter,
1599                    config,
1600                    vd,
1601                    extension_sew.dest().as_eew(),
1602                )?;
1603                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1604                    program_counter,
1605                    config,
1606                    vs2,
1607                    extension_sew.source().as_eew(),
1608                )?;
1609                // The destination may only overlap the narrow source in its highest-numbered part
1610                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
1611                    program_counter,
1612                    vd,
1613                    vs2,
1614                )?;
1615                zvexx_widen_narrow_helpers::execute_extension::<true, _, _>(
1616                    env,
1617                    vd,
1618                    vs2,
1619                    vm,
1620                    extension_sew,
1621                );
1622            }
1623            // vsext.vf4 - sign-extend SEW/4 -> SEW
1624            Self::VsextVf4 { vd, vs2, vm } => {
1625                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1626                    ::core::hint::cold_path();
1627                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1628                        address: PackedAddress::new(
1629                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1630                        ),
1631                    });
1632                }
1633                let Some(config) = env.vector_config() else {
1634                    ::core::hint::cold_path();
1635                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1636                        address: PackedAddress::new(
1637                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1638                        ),
1639                    });
1640                };
1641                let sew = config.vtype().vsew();
1642                let Some(extension_sew) = zvexx_helpers::ExtensionSew::new(sew, VsewFactor::F4)
1643                else {
1644                    ::core::hint::cold_path();
1645                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1646                        address: PackedAddress::new(
1647                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1648                        ),
1649                    });
1650                };
1651                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1652                    program_counter,
1653                    config,
1654                    vd,
1655                    extension_sew.dest().as_eew(),
1656                )?;
1657                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1658                    program_counter,
1659                    config,
1660                    vs2,
1661                    extension_sew.source().as_eew(),
1662                )?;
1663                // The destination may only overlap the narrow source in its highest-numbered part
1664                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
1665                    program_counter,
1666                    vd,
1667                    vs2,
1668                )?;
1669                zvexx_widen_narrow_helpers::execute_extension::<true, _, _>(
1670                    env,
1671                    vd,
1672                    vs2,
1673                    vm,
1674                    extension_sew,
1675                );
1676            }
1677            // vsext.vf8 - sign-extend SEW/8 -> SEW
1678            Self::VsextVf8 { vd, vs2, vm } => {
1679                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1680                    ::core::hint::cold_path();
1681                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1682                        address: PackedAddress::new(
1683                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1684                        ),
1685                    });
1686                }
1687                let Some(config) = env.vector_config() else {
1688                    ::core::hint::cold_path();
1689                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1690                        address: PackedAddress::new(
1691                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1692                        ),
1693                    });
1694                };
1695                let sew = config.vtype().vsew();
1696                let Some(extension_sew) = zvexx_helpers::ExtensionSew::new(sew, VsewFactor::F8)
1697                else {
1698                    ::core::hint::cold_path();
1699                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1700                        address: PackedAddress::new(
1701                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1702                        ),
1703                    });
1704                };
1705                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1706                    program_counter,
1707                    config,
1708                    vd,
1709                    extension_sew.dest().as_eew(),
1710                )?;
1711                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1712                    program_counter,
1713                    config,
1714                    vs2,
1715                    extension_sew.source().as_eew(),
1716                )?;
1717                // The destination may only overlap the narrow source in its highest-numbered part
1718                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
1719                    program_counter,
1720                    vd,
1721                    vs2,
1722                )?;
1723                zvexx_widen_narrow_helpers::execute_extension::<true, _, _>(
1724                    env,
1725                    vd,
1726                    vs2,
1727                    vm,
1728                    extension_sew,
1729                );
1730            }
1731        }
1732
1733        ExecutionResult::ContinueNoWrite
1734    }
1735}