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