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                // SAFETY: alignments checked above
106                unsafe {
107                    zvbc_helpers::execute_vclmul::<Reg, _>(
108                        env,
109                        vd,
110                        vs2,
111                        zvbc_helpers::OpSrc::Vreg(vs1),
112                        sew,
113                        vm,
114                    );
115                }
116            }
117            Self::VclmulVx {
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                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
149                    program_counter,
150                    vd,
151                    group_regs,
152                )?;
153                zvbc_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                    zvbc_helpers::execute_vclmul::<Reg, _>(
163                        env,
164                        vd,
165                        vs2,
166                        zvbc_helpers::OpSrc::Scalar(scalar),
167                        sew,
168                        vm,
169                    );
170                }
171            }
172            // vclmulh: vd[i] = upper SEW bits of clmul(vs2[i], vs1[i])
173            Self::VclmulhVv { vd, vs2, vs1, 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                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
200                    program_counter,
201                    vd,
202                    group_regs,
203                )?;
204                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
205                    program_counter,
206                    vs2,
207                    group_regs,
208                )?;
209                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
210                    program_counter,
211                    vs1,
212                    group_regs,
213                )?;
214                let sew = vtype.vsew();
215                // SAFETY: alignments checked above
216                unsafe {
217                    zvbc_helpers::execute_vclmulh::<Reg, _>(
218                        env,
219                        vd,
220                        vs2,
221                        zvbc_helpers::OpSrc::Vreg(vs1),
222                        sew,
223                        vm,
224                    );
225                }
226            }
227            Self::VclmulhVx {
228                vm,
229                vd,
230                vs2,
231                rs1: _,
232            } => {
233                if !env.vector_instructions_allowed() {
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                if !vm && vd == VReg::V0 {
242                    ::core::hint::cold_path();
243                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
244                        address: PackedAddress::new(
245                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
246                        ),
247                    });
248                }
249                let Some(vtype) = env.vtype() else {
250                    ::core::hint::cold_path();
251                    return ExecutionResult::Err(ExecutionError::IllegalInstruction {
252                        address: PackedAddress::new(
253                            program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
254                        ),
255                    });
256                };
257                let group_regs = vtype.vlmul().register_count();
258                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
259                    program_counter,
260                    vd,
261                    group_regs,
262                )?;
263                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _>(
264                    program_counter,
265                    vs2,
266                    group_regs,
267                )?;
268                let sew = vtype.vsew();
269                let scalar = rs1_value.as_i64().cast_unsigned();
270                // SAFETY: alignments checked above
271                unsafe {
272                    zvbc_helpers::execute_vclmulh::<Reg, _>(
273                        env,
274                        vd,
275                        vs2,
276                        zvbc_helpers::OpSrc::Scalar(scalar),
277                        sew,
278                        vm,
279                    );
280                }
281            }
282        }
283        ExecutionResult::ContinueNoWrite
284    }
285}