ab_riscv_interpreter/v/zvexx/arith/
zvexx_arith_helpers.rs1use crate::v::vector_registers::{VectorRegisterFile, VectorRegistersExt};
4use crate::v::zvexx::load::zvexx_load_helpers::{mask_bit, snapshot_mask};
5use crate::v::zvexx::zvexx_helpers::INSTRUCTION_SIZE;
6use crate::{ExecutionError, PackedAddress, ProgramCounter};
7use ab_riscv_primitives::prelude::*;
8use core::hint::cold_path;
9use core::num::NonZeroU8;
10
11#[inline(always)]
13#[doc(hidden)]
14#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
15pub fn check_vreg_group_alignment<Reg, Memory, PC>(
16 program_counter: &PC,
17 vreg: VReg,
18 group_regs: NonZeroU8,
19) -> Result<(), ExecutionError<Reg::Type>>
20where
21 Reg: Register,
22 PC: ProgramCounter<Reg::Type, Memory>,
23{
24 let group_regs = group_regs.get();
25 let vreg_idx = vreg.to_bits();
26 if !vreg_idx.is_multiple_of(group_regs) || vreg_idx + group_regs > 32 {
27 cold_path();
28 return Err(ExecutionError::IllegalInstruction {
29 address: PackedAddress::new(program_counter.old_pc(INSTRUCTION_SIZE)),
30 });
31 }
32 Ok(())
33}
34
35#[inline(always)]
50#[doc(hidden)]
51#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
52pub fn check_mask_dest_overlap<Reg, Memory, PC>(
53 program_counter: &PC,
54 vd: VReg,
55 src_base: VReg,
56 group_regs: NonZeroU8,
57) -> Result<(), ExecutionError<Reg::Type>>
58where
59 Reg: Register,
60 PC: ProgramCounter<Reg::Type, Memory>,
61{
62 let group_regs = group_regs.get();
63 if group_regs > 1 {
64 let vd_idx = vd.to_bits();
65 let src = src_base.to_bits();
66 if vd_idx > src && vd_idx < src + group_regs {
67 cold_path();
68 return Err(ExecutionError::IllegalInstruction {
69 address: PackedAddress::new(program_counter.old_pc(INSTRUCTION_SIZE)),
70 });
71 }
72 }
73 Ok(())
74}
75
76#[inline(always)]
87#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
88pub(crate) unsafe fn read_element_u64<const VLEN: Vlen>(
89 vregs: &VectorRegisterFile<VLEN>,
90 base_reg: VReg,
91 elem_i: u16,
92 sew: Vsew,
93) -> u64 {
94 let sew_bytes = u32::from(sew.bytes_width());
95 let elems_per_reg = VLEN.bytes() / sew_bytes;
96 let reg_off = u32::from(elem_i) / elems_per_reg;
97 let byte_off = (u32::from(elem_i) % elems_per_reg) * sew_bytes;
98 let reg = vregs
100 .get(unsafe { VReg::from_bits(base_reg.to_bits() + reg_off as u8).unwrap_unchecked() });
101 let src = unsafe { reg.get_unchecked(byte_off as usize..(byte_off + sew_bytes) as usize) };
104 let mut buf = [0u8; 8];
105 unsafe { buf.get_unchecked_mut(..sew_bytes as usize) }.copy_from_slice(src);
107 u64::from_le_bytes(buf)
108}
109
110#[inline(always)]
116#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
117pub(crate) unsafe fn write_element_u64<const VLEN: Vlen>(
118 vregs: &mut VectorRegisterFile<VLEN>,
119 base_reg: VReg,
120 elem_i: u16,
121 sew: Vsew,
122 value: u64,
123) {
124 let sew_bytes = u32::from(sew.bytes_width());
125 let elems_per_reg = VLEN.bytes() / sew_bytes;
126 let reg_off = u32::from(elem_i) / elems_per_reg;
127 let byte_off = (u32::from(elem_i) % elems_per_reg) * sew_bytes;
128 let buf = value.to_le_bytes();
129 let reg = vregs
131 .get_mut(unsafe { VReg::from_bits(base_reg.to_bits() + reg_off as u8).unwrap_unchecked() });
132 let dst = unsafe { reg.get_unchecked_mut(byte_off as usize..(byte_off + sew_bytes) as usize) };
135 dst.copy_from_slice(unsafe { buf.get_unchecked(..sew_bytes as usize) });
137}
138
139#[inline(always)]
149#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
150pub(in super::super) unsafe fn write_mask_bit<const VLEN: Vlen>(
151 vregs: &mut VectorRegisterFile<VLEN>,
152 vd: VReg,
153 elem_i: u16,
154 result: bool,
155) {
156 let byte_idx = usize::from(elem_i / u8::BITS as u16);
157 let bit_idx = elem_i % u8::BITS as u16;
158 let byte = unsafe { vregs.get_mut(vd).get_unchecked_mut(byte_idx) };
160 if result {
161 *byte |= 1 << bit_idx;
162 } else {
163 *byte &= !(1 << bit_idx);
164 }
165}
166
167#[derive(Debug)]
169#[doc(hidden)]
170pub enum OpSrc {
171 Vreg(VReg),
173 Scalar(u64),
175}
176
177#[inline(always)]
189#[doc(hidden)]
190#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
191pub unsafe fn execute_arith_op<Reg, Env, F>(
192 env: &mut Env,
193 vd: VReg,
194 vs2: VReg,
195 src: OpSrc,
196 vm: bool,
197 sew: Vsew,
198 op: F,
199) where
200 Reg: Register,
201 Env: VectorRegistersExt<Reg>,
202 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
203 F: Fn(u64, u64, Vsew) -> u64,
204{
205 let vl = env.vl();
206 let vstart = env.vstart();
207 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
209
210 for i in vstart.range_to(vl) {
211 if !mask_bit(&mask_buf, i) {
212 continue;
213 }
214
215 let a = unsafe { read_element_u64(env.read_vregs(), vs2, i, sew) };
218
219 let b = match src {
220 OpSrc::Vreg(vs1_base) => {
221 unsafe { read_element_u64(env.read_vregs(), vs1_base, i, sew) }
223 }
224 OpSrc::Scalar(val) => val,
225 };
226
227 let result = op(a, b, sew);
228
229 unsafe {
232 write_element_u64(env.write_vregs(), vd, i, sew, result);
233 }
234 }
235
236 env.mark_vs_dirty();
237 env.reset_vstart();
238}
239
240#[inline(always)]
254#[doc(hidden)]
255#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
256pub unsafe fn execute_compare_op<Reg, Env, F>(
257 env: &mut Env,
258 vd: VReg,
259 vs2: VReg,
260 src: OpSrc,
261 vm: bool,
262 sew: Vsew,
263 op: F,
264) where
265 Reg: Register,
266 Env: VectorRegistersExt<Reg>,
267 [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
268 F: Fn(u64, u64, Vsew) -> bool,
269{
270 let vl = env.vl();
271 let vstart = env.vstart();
272 let mask_buf = unsafe { snapshot_mask(env.read_vregs(), vm, vl) };
274
275 for i in vstart.range_to(vl) {
276 if !mask_bit(&mask_buf, i) {
279 continue;
280 }
281
282 let a = unsafe { read_element_u64(env.read_vregs(), vs2, i, sew) };
284
285 let b = match src {
286 OpSrc::Vreg(vs1_base) => {
287 unsafe { read_element_u64(env.read_vregs(), vs1_base, i, sew) }
289 }
290 OpSrc::Scalar(val) => val,
291 };
292
293 let result = op(a, b, sew);
294
295 unsafe {
297 write_mask_bit(env.write_vregs(), vd, i, result);
298 }
299 }
300
301 env.mark_vs_dirty();
302 env.reset_vstart();
303}
304
305#[inline(always)]
307#[doc(hidden)]
308#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
309pub fn sign_extend(val: u64, sew: Vsew) -> i64 {
310 let shift = u64::BITS - u32::from(sew.bits_width());
311 (val.cast_signed() << shift) >> shift
312}
313
314#[inline(always)]
319#[doc(hidden)]
320#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
321pub fn sew_mask(sew: Vsew) -> u64 {
322 if u32::from(sew.bits_width()) == u64::BITS {
323 u64::MAX
324 } else {
325 (1u64 << sew.bits_width()) - 1
326 }
327}