Skip to main content

ab_riscv_interpreter/
zvbb.rs

1//! Zvbb extension
2
3#[cfg(test)]
4mod tests;
5pub mod zvbb_helpers;
6pub mod zvkb;
7
8use crate::v::vector_registers::VectorRegistersExt;
9use crate::v::zvexx::arith::zvexx_arith_helpers;
10use crate::v::zvexx::carry::zvexx_carry_helpers;
11use crate::v::zvexx::config::zvexx_config_helpers;
12use crate::v::zvexx::fixed_point::zvexx_fixed_point_helpers;
13use crate::v::zvexx::load::zvexx_load_helpers;
14use crate::v::zvexx::mask::zvexx_mask_helpers;
15use crate::v::zvexx::muldiv::zvexx_muldiv_helpers;
16use crate::v::zvexx::perm::zvexx_perm_helpers;
17use crate::v::zvexx::reduction::zvexx_reduction_helpers;
18use crate::v::zvexx::store::zvexx_store_helpers;
19use crate::v::zvexx::widen_narrow::zvexx_widen_narrow_helpers;
20use crate::v::zvexx::zvexx_helpers;
21use crate::zicsr::zicsr_helpers;
22use crate::zvbb::zvkb::zvkb_helpers;
23use crate::{
24    CsrError, Csrs, ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands,
25    ExecutionError, ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands,
26    VirtualMemory,
27};
28use ab_riscv_macros::instruction_execution;
29use ab_riscv_primitives::prelude::*;
30use core::fmt;
31use core::ops::ControlFlow;
32
33#[instruction_execution]
34impl<Reg> ExecutableInstructionOperands for ZvbbInstruction<Reg> where Reg: Register {}
35
36#[instruction_execution]
37impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
38    for ZvbbInstruction<Reg>
39where
40    Reg: Register,
41{
42}
43
44#[instruction_execution]
45impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
46    ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
47    for ZvbbInstruction<Reg>
48where
49    Reg: Register,
50    Regs: RegisterFile<Reg>,
51    ExtState: VectorRegistersExt<Reg, CustomError>,
52    [(); ExtState::ELEN as usize]:,
53    [(); ExtState::VLEN as usize]:,
54    [(); ExtState::VLENB as usize]:,
55    Memory: VirtualMemory,
56    PC: ProgramCounter<Reg::Type, Memory, CustomError>,
57    CustomError: fmt::Debug,
58{
59    #[inline(always)]
60    fn execute(
61        self,
62        Rs1Rs2OperandValues {
63            rs1_value,
64            rs2_value,
65        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
66        _regs: &mut Regs,
67        ext_state: &mut ExtState,
68        memory: &mut Memory,
69        program_counter: &mut PC,
70        _system_instruction_handler: &mut InstructionHandler,
71    ) -> Result<
72        ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
73        ExecutionError<Reg::Type, CustomError>,
74    > {
75        match self {
76            // vbrev: reverse all bits within each SEW-wide element
77            Self::VbrevV { vd, vs2, vm } => {
78                if !ext_state.vector_instructions_allowed() {
79                    ::core::hint::cold_path();
80                    return Err(ExecutionError::IllegalInstruction {
81                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
82                    });
83                }
84                if !vm && vd == VReg::V0 {
85                    ::core::hint::cold_path();
86                    return Err(ExecutionError::IllegalInstruction {
87                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
88                    });
89                }
90                let Some(vtype) = ext_state.vtype() else {
91                    ::core::hint::cold_path();
92                    return Err(ExecutionError::IllegalInstruction {
93                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
94                    });
95                };
96                let group_regs = vtype.vlmul().register_count();
97                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
98                    program_counter,
99                    vd,
100                    group_regs,
101                )?;
102                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
103                    program_counter,
104                    vs2,
105                    group_regs,
106                )?;
107                let sew = vtype.vsew();
108                // SAFETY: alignments checked above
109                unsafe {
110                    zvbb_helpers::execute_vbrev::<Reg, _, _>(ext_state, vd, vs2, sew, vm);
111                }
112            }
113            // vclz: count leading zeros within each SEW-wide element; result in [0, SEW]
114            Self::VclzV { vd, vs2, vm } => {
115                if !ext_state.vector_instructions_allowed() {
116                    ::core::hint::cold_path();
117                    return Err(ExecutionError::IllegalInstruction {
118                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
119                    });
120                }
121                if !vm && vd == VReg::V0 {
122                    ::core::hint::cold_path();
123                    return Err(ExecutionError::IllegalInstruction {
124                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
125                    });
126                }
127                let Some(vtype) = ext_state.vtype() else {
128                    ::core::hint::cold_path();
129                    return Err(ExecutionError::IllegalInstruction {
130                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
131                    });
132                };
133                let group_regs = vtype.vlmul().register_count();
134                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
135                    program_counter,
136                    vd,
137                    group_regs,
138                )?;
139                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
140                    program_counter,
141                    vs2,
142                    group_regs,
143                )?;
144                let sew = vtype.vsew();
145                // SAFETY: alignments checked above
146                unsafe {
147                    zvbb_helpers::execute_vclz::<Reg, _, _>(ext_state, vd, vs2, sew, vm);
148                }
149            }
150            // vctz: count trailing zeros within each SEW-wide element; result in [0, SEW]
151            Self::VctzV { vd, vs2, vm } => {
152                if !ext_state.vector_instructions_allowed() {
153                    ::core::hint::cold_path();
154                    return Err(ExecutionError::IllegalInstruction {
155                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
156                    });
157                }
158                if !vm && vd == VReg::V0 {
159                    ::core::hint::cold_path();
160                    return Err(ExecutionError::IllegalInstruction {
161                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
162                    });
163                }
164                let Some(vtype) = ext_state.vtype() else {
165                    ::core::hint::cold_path();
166                    return Err(ExecutionError::IllegalInstruction {
167                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
168                    });
169                };
170                let group_regs = vtype.vlmul().register_count();
171                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
172                    program_counter,
173                    vd,
174                    group_regs,
175                )?;
176                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
177                    program_counter,
178                    vs2,
179                    group_regs,
180                )?;
181                let sew = vtype.vsew();
182                // SAFETY: alignments checked above
183                unsafe {
184                    zvbb_helpers::execute_vctz::<Reg, _, _>(ext_state, vd, vs2, sew, vm);
185                }
186            }
187            // vcpop: population count (number of set bits) within each SEW-wide element
188            Self::VcpopV { vd, vs2, vm } => {
189                if !ext_state.vector_instructions_allowed() {
190                    ::core::hint::cold_path();
191                    return Err(ExecutionError::IllegalInstruction {
192                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
193                    });
194                }
195                if !vm && vd == VReg::V0 {
196                    ::core::hint::cold_path();
197                    return Err(ExecutionError::IllegalInstruction {
198                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
199                    });
200                }
201                let Some(vtype) = ext_state.vtype() else {
202                    ::core::hint::cold_path();
203                    return Err(ExecutionError::IllegalInstruction {
204                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
205                    });
206                };
207                let group_regs = vtype.vlmul().register_count();
208                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
209                    program_counter,
210                    vd,
211                    group_regs,
212                )?;
213                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
214                    program_counter,
215                    vs2,
216                    group_regs,
217                )?;
218                let sew = vtype.vsew();
219                // SAFETY: alignments checked above
220                unsafe {
221                    zvbb_helpers::execute_vcpop::<Reg, _, _>(ext_state, vd, vs2, sew, vm);
222                }
223            }
224            // vwsll: widening shift-left-logical; vd is 2*SEW wide, vs2/src are SEW wide.
225            // SEW=E64 is illegal (cannot double); LMUL=M8 is illegal (EMUL(vd)=16 out of range).
226            Self::VwsllVv { vd, vs2, vs1, vm } => {
227                if !ext_state.vector_instructions_allowed() {
228                    ::core::hint::cold_path();
229                    return Err(ExecutionError::IllegalInstruction {
230                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
231                    });
232                }
233                if !vm && vd == VReg::V0 {
234                    ::core::hint::cold_path();
235                    return Err(ExecutionError::IllegalInstruction {
236                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
237                    });
238                }
239                let Some(vtype) = ext_state.vtype() else {
240                    ::core::hint::cold_path();
241                    return Err(ExecutionError::IllegalInstruction {
242                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
243                    });
244                };
245                let sew = vtype.vsew();
246                let Some(double_sew) = sew.double_width() else {
247                    ::core::hint::cold_path();
248                    return Err(ExecutionError::IllegalInstruction {
249                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
250                    });
251                };
252                let group_regs = vtype.vlmul().register_count();
253                let Some(dest_group_regs) =
254                    vtype.vlmul().data_register_count(double_sew.as_eew(), sew)
255                else {
256                    ::core::hint::cold_path();
257                    return Err(ExecutionError::IllegalInstruction {
258                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
259                    });
260                };
261                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
262                    program_counter,
263                    vd,
264                    dest_group_regs,
265                )?;
266                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
267                    program_counter,
268                    vs2,
269                    group_regs,
270                )?;
271                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
272                    program_counter,
273                    vs1,
274                    group_regs,
275                )?;
276                // SAFETY: alignments checked above
277                unsafe {
278                    zvbb_helpers::execute_vwsll::<Reg, _, _>(
279                        ext_state,
280                        vd,
281                        vs2,
282                        zvbb_helpers::OpSrc::Vreg(vs1),
283                        sew,
284                        double_sew,
285                        vm,
286                    );
287                }
288            }
289            Self::VwsllVx {
290                vm,
291                vd,
292                vs2,
293                rs1: _,
294            } => {
295                if !ext_state.vector_instructions_allowed() {
296                    ::core::hint::cold_path();
297                    return Err(ExecutionError::IllegalInstruction {
298                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
299                    });
300                }
301                if !vm && vd == VReg::V0 {
302                    ::core::hint::cold_path();
303                    return Err(ExecutionError::IllegalInstruction {
304                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
305                    });
306                }
307                let Some(vtype) = ext_state.vtype() else {
308                    ::core::hint::cold_path();
309                    return Err(ExecutionError::IllegalInstruction {
310                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
311                    });
312                };
313                let sew = vtype.vsew();
314                let Some(double_sew) = sew.double_width() else {
315                    ::core::hint::cold_path();
316                    return Err(ExecutionError::IllegalInstruction {
317                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
318                    });
319                };
320                let group_regs = vtype.vlmul().register_count();
321                let Some(dest_group_regs) =
322                    vtype.vlmul().data_register_count(double_sew.as_eew(), sew)
323                else {
324                    ::core::hint::cold_path();
325                    return Err(ExecutionError::IllegalInstruction {
326                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
327                    });
328                };
329                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
330                    program_counter,
331                    vd,
332                    dest_group_regs,
333                )?;
334                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
335                    program_counter,
336                    vs2,
337                    group_regs,
338                )?;
339                let scalar = rs1_value.as_i64().cast_unsigned();
340                // SAFETY: alignments checked above
341                unsafe {
342                    zvbb_helpers::execute_vwsll::<Reg, _, _>(
343                        ext_state,
344                        vd,
345                        vs2,
346                        zvbb_helpers::OpSrc::Scalar(scalar),
347                        sew,
348                        double_sew,
349                        vm,
350                    );
351                }
352            }
353            // vwsll.vi: standard 5-bit immediate; vm is the normal mask-control bit
354            Self::VwsllVi { vd, vs2, uimm, vm } => {
355                if !ext_state.vector_instructions_allowed() {
356                    ::core::hint::cold_path();
357                    return Err(ExecutionError::IllegalInstruction {
358                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
359                    });
360                }
361                if !vm && vd == VReg::V0 {
362                    ::core::hint::cold_path();
363                    return Err(ExecutionError::IllegalInstruction {
364                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
365                    });
366                }
367                let Some(vtype) = ext_state.vtype() else {
368                    ::core::hint::cold_path();
369                    return Err(ExecutionError::IllegalInstruction {
370                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
371                    });
372                };
373                let sew = vtype.vsew();
374                let Some(double_sew) = sew.double_width() else {
375                    ::core::hint::cold_path();
376                    return Err(ExecutionError::IllegalInstruction {
377                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
378                    });
379                };
380                let group_regs = vtype.vlmul().register_count();
381                let Some(dest_group_regs) =
382                    vtype.vlmul().data_register_count(double_sew.as_eew(), sew)
383                else {
384                    ::core::hint::cold_path();
385                    return Err(ExecutionError::IllegalInstruction {
386                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
387                    });
388                };
389                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
390                    program_counter,
391                    vd,
392                    dest_group_regs,
393                )?;
394                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
395                    program_counter,
396                    vs2,
397                    group_regs,
398                )?;
399                // SAFETY: alignments checked above
400                unsafe {
401                    zvbb_helpers::execute_vwsll::<Reg, _, _>(
402                        ext_state,
403                        vd,
404                        vs2,
405                        zvbb_helpers::OpSrc::Scalar(u64::from(uimm)),
406                        sew,
407                        double_sew,
408                        vm,
409                    );
410                }
411            }
412        }
413        Ok(ControlFlow::Continue(Default::default()))
414    }
415}