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, ExecutionResult, FetchInstructionResult, InstructionFetcher,
26    OpaqueThreadedExecutionResult, PackedAddress, ProgramCounter, RegisterFile,
27    Rs1Rs2OperandValues, Rs1Rs2Operands, ThreadedExecutableInstruction, ThreadedExecutionResult,
28    VirtualMemory,
29};
30use ab_riscv_macros::instruction_execution;
31use ab_riscv_primitives::prelude::*;
32
33#[instruction_execution]
34const impl<Reg> ExecutableInstructionOperands for ZvbbInstruction<Reg> where Reg: Register {}
35
36#[instruction_execution]
37const impl<Reg, Env> ExecutableInstructionCsr<Env> for ZvbbInstruction<Reg> where Reg: Register {}
38
39#[instruction_execution]
40impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
41    for ZvbbInstruction<Reg>
42where
43    Reg: Register,
44    Regs: RegisterFile<Reg>,
45    Env: VectorRegistersExt<Reg>,
46    [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
47    Memory: VirtualMemory,
48    PC: ProgramCounter<Reg::Type, Memory>,
49{
50    #[inline(always)]
51    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
52    fn execute(
53        self,
54        Rs1Rs2OperandValues {
55            rs1_value,
56            rs2_value,
57        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
58        _regs: &mut Regs,
59        env: &mut Env,
60        memory: &mut Memory,
61        program_counter: &mut PC,
62    ) -> ExecutionResult<Self::Reg> {
63        match self {
64            // vbrev: reverse all bits within each SEW-wide element
65            Self::VbrevV { vd, vs2, vm } => {
66                if !env.vector_instructions_allowed() {
67                    ::core::hint::cold_path();
68                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
69                        address: PackedAddress::new(
70                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
71                        ),
72                    });
73                }
74                if !vm && vd == VReg::V0 {
75                    ::core::hint::cold_path();
76                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
77                        address: PackedAddress::new(
78                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
79                        ),
80                    });
81                }
82                let Some(vtype) = env.vtype() else {
83                    ::core::hint::cold_path();
84                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
85                        address: PackedAddress::new(
86                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
87                        ),
88                    });
89                };
90                let group_regs = vtype.vlmul().register_count();
91                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _>(
92                    program_counter,
93                    vd,
94                    group_regs,
95                )?;
96                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _>(
97                    program_counter,
98                    vs2,
99                    group_regs,
100                )?;
101                let sew = vtype.vsew();
102                // SAFETY: alignments checked above
103                unsafe {
104                    zvbb_helpers::execute_vbrev::<Reg, _>(env, vd, vs2, sew, vm);
105                }
106            }
107            // vclz: count leading zeros within each SEW-wide element; result in [0, SEW]
108            Self::VclzV { vd, vs2, vm } => {
109                if !env.vector_instructions_allowed() {
110                    ::core::hint::cold_path();
111                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
112                        address: PackedAddress::new(
113                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
114                        ),
115                    });
116                }
117                if !vm && vd == VReg::V0 {
118                    ::core::hint::cold_path();
119                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
120                        address: PackedAddress::new(
121                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
122                        ),
123                    });
124                }
125                let Some(vtype) = env.vtype() else {
126                    ::core::hint::cold_path();
127                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
128                        address: PackedAddress::new(
129                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
130                        ),
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, _>(env, 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 !env.vector_instructions_allowed() {
153                    ::core::hint::cold_path();
154                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
155                        address: PackedAddress::new(
156                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
157                        ),
158                    });
159                }
160                if !vm && vd == VReg::V0 {
161                    ::core::hint::cold_path();
162                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
163                        address: PackedAddress::new(
164                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
165                        ),
166                    });
167                }
168                let Some(vtype) = env.vtype() else {
169                    ::core::hint::cold_path();
170                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
171                        address: PackedAddress::new(
172                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
173                        ),
174                    });
175                };
176                let group_regs = vtype.vlmul().register_count();
177                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _>(
178                    program_counter,
179                    vd,
180                    group_regs,
181                )?;
182                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _>(
183                    program_counter,
184                    vs2,
185                    group_regs,
186                )?;
187                let sew = vtype.vsew();
188                // SAFETY: alignments checked above
189                unsafe {
190                    zvbb_helpers::execute_vctz::<Reg, _>(env, vd, vs2, sew, vm);
191                }
192            }
193            // vcpop: population count (number of set bits) within each SEW-wide element
194            Self::VcpopV { vd, vs2, vm } => {
195                if !env.vector_instructions_allowed() {
196                    ::core::hint::cold_path();
197                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
198                        address: PackedAddress::new(
199                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
200                        ),
201                    });
202                }
203                if !vm && vd == VReg::V0 {
204                    ::core::hint::cold_path();
205                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
206                        address: PackedAddress::new(
207                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
208                        ),
209                    });
210                }
211                let Some(vtype) = env.vtype() else {
212                    ::core::hint::cold_path();
213                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
214                        address: PackedAddress::new(
215                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
216                        ),
217                    });
218                };
219                let group_regs = vtype.vlmul().register_count();
220                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _>(
221                    program_counter,
222                    vd,
223                    group_regs,
224                )?;
225                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _>(
226                    program_counter,
227                    vs2,
228                    group_regs,
229                )?;
230                let sew = vtype.vsew();
231                // SAFETY: alignments checked above
232                unsafe {
233                    zvbb_helpers::execute_vcpop::<Reg, _>(env, vd, vs2, sew, vm);
234                }
235            }
236            // vwsll: widening shift-left-logical; vd is 2*SEW wide, vs2/src are SEW wide.
237            // SEW=E64 is illegal (cannot double); LMUL=M8 is illegal (EMUL(vd)=16 out of range).
238            Self::VwsllVv { vd, vs2, vs1, vm } => {
239                if !env.vector_instructions_allowed() {
240                    ::core::hint::cold_path();
241                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
242                        address: PackedAddress::new(
243                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
244                        ),
245                    });
246                }
247                if !vm && vd == VReg::V0 {
248                    ::core::hint::cold_path();
249                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
250                        address: PackedAddress::new(
251                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
252                        ),
253                    });
254                }
255                let Some(vtype) = env.vtype() else {
256                    ::core::hint::cold_path();
257                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
258                        address: PackedAddress::new(
259                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
260                        ),
261                    });
262                };
263                let sew = vtype.vsew();
264                let Some(double_sew) = sew.double_width() else {
265                    ::core::hint::cold_path();
266                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
267                        address: PackedAddress::new(
268                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
269                        ),
270                    });
271                };
272                let group_regs = vtype.vlmul().register_count();
273                let Some(dest_group_regs) =
274                    vtype.vlmul().data_register_count(double_sew.as_eew(), sew)
275                else {
276                    ::core::hint::cold_path();
277                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
278                        address: PackedAddress::new(
279                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
280                        ),
281                    });
282                };
283                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _>(
284                    program_counter,
285                    vd,
286                    dest_group_regs,
287                )?;
288                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _>(
289                    program_counter,
290                    vs2,
291                    group_regs,
292                )?;
293                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _>(
294                    program_counter,
295                    vs1,
296                    group_regs,
297                )?;
298                // SAFETY: alignments checked above
299                unsafe {
300                    zvbb_helpers::execute_vwsll::<Reg, _>(
301                        env,
302                        vd,
303                        vs2,
304                        zvbb_helpers::OpSrc::Vreg(vs1),
305                        sew,
306                        double_sew,
307                        vm,
308                    );
309                }
310            }
311            Self::VwsllVx {
312                vm,
313                vd,
314                vs2,
315                rs1: _,
316            } => {
317                if !env.vector_instructions_allowed() {
318                    ::core::hint::cold_path();
319                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
320                        address: PackedAddress::new(
321                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
322                        ),
323                    });
324                }
325                if !vm && vd == VReg::V0 {
326                    ::core::hint::cold_path();
327                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
328                        address: PackedAddress::new(
329                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
330                        ),
331                    });
332                }
333                let Some(vtype) = env.vtype() else {
334                    ::core::hint::cold_path();
335                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
336                        address: PackedAddress::new(
337                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
338                        ),
339                    });
340                };
341                let sew = vtype.vsew();
342                let Some(double_sew) = sew.double_width() else {
343                    ::core::hint::cold_path();
344                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
345                        address: PackedAddress::new(
346                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
347                        ),
348                    });
349                };
350                let group_regs = vtype.vlmul().register_count();
351                let Some(dest_group_regs) =
352                    vtype.vlmul().data_register_count(double_sew.as_eew(), sew)
353                else {
354                    ::core::hint::cold_path();
355                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
356                        address: PackedAddress::new(
357                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
358                        ),
359                    });
360                };
361                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _>(
362                    program_counter,
363                    vd,
364                    dest_group_regs,
365                )?;
366                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _>(
367                    program_counter,
368                    vs2,
369                    group_regs,
370                )?;
371                let scalar = rs1_value.as_i64().cast_unsigned();
372                // SAFETY: alignments checked above
373                unsafe {
374                    zvbb_helpers::execute_vwsll::<Reg, _>(
375                        env,
376                        vd,
377                        vs2,
378                        zvbb_helpers::OpSrc::Scalar(scalar),
379                        sew,
380                        double_sew,
381                        vm,
382                    );
383                }
384            }
385            // vwsll.vi: standard 5-bit immediate; vm is the normal mask-control bit
386            Self::VwsllVi { vd, vs2, uimm, vm } => {
387                if !env.vector_instructions_allowed() {
388                    ::core::hint::cold_path();
389                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
390                        address: PackedAddress::new(
391                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
392                        ),
393                    });
394                }
395                if !vm && vd == VReg::V0 {
396                    ::core::hint::cold_path();
397                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
398                        address: PackedAddress::new(
399                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
400                        ),
401                    });
402                }
403                let Some(vtype) = env.vtype() else {
404                    ::core::hint::cold_path();
405                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
406                        address: PackedAddress::new(
407                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
408                        ),
409                    });
410                };
411                let sew = vtype.vsew();
412                let Some(double_sew) = sew.double_width() else {
413                    ::core::hint::cold_path();
414                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
415                        address: PackedAddress::new(
416                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
417                        ),
418                    });
419                };
420                let group_regs = vtype.vlmul().register_count();
421                let Some(dest_group_regs) =
422                    vtype.vlmul().data_register_count(double_sew.as_eew(), sew)
423                else {
424                    ::core::hint::cold_path();
425                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
426                        address: PackedAddress::new(
427                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
428                        ),
429                    });
430                };
431                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _>(
432                    program_counter,
433                    vd,
434                    dest_group_regs,
435                )?;
436                zvbb_helpers::check_vreg_group_alignment::<Reg, _, _>(
437                    program_counter,
438                    vs2,
439                    group_regs,
440                )?;
441                // SAFETY: alignments checked above
442                unsafe {
443                    zvbb_helpers::execute_vwsll::<Reg, _>(
444                        env,
445                        vd,
446                        vs2,
447                        zvbb_helpers::OpSrc::Scalar(u64::from(uimm)),
448                        sew,
449                        double_sew,
450                        vm,
451                    );
452                }
453            }
454        }
455        ExecutionResult::ContinueNoWrite
456    }
457}