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::{VectorRegisters, 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, Hart> ExecutableInstructionOperands for ZvkbInstruction<Hart>
33where
34    Reg: Register,
35    Hart: VectorHartConfig<Reg = Reg>,
36{
37}
38
39#[instruction_execution]
40const impl<Reg, Hart, Env> ExecutableInstructionCsr<Env> for ZvkbInstruction<Hart>
41where
42    Reg: Register,
43    Hart: VectorHartConfig<Reg = Reg>,
44{
45}
46
47#[instruction_execution]
48impl<Reg, Hart, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
49    for ZvkbInstruction<Hart>
50where
51    Reg: Register,
52    Hart: VectorHartConfig<Reg = Reg>,
53    Regs: RegisterFile<Reg>,
54    Env: VectorRegistersExt<Hart = Hart>,
55    Memory: VirtualMemory,
56    PC: ProgramCounter<Reg::Type, Memory>,
57{
58    #[inline(always)]
59    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
60    fn execute(
61        self,
62        Rs1Rs2OperandValues {
63            rs1_value,
64            rs2_value,
65        }: Rs1Rs2OperandValues<Reg::Type>,
66        _regs: &mut Regs,
67        env: &mut Env,
68        memory: &mut Memory,
69        program_counter: &PC,
70    ) -> ExecutionResult<Reg> {
71        match self {
72            // vandn: vd[i] = ~vs1[i] & vs2[i]  (or ~rs1 & vs2[i])
73            Self::VandnVv { vd, vs2, vs1, vm } => {
74                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
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(config) = env.vector_config() 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 sew = config.vtype().vsew();
91                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
92                    program_counter,
93                    config,
94                    vd,
95                    sew.as_eew(),
96                )?;
97                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
98                    program_counter,
99                    config,
100                    vs2,
101                    sew.as_eew(),
102                )?;
103                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
104                    program_counter,
105                    config,
106                    vs1,
107                    sew.as_eew(),
108                )?;
109                zvkb_helpers::execute_vandn::<Reg, _>(
110                    env,
111                    vd,
112                    vs2,
113                    zvkb_helpers::OpSrc::Vreg(vs1),
114                    vm,
115                );
116            }
117            Self::VandnVx {
118                vm,
119                vd,
120                vs2,
121                rs1: _,
122            } => {
123                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
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                let Some(config) = env.vector_config() else {
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 sew = config.vtype().vsew();
140                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
141                    program_counter,
142                    config,
143                    vd,
144                    sew.as_eew(),
145                )?;
146                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
147                    program_counter,
148                    config,
149                    vs2,
150                    sew.as_eew(),
151                )?;
152                let scalar = rs1_value.as_i64().cast_unsigned();
153                zvkb_helpers::execute_vandn::<Reg, _>(
154                    env,
155                    vd,
156                    vs2,
157                    zvkb_helpers::OpSrc::Scalar(scalar),
158                    vm,
159                );
160            }
161            // vbrev8: reverse bits within each byte of each element
162            Self::Vbrev8V { vd, vs2, vm } => {
163                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
164                    ::core::hint::cold_path();
165                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
166                        address: PackedAddress::new(
167                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
168                        ),
169                    });
170                }
171                let Some(config) = env.vector_config() else {
172                    ::core::hint::cold_path();
173                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
174                        address: PackedAddress::new(
175                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
176                        ),
177                    });
178                };
179                let sew = config.vtype().vsew();
180                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
181                    program_counter,
182                    config,
183                    vd,
184                    sew.as_eew(),
185                )?;
186                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
187                    program_counter,
188                    config,
189                    vs2,
190                    sew.as_eew(),
191                )?;
192                zvkb_helpers::execute_vbrev8::<Reg, _>(env, vd, vs2, sew, vm);
193            }
194            // vrev8: reverse bytes within each element
195            Self::Vrev8V { vd, vs2, vm } => {
196                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
197                    ::core::hint::cold_path();
198                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
199                        address: PackedAddress::new(
200                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
201                        ),
202                    });
203                }
204                let Some(config) = env.vector_config() else {
205                    ::core::hint::cold_path();
206                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
207                        address: PackedAddress::new(
208                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
209                        ),
210                    });
211                };
212                let sew = config.vtype().vsew();
213                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
214                    program_counter,
215                    config,
216                    vd,
217                    sew.as_eew(),
218                )?;
219                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
220                    program_counter,
221                    config,
222                    vs2,
223                    sew.as_eew(),
224                )?;
225                zvkb_helpers::execute_vrev8::<Reg, _>(env, vd, vs2, sew, vm);
226            }
227            // vrol: vd[i] = rotate_left(vs2[i], src[i] % SEW)
228            Self::VrolVv { vd, vs2, vs1, vm } => {
229                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
230                    ::core::hint::cold_path();
231                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
232                        address: PackedAddress::new(
233                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
234                        ),
235                    });
236                }
237                let Some(config) = env.vector_config() else {
238                    ::core::hint::cold_path();
239                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
240                        address: PackedAddress::new(
241                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
242                        ),
243                    });
244                };
245                let sew = config.vtype().vsew();
246                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
247                    program_counter,
248                    config,
249                    vd,
250                    sew.as_eew(),
251                )?;
252                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
253                    program_counter,
254                    config,
255                    vs2,
256                    sew.as_eew(),
257                )?;
258                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
259                    program_counter,
260                    config,
261                    vs1,
262                    sew.as_eew(),
263                )?;
264                zvkb_helpers::execute_vrol::<Reg, _>(
265                    env,
266                    vd,
267                    vs2,
268                    zvkb_helpers::OpSrc::Vreg(vs1),
269                    sew,
270                    vm,
271                );
272            }
273            Self::VrolVx {
274                vm,
275                vd,
276                vs2,
277                rs1: _,
278            } => {
279                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
280                    ::core::hint::cold_path();
281                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
282                        address: PackedAddress::new(
283                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
284                        ),
285                    });
286                }
287                let Some(config) = env.vector_config() else {
288                    ::core::hint::cold_path();
289                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
290                        address: PackedAddress::new(
291                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
292                        ),
293                    });
294                };
295                let sew = config.vtype().vsew();
296                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
297                    program_counter,
298                    config,
299                    vd,
300                    sew.as_eew(),
301                )?;
302                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
303                    program_counter,
304                    config,
305                    vs2,
306                    sew.as_eew(),
307                )?;
308                let scalar = rs1_value.as_i64().cast_unsigned();
309                zvkb_helpers::execute_vrol::<Reg, _>(
310                    env,
311                    vd,
312                    vs2,
313                    zvkb_helpers::OpSrc::Scalar(scalar),
314                    sew,
315                    vm,
316                );
317            }
318            // vror: vd[i] = rotate_right(vs2[i], src[i] % SEW)
319            Self::VrorVv { vd, vs2, vs1, vm } => {
320                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
321                    ::core::hint::cold_path();
322                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
323                        address: PackedAddress::new(
324                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
325                        ),
326                    });
327                }
328                let Some(config) = env.vector_config() else {
329                    ::core::hint::cold_path();
330                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
331                        address: PackedAddress::new(
332                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
333                        ),
334                    });
335                };
336                let sew = config.vtype().vsew();
337                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
338                    program_counter,
339                    config,
340                    vd,
341                    sew.as_eew(),
342                )?;
343                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
344                    program_counter,
345                    config,
346                    vs2,
347                    sew.as_eew(),
348                )?;
349                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
350                    program_counter,
351                    config,
352                    vs1,
353                    sew.as_eew(),
354                )?;
355                zvkb_helpers::execute_vror::<Reg, _>(
356                    env,
357                    vd,
358                    vs2,
359                    zvkb_helpers::OpSrc::Vreg(vs1),
360                    sew,
361                    vm,
362                );
363            }
364            Self::VrorVx {
365                vm,
366                vd,
367                vs2,
368                rs1: _,
369            } => {
370                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
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                let Some(config) = env.vector_config() else {
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 sew = config.vtype().vsew();
387                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
388                    program_counter,
389                    config,
390                    vd,
391                    sew.as_eew(),
392                )?;
393                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
394                    program_counter,
395                    config,
396                    vs2,
397                    sew.as_eew(),
398                )?;
399                let scalar = rs1_value.as_i64().cast_unsigned();
400                zvkb_helpers::execute_vror::<Reg, _>(
401                    env,
402                    vd,
403                    vs2,
404                    zvkb_helpers::OpSrc::Scalar(scalar),
405                    sew,
406                    vm,
407                );
408            }
409            // vror.vi: 5-bit immediate in vs1[19:15]; bit[25] is the standard vm mask-control bit
410            Self::VrorVi { vd, vs2, uimm, vm } => {
411                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
412                    ::core::hint::cold_path();
413                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
414                        address: PackedAddress::new(
415                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
416                        ),
417                    });
418                }
419                let Some(config) = env.vector_config() else {
420                    ::core::hint::cold_path();
421                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
422                        address: PackedAddress::new(
423                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
424                        ),
425                    });
426                };
427                let sew = config.vtype().vsew();
428                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
429                    program_counter,
430                    config,
431                    vd,
432                    sew.as_eew(),
433                )?;
434                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
435                    program_counter,
436                    config,
437                    vs2,
438                    sew.as_eew(),
439                )?;
440                zvkb_helpers::execute_vror::<Reg, _>(
441                    env,
442                    vd,
443                    vs2,
444                    zvkb_helpers::OpSrc::Scalar(u64::from(uimm)),
445                    sew,
446                    vm,
447                );
448            }
449        }
450        ExecutionResult::ContinueNoWrite
451    }
452}