ab_riscv_interpreter/v/zvexx/carry/
zvexx_carry_helpers.rs1use crate::v::vector_registers::{VRegGroup, VectorRegisterFile, VectorRegistersExt};
4pub use crate::v::zvexx::arith::zvexx_arith_helpers::{OpSrc, check_mask_dest_overlap};
5use crate::v::zvexx::arith::zvexx_arith_helpers::{sew_mask, write_mask_bit};
6use crate::v::zvexx::load::zvexx_load_helpers::mask_bit;
7use ab_riscv_primitives::prelude::*;
8use core::hint::cold_path;
9
10#[inline(always)]
14#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
15pub(in super::super) fn carry_bit<Hart>(vregs: &VectorRegisterFile<Hart>, i: u16) -> u64
16where
17 Hart: VectorHartConfig,
18{
19 let v0 = vregs.get(VReg::V0);
20 u64::from(mask_bit(v0, i))
21}
22
23#[inline(always)]
32#[doc(hidden)]
33#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
34pub fn execute_carry_add<const WITH_CARRY: bool, Reg, Env>(
35 env: &mut Env,
36 vd: VRegGroup<Env::Hart>,
37 vs2: VRegGroup<Env::Hart>,
38 src: OpSrc<VRegGroup<Env::Hart>>,
39) where
40 Reg: Register,
41 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
42{
43 let vl = vd.vl();
44 let (Some(vs2), Some(src)) = (vs2.with_same_vl(vl), src.with_same_vl(vl)) else {
45 cold_path();
46 return;
47 };
48 for i in vl.indices() {
49 let a = env
50 .read_vregs()
51 .read(vs2, i)
52 .expect("`vs2` has the same `vl` as `vd`, checked above; qed");
53 let b = match src.vreg {
54 Some(vs1) => env
55 .read_vregs()
56 .read(vs1, i)
57 .expect("`vs1` has the same `vl` as `vd`, checked above; qed"),
58 None => src.scalar,
59 };
60 let c = if WITH_CARRY {
61 carry_bit(env.read_vregs(), i)
62 } else {
63 0
64 };
65
66 let result = a.wrapping_add(b).wrapping_add(c);
68 env.write_vregs()
69 .write(vd, i, result)
70 .expect("`i < vl` of `vd`; qed");
71 }
72
73 env.mark_vs_dirty();
74}
75
76#[inline(always)]
85#[doc(hidden)]
86#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
87pub fn execute_carry_sub<Reg, Env>(
88 env: &mut Env,
89 vd: VRegGroup<Env::Hart>,
90 vs2: VRegGroup<Env::Hart>,
91 src: OpSrc<VRegGroup<Env::Hart>>,
92) where
93 Reg: Register,
94 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
95{
96 let vl = vd.vl();
97 let (Some(vs2), Some(src)) = (vs2.with_same_vl(vl), src.with_same_vl(vl)) else {
98 cold_path();
99 return;
100 };
101 for i in vl.indices() {
102 let a = env
103 .read_vregs()
104 .read(vs2, i)
105 .expect("`vs2` has the same `vl` as `vd`, checked above; qed");
106 let b = match src.vreg {
107 Some(vs1) => env
108 .read_vregs()
109 .read(vs1, i)
110 .expect("`vs1` has the same `vl` as `vd`, checked above; qed"),
111 None => src.scalar,
112 };
113 let borrow = carry_bit(env.read_vregs(), i);
114
115 let result = a.wrapping_sub(b).wrapping_sub(borrow);
116 env.write_vregs()
117 .write(vd, i, result)
118 .expect("`i < vl` of `vd`; qed");
119 }
120
121 env.mark_vs_dirty();
122}
123
124#[inline(always)]
137#[doc(hidden)]
138#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
139pub fn execute_carry_add_mask<const WITH_CARRY: bool, Reg, Env>(
140 env: &mut Env,
141 vd: VReg,
142 vs2: VRegGroup<Env::Hart>,
143 src: OpSrc<VRegGroup<Env::Hart>>,
144 sew: Vsew,
145) where
146 Reg: Register,
147 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
148{
149 let vl = vs2.vl();
150 let Some(src) = src.with_same_vl(vl) else {
151 cold_path();
152 return;
153 };
154 let mask = sew_mask(sew);
155
156 for i in vl.indices() {
157 let a = env
158 .read_vregs()
159 .read(vs2, i)
160 .expect("`i < vl` of `vs2`; qed");
161 let b = match src.vreg {
162 Some(vs1) => env
163 .read_vregs()
164 .read(vs1, i)
165 .expect("`vs1` has the same `vl` as `vs2`, checked above; qed"),
166 None => src.scalar,
167 };
168 let c = if WITH_CARRY {
169 carry_bit(env.read_vregs(), i)
170 } else {
171 0
172 };
173
174 let sum = u128::from(a & mask) + u128::from(b & mask) + u128::from(c);
176 let carry_out = (sum >> sew.bits_width()) & 1 != 0;
177
178 write_mask_bit(env.write_vregs(), vd, i, carry_out)
179 .expect("`i < vl <= VLEN`, so the mask bit is within `vd`; qed");
180 }
181
182 env.mark_vs_dirty();
183}
184
185#[inline(always)]
197#[doc(hidden)]
198#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
199pub fn execute_carry_sub_mask<const WITH_BORROW: bool, Reg, Env>(
200 env: &mut Env,
201 vd: VReg,
202 vs2: VRegGroup<Env::Hart>,
203 src: OpSrc<VRegGroup<Env::Hart>>,
204 sew: Vsew,
205) where
206 Reg: Register,
207 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
208{
209 let vl = vs2.vl();
210 let Some(src) = src.with_same_vl(vl) else {
211 cold_path();
212 return;
213 };
214 let mask = sew_mask(sew);
215
216 for i in vl.indices() {
217 let a = env
218 .read_vregs()
219 .read(vs2, i)
220 .expect("`i < vl` of `vs2`; qed");
221 let b = match src.vreg {
222 Some(vs1) => env
223 .read_vregs()
224 .read(vs1, i)
225 .expect("`vs1` has the same `vl` as `vs2`, checked above; qed"),
226 None => src.scalar,
227 };
228 let borrow_in = if WITH_BORROW {
229 carry_bit(env.read_vregs(), i)
230 } else {
231 0
232 };
233
234 let a_m = u128::from(a & mask);
235 let rhs = u128::from(b & mask) + u128::from(borrow_in);
236 let borrow_out = a_m < rhs;
237
238 write_mask_bit(env.write_vregs(), vd, i, borrow_out)
239 .expect("`i < vl <= VLEN`, so the mask bit is within `vd`; qed");
240 }
241
242 env.mark_vs_dirty();
243}