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