1#[cfg(test)]
4mod tests;
5pub mod zvbb_helpers;
6pub mod zvkb;
7
8use crate::v::vector_registers::VectorRegistersExt;
9use crate::v::zvexx::arith::zvexx_arith_helpers;
10use crate::v::zvexx::carry::zvexx_carry_helpers;
11use crate::v::zvexx::config::zvexx_config_helpers;
12use crate::v::zvexx::fixed_point::zvexx_fixed_point_helpers;
13use crate::v::zvexx::load::zvexx_load_helpers;
14use crate::v::zvexx::mask::zvexx_mask_helpers;
15use crate::v::zvexx::muldiv::zvexx_muldiv_helpers;
16use crate::v::zvexx::perm::zvexx_perm_helpers;
17use crate::v::zvexx::reduction::zvexx_reduction_helpers;
18use crate::v::zvexx::store::zvexx_store_helpers;
19use crate::v::zvexx::widen_narrow::zvexx_widen_narrow_helpers;
20use crate::v::zvexx::zvexx_helpers;
21use crate::zicsr::zicsr_helpers;
22use crate::zvbb::zvkb::zvkb_helpers;
23use crate::{
24 CsrError, Csrs, ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands,
25 ExecutionError, ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands,
26 VirtualMemory,
27};
28use ab_riscv_macros::instruction_execution;
29use ab_riscv_primitives::prelude::*;
30use core::fmt;
31use core::ops::ControlFlow;
32
33#[instruction_execution]
34impl<Reg> ExecutableInstructionOperands for ZvbbInstruction<Reg> where Reg: Register {}
35
36#[instruction_execution]
37impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
38 for ZvbbInstruction<Reg>
39where
40 Reg: Register,
41{
42}
43
44#[instruction_execution]
45impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
46 ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
47 for ZvbbInstruction<Reg>
48where
49 Reg: Register,
50 Regs: RegisterFile<Reg>,
51 ExtState: VectorRegistersExt<Reg, CustomError>,
52 [(); SUPPORTED_ELEN_VLEN::<{ ExtState::ELEN }, { ExtState::VLEN }>]:,
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 Self::VbrevV { vd, vs2, 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 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
96 program_counter,
97 vd,
98 group_regs,
99 )?;
100 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
101 program_counter,
102 vs2,
103 group_regs,
104 )?;
105 let sew = vtype.vsew();
106 unsafe {
108 zvbb_helpers::execute_vbrev::<Reg, _, _>(ext_state, vd, vs2, sew, vm);
109 }
110 }
111 Self::VclzV { vd, vs2, vm } => {
113 if !ext_state.vector_instructions_allowed() {
114 ::core::hint::cold_path();
115 return Err(ExecutionError::IllegalInstruction {
116 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
117 });
118 }
119 if !vm && vd == VReg::V0 {
120 ::core::hint::cold_path();
121 return Err(ExecutionError::IllegalInstruction {
122 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
123 });
124 }
125 let Some(vtype) = ext_state.vtype() else {
126 ::core::hint::cold_path();
127 return Err(ExecutionError::IllegalInstruction {
128 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
129 });
130 };
131 let group_regs = vtype.vlmul().register_count();
132 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
133 program_counter,
134 vd,
135 group_regs,
136 )?;
137 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
138 program_counter,
139 vs2,
140 group_regs,
141 )?;
142 let sew = vtype.vsew();
143 unsafe {
145 zvbb_helpers::execute_vclz::<Reg, _, _>(ext_state, vd, vs2, sew, vm);
146 }
147 }
148 Self::VctzV { vd, vs2, vm } => {
150 if !ext_state.vector_instructions_allowed() {
151 ::core::hint::cold_path();
152 return Err(ExecutionError::IllegalInstruction {
153 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
154 });
155 }
156 if !vm && vd == VReg::V0 {
157 ::core::hint::cold_path();
158 return Err(ExecutionError::IllegalInstruction {
159 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
160 });
161 }
162 let Some(vtype) = ext_state.vtype() else {
163 ::core::hint::cold_path();
164 return Err(ExecutionError::IllegalInstruction {
165 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
166 });
167 };
168 let group_regs = vtype.vlmul().register_count();
169 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
170 program_counter,
171 vd,
172 group_regs,
173 )?;
174 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
175 program_counter,
176 vs2,
177 group_regs,
178 )?;
179 let sew = vtype.vsew();
180 unsafe {
182 zvbb_helpers::execute_vctz::<Reg, _, _>(ext_state, vd, vs2, sew, vm);
183 }
184 }
185 Self::VcpopV { vd, vs2, vm } => {
187 if !ext_state.vector_instructions_allowed() {
188 ::core::hint::cold_path();
189 return Err(ExecutionError::IllegalInstruction {
190 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
191 });
192 }
193 if !vm && vd == VReg::V0 {
194 ::core::hint::cold_path();
195 return Err(ExecutionError::IllegalInstruction {
196 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
197 });
198 }
199 let Some(vtype) = ext_state.vtype() else {
200 ::core::hint::cold_path();
201 return Err(ExecutionError::IllegalInstruction {
202 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
203 });
204 };
205 let group_regs = vtype.vlmul().register_count();
206 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
207 program_counter,
208 vd,
209 group_regs,
210 )?;
211 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
212 program_counter,
213 vs2,
214 group_regs,
215 )?;
216 let sew = vtype.vsew();
217 unsafe {
219 zvbb_helpers::execute_vcpop::<Reg, _, _>(ext_state, vd, vs2, sew, vm);
220 }
221 }
222 Self::VwsllVv { vd, vs2, vs1, vm } => {
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 sew = vtype.vsew();
244 let Some(double_sew) = sew.double_width() else {
245 ::core::hint::cold_path();
246 return Err(ExecutionError::IllegalInstruction {
247 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
248 });
249 };
250 let group_regs = vtype.vlmul().register_count();
251 let Some(dest_group_regs) =
252 vtype.vlmul().data_register_count(double_sew.as_eew(), sew)
253 else {
254 ::core::hint::cold_path();
255 return Err(ExecutionError::IllegalInstruction {
256 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
257 });
258 };
259 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
260 program_counter,
261 vd,
262 dest_group_regs,
263 )?;
264 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
265 program_counter,
266 vs2,
267 group_regs,
268 )?;
269 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
270 program_counter,
271 vs1,
272 group_regs,
273 )?;
274 unsafe {
276 zvbb_helpers::execute_vwsll::<Reg, _, _>(
277 ext_state,
278 vd,
279 vs2,
280 zvbb_helpers::OpSrc::Vreg(vs1),
281 sew,
282 double_sew,
283 vm,
284 );
285 }
286 }
287 Self::VwsllVx {
288 vm,
289 vd,
290 vs2,
291 rs1: _,
292 } => {
293 if !ext_state.vector_instructions_allowed() {
294 ::core::hint::cold_path();
295 return Err(ExecutionError::IllegalInstruction {
296 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
297 });
298 }
299 if !vm && vd == VReg::V0 {
300 ::core::hint::cold_path();
301 return Err(ExecutionError::IllegalInstruction {
302 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
303 });
304 }
305 let Some(vtype) = ext_state.vtype() else {
306 ::core::hint::cold_path();
307 return Err(ExecutionError::IllegalInstruction {
308 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
309 });
310 };
311 let sew = vtype.vsew();
312 let Some(double_sew) = sew.double_width() else {
313 ::core::hint::cold_path();
314 return Err(ExecutionError::IllegalInstruction {
315 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
316 });
317 };
318 let group_regs = vtype.vlmul().register_count();
319 let Some(dest_group_regs) =
320 vtype.vlmul().data_register_count(double_sew.as_eew(), sew)
321 else {
322 ::core::hint::cold_path();
323 return Err(ExecutionError::IllegalInstruction {
324 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
325 });
326 };
327 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
328 program_counter,
329 vd,
330 dest_group_regs,
331 )?;
332 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
333 program_counter,
334 vs2,
335 group_regs,
336 )?;
337 let scalar = rs1_value.as_i64().cast_unsigned();
338 unsafe {
340 zvbb_helpers::execute_vwsll::<Reg, _, _>(
341 ext_state,
342 vd,
343 vs2,
344 zvbb_helpers::OpSrc::Scalar(scalar),
345 sew,
346 double_sew,
347 vm,
348 );
349 }
350 }
351 Self::VwsllVi { vd, vs2, uimm, vm } => {
353 if !ext_state.vector_instructions_allowed() {
354 ::core::hint::cold_path();
355 return Err(ExecutionError::IllegalInstruction {
356 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
357 });
358 }
359 if !vm && vd == VReg::V0 {
360 ::core::hint::cold_path();
361 return Err(ExecutionError::IllegalInstruction {
362 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
363 });
364 }
365 let Some(vtype) = ext_state.vtype() else {
366 ::core::hint::cold_path();
367 return Err(ExecutionError::IllegalInstruction {
368 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
369 });
370 };
371 let sew = vtype.vsew();
372 let Some(double_sew) = sew.double_width() else {
373 ::core::hint::cold_path();
374 return Err(ExecutionError::IllegalInstruction {
375 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
376 });
377 };
378 let group_regs = vtype.vlmul().register_count();
379 let Some(dest_group_regs) =
380 vtype.vlmul().data_register_count(double_sew.as_eew(), sew)
381 else {
382 ::core::hint::cold_path();
383 return Err(ExecutionError::IllegalInstruction {
384 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
385 });
386 };
387 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
388 program_counter,
389 vd,
390 dest_group_regs,
391 )?;
392 zvbb_helpers::check_vreg_group_alignment::<Reg, _, _, _>(
393 program_counter,
394 vs2,
395 group_regs,
396 )?;
397 unsafe {
399 zvbb_helpers::execute_vwsll::<Reg, _, _>(
400 ext_state,
401 vd,
402 vs2,
403 zvbb_helpers::OpSrc::Scalar(u64::from(uimm)),
404 sew,
405 double_sew,
406 vm,
407 );
408 }
409 }
410 }
411 Ok(ControlFlow::Continue(Default::default()))
412 }
413}