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