Skip to main content

ab_riscv_interpreter/v/zvexx/
carry.rs

1//! ZveXx carry/borrow arithmetic instructions
2
3#[cfg(test)]
4mod tests;
5pub mod zvexx_carry_helpers;
6
7use crate::v::vector_registers::VectorRegistersExt;
8use crate::v::zvexx::zvexx_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 ZveXxCarryInstruction<Reg> where Reg: Register {}
20
21#[instruction_execution]
22impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
23    for ZveXxCarryInstruction<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 ZveXxCarryInstruction<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            // vadc: add with carry-in from v0, data result
62            Self::VadcVvm { vd, vs2, vs1 } => {
63                if !ext_state.vector_instructions_allowed() {
64                    return Err(ExecutionError::IllegalInstruction {
65                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
66                    });
67                }
68                let vtype = ext_state
69                    .vtype()
70                    .ok_or(ExecutionError::IllegalInstruction {
71                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
72                    })?;
73                let group_regs = vtype.vlmul().register_count();
74                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
75                    program_counter,
76                    vd,
77                    group_regs,
78                )?;
79                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
80                    program_counter,
81                    vs2,
82                    group_regs,
83                )?;
84                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
85                    program_counter,
86                    vs1,
87                    group_regs,
88                )?;
89                // vd must not be v0: v0 holds carry-in
90                if vd == VReg::V0 {
91                    return Err(ExecutionError::IllegalInstruction {
92                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
93                    });
94                }
95                let sew = vtype.vsew();
96                // SAFETY: alignments checked above; vd != v0 checked above
97                unsafe {
98                    zvexx_carry_helpers::execute_carry_add::<Reg, _, _>(
99                        ext_state,
100                        vd,
101                        vs2,
102                        zvexx_carry_helpers::OpSrc::Vreg(vs1),
103                        true,
104                        sew,
105                    );
106                }
107            }
108
109            Self::VadcVxm { vd, vs2, rs1: _ } => {
110                if !ext_state.vector_instructions_allowed() {
111                    return Err(ExecutionError::IllegalInstruction {
112                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
113                    });
114                }
115                let vtype = ext_state
116                    .vtype()
117                    .ok_or(ExecutionError::IllegalInstruction {
118                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
119                    })?;
120                let group_regs = vtype.vlmul().register_count();
121                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
122                    program_counter,
123                    vd,
124                    group_regs,
125                )?;
126                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
127                    program_counter,
128                    vs2,
129                    group_regs,
130                )?;
131                if vd == VReg::V0 {
132                    return Err(ExecutionError::IllegalInstruction {
133                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
134                    });
135                }
136                let sew = vtype.vsew();
137                let scalar = rs1_value.as_i64().cast_unsigned();
138                // SAFETY: alignments checked above; vd != v0 checked above
139                unsafe {
140                    zvexx_carry_helpers::execute_carry_add::<Reg, _, _>(
141                        ext_state,
142                        vd,
143                        vs2,
144                        zvexx_carry_helpers::OpSrc::Scalar(scalar),
145                        true,
146                        sew,
147                    );
148                }
149            }
150
151            Self::VadcVim { vd, vs2, imm } => {
152                if !ext_state.vector_instructions_allowed() {
153                    return Err(ExecutionError::IllegalInstruction {
154                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
155                    });
156                }
157                let vtype = ext_state
158                    .vtype()
159                    .ok_or(ExecutionError::IllegalInstruction {
160                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
161                    })?;
162                let group_regs = vtype.vlmul().register_count();
163                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
164                    program_counter,
165                    vd,
166                    group_regs,
167                )?;
168                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
169                    program_counter,
170                    vs2,
171                    group_regs,
172                )?;
173                if vd == VReg::V0 {
174                    return Err(ExecutionError::IllegalInstruction {
175                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
176                    });
177                }
178                let sew = vtype.vsew();
179                let scalar = i64::from(imm).cast_unsigned();
180                // SAFETY: alignments checked above; vd != v0 checked above
181                unsafe {
182                    zvexx_carry_helpers::execute_carry_add::<Reg, _, _>(
183                        ext_state,
184                        vd,
185                        vs2,
186                        zvexx_carry_helpers::OpSrc::Scalar(scalar),
187                        true,
188                        sew,
189                    );
190                }
191            }
192
193            // vmadc: add and write carry-out mask
194            Self::VmadcVvm { vd, vs2, vs1 } => {
195                if !ext_state.vector_instructions_allowed() {
196                    return Err(ExecutionError::IllegalInstruction {
197                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
198                    });
199                }
200                let vtype = ext_state
201                    .vtype()
202                    .ok_or(ExecutionError::IllegalInstruction {
203                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
204                    })?;
205                let group_regs = vtype.vlmul().register_count();
206                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
207                    program_counter,
208                    vs2,
209                    group_regs,
210                )?;
211                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
212                    program_counter,
213                    vs1,
214                    group_regs,
215                )?;
216                zvexx_carry_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
217                    program_counter,
218                    vd,
219                    vs2,
220                    group_regs,
221                )?;
222                zvexx_carry_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
223                    program_counter,
224                    vd,
225                    vs1,
226                    group_regs,
227                )?;
228                let sew = vtype.vsew();
229                // SAFETY: alignments and overlap checked above
230                unsafe {
231                    zvexx_carry_helpers::execute_carry_add_mask::<Reg, _, _>(
232                        ext_state,
233                        vd,
234                        vs2,
235                        zvexx_carry_helpers::OpSrc::Vreg(vs1),
236                        true,
237                        sew,
238                    );
239                }
240            }
241
242            Self::VmadcVxm { vd, vs2, rs1: _ } => {
243                if !ext_state.vector_instructions_allowed() {
244                    return Err(ExecutionError::IllegalInstruction {
245                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
246                    });
247                }
248                let vtype = ext_state
249                    .vtype()
250                    .ok_or(ExecutionError::IllegalInstruction {
251                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
252                    })?;
253                let group_regs = vtype.vlmul().register_count();
254                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
255                    program_counter,
256                    vs2,
257                    group_regs,
258                )?;
259                zvexx_carry_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
260                    program_counter,
261                    vd,
262                    vs2,
263                    group_regs,
264                )?;
265                let sew = vtype.vsew();
266                let scalar = rs1_value.as_i64().cast_unsigned();
267                // SAFETY: alignments and overlap checked above
268                unsafe {
269                    zvexx_carry_helpers::execute_carry_add_mask::<Reg, _, _>(
270                        ext_state,
271                        vd,
272                        vs2,
273                        zvexx_carry_helpers::OpSrc::Scalar(scalar),
274                        true,
275                        sew,
276                    );
277                }
278            }
279
280            Self::VmadcVim { vd, vs2, imm } => {
281                if !ext_state.vector_instructions_allowed() {
282                    return Err(ExecutionError::IllegalInstruction {
283                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
284                    });
285                }
286                let vtype = ext_state
287                    .vtype()
288                    .ok_or(ExecutionError::IllegalInstruction {
289                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
290                    })?;
291                let group_regs = vtype.vlmul().register_count();
292                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
293                    program_counter,
294                    vs2,
295                    group_regs,
296                )?;
297                zvexx_carry_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
298                    program_counter,
299                    vd,
300                    vs2,
301                    group_regs,
302                )?;
303                let sew = vtype.vsew();
304                let scalar = i64::from(imm).cast_unsigned();
305                // SAFETY: alignments and overlap checked above
306                unsafe {
307                    zvexx_carry_helpers::execute_carry_add_mask::<Reg, _, _>(
308                        ext_state,
309                        vd,
310                        vs2,
311                        zvexx_carry_helpers::OpSrc::Scalar(scalar),
312                        true,
313                        sew,
314                    );
315                }
316            }
317
318            Self::VmadcVv { vd, vs2, vs1 } => {
319                if !ext_state.vector_instructions_allowed() {
320                    return Err(ExecutionError::IllegalInstruction {
321                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
322                    });
323                }
324                let vtype = ext_state
325                    .vtype()
326                    .ok_or(ExecutionError::IllegalInstruction {
327                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
328                    })?;
329                let group_regs = vtype.vlmul().register_count();
330                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
331                    program_counter,
332                    vs2,
333                    group_regs,
334                )?;
335                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
336                    program_counter,
337                    vs1,
338                    group_regs,
339                )?;
340                zvexx_carry_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
341                    program_counter,
342                    vd,
343                    vs2,
344                    group_regs,
345                )?;
346                zvexx_carry_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
347                    program_counter,
348                    vd,
349                    vs1,
350                    group_regs,
351                )?;
352                let sew = vtype.vsew();
353                // SAFETY: alignments and overlap checked above
354                unsafe {
355                    zvexx_carry_helpers::execute_carry_add_mask::<Reg, _, _>(
356                        ext_state,
357                        vd,
358                        vs2,
359                        zvexx_carry_helpers::OpSrc::Vreg(vs1),
360                        false,
361                        sew,
362                    );
363                }
364            }
365
366            Self::VmadcVx { vd, vs2, rs1: _ } => {
367                if !ext_state.vector_instructions_allowed() {
368                    return Err(ExecutionError::IllegalInstruction {
369                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
370                    });
371                }
372                let vtype = ext_state
373                    .vtype()
374                    .ok_or(ExecutionError::IllegalInstruction {
375                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
376                    })?;
377                let group_regs = vtype.vlmul().register_count();
378                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
379                    program_counter,
380                    vs2,
381                    group_regs,
382                )?;
383                zvexx_carry_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
384                    program_counter,
385                    vd,
386                    vs2,
387                    group_regs,
388                )?;
389                let sew = vtype.vsew();
390                let scalar = rs1_value.as_i64().cast_unsigned();
391                // SAFETY: alignments and overlap checked above
392                unsafe {
393                    zvexx_carry_helpers::execute_carry_add_mask::<Reg, _, _>(
394                        ext_state,
395                        vd,
396                        vs2,
397                        zvexx_carry_helpers::OpSrc::Scalar(scalar),
398                        false,
399                        sew,
400                    );
401                }
402            }
403
404            Self::VmadcVi { vd, vs2, imm } => {
405                if !ext_state.vector_instructions_allowed() {
406                    return Err(ExecutionError::IllegalInstruction {
407                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
408                    });
409                }
410                let vtype = ext_state
411                    .vtype()
412                    .ok_or(ExecutionError::IllegalInstruction {
413                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
414                    })?;
415                let group_regs = vtype.vlmul().register_count();
416                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
417                    program_counter,
418                    vs2,
419                    group_regs,
420                )?;
421                zvexx_carry_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
422                    program_counter,
423                    vd,
424                    vs2,
425                    group_regs,
426                )?;
427                let sew = vtype.vsew();
428                let scalar = i64::from(imm).cast_unsigned();
429                // SAFETY: alignments and overlap checked above
430                unsafe {
431                    zvexx_carry_helpers::execute_carry_add_mask::<Reg, _, _>(
432                        ext_state,
433                        vd,
434                        vs2,
435                        zvexx_carry_helpers::OpSrc::Scalar(scalar),
436                        false,
437                        sew,
438                    );
439                }
440            }
441
442            // vsbc: subtract with borrow-in from v0, data result
443            Self::VsbcVvm { vd, vs2, vs1 } => {
444                if !ext_state.vector_instructions_allowed() {
445                    return Err(ExecutionError::IllegalInstruction {
446                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
447                    });
448                }
449                let vtype = ext_state
450                    .vtype()
451                    .ok_or(ExecutionError::IllegalInstruction {
452                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
453                    })?;
454                let group_regs = vtype.vlmul().register_count();
455                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
456                    program_counter,
457                    vd,
458                    group_regs,
459                )?;
460                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
461                    program_counter,
462                    vs2,
463                    group_regs,
464                )?;
465                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
466                    program_counter,
467                    vs1,
468                    group_regs,
469                )?;
470                if vd == VReg::V0 {
471                    return Err(ExecutionError::IllegalInstruction {
472                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
473                    });
474                }
475                let sew = vtype.vsew();
476                // SAFETY: alignments checked above; vd != v0 checked above
477                unsafe {
478                    zvexx_carry_helpers::execute_carry_sub::<Reg, _, _>(
479                        ext_state,
480                        vd,
481                        vs2,
482                        zvexx_carry_helpers::OpSrc::Vreg(vs1),
483                        sew,
484                    );
485                }
486            }
487
488            Self::VsbcVxm { vd, vs2, rs1: _ } => {
489                if !ext_state.vector_instructions_allowed() {
490                    return Err(ExecutionError::IllegalInstruction {
491                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
492                    });
493                }
494                let vtype = ext_state
495                    .vtype()
496                    .ok_or(ExecutionError::IllegalInstruction {
497                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
498                    })?;
499                let group_regs = vtype.vlmul().register_count();
500                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
501                    program_counter,
502                    vd,
503                    group_regs,
504                )?;
505                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
506                    program_counter,
507                    vs2,
508                    group_regs,
509                )?;
510                if vd == VReg::V0 {
511                    return Err(ExecutionError::IllegalInstruction {
512                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
513                    });
514                }
515                let sew = vtype.vsew();
516                let scalar = rs1_value.as_i64().cast_unsigned();
517                // SAFETY: alignments checked above; vd != v0 checked above
518                unsafe {
519                    zvexx_carry_helpers::execute_carry_sub::<Reg, _, _>(
520                        ext_state,
521                        vd,
522                        vs2,
523                        zvexx_carry_helpers::OpSrc::Scalar(scalar),
524                        sew,
525                    );
526                }
527            }
528
529            // vmsbc: subtract and write borrow-out mask
530            Self::VmsbcVvm { vd, vs2, vs1 } => {
531                if !ext_state.vector_instructions_allowed() {
532                    return Err(ExecutionError::IllegalInstruction {
533                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
534                    });
535                }
536                let vtype = ext_state
537                    .vtype()
538                    .ok_or(ExecutionError::IllegalInstruction {
539                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
540                    })?;
541                let group_regs = vtype.vlmul().register_count();
542                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
543                    program_counter,
544                    vs2,
545                    group_regs,
546                )?;
547                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
548                    program_counter,
549                    vs1,
550                    group_regs,
551                )?;
552                zvexx_carry_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
553                    program_counter,
554                    vd,
555                    vs2,
556                    group_regs,
557                )?;
558                zvexx_carry_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
559                    program_counter,
560                    vd,
561                    vs1,
562                    group_regs,
563                )?;
564                let sew = vtype.vsew();
565                // SAFETY: alignments and overlap checked above
566                unsafe {
567                    zvexx_carry_helpers::execute_carry_sub_mask::<Reg, _, _>(
568                        ext_state,
569                        vd,
570                        vs2,
571                        zvexx_carry_helpers::OpSrc::Vreg(vs1),
572                        true,
573                        sew,
574                    );
575                }
576            }
577
578            Self::VmsbcVxm { vd, vs2, rs1: _ } => {
579                if !ext_state.vector_instructions_allowed() {
580                    return Err(ExecutionError::IllegalInstruction {
581                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
582                    });
583                }
584                let vtype = ext_state
585                    .vtype()
586                    .ok_or(ExecutionError::IllegalInstruction {
587                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
588                    })?;
589                let group_regs = vtype.vlmul().register_count();
590                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
591                    program_counter,
592                    vs2,
593                    group_regs,
594                )?;
595                zvexx_carry_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
596                    program_counter,
597                    vd,
598                    vs2,
599                    group_regs,
600                )?;
601                let sew = vtype.vsew();
602                let scalar = rs1_value.as_i64().cast_unsigned();
603                // SAFETY: alignments and overlap checked above
604                unsafe {
605                    zvexx_carry_helpers::execute_carry_sub_mask::<Reg, _, _>(
606                        ext_state,
607                        vd,
608                        vs2,
609                        zvexx_carry_helpers::OpSrc::Scalar(scalar),
610                        true,
611                        sew,
612                    );
613                }
614            }
615
616            Self::VmsbcVv { vd, vs2, vs1 } => {
617                if !ext_state.vector_instructions_allowed() {
618                    return Err(ExecutionError::IllegalInstruction {
619                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
620                    });
621                }
622                let vtype = ext_state
623                    .vtype()
624                    .ok_or(ExecutionError::IllegalInstruction {
625                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
626                    })?;
627                let group_regs = vtype.vlmul().register_count();
628                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
629                    program_counter,
630                    vs2,
631                    group_regs,
632                )?;
633                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
634                    program_counter,
635                    vs1,
636                    group_regs,
637                )?;
638                zvexx_carry_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
639                    program_counter,
640                    vd,
641                    vs2,
642                    group_regs,
643                )?;
644                zvexx_carry_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
645                    program_counter,
646                    vd,
647                    vs1,
648                    group_regs,
649                )?;
650                let sew = vtype.vsew();
651                // SAFETY: alignments and overlap checked above
652                unsafe {
653                    zvexx_carry_helpers::execute_carry_sub_mask::<Reg, _, _>(
654                        ext_state,
655                        vd,
656                        vs2,
657                        zvexx_carry_helpers::OpSrc::Vreg(vs1),
658                        false,
659                        sew,
660                    );
661                }
662            }
663
664            Self::VmsbcVx { vd, vs2, rs1: _ } => {
665                if !ext_state.vector_instructions_allowed() {
666                    return Err(ExecutionError::IllegalInstruction {
667                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
668                    });
669                }
670                let vtype = ext_state
671                    .vtype()
672                    .ok_or(ExecutionError::IllegalInstruction {
673                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
674                    })?;
675                let group_regs = vtype.vlmul().register_count();
676                zvexx_carry_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
677                    program_counter,
678                    vs2,
679                    group_regs,
680                )?;
681                zvexx_carry_helpers::check_mask_dest_no_overlap::<Reg, _, _, _>(
682                    program_counter,
683                    vd,
684                    vs2,
685                    group_regs,
686                )?;
687                let sew = vtype.vsew();
688                let scalar = rs1_value.as_i64().cast_unsigned();
689                // SAFETY: alignments and overlap checked above
690                unsafe {
691                    zvexx_carry_helpers::execute_carry_sub_mask::<Reg, _, _>(
692                        ext_state,
693                        vd,
694                        vs2,
695                        zvexx_carry_helpers::OpSrc::Scalar(scalar),
696                        false,
697                        sew,
698                    );
699                }
700            }
701        }
702
703        Ok(ControlFlow::Continue(Default::default()))
704    }
705}