1#[cfg(test)]
4mod tests;
5pub mod zvexx_mask_helpers;
6
7use crate::v::vector_registers::VectorRegistersExt;
8use crate::v::zvexx::zvexx_helpers;
9use crate::{
10 ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands, ExecutionError,
11 ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands, VirtualMemory,
12};
13use ab_riscv_macros::instruction_execution;
14use ab_riscv_primitives::prelude::*;
15use core::fmt;
16use core::ops::ControlFlow;
17
18#[instruction_execution]
19impl<Reg> ExecutableInstructionOperands for ZveXxMaskInstruction<Reg> where Reg: Register {}
20
21#[instruction_execution]
22impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
23 for ZveXxMaskInstruction<Reg>
24where
25 Reg: Register,
26{
27}
28
29#[instruction_execution]
30impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
31 ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
32 for ZveXxMaskInstruction<Reg>
33where
34 Reg: Register,
35 Regs: RegisterFile<Reg>,
36 ExtState: VectorRegistersExt<Reg, CustomError>,
37 [(); SUPPORTED_ELEN_VLEN::<{ ExtState::ELEN }, { ExtState::VLEN }>]:,
38 Memory: VirtualMemory,
39 PC: ProgramCounter<Reg::Type, Memory, CustomError>,
40 CustomError: fmt::Debug,
41{
42 #[inline(always)]
43 fn execute(
44 self,
45 Rs1Rs2OperandValues {
46 rs1_value: _,
47 rs2_value: _,
48 }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
49 _regs: &mut Regs,
50 ext_state: &mut ExtState,
51 _memory: &mut Memory,
52 program_counter: &mut PC,
53 _system_instruction_handler: &mut InstructionHandler,
54 ) -> Result<
55 ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
56 ExecutionError<Reg::Type, CustomError>,
57 > {
58 match self {
59 Self::Vmandn { vd, vs2, vs1 } => {
66 if !ext_state.vector_instructions_allowed() {
67 ::core::hint::cold_path();
68 return Err(ExecutionError::IllegalInstruction {
69 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
70 });
71 }
72 if ext_state.vtype().is_none() {
73 ::core::hint::cold_path();
74 return Err(ExecutionError::IllegalInstruction {
75 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
76 });
77 }
78 unsafe {
82 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
83 a && !b
84 });
85 }
86 }
87 Self::Vmand { vd, vs2, vs1 } => {
88 if !ext_state.vector_instructions_allowed() {
89 ::core::hint::cold_path();
90 return Err(ExecutionError::IllegalInstruction {
91 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
92 });
93 }
94 if ext_state.vtype().is_none() {
95 ::core::hint::cold_path();
96 return Err(ExecutionError::IllegalInstruction {
97 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
98 });
99 }
100 unsafe {
102 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
103 a & b
104 });
105 }
106 }
107 Self::Vmor { vd, vs2, vs1 } => {
108 if !ext_state.vector_instructions_allowed() {
109 ::core::hint::cold_path();
110 return Err(ExecutionError::IllegalInstruction {
111 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
112 });
113 }
114 if ext_state.vtype().is_none() {
115 ::core::hint::cold_path();
116 return Err(ExecutionError::IllegalInstruction {
117 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
118 });
119 }
120 unsafe {
122 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
123 a | b
124 });
125 }
126 }
127 Self::Vmxor { vd, vs2, vs1 } => {
128 if !ext_state.vector_instructions_allowed() {
129 ::core::hint::cold_path();
130 return Err(ExecutionError::IllegalInstruction {
131 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
132 });
133 }
134 if ext_state.vtype().is_none() {
135 ::core::hint::cold_path();
136 return Err(ExecutionError::IllegalInstruction {
137 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
138 });
139 }
140 unsafe {
142 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
143 a ^ b
144 });
145 }
146 }
147 Self::Vmorn { vd, vs2, vs1 } => {
148 if !ext_state.vector_instructions_allowed() {
149 ::core::hint::cold_path();
150 return Err(ExecutionError::IllegalInstruction {
151 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
152 });
153 }
154 if ext_state.vtype().is_none() {
155 ::core::hint::cold_path();
156 return Err(ExecutionError::IllegalInstruction {
157 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
158 });
159 }
160 unsafe {
162 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
163 a || !b
164 });
165 }
166 }
167 Self::Vmnand { vd, vs2, vs1 } => {
168 if !ext_state.vector_instructions_allowed() {
169 ::core::hint::cold_path();
170 return Err(ExecutionError::IllegalInstruction {
171 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
172 });
173 }
174 if ext_state.vtype().is_none() {
175 ::core::hint::cold_path();
176 return Err(ExecutionError::IllegalInstruction {
177 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
178 });
179 }
180 unsafe {
182 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
183 !(a & b)
184 });
185 }
186 }
187 Self::Vmnor { vd, vs2, vs1 } => {
188 if !ext_state.vector_instructions_allowed() {
189 ::core::hint::cold_path();
190 return Err(ExecutionError::IllegalInstruction {
191 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
192 });
193 }
194 if ext_state.vtype().is_none() {
195 ::core::hint::cold_path();
196 return Err(ExecutionError::IllegalInstruction {
197 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
198 });
199 }
200 unsafe {
202 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
203 !(a | b)
204 });
205 }
206 }
207 Self::Vmxnor { vd, vs2, vs1 } => {
208 if !ext_state.vector_instructions_allowed() {
209 ::core::hint::cold_path();
210 return Err(ExecutionError::IllegalInstruction {
211 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
212 });
213 }
214 if ext_state.vtype().is_none() {
215 ::core::hint::cold_path();
216 return Err(ExecutionError::IllegalInstruction {
217 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
218 });
219 }
220 unsafe {
222 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
223 !(a ^ b)
224 });
225 }
226 }
227 Self::Vcpop { rd, vs2, vm } => {
229 if !ext_state.vector_instructions_allowed() {
230 ::core::hint::cold_path();
231 return Err(ExecutionError::IllegalInstruction {
232 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
233 });
234 }
235 if ext_state.vtype().is_none() {
237 ::core::hint::cold_path();
238 return Err(ExecutionError::IllegalInstruction {
239 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
240 });
241 }
242 let rd_value = unsafe { zvexx_mask_helpers::execute_vcpop(ext_state, vs2, vm) };
244
245 return Ok(ControlFlow::Continue((rd, rd_value)));
246 }
247 Self::Vfirst { rd, vs2, vm } => {
249 if !ext_state.vector_instructions_allowed() {
250 ::core::hint::cold_path();
251 return Err(ExecutionError::IllegalInstruction {
252 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
253 });
254 }
255 if ext_state.vtype().is_none() {
256 ::core::hint::cold_path();
257 return Err(ExecutionError::IllegalInstruction {
258 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
259 });
260 }
261 let rd_value = unsafe { zvexx_mask_helpers::execute_vfirst(ext_state, vs2, vm) };
263
264 return Ok(ControlFlow::Continue((rd, rd_value)));
265 }
266 Self::Vmsbf { vd, vs2, vm } => {
269 if !ext_state.vector_instructions_allowed() {
270 ::core::hint::cold_path();
271 return Err(ExecutionError::IllegalInstruction {
272 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
273 });
274 }
275 if ext_state.vtype().is_none() {
276 ::core::hint::cold_path();
277 return Err(ExecutionError::IllegalInstruction {
278 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
279 });
280 }
281 if ext_state.vstart() != Vstart::ZERO {
284 ::core::hint::cold_path();
285 return Err(ExecutionError::IllegalInstruction {
286 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
287 });
288 }
289 if vd == vs2 {
291 ::core::hint::cold_path();
292 return Err(ExecutionError::IllegalInstruction {
293 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
294 });
295 }
296 if !vm && vd == VReg::V0 {
297 ::core::hint::cold_path();
298 return Err(ExecutionError::IllegalInstruction {
299 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
300 });
301 }
302 let vl = ext_state.vl();
303 unsafe {
306 zvexx_mask_helpers::execute_vmsbf(ext_state, vd, vs2, vm, vl);
307 }
308 }
309 Self::Vmsof { vd, vs2, vm } => {
312 if !ext_state.vector_instructions_allowed() {
313 ::core::hint::cold_path();
314 return Err(ExecutionError::IllegalInstruction {
315 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
316 });
317 }
318 if ext_state.vtype().is_none() {
319 ::core::hint::cold_path();
320 return Err(ExecutionError::IllegalInstruction {
321 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
322 });
323 }
324 if ext_state.vstart() != Vstart::ZERO {
327 ::core::hint::cold_path();
328 return Err(ExecutionError::IllegalInstruction {
329 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
330 });
331 }
332 if vd == vs2 {
333 ::core::hint::cold_path();
334 return Err(ExecutionError::IllegalInstruction {
335 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
336 });
337 }
338 if !vm && vd == VReg::V0 {
339 ::core::hint::cold_path();
340 return Err(ExecutionError::IllegalInstruction {
341 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
342 });
343 }
344 let vl = ext_state.vl();
345 unsafe {
347 zvexx_mask_helpers::execute_vmsof(ext_state, vd, vs2, vm, vl);
348 }
349 }
350 Self::Vmsif { vd, vs2, 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 ext_state.vtype().is_none() {
360 ::core::hint::cold_path();
361 return Err(ExecutionError::IllegalInstruction {
362 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
363 });
364 }
365 if ext_state.vstart() != Vstart::ZERO {
368 ::core::hint::cold_path();
369 return Err(ExecutionError::IllegalInstruction {
370 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
371 });
372 }
373 if vd == vs2 {
374 ::core::hint::cold_path();
375 return Err(ExecutionError::IllegalInstruction {
376 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
377 });
378 }
379 if !vm && vd == VReg::V0 {
380 ::core::hint::cold_path();
381 return Err(ExecutionError::IllegalInstruction {
382 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
383 });
384 }
385 let vl = ext_state.vl();
386 unsafe {
388 zvexx_mask_helpers::execute_vmsif(ext_state, vd, vs2, vm, vl);
389 }
390 }
391 Self::Viota { vd, vs2, vm } => {
398 if !ext_state.vector_instructions_allowed() {
399 ::core::hint::cold_path();
400 return Err(ExecutionError::IllegalInstruction {
401 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
402 });
403 }
404 let Some(vtype) = ext_state.vtype() else {
405 ::core::hint::cold_path();
406 return Err(ExecutionError::IllegalInstruction {
407 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
408 });
409 };
410 if ext_state.vstart() != Vstart::ZERO {
412 ::core::hint::cold_path();
413 return Err(ExecutionError::IllegalInstruction {
414 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
415 });
416 }
417 let group_regs = vtype.vlmul().register_count().get();
418 let vd_idx = vd.to_bits();
419 if !vd_idx.is_multiple_of(group_regs) || vd_idx + group_regs > 32 {
420 ::core::hint::cold_path();
421 return Err(ExecutionError::IllegalInstruction {
422 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
423 });
424 }
425 let vd_start = u32::from(vd.to_bits());
427 let vs2_start = u32::from(vs2.to_bits());
428 if vd_start < vs2_start + 1 && vs2_start < vd_start + u32::from(group_regs) {
429 ::core::hint::cold_path();
430 return Err(ExecutionError::IllegalInstruction {
431 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
432 });
433 }
434 if !vm && vd == VReg::V0 {
435 ::core::hint::cold_path();
436 return Err(ExecutionError::IllegalInstruction {
437 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
438 });
439 }
440 let sew = vtype.vsew();
441 let vl = ext_state.vl();
442 unsafe {
446 zvexx_mask_helpers::execute_viota(ext_state, vd, vs2, vm, vl, sew);
447 }
448 }
449 Self::Vid { vd, vm } => {
452 if !ext_state.vector_instructions_allowed() {
453 ::core::hint::cold_path();
454 return Err(ExecutionError::IllegalInstruction {
455 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
456 });
457 }
458 let Some(vtype) = ext_state.vtype() else {
459 ::core::hint::cold_path();
460 return Err(ExecutionError::IllegalInstruction {
461 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
462 });
463 };
464 let group_regs = vtype.vlmul().register_count().get();
465 let vd_idx = vd.to_bits();
466 if !vd_idx.is_multiple_of(group_regs) || vd_idx + group_regs > 32 {
467 ::core::hint::cold_path();
468 return Err(ExecutionError::IllegalInstruction {
469 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
470 });
471 }
472 if !vm && vd == VReg::V0 {
473 ::core::hint::cold_path();
474 return Err(ExecutionError::IllegalInstruction {
475 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
476 });
477 }
478 let sew = vtype.vsew();
479 unsafe {
482 zvexx_mask_helpers::execute_vid(ext_state, vd, vm, sew);
483 }
484 }
485 }
486
487 Ok(ControlFlow::Continue(Default::default()))
488 }
489}