Skip to main content

ab_riscv_interpreter/v/zvexx/
arith.rs

1//! ZveXx integer arithmetic instructions
2
3#[cfg(test)]
4mod tests;
5pub mod zvexx_arith_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 ZveXxArithInstruction<Hart>
20where
21    Reg: Register,
22    Hart: VectorHartConfig<Reg = Reg>,
23{
24}
25
26#[instruction_execution]
27const impl<Reg, Hart, Env> ExecutableInstructionCsr<Env> for ZveXxArithInstruction<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 ZveXxArithInstruction<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            // vadd
60            Self::VaddVv { 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 vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
79                    program_counter,
80                    config,
81                    vd,
82                    sew.as_eew(),
83                )?;
84                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
85                    program_counter,
86                    config,
87                    vs2,
88                    sew.as_eew(),
89                )?;
90                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
91                    program_counter,
92                    config,
93                    vs1,
94                    sew.as_eew(),
95                )?;
96                zvexx_arith_helpers::execute_arith_op(
97                    env,
98                    vd,
99                    vs2,
100                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
101                    vm,
102                    sew,
103                    |a, b, _| a.wrapping_add(b),
104                );
105            }
106            Self::VaddVx {
107                vd,
108                vs2,
109                rs1: _,
110                vm,
111            } => {
112                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
113                    ::core::hint::cold_path();
114                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
115                        address: PackedAddress::new(
116                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
117                        ),
118                    });
119                }
120                let Some(config) = env.vector_config() else {
121                    ::core::hint::cold_path();
122                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
123                        address: PackedAddress::new(
124                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
125                        ),
126                    });
127                };
128                let sew = config.vtype().vsew();
129                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
130                    program_counter,
131                    config,
132                    vd,
133                    sew.as_eew(),
134                )?;
135                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
136                    program_counter,
137                    config,
138                    vs2,
139                    sew.as_eew(),
140                )?;
141                let scalar = rs1_value.as_i64().cast_unsigned();
142                zvexx_arith_helpers::execute_arith_op(
143                    env,
144                    vd,
145                    vs2,
146                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
147                    vm,
148                    sew,
149                    |a, b, _| a.wrapping_add(b),
150                );
151            }
152            Self::VaddVi { vd, vs2, imm, vm } => {
153                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
154                    ::core::hint::cold_path();
155                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
156                        address: PackedAddress::new(
157                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
158                        ),
159                    });
160                }
161                let Some(config) = env.vector_config() else {
162                    ::core::hint::cold_path();
163                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
164                        address: PackedAddress::new(
165                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
166                        ),
167                    });
168                };
169                let sew = config.vtype().vsew();
170                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
171                    program_counter,
172                    config,
173                    vd,
174                    sew.as_eew(),
175                )?;
176                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
177                    program_counter,
178                    config,
179                    vs2,
180                    sew.as_eew(),
181                )?;
182                // Sign-extend imm to u64 so wrapping_add works correctly for all SEW
183                let scalar = i64::from(imm).cast_unsigned();
184                zvexx_arith_helpers::execute_arith_op(
185                    env,
186                    vd,
187                    vs2,
188                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
189                    vm,
190                    sew,
191                    |a, b, _| a.wrapping_add(b),
192                );
193            }
194            // vsub / vrsub
195            Self::VsubVv { vd, vs2, vs1, vm } => {
196                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
197                    ::core::hint::cold_path();
198                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
199                        address: PackedAddress::new(
200                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
201                        ),
202                    });
203                }
204                let Some(config) = env.vector_config() else {
205                    ::core::hint::cold_path();
206                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
207                        address: PackedAddress::new(
208                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
209                        ),
210                    });
211                };
212                let sew = config.vtype().vsew();
213                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
214                    program_counter,
215                    config,
216                    vd,
217                    sew.as_eew(),
218                )?;
219                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
220                    program_counter,
221                    config,
222                    vs2,
223                    sew.as_eew(),
224                )?;
225                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
226                    program_counter,
227                    config,
228                    vs1,
229                    sew.as_eew(),
230                )?;
231                zvexx_arith_helpers::execute_arith_op(
232                    env,
233                    vd,
234                    vs2,
235                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
236                    vm,
237                    sew,
238                    |a, b, _| a.wrapping_sub(b),
239                );
240            }
241            Self::VsubVx {
242                vd,
243                vs2,
244                rs1: _,
245                vm,
246            } => {
247                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
248                    ::core::hint::cold_path();
249                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
250                        address: PackedAddress::new(
251                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
252                        ),
253                    });
254                }
255                let Some(config) = env.vector_config() else {
256                    ::core::hint::cold_path();
257                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
258                        address: PackedAddress::new(
259                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
260                        ),
261                    });
262                };
263                let sew = config.vtype().vsew();
264                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
265                    program_counter,
266                    config,
267                    vd,
268                    sew.as_eew(),
269                )?;
270                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
271                    program_counter,
272                    config,
273                    vs2,
274                    sew.as_eew(),
275                )?;
276                let scalar = rs1_value.as_i64().cast_unsigned();
277                zvexx_arith_helpers::execute_arith_op(
278                    env,
279                    vd,
280                    vs2,
281                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
282                    vm,
283                    sew,
284                    |a, b, _| a.wrapping_sub(b),
285                );
286            }
287            Self::VrsubVx {
288                vd,
289                vs2,
290                rs1: _,
291                vm,
292            } => {
293                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
294                    ::core::hint::cold_path();
295                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
296                        address: PackedAddress::new(
297                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
298                        ),
299                    });
300                }
301                let Some(config) = env.vector_config() else {
302                    ::core::hint::cold_path();
303                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
304                        address: PackedAddress::new(
305                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
306                        ),
307                    });
308                };
309                let sew = config.vtype().vsew();
310                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
311                    program_counter,
312                    config,
313                    vd,
314                    sew.as_eew(),
315                )?;
316                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
317                    program_counter,
318                    config,
319                    vs2,
320                    sew.as_eew(),
321                )?;
322                let scalar = rs1_value.as_i64().cast_unsigned();
323                // vrsub: result = src - vs2[i]
324                zvexx_arith_helpers::execute_arith_op(
325                    env,
326                    vd,
327                    vs2,
328                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
329                    vm,
330                    sew,
331                    |a, b, _| b.wrapping_sub(a),
332                );
333            }
334            Self::VrsubVi { vd, vs2, imm, vm } => {
335                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
336                    ::core::hint::cold_path();
337                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
338                        address: PackedAddress::new(
339                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
340                        ),
341                    });
342                }
343                let Some(config) = env.vector_config() else {
344                    ::core::hint::cold_path();
345                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
346                        address: PackedAddress::new(
347                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
348                        ),
349                    });
350                };
351                let sew = config.vtype().vsew();
352                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
353                    program_counter,
354                    config,
355                    vd,
356                    sew.as_eew(),
357                )?;
358                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
359                    program_counter,
360                    config,
361                    vs2,
362                    sew.as_eew(),
363                )?;
364                let scalar = i64::from(imm).cast_unsigned();
365                zvexx_arith_helpers::execute_arith_op(
366                    env,
367                    vd,
368                    vs2,
369                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
370                    vm,
371                    sew,
372                    |a, b, _| b.wrapping_sub(a),
373                );
374            }
375            // vand
376            Self::VandVv { vd, vs2, vs1, vm } => {
377                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
378                    ::core::hint::cold_path();
379                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
380                        address: PackedAddress::new(
381                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
382                        ),
383                    });
384                }
385                let Some(config) = env.vector_config() else {
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                let sew = config.vtype().vsew();
394                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
395                    program_counter,
396                    config,
397                    vd,
398                    sew.as_eew(),
399                )?;
400                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
401                    program_counter,
402                    config,
403                    vs2,
404                    sew.as_eew(),
405                )?;
406                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
407                    program_counter,
408                    config,
409                    vs1,
410                    sew.as_eew(),
411                )?;
412                zvexx_arith_helpers::execute_arith_op(
413                    env,
414                    vd,
415                    vs2,
416                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
417                    vm,
418                    sew,
419                    |a, b, _| a & b,
420                );
421            }
422            Self::VandVx {
423                vd,
424                vs2,
425                rs1: _,
426                vm,
427            } => {
428                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
429                    ::core::hint::cold_path();
430                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
431                        address: PackedAddress::new(
432                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
433                        ),
434                    });
435                }
436                let Some(config) = env.vector_config() else {
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                let sew = config.vtype().vsew();
445                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
446                    program_counter,
447                    config,
448                    vd,
449                    sew.as_eew(),
450                )?;
451                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
452                    program_counter,
453                    config,
454                    vs2,
455                    sew.as_eew(),
456                )?;
457                let scalar = rs1_value.as_i64().cast_unsigned();
458                zvexx_arith_helpers::execute_arith_op(
459                    env,
460                    vd,
461                    vs2,
462                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
463                    vm,
464                    sew,
465                    |a, b, _| a & b,
466                );
467            }
468            Self::VandVi { vd, vs2, imm, vm } => {
469                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
470                    ::core::hint::cold_path();
471                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
472                        address: PackedAddress::new(
473                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
474                        ),
475                    });
476                }
477                let Some(config) = env.vector_config() else {
478                    ::core::hint::cold_path();
479                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
480                        address: PackedAddress::new(
481                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
482                        ),
483                    });
484                };
485                let sew = config.vtype().vsew();
486                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
487                    program_counter,
488                    config,
489                    vd,
490                    sew.as_eew(),
491                )?;
492                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
493                    program_counter,
494                    config,
495                    vs2,
496                    sew.as_eew(),
497                )?;
498                let scalar = i64::from(imm).cast_unsigned();
499                zvexx_arith_helpers::execute_arith_op(
500                    env,
501                    vd,
502                    vs2,
503                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
504                    vm,
505                    sew,
506                    |a, b, _| a & b,
507                );
508            }
509            // vor
510            Self::VorVv { vd, vs2, vs1, vm } => {
511                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
512                    ::core::hint::cold_path();
513                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
514                        address: PackedAddress::new(
515                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
516                        ),
517                    });
518                }
519                let Some(config) = env.vector_config() else {
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 sew = config.vtype().vsew();
528                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
529                    program_counter,
530                    config,
531                    vd,
532                    sew.as_eew(),
533                )?;
534                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
535                    program_counter,
536                    config,
537                    vs2,
538                    sew.as_eew(),
539                )?;
540                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
541                    program_counter,
542                    config,
543                    vs1,
544                    sew.as_eew(),
545                )?;
546                zvexx_arith_helpers::execute_arith_op(
547                    env,
548                    vd,
549                    vs2,
550                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
551                    vm,
552                    sew,
553                    |a, b, _| a | b,
554                );
555            }
556            Self::VorVx {
557                vd,
558                vs2,
559                rs1: _,
560                vm,
561            } => {
562                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
563                    ::core::hint::cold_path();
564                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
565                        address: PackedAddress::new(
566                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
567                        ),
568                    });
569                }
570                let Some(config) = env.vector_config() else {
571                    ::core::hint::cold_path();
572                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
573                        address: PackedAddress::new(
574                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
575                        ),
576                    });
577                };
578                let sew = config.vtype().vsew();
579                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
580                    program_counter,
581                    config,
582                    vd,
583                    sew.as_eew(),
584                )?;
585                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
586                    program_counter,
587                    config,
588                    vs2,
589                    sew.as_eew(),
590                )?;
591                let scalar = rs1_value.as_i64().cast_unsigned();
592                zvexx_arith_helpers::execute_arith_op(
593                    env,
594                    vd,
595                    vs2,
596                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
597                    vm,
598                    sew,
599                    |a, b, _| a | b,
600                );
601            }
602            Self::VorVi { vd, vs2, imm, vm } => {
603                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
604                    ::core::hint::cold_path();
605                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
606                        address: PackedAddress::new(
607                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
608                        ),
609                    });
610                }
611                let Some(config) = env.vector_config() else {
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                let sew = config.vtype().vsew();
620                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
621                    program_counter,
622                    config,
623                    vd,
624                    sew.as_eew(),
625                )?;
626                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
627                    program_counter,
628                    config,
629                    vs2,
630                    sew.as_eew(),
631                )?;
632                let scalar = i64::from(imm).cast_unsigned();
633                zvexx_arith_helpers::execute_arith_op(
634                    env,
635                    vd,
636                    vs2,
637                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
638                    vm,
639                    sew,
640                    |a, b, _| a | b,
641                );
642            }
643            // vxor
644            Self::VxorVv { vd, vs2, vs1, vm } => {
645                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
646                    ::core::hint::cold_path();
647                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
648                        address: PackedAddress::new(
649                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
650                        ),
651                    });
652                }
653                let Some(config) = env.vector_config() else {
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                let sew = config.vtype().vsew();
662                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
663                    program_counter,
664                    config,
665                    vd,
666                    sew.as_eew(),
667                )?;
668                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
669                    program_counter,
670                    config,
671                    vs2,
672                    sew.as_eew(),
673                )?;
674                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
675                    program_counter,
676                    config,
677                    vs1,
678                    sew.as_eew(),
679                )?;
680                zvexx_arith_helpers::execute_arith_op(
681                    env,
682                    vd,
683                    vs2,
684                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
685                    vm,
686                    sew,
687                    |a, b, _| a ^ b,
688                );
689            }
690            Self::VxorVx {
691                vd,
692                vs2,
693                rs1: _,
694                vm,
695            } => {
696                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
697                    ::core::hint::cold_path();
698                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
699                        address: PackedAddress::new(
700                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
701                        ),
702                    });
703                }
704                let Some(config) = env.vector_config() else {
705                    ::core::hint::cold_path();
706                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
707                        address: PackedAddress::new(
708                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
709                        ),
710                    });
711                };
712                let sew = config.vtype().vsew();
713                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
714                    program_counter,
715                    config,
716                    vd,
717                    sew.as_eew(),
718                )?;
719                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
720                    program_counter,
721                    config,
722                    vs2,
723                    sew.as_eew(),
724                )?;
725                let scalar = rs1_value.as_i64().cast_unsigned();
726                zvexx_arith_helpers::execute_arith_op(
727                    env,
728                    vd,
729                    vs2,
730                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
731                    vm,
732                    sew,
733                    |a, b, _| a ^ b,
734                );
735            }
736            Self::VxorVi { vd, vs2, imm, vm } => {
737                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
738                    ::core::hint::cold_path();
739                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
740                        address: PackedAddress::new(
741                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
742                        ),
743                    });
744                }
745                let Some(config) = env.vector_config() else {
746                    ::core::hint::cold_path();
747                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
748                        address: PackedAddress::new(
749                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
750                        ),
751                    });
752                };
753                let sew = config.vtype().vsew();
754                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
755                    program_counter,
756                    config,
757                    vd,
758                    sew.as_eew(),
759                )?;
760                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
761                    program_counter,
762                    config,
763                    vs2,
764                    sew.as_eew(),
765                )?;
766                let scalar = i64::from(imm).cast_unsigned();
767                zvexx_arith_helpers::execute_arith_op(
768                    env,
769                    vd,
770                    vs2,
771                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
772                    vm,
773                    sew,
774                    |a, b, _| a ^ b,
775                );
776            }
777            // vsll
778            Self::VsllVv { vd, vs2, vs1, vm } => {
779                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
780                    ::core::hint::cold_path();
781                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
782                        address: PackedAddress::new(
783                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
784                        ),
785                    });
786                }
787                let Some(config) = env.vector_config() else {
788                    ::core::hint::cold_path();
789                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
790                        address: PackedAddress::new(
791                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
792                        ),
793                    });
794                };
795                let sew = config.vtype().vsew();
796                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
797                    program_counter,
798                    config,
799                    vd,
800                    sew.as_eew(),
801                )?;
802                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
803                    program_counter,
804                    config,
805                    vs2,
806                    sew.as_eew(),
807                )?;
808                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
809                    program_counter,
810                    config,
811                    vs1,
812                    sew.as_eew(),
813                )?;
814                zvexx_arith_helpers::execute_arith_op(
815                    env,
816                    vd,
817                    vs2,
818                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
819                    vm,
820                    sew,
821                    // Shift amount masked to log2(SEW) bits per spec ยง12.6
822                    |a, b, sew| a << (b & u64::from(sew.bits_width() - 1)),
823                );
824            }
825            Self::VsllVx {
826                vd,
827                vs2,
828                rs1: _,
829                vm,
830            } => {
831                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
832                    ::core::hint::cold_path();
833                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
834                        address: PackedAddress::new(
835                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
836                        ),
837                    });
838                }
839                let Some(config) = env.vector_config() else {
840                    ::core::hint::cold_path();
841                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
842                        address: PackedAddress::new(
843                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
844                        ),
845                    });
846                };
847                let sew = config.vtype().vsew();
848                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
849                    program_counter,
850                    config,
851                    vd,
852                    sew.as_eew(),
853                )?;
854                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
855                    program_counter,
856                    config,
857                    vs2,
858                    sew.as_eew(),
859                )?;
860                let scalar = rs1_value.as_u64();
861                zvexx_arith_helpers::execute_arith_op(
862                    env,
863                    vd,
864                    vs2,
865                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
866                    vm,
867                    sew,
868                    |a, b, sew| a << (b & u64::from(sew.bits_width() - 1)),
869                );
870            }
871            Self::VsllVi { vd, vs2, uimm, vm } => {
872                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
873                    ::core::hint::cold_path();
874                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
875                        address: PackedAddress::new(
876                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
877                        ),
878                    });
879                }
880                let Some(config) = env.vector_config() else {
881                    ::core::hint::cold_path();
882                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
883                        address: PackedAddress::new(
884                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
885                        ),
886                    });
887                };
888                let sew = config.vtype().vsew();
889                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
890                    program_counter,
891                    config,
892                    vd,
893                    sew.as_eew(),
894                )?;
895                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
896                    program_counter,
897                    config,
898                    vs2,
899                    sew.as_eew(),
900                )?;
901                // Immediate is already unsigned 5-bit; mask to log2(SEW) here too
902                let shamt = u64::from(uimm) & u64::from(sew.bits_width() - 1);
903                zvexx_arith_helpers::execute_arith_op(
904                    env,
905                    vd,
906                    vs2,
907                    zvexx_arith_helpers::OpSrc::Scalar(shamt),
908                    vm,
909                    sew,
910                    |a, b, _| a << b,
911                );
912            }
913            // vsrl
914            Self::VsrlVv { vd, vs2, vs1, vm } => {
915                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
916                    ::core::hint::cold_path();
917                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
918                        address: PackedAddress::new(
919                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
920                        ),
921                    });
922                }
923                let Some(config) = env.vector_config() else {
924                    ::core::hint::cold_path();
925                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
926                        address: PackedAddress::new(
927                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
928                        ),
929                    });
930                };
931                let sew = config.vtype().vsew();
932                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
933                    program_counter,
934                    config,
935                    vd,
936                    sew.as_eew(),
937                )?;
938                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
939                    program_counter,
940                    config,
941                    vs2,
942                    sew.as_eew(),
943                )?;
944                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
945                    program_counter,
946                    config,
947                    vs1,
948                    sew.as_eew(),
949                )?;
950                zvexx_arith_helpers::execute_arith_op(
951                    env,
952                    vd,
953                    vs2,
954                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
955                    vm,
956                    sew,
957                    // Logical right shift; operate on the SEW-wide portion only
958                    |a, b, sew| {
959                        let mask = zvexx_arith_helpers::sew_mask(sew);
960                        let shamt = b & u64::from(sew.bits_width() - 1);
961                        (a & mask) >> shamt
962                    },
963                );
964            }
965            Self::VsrlVx {
966                vd,
967                vs2,
968                rs1: _,
969                vm,
970            } => {
971                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
972                    ::core::hint::cold_path();
973                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
974                        address: PackedAddress::new(
975                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
976                        ),
977                    });
978                }
979                let Some(config) = env.vector_config() else {
980                    ::core::hint::cold_path();
981                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
982                        address: PackedAddress::new(
983                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
984                        ),
985                    });
986                };
987                let sew = config.vtype().vsew();
988                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
989                    program_counter,
990                    config,
991                    vd,
992                    sew.as_eew(),
993                )?;
994                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
995                    program_counter,
996                    config,
997                    vs2,
998                    sew.as_eew(),
999                )?;
1000                let scalar = rs1_value.as_u64();
1001                zvexx_arith_helpers::execute_arith_op(
1002                    env,
1003                    vd,
1004                    vs2,
1005                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
1006                    vm,
1007                    sew,
1008                    |a, b, sew| {
1009                        let mask = zvexx_arith_helpers::sew_mask(sew);
1010                        let shamt = b & u64::from(sew.bits_width() - 1);
1011                        (a & mask) >> shamt
1012                    },
1013                );
1014            }
1015            Self::VsrlVi { vd, vs2, uimm, vm } => {
1016                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1017                    ::core::hint::cold_path();
1018                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1019                        address: PackedAddress::new(
1020                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1021                        ),
1022                    });
1023                }
1024                let Some(config) = env.vector_config() else {
1025                    ::core::hint::cold_path();
1026                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1027                        address: PackedAddress::new(
1028                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1029                        ),
1030                    });
1031                };
1032                let sew = config.vtype().vsew();
1033                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1034                    program_counter,
1035                    config,
1036                    vd,
1037                    sew.as_eew(),
1038                )?;
1039                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1040                    program_counter,
1041                    config,
1042                    vs2,
1043                    sew.as_eew(),
1044                )?;
1045                let shamt = u64::from(uimm) & u64::from(sew.bits_width() - 1);
1046                zvexx_arith_helpers::execute_arith_op(
1047                    env,
1048                    vd,
1049                    vs2,
1050                    zvexx_arith_helpers::OpSrc::Scalar(shamt),
1051                    vm,
1052                    sew,
1053                    |a, b, sew| (a & zvexx_arith_helpers::sew_mask(sew)) >> b,
1054                );
1055            }
1056            // vsra
1057            Self::VsraVv { vd, vs2, vs1, vm } => {
1058                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1059                    ::core::hint::cold_path();
1060                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1061                        address: PackedAddress::new(
1062                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1063                        ),
1064                    });
1065                }
1066                let Some(config) = env.vector_config() else {
1067                    ::core::hint::cold_path();
1068                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1069                        address: PackedAddress::new(
1070                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1071                        ),
1072                    });
1073                };
1074                let sew = config.vtype().vsew();
1075                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1076                    program_counter,
1077                    config,
1078                    vd,
1079                    sew.as_eew(),
1080                )?;
1081                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1082                    program_counter,
1083                    config,
1084                    vs2,
1085                    sew.as_eew(),
1086                )?;
1087                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1088                    program_counter,
1089                    config,
1090                    vs1,
1091                    sew.as_eew(),
1092                )?;
1093                zvexx_arith_helpers::execute_arith_op(
1094                    env,
1095                    vd,
1096                    vs2,
1097                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
1098                    vm,
1099                    sew,
1100                    |a, b, sew| {
1101                        let shamt = b & u64::from(sew.bits_width() - 1);
1102                        let signed = zvexx_arith_helpers::sign_extend(a, sew);
1103                        (signed >> shamt).cast_unsigned()
1104                    },
1105                );
1106            }
1107            Self::VsraVx {
1108                vd,
1109                vs2,
1110                rs1: _,
1111                vm,
1112            } => {
1113                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1114                    ::core::hint::cold_path();
1115                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1116                        address: PackedAddress::new(
1117                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1118                        ),
1119                    });
1120                }
1121                let Some(config) = env.vector_config() else {
1122                    ::core::hint::cold_path();
1123                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1124                        address: PackedAddress::new(
1125                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1126                        ),
1127                    });
1128                };
1129                let sew = config.vtype().vsew();
1130                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1131                    program_counter,
1132                    config,
1133                    vd,
1134                    sew.as_eew(),
1135                )?;
1136                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1137                    program_counter,
1138                    config,
1139                    vs2,
1140                    sew.as_eew(),
1141                )?;
1142                let scalar = rs1_value.as_u64();
1143                zvexx_arith_helpers::execute_arith_op(
1144                    env,
1145                    vd,
1146                    vs2,
1147                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
1148                    vm,
1149                    sew,
1150                    |a, b, sew| {
1151                        let shamt = b & u64::from(sew.bits_width() - 1);
1152                        let signed = zvexx_arith_helpers::sign_extend(a, sew);
1153                        (signed >> shamt).cast_unsigned()
1154                    },
1155                );
1156            }
1157            Self::VsraVi { vd, vs2, uimm, vm } => {
1158                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1159                    ::core::hint::cold_path();
1160                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1161                        address: PackedAddress::new(
1162                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1163                        ),
1164                    });
1165                }
1166                let Some(config) = env.vector_config() else {
1167                    ::core::hint::cold_path();
1168                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1169                        address: PackedAddress::new(
1170                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1171                        ),
1172                    });
1173                };
1174                let sew = config.vtype().vsew();
1175                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1176                    program_counter,
1177                    config,
1178                    vd,
1179                    sew.as_eew(),
1180                )?;
1181                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1182                    program_counter,
1183                    config,
1184                    vs2,
1185                    sew.as_eew(),
1186                )?;
1187                let shamt = u64::from(uimm) & u64::from(sew.bits_width() - 1);
1188                zvexx_arith_helpers::execute_arith_op(
1189                    env,
1190                    vd,
1191                    vs2,
1192                    zvexx_arith_helpers::OpSrc::Scalar(shamt),
1193                    vm,
1194                    sew,
1195                    |a, b, sew| {
1196                        let signed = zvexx_arith_helpers::sign_extend(a, sew);
1197                        (signed >> b).cast_unsigned()
1198                    },
1199                );
1200            }
1201            // vminu / vmin
1202            Self::VminuVv { vd, vs2, vs1, vm } => {
1203                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1204                    ::core::hint::cold_path();
1205                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1206                        address: PackedAddress::new(
1207                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1208                        ),
1209                    });
1210                }
1211                let Some(config) = env.vector_config() else {
1212                    ::core::hint::cold_path();
1213                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1214                        address: PackedAddress::new(
1215                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1216                        ),
1217                    });
1218                };
1219                let sew = config.vtype().vsew();
1220                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1221                    program_counter,
1222                    config,
1223                    vd,
1224                    sew.as_eew(),
1225                )?;
1226                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1227                    program_counter,
1228                    config,
1229                    vs2,
1230                    sew.as_eew(),
1231                )?;
1232                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1233                    program_counter,
1234                    config,
1235                    vs1,
1236                    sew.as_eew(),
1237                )?;
1238                zvexx_arith_helpers::execute_arith_op(
1239                    env,
1240                    vd,
1241                    vs2,
1242                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
1243                    vm,
1244                    sew,
1245                    |a, b, sew| {
1246                        let mask = zvexx_arith_helpers::sew_mask(sew);
1247                        if a & mask <= b & mask { a } else { b }
1248                    },
1249                );
1250            }
1251            Self::VminuVx {
1252                vd,
1253                vs2,
1254                rs1: _,
1255                vm,
1256            } => {
1257                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1258                    ::core::hint::cold_path();
1259                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1260                        address: PackedAddress::new(
1261                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1262                        ),
1263                    });
1264                }
1265                let Some(config) = env.vector_config() else {
1266                    ::core::hint::cold_path();
1267                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1268                        address: PackedAddress::new(
1269                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1270                        ),
1271                    });
1272                };
1273                let sew = config.vtype().vsew();
1274                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1275                    program_counter,
1276                    config,
1277                    vd,
1278                    sew.as_eew(),
1279                )?;
1280                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1281                    program_counter,
1282                    config,
1283                    vs2,
1284                    sew.as_eew(),
1285                )?;
1286                let scalar = rs1_value.as_i64().cast_unsigned();
1287                zvexx_arith_helpers::execute_arith_op(
1288                    env,
1289                    vd,
1290                    vs2,
1291                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
1292                    vm,
1293                    sew,
1294                    |a, b, sew| {
1295                        let mask = zvexx_arith_helpers::sew_mask(sew);
1296                        if a & mask <= b & mask { a } else { b }
1297                    },
1298                );
1299            }
1300            Self::VminVv { vd, vs2, vs1, vm } => {
1301                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1302                    ::core::hint::cold_path();
1303                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1304                        address: PackedAddress::new(
1305                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1306                        ),
1307                    });
1308                }
1309                let Some(config) = env.vector_config() else {
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                let sew = config.vtype().vsew();
1318                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1319                    program_counter,
1320                    config,
1321                    vd,
1322                    sew.as_eew(),
1323                )?;
1324                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1325                    program_counter,
1326                    config,
1327                    vs2,
1328                    sew.as_eew(),
1329                )?;
1330                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1331                    program_counter,
1332                    config,
1333                    vs1,
1334                    sew.as_eew(),
1335                )?;
1336                zvexx_arith_helpers::execute_arith_op(
1337                    env,
1338                    vd,
1339                    vs2,
1340                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
1341                    vm,
1342                    sew,
1343                    |a, b, sew| {
1344                        if zvexx_arith_helpers::sign_extend(a, sew)
1345                            <= zvexx_arith_helpers::sign_extend(b, sew)
1346                        {
1347                            a
1348                        } else {
1349                            b
1350                        }
1351                    },
1352                );
1353            }
1354            Self::VminVx {
1355                vd,
1356                vs2,
1357                rs1: _,
1358                vm,
1359            } => {
1360                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1361                    ::core::hint::cold_path();
1362                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1363                        address: PackedAddress::new(
1364                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1365                        ),
1366                    });
1367                }
1368                let Some(config) = env.vector_config() else {
1369                    ::core::hint::cold_path();
1370                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1371                        address: PackedAddress::new(
1372                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1373                        ),
1374                    });
1375                };
1376                let sew = config.vtype().vsew();
1377                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1378                    program_counter,
1379                    config,
1380                    vd,
1381                    sew.as_eew(),
1382                )?;
1383                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1384                    program_counter,
1385                    config,
1386                    vs2,
1387                    sew.as_eew(),
1388                )?;
1389                let scalar = rs1_value.as_i64().cast_unsigned();
1390                zvexx_arith_helpers::execute_arith_op(
1391                    env,
1392                    vd,
1393                    vs2,
1394                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
1395                    vm,
1396                    sew,
1397                    |a, b, sew| {
1398                        if zvexx_arith_helpers::sign_extend(a, sew)
1399                            <= zvexx_arith_helpers::sign_extend(b, sew)
1400                        {
1401                            a
1402                        } else {
1403                            b
1404                        }
1405                    },
1406                );
1407            }
1408            // vmaxu / vmax
1409            Self::VmaxuVv { vd, vs2, vs1, vm } => {
1410                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1411                    ::core::hint::cold_path();
1412                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1413                        address: PackedAddress::new(
1414                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1415                        ),
1416                    });
1417                }
1418                let Some(config) = env.vector_config() else {
1419                    ::core::hint::cold_path();
1420                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1421                        address: PackedAddress::new(
1422                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1423                        ),
1424                    });
1425                };
1426                let sew = config.vtype().vsew();
1427                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1428                    program_counter,
1429                    config,
1430                    vd,
1431                    sew.as_eew(),
1432                )?;
1433                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1434                    program_counter,
1435                    config,
1436                    vs2,
1437                    sew.as_eew(),
1438                )?;
1439                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1440                    program_counter,
1441                    config,
1442                    vs1,
1443                    sew.as_eew(),
1444                )?;
1445                zvexx_arith_helpers::execute_arith_op(
1446                    env,
1447                    vd,
1448                    vs2,
1449                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
1450                    vm,
1451                    sew,
1452                    |a, b, sew| {
1453                        let mask = zvexx_arith_helpers::sew_mask(sew);
1454                        if a & mask >= b & mask { a } else { b }
1455                    },
1456                );
1457            }
1458            Self::VmaxuVx {
1459                vd,
1460                vs2,
1461                rs1: _,
1462                vm,
1463            } => {
1464                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1465                    ::core::hint::cold_path();
1466                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1467                        address: PackedAddress::new(
1468                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1469                        ),
1470                    });
1471                }
1472                let Some(config) = env.vector_config() else {
1473                    ::core::hint::cold_path();
1474                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1475                        address: PackedAddress::new(
1476                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1477                        ),
1478                    });
1479                };
1480                let sew = config.vtype().vsew();
1481                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1482                    program_counter,
1483                    config,
1484                    vd,
1485                    sew.as_eew(),
1486                )?;
1487                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1488                    program_counter,
1489                    config,
1490                    vs2,
1491                    sew.as_eew(),
1492                )?;
1493                let scalar = rs1_value.as_i64().cast_unsigned();
1494                zvexx_arith_helpers::execute_arith_op(
1495                    env,
1496                    vd,
1497                    vs2,
1498                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
1499                    vm,
1500                    sew,
1501                    |a, b, sew| {
1502                        let mask = zvexx_arith_helpers::sew_mask(sew);
1503                        if a & mask >= b & mask { a } else { b }
1504                    },
1505                );
1506            }
1507            Self::VmaxVv { vd, vs2, vs1, vm } => {
1508                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1509                    ::core::hint::cold_path();
1510                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1511                        address: PackedAddress::new(
1512                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1513                        ),
1514                    });
1515                }
1516                let Some(config) = env.vector_config() else {
1517                    ::core::hint::cold_path();
1518                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1519                        address: PackedAddress::new(
1520                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1521                        ),
1522                    });
1523                };
1524                let sew = config.vtype().vsew();
1525                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1526                    program_counter,
1527                    config,
1528                    vd,
1529                    sew.as_eew(),
1530                )?;
1531                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1532                    program_counter,
1533                    config,
1534                    vs2,
1535                    sew.as_eew(),
1536                )?;
1537                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1538                    program_counter,
1539                    config,
1540                    vs1,
1541                    sew.as_eew(),
1542                )?;
1543                zvexx_arith_helpers::execute_arith_op(
1544                    env,
1545                    vd,
1546                    vs2,
1547                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
1548                    vm,
1549                    sew,
1550                    |a, b, sew| {
1551                        if zvexx_arith_helpers::sign_extend(a, sew)
1552                            >= zvexx_arith_helpers::sign_extend(b, sew)
1553                        {
1554                            a
1555                        } else {
1556                            b
1557                        }
1558                    },
1559                );
1560            }
1561            Self::VmaxVx {
1562                vd,
1563                vs2,
1564                rs1: _,
1565                vm,
1566            } => {
1567                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1568                    ::core::hint::cold_path();
1569                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1570                        address: PackedAddress::new(
1571                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1572                        ),
1573                    });
1574                }
1575                let Some(config) = env.vector_config() else {
1576                    ::core::hint::cold_path();
1577                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1578                        address: PackedAddress::new(
1579                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1580                        ),
1581                    });
1582                };
1583                let sew = config.vtype().vsew();
1584                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1585                    program_counter,
1586                    config,
1587                    vd,
1588                    sew.as_eew(),
1589                )?;
1590                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1591                    program_counter,
1592                    config,
1593                    vs2,
1594                    sew.as_eew(),
1595                )?;
1596                let scalar = rs1_value.as_i64().cast_unsigned();
1597                zvexx_arith_helpers::execute_arith_op(
1598                    env,
1599                    vd,
1600                    vs2,
1601                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
1602                    vm,
1603                    sew,
1604                    |a, b, sew| {
1605                        if zvexx_arith_helpers::sign_extend(a, sew)
1606                            >= zvexx_arith_helpers::sign_extend(b, sew)
1607                        {
1608                            a
1609                        } else {
1610                            b
1611                        }
1612                    },
1613                );
1614            }
1615            // vmseq
1616            Self::VmseqVv { vd, vs2, vs1, vm } => {
1617                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1618                    ::core::hint::cold_path();
1619                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1620                        address: PackedAddress::new(
1621                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1622                        ),
1623                    });
1624                }
1625                let Some(config) = env.vector_config() else {
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 sew = config.vtype().vsew();
1634                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1635                    program_counter,
1636                    config,
1637                    vs2,
1638                    sew.as_eew(),
1639                )?;
1640                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1641                    program_counter,
1642                    config,
1643                    vs1,
1644                    sew.as_eew(),
1645                )?;
1646                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
1647                    program_counter,
1648                    vd,
1649                    vs2,
1650                )?;
1651                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
1652                    program_counter,
1653                    vd,
1654                    vs1,
1655                )?;
1656                zvexx_arith_helpers::execute_compare_op(
1657                    env,
1658                    vd,
1659                    vs2,
1660                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
1661                    vm,
1662                    sew,
1663                    |a, b, sew| {
1664                        (a & zvexx_arith_helpers::sew_mask(sew))
1665                            == (b & zvexx_arith_helpers::sew_mask(sew))
1666                    },
1667                );
1668            }
1669            Self::VmseqVx {
1670                vd,
1671                vs2,
1672                rs1: _,
1673                vm,
1674            } => {
1675                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1676                    ::core::hint::cold_path();
1677                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1678                        address: PackedAddress::new(
1679                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1680                        ),
1681                    });
1682                }
1683                let Some(config) = env.vector_config() else {
1684                    ::core::hint::cold_path();
1685                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1686                        address: PackedAddress::new(
1687                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1688                        ),
1689                    });
1690                };
1691                let sew = config.vtype().vsew();
1692                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1693                    program_counter,
1694                    config,
1695                    vs2,
1696                    sew.as_eew(),
1697                )?;
1698                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
1699                    program_counter,
1700                    vd,
1701                    vs2,
1702                )?;
1703                let scalar = rs1_value.as_i64().cast_unsigned();
1704                zvexx_arith_helpers::execute_compare_op(
1705                    env,
1706                    vd,
1707                    vs2,
1708                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
1709                    vm,
1710                    sew,
1711                    |a, b, sew| {
1712                        (a & zvexx_arith_helpers::sew_mask(sew))
1713                            == (b & zvexx_arith_helpers::sew_mask(sew))
1714                    },
1715                );
1716            }
1717            Self::VmseqVi { vd, vs2, imm, vm } => {
1718                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1719                    ::core::hint::cold_path();
1720                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1721                        address: PackedAddress::new(
1722                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1723                        ),
1724                    });
1725                }
1726                let Some(config) = env.vector_config() else {
1727                    ::core::hint::cold_path();
1728                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1729                        address: PackedAddress::new(
1730                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1731                        ),
1732                    });
1733                };
1734                let sew = config.vtype().vsew();
1735                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1736                    program_counter,
1737                    config,
1738                    vs2,
1739                    sew.as_eew(),
1740                )?;
1741                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
1742                    program_counter,
1743                    vd,
1744                    vs2,
1745                )?;
1746                let scalar = i64::from(imm).cast_unsigned();
1747                zvexx_arith_helpers::execute_compare_op(
1748                    env,
1749                    vd,
1750                    vs2,
1751                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
1752                    vm,
1753                    sew,
1754                    |a, b, sew| {
1755                        (a & zvexx_arith_helpers::sew_mask(sew))
1756                            == (b & zvexx_arith_helpers::sew_mask(sew))
1757                    },
1758                );
1759            }
1760            // vmsne
1761            Self::VmsneVv { vd, vs2, vs1, vm } => {
1762                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1763                    ::core::hint::cold_path();
1764                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1765                        address: PackedAddress::new(
1766                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1767                        ),
1768                    });
1769                }
1770                let Some(config) = env.vector_config() else {
1771                    ::core::hint::cold_path();
1772                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1773                        address: PackedAddress::new(
1774                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1775                        ),
1776                    });
1777                };
1778                let sew = config.vtype().vsew();
1779                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1780                    program_counter,
1781                    config,
1782                    vs2,
1783                    sew.as_eew(),
1784                )?;
1785                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1786                    program_counter,
1787                    config,
1788                    vs1,
1789                    sew.as_eew(),
1790                )?;
1791                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
1792                    program_counter,
1793                    vd,
1794                    vs2,
1795                )?;
1796                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
1797                    program_counter,
1798                    vd,
1799                    vs1,
1800                )?;
1801                zvexx_arith_helpers::execute_compare_op(
1802                    env,
1803                    vd,
1804                    vs2,
1805                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
1806                    vm,
1807                    sew,
1808                    |a, b, sew| {
1809                        (a & zvexx_arith_helpers::sew_mask(sew))
1810                            != (b & zvexx_arith_helpers::sew_mask(sew))
1811                    },
1812                );
1813            }
1814            Self::VmsneVx {
1815                vd,
1816                vs2,
1817                rs1: _,
1818                vm,
1819            } => {
1820                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1821                    ::core::hint::cold_path();
1822                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1823                        address: PackedAddress::new(
1824                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1825                        ),
1826                    });
1827                }
1828                let Some(config) = env.vector_config() else {
1829                    ::core::hint::cold_path();
1830                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1831                        address: PackedAddress::new(
1832                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1833                        ),
1834                    });
1835                };
1836                let sew = config.vtype().vsew();
1837                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1838                    program_counter,
1839                    config,
1840                    vs2,
1841                    sew.as_eew(),
1842                )?;
1843                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
1844                    program_counter,
1845                    vd,
1846                    vs2,
1847                )?;
1848                let scalar = rs1_value.as_i64().cast_unsigned();
1849                zvexx_arith_helpers::execute_compare_op(
1850                    env,
1851                    vd,
1852                    vs2,
1853                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
1854                    vm,
1855                    sew,
1856                    |a, b, sew| {
1857                        (a & zvexx_arith_helpers::sew_mask(sew))
1858                            != (b & zvexx_arith_helpers::sew_mask(sew))
1859                    },
1860                );
1861            }
1862            Self::VmsneVi { vd, vs2, imm, vm } => {
1863                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1864                    ::core::hint::cold_path();
1865                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1866                        address: PackedAddress::new(
1867                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1868                        ),
1869                    });
1870                }
1871                let Some(config) = env.vector_config() else {
1872                    ::core::hint::cold_path();
1873                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1874                        address: PackedAddress::new(
1875                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1876                        ),
1877                    });
1878                };
1879                let sew = config.vtype().vsew();
1880                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1881                    program_counter,
1882                    config,
1883                    vs2,
1884                    sew.as_eew(),
1885                )?;
1886                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
1887                    program_counter,
1888                    vd,
1889                    vs2,
1890                )?;
1891                let scalar = i64::from(imm).cast_unsigned();
1892                zvexx_arith_helpers::execute_compare_op(
1893                    env,
1894                    vd,
1895                    vs2,
1896                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
1897                    vm,
1898                    sew,
1899                    |a, b, sew| {
1900                        (a & zvexx_arith_helpers::sew_mask(sew))
1901                            != (b & zvexx_arith_helpers::sew_mask(sew))
1902                    },
1903                );
1904            }
1905            // vmsltu (unsigned <)
1906            Self::VmsltuVv { vd, vs2, vs1, vm } => {
1907                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1908                    ::core::hint::cold_path();
1909                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1910                        address: PackedAddress::new(
1911                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1912                        ),
1913                    });
1914                }
1915                let Some(config) = env.vector_config() else {
1916                    ::core::hint::cold_path();
1917                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1918                        address: PackedAddress::new(
1919                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1920                        ),
1921                    });
1922                };
1923                let sew = config.vtype().vsew();
1924                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1925                    program_counter,
1926                    config,
1927                    vs2,
1928                    sew.as_eew(),
1929                )?;
1930                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1931                    program_counter,
1932                    config,
1933                    vs1,
1934                    sew.as_eew(),
1935                )?;
1936                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
1937                    program_counter,
1938                    vd,
1939                    vs2,
1940                )?;
1941                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
1942                    program_counter,
1943                    vd,
1944                    vs1,
1945                )?;
1946                zvexx_arith_helpers::execute_compare_op(
1947                    env,
1948                    vd,
1949                    vs2,
1950                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
1951                    vm,
1952                    sew,
1953                    |a, b, sew| {
1954                        (a & zvexx_arith_helpers::sew_mask(sew))
1955                            < (b & zvexx_arith_helpers::sew_mask(sew))
1956                    },
1957                );
1958            }
1959            Self::VmsltuVx {
1960                vd,
1961                vs2,
1962                rs1: _,
1963                vm,
1964            } => {
1965                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
1966                    ::core::hint::cold_path();
1967                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1968                        address: PackedAddress::new(
1969                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1970                        ),
1971                    });
1972                }
1973                let Some(config) = env.vector_config() else {
1974                    ::core::hint::cold_path();
1975                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
1976                        address: PackedAddress::new(
1977                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
1978                        ),
1979                    });
1980                };
1981                let sew = config.vtype().vsew();
1982                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
1983                    program_counter,
1984                    config,
1985                    vs2,
1986                    sew.as_eew(),
1987                )?;
1988                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
1989                    program_counter,
1990                    vd,
1991                    vs2,
1992                )?;
1993                let scalar = rs1_value.as_i64().cast_unsigned();
1994                zvexx_arith_helpers::execute_compare_op(
1995                    env,
1996                    vd,
1997                    vs2,
1998                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
1999                    vm,
2000                    sew,
2001                    |a, b, sew| {
2002                        (a & zvexx_arith_helpers::sew_mask(sew))
2003                            < (b & zvexx_arith_helpers::sew_mask(sew))
2004                    },
2005                );
2006            }
2007            // vmslt (signed <)
2008            Self::VmsltVv { vd, vs2, vs1, vm } => {
2009                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
2010                    ::core::hint::cold_path();
2011                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2012                        address: PackedAddress::new(
2013                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2014                        ),
2015                    });
2016                }
2017                let Some(config) = env.vector_config() else {
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 sew = config.vtype().vsew();
2026                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2027                    program_counter,
2028                    config,
2029                    vs2,
2030                    sew.as_eew(),
2031                )?;
2032                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2033                    program_counter,
2034                    config,
2035                    vs1,
2036                    sew.as_eew(),
2037                )?;
2038                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2039                    program_counter,
2040                    vd,
2041                    vs2,
2042                )?;
2043                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2044                    program_counter,
2045                    vd,
2046                    vs1,
2047                )?;
2048                zvexx_arith_helpers::execute_compare_op(
2049                    env,
2050                    vd,
2051                    vs2,
2052                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
2053                    vm,
2054                    sew,
2055                    |a, b, sew| {
2056                        zvexx_arith_helpers::sign_extend(a, sew)
2057                            < zvexx_arith_helpers::sign_extend(b, sew)
2058                    },
2059                );
2060            }
2061            Self::VmsltVx {
2062                vd,
2063                vs2,
2064                rs1: _,
2065                vm,
2066            } => {
2067                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
2068                    ::core::hint::cold_path();
2069                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2070                        address: PackedAddress::new(
2071                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2072                        ),
2073                    });
2074                }
2075                let Some(config) = env.vector_config() else {
2076                    ::core::hint::cold_path();
2077                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2078                        address: PackedAddress::new(
2079                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2080                        ),
2081                    });
2082                };
2083                let sew = config.vtype().vsew();
2084                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2085                    program_counter,
2086                    config,
2087                    vs2,
2088                    sew.as_eew(),
2089                )?;
2090                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2091                    program_counter,
2092                    vd,
2093                    vs2,
2094                )?;
2095                let scalar = rs1_value.as_i64().cast_unsigned();
2096                zvexx_arith_helpers::execute_compare_op(
2097                    env,
2098                    vd,
2099                    vs2,
2100                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
2101                    vm,
2102                    sew,
2103                    |a, b, sew| {
2104                        zvexx_arith_helpers::sign_extend(a, sew)
2105                            < zvexx_arith_helpers::sign_extend(b, sew)
2106                    },
2107                );
2108            }
2109            // vmsleu (unsigned <=)
2110            Self::VmsleuVv { vd, vs2, vs1, vm } => {
2111                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
2112                    ::core::hint::cold_path();
2113                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2114                        address: PackedAddress::new(
2115                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2116                        ),
2117                    });
2118                }
2119                let Some(config) = env.vector_config() else {
2120                    ::core::hint::cold_path();
2121                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2122                        address: PackedAddress::new(
2123                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2124                        ),
2125                    });
2126                };
2127                let sew = config.vtype().vsew();
2128                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2129                    program_counter,
2130                    config,
2131                    vs2,
2132                    sew.as_eew(),
2133                )?;
2134                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2135                    program_counter,
2136                    config,
2137                    vs1,
2138                    sew.as_eew(),
2139                )?;
2140                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2141                    program_counter,
2142                    vd,
2143                    vs2,
2144                )?;
2145                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2146                    program_counter,
2147                    vd,
2148                    vs1,
2149                )?;
2150                zvexx_arith_helpers::execute_compare_op(
2151                    env,
2152                    vd,
2153                    vs2,
2154                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
2155                    vm,
2156                    sew,
2157                    |a, b, sew| {
2158                        (a & zvexx_arith_helpers::sew_mask(sew))
2159                            <= (b & zvexx_arith_helpers::sew_mask(sew))
2160                    },
2161                );
2162            }
2163            Self::VmsleuVx {
2164                vd,
2165                vs2,
2166                rs1: _,
2167                vm,
2168            } => {
2169                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
2170                    ::core::hint::cold_path();
2171                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2172                        address: PackedAddress::new(
2173                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2174                        ),
2175                    });
2176                }
2177                let Some(config) = env.vector_config() else {
2178                    ::core::hint::cold_path();
2179                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2180                        address: PackedAddress::new(
2181                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2182                        ),
2183                    });
2184                };
2185                let sew = config.vtype().vsew();
2186                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2187                    program_counter,
2188                    config,
2189                    vs2,
2190                    sew.as_eew(),
2191                )?;
2192                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2193                    program_counter,
2194                    vd,
2195                    vs2,
2196                )?;
2197                let scalar = rs1_value.as_i64().cast_unsigned();
2198                zvexx_arith_helpers::execute_compare_op(
2199                    env,
2200                    vd,
2201                    vs2,
2202                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
2203                    vm,
2204                    sew,
2205                    |a, b, sew| {
2206                        (a & zvexx_arith_helpers::sew_mask(sew))
2207                            <= (b & zvexx_arith_helpers::sew_mask(sew))
2208                    },
2209                );
2210            }
2211            Self::VmsleuVi { vd, vs2, imm, vm } => {
2212                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
2213                    ::core::hint::cold_path();
2214                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2215                        address: PackedAddress::new(
2216                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2217                        ),
2218                    });
2219                }
2220                let Some(config) = env.vector_config() else {
2221                    ::core::hint::cold_path();
2222                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2223                        address: PackedAddress::new(
2224                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2225                        ),
2226                    });
2227                };
2228                let sew = config.vtype().vsew();
2229                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2230                    program_counter,
2231                    config,
2232                    vs2,
2233                    sew.as_eew(),
2234                )?;
2235                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2236                    program_counter,
2237                    vd,
2238                    vs2,
2239                )?;
2240                // Per spec ยง12.8: for vmsleu.vi, the immediate is sign-extended to XLEN
2241                // then the comparison is unsigned. A negative i8 immediate sign-extends to
2242                // a large u64 (e.g. -1 -> 0xFFFF...FF). Both operands are masked to SEW
2243                // before comparing, so the effective immediate is (0xFFFF...FF &
2244                // zve64x_arith_helpers::sew_mask), which equals
2245                // zve64x_arith_helpers::sew_mask (the maximum SEW-wide unsigned value). This means
2246                // vs2[i] <= imm is always true for SEW < XLEN when imm < 0.
2247                let scalar = i64::from(imm).cast_unsigned();
2248                zvexx_arith_helpers::execute_compare_op(
2249                    env,
2250                    vd,
2251                    vs2,
2252                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
2253                    vm,
2254                    sew,
2255                    |a, b, sew| {
2256                        (a & zvexx_arith_helpers::sew_mask(sew))
2257                            <= (b & zvexx_arith_helpers::sew_mask(sew))
2258                    },
2259                );
2260            }
2261            // vmsle (signed <=)
2262            Self::VmsleVv { vd, vs2, vs1, vm } => {
2263                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
2264                    ::core::hint::cold_path();
2265                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2266                        address: PackedAddress::new(
2267                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2268                        ),
2269                    });
2270                }
2271                let Some(config) = env.vector_config() else {
2272                    ::core::hint::cold_path();
2273                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2274                        address: PackedAddress::new(
2275                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2276                        ),
2277                    });
2278                };
2279                let sew = config.vtype().vsew();
2280                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2281                    program_counter,
2282                    config,
2283                    vs2,
2284                    sew.as_eew(),
2285                )?;
2286                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2287                    program_counter,
2288                    config,
2289                    vs1,
2290                    sew.as_eew(),
2291                )?;
2292                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2293                    program_counter,
2294                    vd,
2295                    vs2,
2296                )?;
2297                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2298                    program_counter,
2299                    vd,
2300                    vs1,
2301                )?;
2302                zvexx_arith_helpers::execute_compare_op(
2303                    env,
2304                    vd,
2305                    vs2,
2306                    zvexx_arith_helpers::OpSrc::Vreg(vs1),
2307                    vm,
2308                    sew,
2309                    |a, b, sew| {
2310                        zvexx_arith_helpers::sign_extend(a, sew)
2311                            <= zvexx_arith_helpers::sign_extend(b, sew)
2312                    },
2313                );
2314            }
2315            Self::VmsleVx {
2316                vd,
2317                vs2,
2318                rs1: _,
2319                vm,
2320            } => {
2321                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
2322                    ::core::hint::cold_path();
2323                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2324                        address: PackedAddress::new(
2325                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2326                        ),
2327                    });
2328                }
2329                let Some(config) = env.vector_config() else {
2330                    ::core::hint::cold_path();
2331                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2332                        address: PackedAddress::new(
2333                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2334                        ),
2335                    });
2336                };
2337                let sew = config.vtype().vsew();
2338                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2339                    program_counter,
2340                    config,
2341                    vs2,
2342                    sew.as_eew(),
2343                )?;
2344                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2345                    program_counter,
2346                    vd,
2347                    vs2,
2348                )?;
2349                let scalar = rs1_value.as_i64().cast_unsigned();
2350                zvexx_arith_helpers::execute_compare_op(
2351                    env,
2352                    vd,
2353                    vs2,
2354                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
2355                    vm,
2356                    sew,
2357                    |a, b, sew| {
2358                        zvexx_arith_helpers::sign_extend(a, sew)
2359                            <= zvexx_arith_helpers::sign_extend(b, sew)
2360                    },
2361                );
2362            }
2363            Self::VmsleVi { vd, vs2, imm, vm } => {
2364                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
2365                    ::core::hint::cold_path();
2366                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2367                        address: PackedAddress::new(
2368                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2369                        ),
2370                    });
2371                }
2372                let Some(config) = env.vector_config() else {
2373                    ::core::hint::cold_path();
2374                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2375                        address: PackedAddress::new(
2376                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2377                        ),
2378                    });
2379                };
2380                let sew = config.vtype().vsew();
2381                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2382                    program_counter,
2383                    config,
2384                    vs2,
2385                    sew.as_eew(),
2386                )?;
2387                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2388                    program_counter,
2389                    vd,
2390                    vs2,
2391                )?;
2392                let scalar = i64::from(imm).cast_unsigned();
2393                zvexx_arith_helpers::execute_compare_op(
2394                    env,
2395                    vd,
2396                    vs2,
2397                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
2398                    vm,
2399                    sew,
2400                    |a, b, sew| {
2401                        zvexx_arith_helpers::sign_extend(a, sew)
2402                            <= zvexx_arith_helpers::sign_extend(b, sew)
2403                    },
2404                );
2405            }
2406            // vmsgtu (unsigned >): no vv form; vx and vi only
2407            Self::VmsgtuVx {
2408                vd,
2409                vs2,
2410                rs1: _,
2411                vm,
2412            } => {
2413                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
2414                    ::core::hint::cold_path();
2415                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2416                        address: PackedAddress::new(
2417                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2418                        ),
2419                    });
2420                }
2421                let Some(config) = env.vector_config() else {
2422                    ::core::hint::cold_path();
2423                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2424                        address: PackedAddress::new(
2425                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2426                        ),
2427                    });
2428                };
2429                let sew = config.vtype().vsew();
2430                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2431                    program_counter,
2432                    config,
2433                    vs2,
2434                    sew.as_eew(),
2435                )?;
2436                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2437                    program_counter,
2438                    vd,
2439                    vs2,
2440                )?;
2441                let scalar = rs1_value.as_i64().cast_unsigned();
2442                zvexx_arith_helpers::execute_compare_op(
2443                    env,
2444                    vd,
2445                    vs2,
2446                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
2447                    vm,
2448                    sew,
2449                    |a, b, sew| {
2450                        (a & zvexx_arith_helpers::sew_mask(sew))
2451                            > (b & zvexx_arith_helpers::sew_mask(sew))
2452                    },
2453                );
2454            }
2455            Self::VmsgtuVi { vd, vs2, imm, vm } => {
2456                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
2457                    ::core::hint::cold_path();
2458                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2459                        address: PackedAddress::new(
2460                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2461                        ),
2462                    });
2463                }
2464                let Some(config) = env.vector_config() else {
2465                    ::core::hint::cold_path();
2466                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2467                        address: PackedAddress::new(
2468                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2469                        ),
2470                    });
2471                };
2472                let sew = config.vtype().vsew();
2473                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2474                    program_counter,
2475                    config,
2476                    vs2,
2477                    sew.as_eew(),
2478                )?;
2479                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2480                    program_counter,
2481                    vd,
2482                    vs2,
2483                )?;
2484                let scalar = i64::from(imm).cast_unsigned();
2485                zvexx_arith_helpers::execute_compare_op(
2486                    env,
2487                    vd,
2488                    vs2,
2489                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
2490                    vm,
2491                    sew,
2492                    |a, b, sew| {
2493                        (a & zvexx_arith_helpers::sew_mask(sew))
2494                            > (b & zvexx_arith_helpers::sew_mask(sew))
2495                    },
2496                );
2497            }
2498            // vmsgt (signed >): no vv form; vx and vi only
2499            Self::VmsgtVx {
2500                vd,
2501                vs2,
2502                rs1: _,
2503                vm,
2504            } => {
2505                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
2506                    ::core::hint::cold_path();
2507                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2508                        address: PackedAddress::new(
2509                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2510                        ),
2511                    });
2512                }
2513                let Some(config) = env.vector_config() else {
2514                    ::core::hint::cold_path();
2515                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2516                        address: PackedAddress::new(
2517                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2518                        ),
2519                    });
2520                };
2521                let sew = config.vtype().vsew();
2522                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2523                    program_counter,
2524                    config,
2525                    vs2,
2526                    sew.as_eew(),
2527                )?;
2528                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2529                    program_counter,
2530                    vd,
2531                    vs2,
2532                )?;
2533                let scalar = rs1_value.as_i64().cast_unsigned();
2534                zvexx_arith_helpers::execute_compare_op(
2535                    env,
2536                    vd,
2537                    vs2,
2538                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
2539                    vm,
2540                    sew,
2541                    |a, b, sew| {
2542                        zvexx_arith_helpers::sign_extend(a, sew)
2543                            > zvexx_arith_helpers::sign_extend(b, sew)
2544                    },
2545                );
2546            }
2547            Self::VmsgtVi { vd, vs2, imm, vm } => {
2548                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
2549                    ::core::hint::cold_path();
2550                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2551                        address: PackedAddress::new(
2552                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2553                        ),
2554                    });
2555                }
2556                let Some(config) = env.vector_config() else {
2557                    ::core::hint::cold_path();
2558                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
2559                        address: PackedAddress::new(
2560                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
2561                        ),
2562                    });
2563                };
2564                let sew = config.vtype().vsew();
2565                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
2566                    program_counter,
2567                    config,
2568                    vs2,
2569                    sew.as_eew(),
2570                )?;
2571                zvexx_arith_helpers::check_mask_dest_overlap::<Reg, Env, _, _>(
2572                    program_counter,
2573                    vd,
2574                    vs2,
2575                )?;
2576                let scalar = i64::from(imm).cast_unsigned();
2577                zvexx_arith_helpers::execute_compare_op(
2578                    env,
2579                    vd,
2580                    vs2,
2581                    zvexx_arith_helpers::OpSrc::Scalar(scalar),
2582                    vm,
2583                    sew,
2584                    |a, b, sew| {
2585                        zvexx_arith_helpers::sign_extend(a, sew)
2586                            > zvexx_arith_helpers::sign_extend(b, sew)
2587                    },
2588                );
2589            }
2590        }
2591
2592        ExecutionResult::ContinueNoWrite
2593    }
2594}