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, ExecutionResult, FetchInstructionResult, InstructionFetcher,
24    OpaqueThreadedExecutionResult, PackedAddress, ProgramCounter, RegisterFile,
25    Rs1Rs2OperandValues, Rs1Rs2Operands, ThreadedExecutableInstruction, ThreadedExecutionResult,
26    VirtualMemory,
27};
28use ab_riscv_macros::instruction_execution;
29use ab_riscv_primitives::prelude::*;
30
31#[instruction_execution]
32const impl<Reg> ExecutableInstructionOperands for ZvkbInstruction<Reg> where Reg: Register {}
33
34#[instruction_execution]
35const impl<Reg, Env> ExecutableInstructionCsr<Env> for ZvkbInstruction<Reg> where Reg: Register {}
36
37#[instruction_execution]
38impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
39    for ZvkbInstruction<Reg>
40where
41    Reg: Register,
42    Regs: RegisterFile<Reg>,
43    Env: VectorRegistersExt<Reg>,
44    [(); SUPPORTED_ELEN_VLEN::<{ Env::ELEN }, { Env::VLEN }>]:,
45    Memory: VirtualMemory,
46    PC: ProgramCounter<Reg::Type, Memory>,
47{
48    #[inline(always)]
49    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
50    fn execute(
51        self,
52        Rs1Rs2OperandValues {
53            rs1_value,
54            rs2_value,
55        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
56        _regs: &mut Regs,
57        env: &mut Env,
58        memory: &mut Memory,
59        program_counter: &mut PC,
60    ) -> ExecutionResult<Self::Reg> {
61        match self {
62            // vandn: vd[i] = ~vs1[i] & vs2[i]  (or ~rs1 & vs2[i])
63            Self::VandnVv { vd, vs2, vs1, vm } => {
64                if !env.vector_instructions_allowed() {
65                    ::core::hint::cold_path();
66                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
67                        address: PackedAddress::new(
68                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
69                        ),
70                    });
71                }
72                if !vm && vd == VReg::V0 {
73                    ::core::hint::cold_path();
74                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
75                        address: PackedAddress::new(
76                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
77                        ),
78                    });
79                }
80                let Some(vtype) = env.vtype() else {
81                    ::core::hint::cold_path();
82                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
83                        address: PackedAddress::new(
84                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
85                        ),
86                    });
87                };
88                let group_regs = vtype.vlmul().register_count();
89                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
90                    program_counter,
91                    vd,
92                    group_regs,
93                )?;
94                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
95                    program_counter,
96                    vs2,
97                    group_regs,
98                )?;
99                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
100                    program_counter,
101                    vs1,
102                    group_regs,
103                )?;
104                let sew = vtype.vsew();
105                // SAFETY: alignments checked above
106                unsafe {
107                    zvkb_helpers::execute_vandn::<Reg, _>(
108                        env,
109                        vd,
110                        vs2,
111                        zvkb_helpers::OpSrc::Vreg(vs1),
112                        sew,
113                        vm,
114                    );
115                }
116            }
117            Self::VandnVx {
118                vm,
119                vd,
120                vs2,
121                rs1: _,
122            } => {
123                if !env.vector_instructions_allowed() {
124                    ::core::hint::cold_path();
125                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
126                        address: PackedAddress::new(
127                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
128                        ),
129                    });
130                }
131                if !vm && vd == VReg::V0 {
132                    ::core::hint::cold_path();
133                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
134                        address: PackedAddress::new(
135                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
136                        ),
137                    });
138                }
139                let Some(vtype) = env.vtype() else {
140                    ::core::hint::cold_path();
141                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
142                        address: PackedAddress::new(
143                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
144                        ),
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                        env,
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 !env.vector_instructions_allowed() {
175                    ::core::hint::cold_path();
176                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
177                        address: PackedAddress::new(
178                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
179                        ),
180                    });
181                }
182                if !vm && vd == VReg::V0 {
183                    ::core::hint::cold_path();
184                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
185                        address: PackedAddress::new(
186                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
187                        ),
188                    });
189                }
190                let Some(vtype) = env.vtype() else {
191                    ::core::hint::cold_path();
192                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
193                        address: PackedAddress::new(
194                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
195                        ),
196                    });
197                };
198                let group_regs = vtype.vlmul().register_count();
199                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
200                    program_counter,
201                    vd,
202                    group_regs,
203                )?;
204                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
205                    program_counter,
206                    vs2,
207                    group_regs,
208                )?;
209                let sew = vtype.vsew();
210                // SAFETY: alignments checked above
211                unsafe {
212                    zvkb_helpers::execute_vbrev8::<Reg, _>(env, vd, vs2, sew, vm);
213                }
214            }
215            // vrev8: reverse bytes within each element
216            Self::Vrev8V { vd, vs2, vm } => {
217                if !env.vector_instructions_allowed() {
218                    ::core::hint::cold_path();
219                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
220                        address: PackedAddress::new(
221                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
222                        ),
223                    });
224                }
225                if !vm && vd == VReg::V0 {
226                    ::core::hint::cold_path();
227                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
228                        address: PackedAddress::new(
229                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
230                        ),
231                    });
232                }
233                let Some(vtype) = env.vtype() else {
234                    ::core::hint::cold_path();
235                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
236                        address: PackedAddress::new(
237                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
238                        ),
239                    });
240                };
241                let group_regs = vtype.vlmul().register_count();
242                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
243                    program_counter,
244                    vd,
245                    group_regs,
246                )?;
247                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
248                    program_counter,
249                    vs2,
250                    group_regs,
251                )?;
252                let sew = vtype.vsew();
253                // SAFETY: alignments checked above
254                unsafe {
255                    zvkb_helpers::execute_vrev8::<Reg, _>(env, vd, vs2, sew, vm);
256                }
257            }
258            // vrol: vd[i] = rotate_left(vs2[i], src[i] % SEW)
259            Self::VrolVv { vd, vs2, vs1, vm } => {
260                if !env.vector_instructions_allowed() {
261                    ::core::hint::cold_path();
262                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
263                        address: PackedAddress::new(
264                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
265                        ),
266                    });
267                }
268                if !vm && vd == VReg::V0 {
269                    ::core::hint::cold_path();
270                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
271                        address: PackedAddress::new(
272                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
273                        ),
274                    });
275                }
276                let Some(vtype) = env.vtype() else {
277                    ::core::hint::cold_path();
278                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
279                        address: PackedAddress::new(
280                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
281                        ),
282                    });
283                };
284                let group_regs = vtype.vlmul().register_count();
285                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
286                    program_counter,
287                    vd,
288                    group_regs,
289                )?;
290                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
291                    program_counter,
292                    vs2,
293                    group_regs,
294                )?;
295                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
296                    program_counter,
297                    vs1,
298                    group_regs,
299                )?;
300                let sew = vtype.vsew();
301                // SAFETY: alignments checked above
302                unsafe {
303                    zvkb_helpers::execute_vrol::<Reg, _>(
304                        env,
305                        vd,
306                        vs2,
307                        zvkb_helpers::OpSrc::Vreg(vs1),
308                        sew,
309                        vm,
310                    );
311                }
312            }
313            Self::VrolVx {
314                vm,
315                vd,
316                vs2,
317                rs1: _,
318            } => {
319                if !env.vector_instructions_allowed() {
320                    ::core::hint::cold_path();
321                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
322                        address: PackedAddress::new(
323                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
324                        ),
325                    });
326                }
327                if !vm && vd == VReg::V0 {
328                    ::core::hint::cold_path();
329                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
330                        address: PackedAddress::new(
331                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
332                        ),
333                    });
334                }
335                let Some(vtype) = env.vtype() else {
336                    ::core::hint::cold_path();
337                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
338                        address: PackedAddress::new(
339                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
340                        ),
341                    });
342                };
343                let group_regs = vtype.vlmul().register_count();
344                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
345                    program_counter,
346                    vd,
347                    group_regs,
348                )?;
349                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
350                    program_counter,
351                    vs2,
352                    group_regs,
353                )?;
354                let sew = vtype.vsew();
355                let scalar = rs1_value.as_i64().cast_unsigned();
356                // SAFETY: alignments checked above
357                unsafe {
358                    zvkb_helpers::execute_vrol::<Reg, _>(
359                        env,
360                        vd,
361                        vs2,
362                        zvkb_helpers::OpSrc::Scalar(scalar),
363                        sew,
364                        vm,
365                    );
366                }
367            }
368            // vror: vd[i] = rotate_right(vs2[i], src[i] % SEW)
369            Self::VrorVv { vd, vs2, vs1, vm } => {
370                if !env.vector_instructions_allowed() {
371                    ::core::hint::cold_path();
372                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
373                        address: PackedAddress::new(
374                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
375                        ),
376                    });
377                }
378                if !vm && vd == VReg::V0 {
379                    ::core::hint::cold_path();
380                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
381                        address: PackedAddress::new(
382                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
383                        ),
384                    });
385                }
386                let Some(vtype) = env.vtype() else {
387                    ::core::hint::cold_path();
388                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
389                        address: PackedAddress::new(
390                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
391                        ),
392                    });
393                };
394                let group_regs = vtype.vlmul().register_count();
395                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
396                    program_counter,
397                    vd,
398                    group_regs,
399                )?;
400                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
401                    program_counter,
402                    vs2,
403                    group_regs,
404                )?;
405                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
406                    program_counter,
407                    vs1,
408                    group_regs,
409                )?;
410                let sew = vtype.vsew();
411                // SAFETY: alignments checked above
412                unsafe {
413                    zvkb_helpers::execute_vror::<Reg, _>(
414                        env,
415                        vd,
416                        vs2,
417                        zvkb_helpers::OpSrc::Vreg(vs1),
418                        sew,
419                        vm,
420                    );
421                }
422            }
423            Self::VrorVx {
424                vm,
425                vd,
426                vs2,
427                rs1: _,
428            } => {
429                if !env.vector_instructions_allowed() {
430                    ::core::hint::cold_path();
431                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
432                        address: PackedAddress::new(
433                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
434                        ),
435                    });
436                }
437                if !vm && vd == VReg::V0 {
438                    ::core::hint::cold_path();
439                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
440                        address: PackedAddress::new(
441                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
442                        ),
443                    });
444                }
445                let Some(vtype) = env.vtype() else {
446                    ::core::hint::cold_path();
447                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
448                        address: PackedAddress::new(
449                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
450                        ),
451                    });
452                };
453                let group_regs = vtype.vlmul().register_count();
454                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
455                    program_counter,
456                    vd,
457                    group_regs,
458                )?;
459                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
460                    program_counter,
461                    vs2,
462                    group_regs,
463                )?;
464                let sew = vtype.vsew();
465                let scalar = rs1_value.as_i64().cast_unsigned();
466                // SAFETY: alignments checked above
467                unsafe {
468                    zvkb_helpers::execute_vror::<Reg, _>(
469                        env,
470                        vd,
471                        vs2,
472                        zvkb_helpers::OpSrc::Scalar(scalar),
473                        sew,
474                        vm,
475                    );
476                }
477            }
478            // vror.vi: 5-bit immediate in vs1[19:15]; bit[25] is the standard vm mask-control bit
479            Self::VrorVi { vd, vs2, uimm, vm } => {
480                if !env.vector_instructions_allowed() {
481                    ::core::hint::cold_path();
482                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
483                        address: PackedAddress::new(
484                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
485                        ),
486                    });
487                }
488                if !vm && vd == VReg::V0 {
489                    ::core::hint::cold_path();
490                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
491                        address: PackedAddress::new(
492                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
493                        ),
494                    });
495                }
496                let Some(vtype) = env.vtype() else {
497                    ::core::hint::cold_path();
498                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
499                        address: PackedAddress::new(
500                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
501                        ),
502                    });
503                };
504                let group_regs = vtype.vlmul().register_count();
505                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
506                    program_counter,
507                    vd,
508                    group_regs,
509                )?;
510                zvkb_helpers::check_vreg_group_alignment::<Reg, _, _>(
511                    program_counter,
512                    vs2,
513                    group_regs,
514                )?;
515                let sew = vtype.vsew();
516                // SAFETY: alignments checked above
517                unsafe {
518                    zvkb_helpers::execute_vror::<Reg, _>(
519                        env,
520                        vd,
521                        vs2,
522                        zvkb_helpers::OpSrc::Scalar(u64::from(uimm)),
523                        sew,
524                        vm,
525                    );
526                }
527            }
528        }
529        ExecutionResult::ContinueNoWrite
530    }
531}