Skip to main content

ab_riscv_interpreter/
zvbc.rs

1//! Zvbc extension
2
3#[cfg(test)]
4mod tests;
5pub mod zvbc_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 ZvbcInstruction<Hart>
33where
34    Reg: Register,
35    Hart: VectorHartConfig<Reg = Reg>,
36{
37}
38
39#[instruction_execution]
40const impl<Reg, Hart, Env> ExecutableInstructionCsr<Env> for ZvbcInstruction<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 ZvbcInstruction<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            // vclmul: vd[i] = lower SEW bits of clmul(vs2[i], vs1[i])
73            Self::VclmulVv { 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                // Per spec, Zvbc's carry-less multiply is only defined at SEW=64; any other SEW is
110                // a reserved encoding
111                if sew != Vsew::E64 {
112                    ::core::hint::cold_path();
113                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
114                        address: PackedAddress::new(
115                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
116                        ),
117                    });
118                }
119                zvbc_helpers::execute_vclmul::<Reg, _>(
120                    env,
121                    vd,
122                    vs2,
123                    zvbc_helpers::OpSrc::Vreg(vs1),
124                    sew,
125                    vm,
126                );
127            }
128            Self::VclmulVx {
129                vm,
130                vd,
131                vs2,
132                rs1: _,
133            } => {
134                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
135                    ::core::hint::cold_path();
136                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
137                        address: PackedAddress::new(
138                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
139                        ),
140                    });
141                }
142                let Some(config) = env.vector_config() else {
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 sew = config.vtype().vsew();
151                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
152                    program_counter,
153                    config,
154                    vd,
155                    sew.as_eew(),
156                )?;
157                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
158                    program_counter,
159                    config,
160                    vs2,
161                    sew.as_eew(),
162                )?;
163                // Per spec, Zvbc's carry-less multiply is only defined at SEW=64; any other SEW is
164                // a reserved encoding
165                if sew != Vsew::E64 {
166                    ::core::hint::cold_path();
167                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
168                        address: PackedAddress::new(
169                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
170                        ),
171                    });
172                }
173                let scalar = rs1_value.as_i64().cast_unsigned();
174                zvbc_helpers::execute_vclmul::<Reg, _>(
175                    env,
176                    vd,
177                    vs2,
178                    zvbc_helpers::OpSrc::Scalar(scalar),
179                    sew,
180                    vm,
181                );
182            }
183            // vclmulh: vd[i] = upper SEW bits of clmul(vs2[i], vs1[i])
184            Self::VclmulhVv { vd, vs2, vs1, vm } => {
185                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
186                    ::core::hint::cold_path();
187                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
188                        address: PackedAddress::new(
189                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
190                        ),
191                    });
192                }
193                let Some(config) = env.vector_config() else {
194                    ::core::hint::cold_path();
195                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
196                        address: PackedAddress::new(
197                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
198                        ),
199                    });
200                };
201                let sew = config.vtype().vsew();
202                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
203                    program_counter,
204                    config,
205                    vd,
206                    sew.as_eew(),
207                )?;
208                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
209                    program_counter,
210                    config,
211                    vs2,
212                    sew.as_eew(),
213                )?;
214                let vs1 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
215                    program_counter,
216                    config,
217                    vs1,
218                    sew.as_eew(),
219                )?;
220                // Per spec, Zvbc's carry-less multiply is only defined at SEW=64; any other SEW is
221                // a reserved encoding
222                if sew != Vsew::E64 {
223                    ::core::hint::cold_path();
224                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
225                        address: PackedAddress::new(
226                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
227                        ),
228                    });
229                }
230                zvbc_helpers::execute_vclmulh::<Reg, _>(
231                    env,
232                    vd,
233                    vs2,
234                    zvbc_helpers::OpSrc::Vreg(vs1),
235                    sew,
236                    vm,
237                );
238            }
239            Self::VclmulhVx {
240                vm,
241                vd,
242                vs2,
243                rs1: _,
244            } => {
245                if !zvexx_helpers::non_memory_instruction_allowed::<Reg, _>(env) {
246                    ::core::hint::cold_path();
247                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
248                        address: PackedAddress::new(
249                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
250                        ),
251                    });
252                }
253                let Some(config) = env.vector_config() else {
254                    ::core::hint::cold_path();
255                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
256                        address: PackedAddress::new(
257                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
258                        ),
259                    });
260                };
261                let sew = config.vtype().vsew();
262                let vd = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
263                    program_counter,
264                    config,
265                    vd,
266                    sew.as_eew(),
267                )?;
268                let vs2 = zvexx_helpers::vreg_group::<Reg, Env, _, _>(
269                    program_counter,
270                    config,
271                    vs2,
272                    sew.as_eew(),
273                )?;
274                // Per spec, Zvbc's carry-less multiply is only defined at SEW=64; any other SEW is
275                // a reserved encoding
276                if sew != Vsew::E64 {
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 scalar = rs1_value.as_i64().cast_unsigned();
285                zvbc_helpers::execute_vclmulh::<Reg, _>(
286                    env,
287                    vd,
288                    vs2,
289                    zvbc_helpers::OpSrc::Scalar(scalar),
290                    sew,
291                    vm,
292                );
293            }
294        }
295        ExecutionResult::ContinueNoWrite
296    }
297}