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::{VectorRegisters, 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, Hart> ExecutableInstructionOperands for ZvbbInstruction<Hart>
35where
36    Reg: Register,
37    Hart: VectorHartConfig<Reg = Reg>,
38{
39}
40
41#[instruction_execution]
42const impl<Reg, Hart, Env> ExecutableInstructionCsr<Env> for ZvbbInstruction<Hart>
43where
44    Reg: Register,
45    Hart: VectorHartConfig<Reg = Reg>,
46{
47}
48
49#[instruction_execution]
50impl<Reg, Hart, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
51    for ZvbbInstruction<Hart>
52where
53    Reg: Register,
54    Hart: VectorHartConfig<Reg = Reg>,
55    Regs: RegisterFile<Reg>,
56    Env: VectorRegistersExt<Hart = Hart>,
57    Memory: VirtualMemory,
58    PC: ProgramCounter<Reg::Type, Memory>,
59{
60    #[inline(always)]
61    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
62    fn execute(
63        self,
64        Rs1Rs2OperandValues {
65            rs1_value,
66            rs2_value,
67        }: Rs1Rs2OperandValues<Reg::Type>,
68        _regs: &mut Regs,
69        env: &mut Env,
70        memory: &mut Memory,
71        program_counter: &PC,
72    ) -> ExecutionResult<Reg> {
73        match self {
74            // vbrev: reverse all bits within each SEW-wide element
75            Self::VbrevV { vd, vs2, vm } => {
76                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
77                    ::core::hint::cold_path();
78                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
79                        address: PackedAddress::new(
80                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
81                        ),
82                    });
83                }
84                let Some(config) = env.vector_config() else {
85                    ::core::hint::cold_path();
86                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
87                        address: PackedAddress::new(
88                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
89                        ),
90                    });
91                };
92                let sew = config.vtype().vsew();
93                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
94                    program_counter,
95                    config,
96                    vd,
97                    sew.as_eew(),
98                )?;
99                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
100                    program_counter,
101                    config,
102                    vs2,
103                    sew.as_eew(),
104                )?;
105                zvbb_helpers::execute_vbrev::<Reg, _>(env, vd, vs2, sew, vm);
106            }
107            // vclz: count leading zeros within each SEW-wide element; result in [0, SEW]
108            Self::VclzV { vd, vs2, vm } => {
109                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
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                let Some(config) = env.vector_config() else {
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 sew = config.vtype().vsew();
126                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
127                    program_counter,
128                    config,
129                    vd,
130                    sew.as_eew(),
131                )?;
132                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
133                    program_counter,
134                    config,
135                    vs2,
136                    sew.as_eew(),
137                )?;
138                zvbb_helpers::execute_vclz::<Reg, _>(env, vd, vs2, sew, vm);
139            }
140            // vctz: count trailing zeros within each SEW-wide element; result in [0, SEW]
141            Self::VctzV { vd, vs2, vm } => {
142                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
143                    ::core::hint::cold_path();
144                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
145                        address: PackedAddress::new(
146                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
147                        ),
148                    });
149                }
150                let Some(config) = env.vector_config() else {
151                    ::core::hint::cold_path();
152                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
153                        address: PackedAddress::new(
154                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
155                        ),
156                    });
157                };
158                let sew = config.vtype().vsew();
159                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
160                    program_counter,
161                    config,
162                    vd,
163                    sew.as_eew(),
164                )?;
165                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
166                    program_counter,
167                    config,
168                    vs2,
169                    sew.as_eew(),
170                )?;
171                zvbb_helpers::execute_vctz::<Reg, _>(env, vd, vs2, sew, vm);
172            }
173            // vcpop: population count (number of set bits) within each SEW-wide element
174            Self::VcpopV { vd, vs2, vm } => {
175                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
176                    ::core::hint::cold_path();
177                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
178                        address: PackedAddress::new(
179                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
180                        ),
181                    });
182                }
183                let Some(config) = env.vector_config() else {
184                    ::core::hint::cold_path();
185                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
186                        address: PackedAddress::new(
187                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
188                        ),
189                    });
190                };
191                let sew = config.vtype().vsew();
192                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
193                    program_counter,
194                    config,
195                    vd,
196                    sew.as_eew(),
197                )?;
198                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
199                    program_counter,
200                    config,
201                    vs2,
202                    sew.as_eew(),
203                )?;
204                zvbb_helpers::execute_vcpop::<Reg, _>(env, vd, vs2, vm);
205            }
206            // vwsll: widening shift-left-logical; vd is 2*SEW wide, vs2/src are SEW wide.
207            // SEW=E64 is illegal (cannot double); LMUL=M8 is illegal (EMUL(vd)=16 out of range).
208            Self::VwsllVv { vd, vs2, vs1, vm } => {
209                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
210                    ::core::hint::cold_path();
211                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
212                        address: PackedAddress::new(
213                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
214                        ),
215                    });
216                }
217                let Some(config) = env.vector_config() else {
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                let sew = config.vtype().vsew();
226                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
227                    ::core::hint::cold_path();
228                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
229                        address: PackedAddress::new(
230                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
231                        ),
232                    });
233                };
234                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
235                    program_counter,
236                    config,
237                    vd,
238                    widening_sew.wide().as_eew(),
239                )?;
240                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
241                    program_counter,
242                    config,
243                    vs2,
244                    sew.as_eew(),
245                )?;
246                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
247                    program_counter,
248                    config,
249                    vs1,
250                    sew.as_eew(),
251                )?;
252                // The wide destination may only overlap narrow sources in its highest-numbered part
253                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
254                    program_counter,
255                    vd,
256                    vs2,
257                )?;
258                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
259                    program_counter,
260                    vd,
261                    vs1,
262                )?;
263                zvbb_helpers::execute_vwsll::<Reg, _>(
264                    env,
265                    vd,
266                    vs2,
267                    zvbb_helpers::OpSrc::Vreg(vs1),
268                    widening_sew,
269                    vm,
270                );
271            }
272            Self::VwsllVx {
273                vm,
274                vd,
275                vs2,
276                rs1: _,
277            } => {
278                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
279                    ::core::hint::cold_path();
280                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
281                        address: PackedAddress::new(
282                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
283                        ),
284                    });
285                }
286                let Some(config) = env.vector_config() else {
287                    ::core::hint::cold_path();
288                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
289                        address: PackedAddress::new(
290                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
291                        ),
292                    });
293                };
294                let sew = config.vtype().vsew();
295                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
296                    ::core::hint::cold_path();
297                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
298                        address: PackedAddress::new(
299                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
300                        ),
301                    });
302                };
303                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
304                    program_counter,
305                    config,
306                    vd,
307                    widening_sew.wide().as_eew(),
308                )?;
309                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
310                    program_counter,
311                    config,
312                    vs2,
313                    sew.as_eew(),
314                )?;
315                // The wide destination may only overlap narrow sources in its highest-numbered part
316                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
317                    program_counter,
318                    vd,
319                    vs2,
320                )?;
321                let scalar = rs1_value.as_i64().cast_unsigned();
322                zvbb_helpers::execute_vwsll::<Reg, _>(
323                    env,
324                    vd,
325                    vs2,
326                    zvbb_helpers::OpSrc::Scalar(scalar),
327                    widening_sew,
328                    vm,
329                );
330            }
331            // vwsll.vi: standard 5-bit immediate; vm is the normal mask-control bit
332            Self::VwsllVi { vd, vs2, uimm, vm } => {
333                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
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 Some(config) = env.vector_config() else {
342                    ::core::hint::cold_path();
343                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
344                        address: PackedAddress::new(
345                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
346                        ),
347                    });
348                };
349                let sew = config.vtype().vsew();
350                let Some(widening_sew) = zvexx_helpers::WideningSew::<Env::Hart>::new(sew) else {
351                    ::core::hint::cold_path();
352                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
353                        address: PackedAddress::new(
354                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
355                        ),
356                    });
357                };
358                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
359                    program_counter,
360                    config,
361                    vd,
362                    widening_sew.wide().as_eew(),
363                )?;
364                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
365                    program_counter,
366                    config,
367                    vs2,
368                    sew.as_eew(),
369                )?;
370                // The wide destination may only overlap narrow sources in its highest-numbered part
371                zvexx_helpers::check_destination_overlap::<Reg, Env, _, _>(
372                    program_counter,
373                    vd,
374                    vs2,
375                )?;
376                zvbb_helpers::execute_vwsll::<Reg, _>(
377                    env,
378                    vd,
379                    vs2,
380                    zvbb_helpers::OpSrc::Scalar(u64::from(uimm)),
381                    widening_sew,
382                    vm,
383                );
384            }
385        }
386        ExecutionResult::ContinueNoWrite
387    }
388}