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