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::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 ZvbcInstruction<Reg> where Reg: Register {}
33
34#[instruction_execution]
35const impl<Reg, Env> ExecutableInstructionCsr<Env> for ZvbcInstruction<Reg> where Reg: Register {}
36
37#[instruction_execution]
38impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
39    for ZvbcInstruction<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            // vclmul: vd[i] = lower SEW bits of clmul(vs2[i], vs1[i])
63            Self::VclmulVv { 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                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
90                    program_counter,
91                    vd,
92                    group_regs,
93                )?;
94                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
95                    program_counter,
96                    vs2,
97                    group_regs,
98                )?;
99                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
100                    program_counter,
101                    vs1,
102                    group_regs,
103                )?;
104                let sew = vtype.vsew();
105                // Per spec, Zvbc's carry-less multiply is only defined at SEW=64; any other SEW is
106                // a reserved encoding
107                if sew != Vsew::E64 {
108                    ::core::hint::cold_path();
109                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
110                        address: PackedAddress::new(
111                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
112                        ),
113                    });
114                }
115                // SAFETY: alignments checked above
116                unsafe {
117                    zvbc_helpers::execute_vclmul::<Reg, _>(
118                        env,
119                        vd,
120                        vs2,
121                        zvbc_helpers::OpSrc::Vreg(vs1),
122                        sew,
123                        vm,
124                    );
125                }
126            }
127            Self::VclmulVx {
128                vm,
129                vd,
130                vs2,
131                rs1: _,
132            } => {
133                if !env.vector_instructions_allowed() {
134                    ::core::hint::cold_path();
135                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
136                        address: PackedAddress::new(
137                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
138                        ),
139                    });
140                }
141                if !vm && vd == VReg::V0 {
142                    ::core::hint::cold_path();
143                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
144                        address: PackedAddress::new(
145                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
146                        ),
147                    });
148                }
149                let Some(vtype) = env.vtype() else {
150                    ::core::hint::cold_path();
151                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
152                        address: PackedAddress::new(
153                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
154                        ),
155                    });
156                };
157                let group_regs = vtype.vlmul().register_count();
158                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
159                    program_counter,
160                    vd,
161                    group_regs,
162                )?;
163                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
164                    program_counter,
165                    vs2,
166                    group_regs,
167                )?;
168                let sew = vtype.vsew();
169                // Per spec, Zvbc's carry-less multiply is only defined at SEW=64; any other SEW is
170                // a reserved encoding
171                if sew != Vsew::E64 {
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 scalar = rs1_value.as_i64().cast_unsigned();
180                // SAFETY: alignments checked above
181                unsafe {
182                    zvbc_helpers::execute_vclmul::<Reg, _>(
183                        env,
184                        vd,
185                        vs2,
186                        zvbc_helpers::OpSrc::Scalar(scalar),
187                        sew,
188                        vm,
189                    );
190                }
191            }
192            // vclmulh: vd[i] = upper SEW bits of clmul(vs2[i], vs1[i])
193            Self::VclmulhVv { vd, vs2, vs1, vm } => {
194                if !env.vector_instructions_allowed() {
195                    ::core::hint::cold_path();
196                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
197                        address: PackedAddress::new(
198                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
199                        ),
200                    });
201                }
202                if !vm && vd == VReg::V0 {
203                    ::core::hint::cold_path();
204                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
205                        address: PackedAddress::new(
206                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
207                        ),
208                    });
209                }
210                let Some(vtype) = env.vtype() else {
211                    ::core::hint::cold_path();
212                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
213                        address: PackedAddress::new(
214                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
215                        ),
216                    });
217                };
218                let group_regs = vtype.vlmul().register_count();
219                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
220                    program_counter,
221                    vd,
222                    group_regs,
223                )?;
224                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
225                    program_counter,
226                    vs2,
227                    group_regs,
228                )?;
229                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
230                    program_counter,
231                    vs1,
232                    group_regs,
233                )?;
234                let sew = vtype.vsew();
235                // Per spec, Zvbc's carry-less multiply is only defined at SEW=64; any other SEW is
236                // a reserved encoding
237                if sew != Vsew::E64 {
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                // SAFETY: alignments checked above
246                unsafe {
247                    zvbc_helpers::execute_vclmulh::<Reg, _>(
248                        env,
249                        vd,
250                        vs2,
251                        zvbc_helpers::OpSrc::Vreg(vs1),
252                        sew,
253                        vm,
254                    );
255                }
256            }
257            Self::VclmulhVx {
258                vm,
259                vd,
260                vs2,
261                rs1: _,
262            } => {
263                if !env.vector_instructions_allowed() {
264                    ::core::hint::cold_path();
265                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
266                        address: PackedAddress::new(
267                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
268                        ),
269                    });
270                }
271                if !vm && vd == VReg::V0 {
272                    ::core::hint::cold_path();
273                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
274                        address: PackedAddress::new(
275                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
276                        ),
277                    });
278                }
279                let Some(vtype) = env.vtype() else {
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 group_regs = vtype.vlmul().register_count();
288                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
289                    program_counter,
290                    vd,
291                    group_regs,
292                )?;
293                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
294                    program_counter,
295                    vs2,
296                    group_regs,
297                )?;
298                let sew = vtype.vsew();
299                // Per spec, Zvbc's carry-less multiply is only defined at SEW=64; any other SEW is
300                // a reserved encoding
301                if sew != Vsew::E64 {
302                    ::core::hint::cold_path();
303                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
304                        address: PackedAddress::new(
305                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
306                        ),
307                    });
308                }
309                let scalar = rs1_value.as_i64().cast_unsigned();
310                // SAFETY: alignments checked above
311                unsafe {
312                    zvbc_helpers::execute_vclmulh::<Reg, _>(
313                        env,
314                        vd,
315                        vs2,
316                        zvbc_helpers::OpSrc::Scalar(scalar),
317                        sew,
318                        vm,
319                    );
320                }
321            }
322        }
323        ExecutionResult::ContinueNoWrite
324    }
325}