Skip to main content

ab_riscv_interpreter/v/zve64x/
widen_narrow.rs

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