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    [(); ExtState::ELEN as usize]:,
51    [(); ExtState::VLEN as usize]:,
52    [(); ExtState::VLENB as usize]:,
53    Memory: VirtualMemory,
54    PC: ProgramCounter<Reg::Type, Memory, CustomError>,
55    CustomError: fmt::Debug,
56{
57    #[inline(always)]
58    fn execute(
59        self,
60        Rs1Rs2OperandValues {
61            rs1_value,
62            rs2_value,
63        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
64        _regs: &mut Regs,
65        ext_state: &mut ExtState,
66        memory: &mut Memory,
67        program_counter: &mut PC,
68        _system_instruction_handler: &mut InstructionHandler,
69    ) -> Result<
70        ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
71        ExecutionError<Reg::Type, CustomError>,
72    > {
73        match self {
74            // vclmul: vd[i] = lower SEW bits of clmul(vs2[i], vs1[i])
75            Self::VclmulVv { vd, vs2, vs1, vm } => {
76                if !ext_state.vector_instructions_allowed() {
77                    ::core::hint::cold_path();
78                    return Err(ExecutionError::IllegalInstruction {
79                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
80                    });
81                }
82                if !vm && vd == VReg::V0 {
83                    ::core::hint::cold_path();
84                    return Err(ExecutionError::IllegalInstruction {
85                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
86                    });
87                }
88                let Some(vtype) = ext_state.vtype() else {
89                    ::core::hint::cold_path();
90                    return Err(ExecutionError::IllegalInstruction {
91                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
92                    });
93                };
94                let group_regs = vtype.vlmul().register_count();
95                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
96                    program_counter,
97                    vd,
98                    group_regs,
99                )?;
100                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
101                    program_counter,
102                    vs2,
103                    group_regs,
104                )?;
105                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
106                    program_counter,
107                    vs1,
108                    group_regs,
109                )?;
110                let sew = vtype.vsew();
111                // SAFETY: alignments checked above
112                unsafe {
113                    zvbc_helpers::execute_vclmul::<Reg, _, _>(
114                        ext_state,
115                        vd,
116                        vs2,
117                        zvbc_helpers::OpSrc::Vreg(vs1),
118                        sew,
119                        vm,
120                    );
121                }
122            }
123            Self::VclmulVx {
124                vm,
125                vd,
126                vs2,
127                rs1: _,
128            } => {
129                if !ext_state.vector_instructions_allowed() {
130                    ::core::hint::cold_path();
131                    return Err(ExecutionError::IllegalInstruction {
132                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
133                    });
134                }
135                if !vm && vd == VReg::V0 {
136                    ::core::hint::cold_path();
137                    return Err(ExecutionError::IllegalInstruction {
138                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
139                    });
140                }
141                let Some(vtype) = ext_state.vtype() else {
142                    ::core::hint::cold_path();
143                    return Err(ExecutionError::IllegalInstruction {
144                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
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                        ext_state,
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 !ext_state.vector_instructions_allowed() {
175                    ::core::hint::cold_path();
176                    return Err(ExecutionError::IllegalInstruction {
177                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
178                    });
179                }
180                if !vm && vd == VReg::V0 {
181                    ::core::hint::cold_path();
182                    return Err(ExecutionError::IllegalInstruction {
183                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
184                    });
185                }
186                let Some(vtype) = ext_state.vtype() else {
187                    ::core::hint::cold_path();
188                    return Err(ExecutionError::IllegalInstruction {
189                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
190                    });
191                };
192                let group_regs = vtype.vlmul().register_count();
193                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
194                    program_counter,
195                    vd,
196                    group_regs,
197                )?;
198                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
199                    program_counter,
200                    vs2,
201                    group_regs,
202                )?;
203                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
204                    program_counter,
205                    vs1,
206                    group_regs,
207                )?;
208                let sew = vtype.vsew();
209                // SAFETY: alignments checked above
210                unsafe {
211                    zvbc_helpers::execute_vclmulh::<Reg, _, _>(
212                        ext_state,
213                        vd,
214                        vs2,
215                        zvbc_helpers::OpSrc::Vreg(vs1),
216                        sew,
217                        vm,
218                    );
219                }
220            }
221            Self::VclmulhVx {
222                vm,
223                vd,
224                vs2,
225                rs1: _,
226            } => {
227                if !ext_state.vector_instructions_allowed() {
228                    ::core::hint::cold_path();
229                    return Err(ExecutionError::IllegalInstruction {
230                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
231                    });
232                }
233                if !vm && vd == VReg::V0 {
234                    ::core::hint::cold_path();
235                    return Err(ExecutionError::IllegalInstruction {
236                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
237                    });
238                }
239                let Some(vtype) = ext_state.vtype() else {
240                    ::core::hint::cold_path();
241                    return Err(ExecutionError::IllegalInstruction {
242                        address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
243                    });
244                };
245                let group_regs = vtype.vlmul().register_count();
246                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
247                    program_counter,
248                    vd,
249                    group_regs,
250                )?;
251                zvbc_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
252                    program_counter,
253                    vs2,
254                    group_regs,
255                )?;
256                let sew = vtype.vsew();
257                let scalar = rs1_value.as_i64().cast_unsigned();
258                // SAFETY: alignments checked above
259                unsafe {
260                    zvbc_helpers::execute_vclmulh::<Reg, _, _>(
261                        ext_state,
262                        vd,
263                        vs2,
264                        zvbc_helpers::OpSrc::Scalar(scalar),
265                        sew,
266                        vm,
267                    );
268                }
269            }
270        }
271        Ok(ControlFlow::Continue(Default::default()))
272    }
273}