Skip to main content

ab_riscv_interpreter/zvbb/
zvkb.rs

1//! Zvkb extension
2
3#[cfg(test)]
4mod tests;
5pub mod zvkb_helpers;
6
7use crate::v::vector_registers::VectorRegistersExt;
8use crate::v::zvexx::arith::zvexx_arith_helpers;
9use crate::v::zvexx::carry::zvexx_carry_helpers;
10use crate::v::zvexx::config::zvexx_config_helpers;
11use crate::v::zvexx::fixed_point::zvexx_fixed_point_helpers;
12use crate::v::zvexx::load::zvexx_load_helpers;
13use crate::v::zvexx::mask::zvexx_mask_helpers;
14use crate::v::zvexx::muldiv::zvexx_muldiv_helpers;
15use crate::v::zvexx::perm::zvexx_perm_helpers;
16use crate::v::zvexx::reduction::zvexx_reduction_helpers;
17use crate::v::zvexx::store::zvexx_store_helpers;
18use crate::v::zvexx::widen_narrow::zvexx_widen_narrow_helpers;
19use crate::v::zvexx::zvexx_helpers;
20use crate::zicsr::zicsr_helpers;
21use crate::{
22    CsrError, Csrs, ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands,
23    ExecutionError, ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands,
24    VirtualMemory,
25};
26use ab_riscv_macros::instruction_execution;
27use ab_riscv_primitives::prelude::*;
28use core::fmt;
29use core::ops::ControlFlow;
30
31#[instruction_execution]
32impl<Reg> ExecutableInstructionOperands for ZvkbInstruction<Reg> where Reg: Register {}
33
34#[instruction_execution]
35impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
36    for ZvkbInstruction<Reg>
37where
38    Reg: Register,
39{
40}
41
42#[instruction_execution]
43impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
44    ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
45    for ZvkbInstruction<Reg>
46where
47    Reg: Register,
48    Regs: RegisterFile<Reg>,
49    ExtState: VectorRegistersExt<Reg, CustomError>,
50    [(); SUPPORTED_ELEN_VLEN::<{ ExtState::ELEN }, { ExtState::VLEN }>]:,
51    Memory: VirtualMemory,
52    PC: ProgramCounter<Reg::Type, Memory, CustomError>,
53    CustomError: fmt::Debug,
54{
55    #[inline(always)]
56    fn execute(
57        self,
58        Rs1Rs2OperandValues {
59            rs1_value,
60            rs2_value,
61        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
62        _regs: &mut Regs,
63        ext_state: &mut ExtState,
64        memory: &mut Memory,
65        program_counter: &mut PC,
66        _system_instruction_handler: &mut InstructionHandler,
67    ) -> Result<
68        ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
69        ExecutionError<Reg::Type, CustomError>,
70    > {
71        match self {
72            // vandn: vd[i] = ~vs1[i] & vs2[i]  (or ~rs1 & vs2[i])
73            Self::VandnVv { vd, vs2, vs1, vm } => {
74                if !ext_state.vector_instructions_allowed() {
75                    ::core::hint::cold_path();
76                    return Err(ExecutionError::IllegalInstruction {
77                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
78                    });
79                }
80                if !vm && vd == VReg::V0 {
81                    ::core::hint::cold_path();
82                    return Err(ExecutionError::IllegalInstruction {
83                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
84                    });
85                }
86                let Some(vtype) = ext_state.vtype() else {
87                    ::core::hint::cold_path();
88                    return Err(ExecutionError::IllegalInstruction {
89                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
90                    });
91                };
92                let group_regs = vtype.vlmul().register_count();
93                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
94                    program_counter,
95                    vd,
96                    group_regs,
97                )?;
98                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
99                    program_counter,
100                    vs2,
101                    group_regs,
102                )?;
103                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
104                    program_counter,
105                    vs1,
106                    group_regs,
107                )?;
108                let sew = vtype.vsew();
109                // SAFETY: alignments checked above
110                unsafe {
111                    zvkb_helpers::execute_vandn::<Reg, _, _>(
112                        ext_state,
113                        vd,
114                        vs2,
115                        zvkb_helpers::OpSrc::Vreg(vs1),
116                        sew,
117                        vm,
118                    );
119                }
120            }
121            Self::VandnVx {
122                vm,
123                vd,
124                vs2,
125                rs1: _,
126            } => {
127                if !ext_state.vector_instructions_allowed() {
128                    ::core::hint::cold_path();
129                    return Err(ExecutionError::IllegalInstruction {
130                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
131                    });
132                }
133                if !vm && vd == VReg::V0 {
134                    ::core::hint::cold_path();
135                    return Err(ExecutionError::IllegalInstruction {
136                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
137                    });
138                }
139                let Some(vtype) = ext_state.vtype() else {
140                    ::core::hint::cold_path();
141                    return Err(ExecutionError::IllegalInstruction {
142                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
143                    });
144                };
145                let group_regs = vtype.vlmul().register_count();
146                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
147                    program_counter,
148                    vd,
149                    group_regs,
150                )?;
151                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
152                    program_counter,
153                    vs2,
154                    group_regs,
155                )?;
156                let sew = vtype.vsew();
157                let scalar = rs1_value.as_i64().cast_unsigned();
158                // SAFETY: alignments checked above
159                unsafe {
160                    zvkb_helpers::execute_vandn::<Reg, _, _>(
161                        ext_state,
162                        vd,
163                        vs2,
164                        zvkb_helpers::OpSrc::Scalar(scalar),
165                        sew,
166                        vm,
167                    );
168                }
169            }
170            // vbrev8: reverse bits within each byte of each element
171            Self::Vbrev8V { vd, vs2, vm } => {
172                if !ext_state.vector_instructions_allowed() {
173                    ::core::hint::cold_path();
174                    return Err(ExecutionError::IllegalInstruction {
175                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
176                    });
177                }
178                if !vm && vd == VReg::V0 {
179                    ::core::hint::cold_path();
180                    return Err(ExecutionError::IllegalInstruction {
181                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
182                    });
183                }
184                let Some(vtype) = ext_state.vtype() else {
185                    ::core::hint::cold_path();
186                    return Err(ExecutionError::IllegalInstruction {
187                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
188                    });
189                };
190                let group_regs = vtype.vlmul().register_count();
191                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
192                    program_counter,
193                    vd,
194                    group_regs,
195                )?;
196                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
197                    program_counter,
198                    vs2,
199                    group_regs,
200                )?;
201                let sew = vtype.vsew();
202                // SAFETY: alignments checked above
203                unsafe {
204                    zvkb_helpers::execute_vbrev8::<Reg, _, _>(ext_state, vd, vs2, sew, vm);
205                }
206            }
207            // vrev8: reverse bytes within each element
208            Self::Vrev8V { vd, vs2, vm } => {
209                if !ext_state.vector_instructions_allowed() {
210                    ::core::hint::cold_path();
211                    return Err(ExecutionError::IllegalInstruction {
212                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
213                    });
214                }
215                if !vm && vd == VReg::V0 {
216                    ::core::hint::cold_path();
217                    return Err(ExecutionError::IllegalInstruction {
218                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
219                    });
220                }
221                let Some(vtype) = ext_state.vtype() else {
222                    ::core::hint::cold_path();
223                    return Err(ExecutionError::IllegalInstruction {
224                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
225                    });
226                };
227                let group_regs = vtype.vlmul().register_count();
228                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
229                    program_counter,
230                    vd,
231                    group_regs,
232                )?;
233                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
234                    program_counter,
235                    vs2,
236                    group_regs,
237                )?;
238                let sew = vtype.vsew();
239                // SAFETY: alignments checked above
240                unsafe {
241                    zvkb_helpers::execute_vrev8::<Reg, _, _>(ext_state, vd, vs2, sew, vm);
242                }
243            }
244            // vrol: vd[i] = rotate_left(vs2[i], src[i] % SEW)
245            Self::VrolVv { vd, vs2, vs1, vm } => {
246                if !ext_state.vector_instructions_allowed() {
247                    ::core::hint::cold_path();
248                    return Err(ExecutionError::IllegalInstruction {
249                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
250                    });
251                }
252                if !vm && vd == VReg::V0 {
253                    ::core::hint::cold_path();
254                    return Err(ExecutionError::IllegalInstruction {
255                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
256                    });
257                }
258                let Some(vtype) = ext_state.vtype() else {
259                    ::core::hint::cold_path();
260                    return Err(ExecutionError::IllegalInstruction {
261                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
262                    });
263                };
264                let group_regs = vtype.vlmul().register_count();
265                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
266                    program_counter,
267                    vd,
268                    group_regs,
269                )?;
270                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
271                    program_counter,
272                    vs2,
273                    group_regs,
274                )?;
275                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
276                    program_counter,
277                    vs1,
278                    group_regs,
279                )?;
280                let sew = vtype.vsew();
281                // SAFETY: alignments checked above
282                unsafe {
283                    zvkb_helpers::execute_vrol::<Reg, _, _>(
284                        ext_state,
285                        vd,
286                        vs2,
287                        zvkb_helpers::OpSrc::Vreg(vs1),
288                        sew,
289                        vm,
290                    );
291                }
292            }
293            Self::VrolVx {
294                vm,
295                vd,
296                vs2,
297                rs1: _,
298            } => {
299                if !ext_state.vector_instructions_allowed() {
300                    ::core::hint::cold_path();
301                    return Err(ExecutionError::IllegalInstruction {
302                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
303                    });
304                }
305                if !vm && vd == VReg::V0 {
306                    ::core::hint::cold_path();
307                    return Err(ExecutionError::IllegalInstruction {
308                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
309                    });
310                }
311                let Some(vtype) = ext_state.vtype() else {
312                    ::core::hint::cold_path();
313                    return Err(ExecutionError::IllegalInstruction {
314                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
315                    });
316                };
317                let group_regs = vtype.vlmul().register_count();
318                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
319                    program_counter,
320                    vd,
321                    group_regs,
322                )?;
323                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
324                    program_counter,
325                    vs2,
326                    group_regs,
327                )?;
328                let sew = vtype.vsew();
329                let scalar = rs1_value.as_i64().cast_unsigned();
330                // SAFETY: alignments checked above
331                unsafe {
332                    zvkb_helpers::execute_vrol::<Reg, _, _>(
333                        ext_state,
334                        vd,
335                        vs2,
336                        zvkb_helpers::OpSrc::Scalar(scalar),
337                        sew,
338                        vm,
339                    );
340                }
341            }
342            // vror: vd[i] = rotate_right(vs2[i], src[i] % SEW)
343            Self::VrorVv { vd, vs2, vs1, vm } => {
344                if !ext_state.vector_instructions_allowed() {
345                    ::core::hint::cold_path();
346                    return Err(ExecutionError::IllegalInstruction {
347                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
348                    });
349                }
350                if !vm && vd == VReg::V0 {
351                    ::core::hint::cold_path();
352                    return Err(ExecutionError::IllegalInstruction {
353                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
354                    });
355                }
356                let Some(vtype) = ext_state.vtype() else {
357                    ::core::hint::cold_path();
358                    return Err(ExecutionError::IllegalInstruction {
359                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
360                    });
361                };
362                let group_regs = vtype.vlmul().register_count();
363                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
364                    program_counter,
365                    vd,
366                    group_regs,
367                )?;
368                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
369                    program_counter,
370                    vs2,
371                    group_regs,
372                )?;
373                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
374                    program_counter,
375                    vs1,
376                    group_regs,
377                )?;
378                let sew = vtype.vsew();
379                // SAFETY: alignments checked above
380                unsafe {
381                    zvkb_helpers::execute_vror::<Reg, _, _>(
382                        ext_state,
383                        vd,
384                        vs2,
385                        zvkb_helpers::OpSrc::Vreg(vs1),
386                        sew,
387                        vm,
388                    );
389                }
390            }
391            Self::VrorVx {
392                vm,
393                vd,
394                vs2,
395                rs1: _,
396            } => {
397                if !ext_state.vector_instructions_allowed() {
398                    ::core::hint::cold_path();
399                    return Err(ExecutionError::IllegalInstruction {
400                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
401                    });
402                }
403                if !vm && vd == VReg::V0 {
404                    ::core::hint::cold_path();
405                    return Err(ExecutionError::IllegalInstruction {
406                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
407                    });
408                }
409                let Some(vtype) = ext_state.vtype() else {
410                    ::core::hint::cold_path();
411                    return Err(ExecutionError::IllegalInstruction {
412                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
413                    });
414                };
415                let group_regs = vtype.vlmul().register_count();
416                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
417                    program_counter,
418                    vd,
419                    group_regs,
420                )?;
421                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
422                    program_counter,
423                    vs2,
424                    group_regs,
425                )?;
426                let sew = vtype.vsew();
427                let scalar = rs1_value.as_i64().cast_unsigned();
428                // SAFETY: alignments checked above
429                unsafe {
430                    zvkb_helpers::execute_vror::<Reg, _, _>(
431                        ext_state,
432                        vd,
433                        vs2,
434                        zvkb_helpers::OpSrc::Scalar(scalar),
435                        sew,
436                        vm,
437                    );
438                }
439            }
440            // vror.vi: 5-bit immediate in vs1[19:15]; bit[25] is the standard vm mask-control bit
441            Self::VrorVi { vd, vs2, uimm, vm } => {
442                if !ext_state.vector_instructions_allowed() {
443                    ::core::hint::cold_path();
444                    return Err(ExecutionError::IllegalInstruction {
445                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
446                    });
447                }
448                if !vm && vd == VReg::V0 {
449                    ::core::hint::cold_path();
450                    return Err(ExecutionError::IllegalInstruction {
451                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
452                    });
453                }
454                let Some(vtype) = ext_state.vtype() else {
455                    ::core::hint::cold_path();
456                    return Err(ExecutionError::IllegalInstruction {
457                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
458                    });
459                };
460                let group_regs = vtype.vlmul().register_count();
461                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
462                    program_counter,
463                    vd,
464                    group_regs,
465                )?;
466                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
467                    program_counter,
468                    vs2,
469                    group_regs,
470                )?;
471                let sew = vtype.vsew();
472                // SAFETY: alignments checked above
473                unsafe {
474                    zvkb_helpers::execute_vror::<Reg, _, _>(
475                        ext_state,
476                        vd,
477                        vs2,
478                        zvkb_helpers::OpSrc::Scalar(u64::from(uimm)),
479                        sew,
480                        vm,
481                    );
482                }
483            }
484        }
485        Ok(ControlFlow::Continue(Default::default()))
486    }
487}