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, ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands,
24    VirtualMemory,
25};
26use ab_riscv_macros::instruction_execution;
27use ab_riscv_primitives::prelude::*;
28use core::fmt;
29use core::ops::ControlFlow;
30
31#[instruction_execution]
32impl<Reg> ExecutableInstructionOperands for ZvbcInstruction<Reg> where Reg: Register {}
33
34#[instruction_execution]
35impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
36    for ZvbcInstruction<Reg>
37where
38    Reg: Register,
39{
40}
41
42#[instruction_execution]
43impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
44    ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
45    for ZvbcInstruction<Reg>
46where
47    Reg: Register,
48    Regs: RegisterFile<Reg>,
49    ExtState: VectorRegistersExt<Reg, CustomError>,
50    [(); SUPPORTED_ELEN_VLEN::<{ ExtState::ELEN }, { ExtState::VLEN }>]:,
51    Memory: VirtualMemory,
52    PC: ProgramCounter<Reg::Type, Memory, CustomError>,
53    CustomError: fmt::Debug,
54{
55    #[inline(always)]
56    fn execute(
57        self,
58        Rs1Rs2OperandValues {
59            rs1_value,
60            rs2_value,
61        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
62        _regs: &mut Regs,
63        ext_state: &mut ExtState,
64        memory: &mut Memory,
65        program_counter: &mut PC,
66        _system_instruction_handler: &mut InstructionHandler,
67    ) -> Result<
68        ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
69        ExecutionError<Reg::Type, CustomError>,
70    > {
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 !ext_state.vector_instructions_allowed() {
75                    ::core::hint::cold_path();
76                    return Err(ExecutionError::IllegalInstruction {
77                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
78                    });
79                }
80                if !vm && vd == VReg::V0 {
81                    ::core::hint::cold_path();
82                    return Err(ExecutionError::IllegalInstruction {
83                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
84                    });
85                }
86                let Some(vtype) = ext_state.vtype() else {
87                    ::core::hint::cold_path();
88                    return Err(ExecutionError::IllegalInstruction {
89                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
90                    });
91                };
92                let group_regs = vtype.vlmul().register_count();
93                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
94                    program_counter,
95                    vd,
96                    group_regs,
97                )?;
98                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
99                    program_counter,
100                    vs2,
101                    group_regs,
102                )?;
103                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
104                    program_counter,
105                    vs1,
106                    group_regs,
107                )?;
108                let sew = vtype.vsew();
109                // SAFETY: alignments checked above
110                unsafe {
111                    zvbc_helpers::execute_vclmul::<Reg, _, _>(
112                        ext_state,
113                        vd,
114                        vs2,
115                        zvbc_helpers::OpSrc::Vreg(vs1),
116                        sew,
117                        vm,
118                    );
119                }
120            }
121            Self::VclmulVx {
122                vm,
123                vd,
124                vs2,
125                rs1: _,
126            } => {
127                if !ext_state.vector_instructions_allowed() {
128                    ::core::hint::cold_path();
129                    return Err(ExecutionError::IllegalInstruction {
130                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
131                    });
132                }
133                if !vm && vd == VReg::V0 {
134                    ::core::hint::cold_path();
135                    return Err(ExecutionError::IllegalInstruction {
136                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
137                    });
138                }
139                let Some(vtype) = ext_state.vtype() else {
140                    ::core::hint::cold_path();
141                    return Err(ExecutionError::IllegalInstruction {
142                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
143                    });
144                };
145                let group_regs = vtype.vlmul().register_count();
146                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
147                    program_counter,
148                    vd,
149                    group_regs,
150                )?;
151                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
152                    program_counter,
153                    vs2,
154                    group_regs,
155                )?;
156                let sew = vtype.vsew();
157                let scalar = rs1_value.as_i64().cast_unsigned();
158                // SAFETY: alignments checked above
159                unsafe {
160                    zvbc_helpers::execute_vclmul::<Reg, _, _>(
161                        ext_state,
162                        vd,
163                        vs2,
164                        zvbc_helpers::OpSrc::Scalar(scalar),
165                        sew,
166                        vm,
167                    );
168                }
169            }
170            // vclmulh: vd[i] = upper SEW bits of clmul(vs2[i], vs1[i])
171            Self::VclmulhVv { vd, vs2, vs1, vm } => {
172                if !ext_state.vector_instructions_allowed() {
173                    ::core::hint::cold_path();
174                    return Err(ExecutionError::IllegalInstruction {
175                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
176                    });
177                }
178                if !vm && vd == VReg::V0 {
179                    ::core::hint::cold_path();
180                    return Err(ExecutionError::IllegalInstruction {
181                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
182                    });
183                }
184                let Some(vtype) = ext_state.vtype() else {
185                    ::core::hint::cold_path();
186                    return Err(ExecutionError::IllegalInstruction {
187                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
188                    });
189                };
190                let group_regs = vtype.vlmul().register_count();
191                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
192                    program_counter,
193                    vd,
194                    group_regs,
195                )?;
196                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
197                    program_counter,
198                    vs2,
199                    group_regs,
200                )?;
201                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
202                    program_counter,
203                    vs1,
204                    group_regs,
205                )?;
206                let sew = vtype.vsew();
207                // SAFETY: alignments checked above
208                unsafe {
209                    zvbc_helpers::execute_vclmulh::<Reg, _, _>(
210                        ext_state,
211                        vd,
212                        vs2,
213                        zvbc_helpers::OpSrc::Vreg(vs1),
214                        sew,
215                        vm,
216                    );
217                }
218            }
219            Self::VclmulhVx {
220                vm,
221                vd,
222                vs2,
223                rs1: _,
224            } => {
225                if !ext_state.vector_instructions_allowed() {
226                    ::core::hint::cold_path();
227                    return Err(ExecutionError::IllegalInstruction {
228                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
229                    });
230                }
231                if !vm && vd == VReg::V0 {
232                    ::core::hint::cold_path();
233                    return Err(ExecutionError::IllegalInstruction {
234                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
235                    });
236                }
237                let Some(vtype) = ext_state.vtype() else {
238                    ::core::hint::cold_path();
239                    return Err(ExecutionError::IllegalInstruction {
240                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
241                    });
242                };
243                let group_regs = vtype.vlmul().register_count();
244                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
245                    program_counter,
246                    vd,
247                    group_regs,
248                )?;
249                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
250                    program_counter,
251                    vs2,
252                    group_regs,
253                )?;
254                let sew = vtype.vsew();
255                let scalar = rs1_value.as_i64().cast_unsigned();
256                // SAFETY: alignments checked above
257                unsafe {
258                    zvbc_helpers::execute_vclmulh::<Reg, _, _>(
259                        ext_state,
260                        vd,
261                        vs2,
262                        zvbc_helpers::OpSrc::Scalar(scalar),
263                        sew,
264                        vm,
265                    );
266                }
267            }
268        }
269        Ok(ControlFlow::Continue(Default::default()))
270    }
271}