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