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 [(); ExtState::ELEN as usize]:,
38 [(); ExtState::VLEN as usize]:,
39 [(); ExtState::VLENB as usize]:,
40 Memory: VirtualMemory,
41 PC: ProgramCounter<Reg::Type, Memory, CustomError>,
42 CustomError: fmt::Debug,
43{
44 #[inline(always)]
45 fn execute(
46 self,
47 Rs1Rs2OperandValues {
48 rs1_value: _,
49 rs2_value: _,
50 }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
51 _regs: &mut Regs,
52 ext_state: &mut ExtState,
53 _memory: &mut Memory,
54 program_counter: &mut PC,
55 _system_instruction_handler: &mut InstructionHandler,
56 ) -> Result<
57 ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
58 ExecutionError<Reg::Type, CustomError>,
59 > {
60 match self {
61 Self::Vmandn { vd, vs2, vs1 } => {
68 if !ext_state.vector_instructions_allowed() {
69 ::core::hint::cold_path();
70 return Err(ExecutionError::IllegalInstruction {
71 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
72 });
73 }
74 if ext_state.vtype().is_none() {
75 ::core::hint::cold_path();
76 return Err(ExecutionError::IllegalInstruction {
77 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
78 });
79 }
80 unsafe {
84 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
85 a && !b
86 });
87 }
88 }
89 Self::Vmand { vd, vs2, vs1 } => {
90 if !ext_state.vector_instructions_allowed() {
91 ::core::hint::cold_path();
92 return Err(ExecutionError::IllegalInstruction {
93 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
94 });
95 }
96 if ext_state.vtype().is_none() {
97 ::core::hint::cold_path();
98 return Err(ExecutionError::IllegalInstruction {
99 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
100 });
101 }
102 unsafe {
104 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
105 a & b
106 });
107 }
108 }
109 Self::Vmor { vd, vs2, vs1 } => {
110 if !ext_state.vector_instructions_allowed() {
111 ::core::hint::cold_path();
112 return Err(ExecutionError::IllegalInstruction {
113 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
114 });
115 }
116 if ext_state.vtype().is_none() {
117 ::core::hint::cold_path();
118 return Err(ExecutionError::IllegalInstruction {
119 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
120 });
121 }
122 unsafe {
124 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
125 a | b
126 });
127 }
128 }
129 Self::Vmxor { vd, vs2, vs1 } => {
130 if !ext_state.vector_instructions_allowed() {
131 ::core::hint::cold_path();
132 return Err(ExecutionError::IllegalInstruction {
133 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
134 });
135 }
136 if ext_state.vtype().is_none() {
137 ::core::hint::cold_path();
138 return Err(ExecutionError::IllegalInstruction {
139 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
140 });
141 }
142 unsafe {
144 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
145 a ^ b
146 });
147 }
148 }
149 Self::Vmorn { vd, vs2, vs1 } => {
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 ext_state.vtype().is_none() {
157 ::core::hint::cold_path();
158 return Err(ExecutionError::IllegalInstruction {
159 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
160 });
161 }
162 unsafe {
164 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
165 a || !b
166 });
167 }
168 }
169 Self::Vmnand { vd, vs2, vs1 } => {
170 if !ext_state.vector_instructions_allowed() {
171 ::core::hint::cold_path();
172 return Err(ExecutionError::IllegalInstruction {
173 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
174 });
175 }
176 if ext_state.vtype().is_none() {
177 ::core::hint::cold_path();
178 return Err(ExecutionError::IllegalInstruction {
179 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
180 });
181 }
182 unsafe {
184 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
185 !(a & b)
186 });
187 }
188 }
189 Self::Vmnor { vd, vs2, vs1 } => {
190 if !ext_state.vector_instructions_allowed() {
191 ::core::hint::cold_path();
192 return Err(ExecutionError::IllegalInstruction {
193 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
194 });
195 }
196 if ext_state.vtype().is_none() {
197 ::core::hint::cold_path();
198 return Err(ExecutionError::IllegalInstruction {
199 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
200 });
201 }
202 unsafe {
204 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
205 !(a | b)
206 });
207 }
208 }
209 Self::Vmxnor { vd, vs2, vs1 } => {
210 if !ext_state.vector_instructions_allowed() {
211 ::core::hint::cold_path();
212 return Err(ExecutionError::IllegalInstruction {
213 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
214 });
215 }
216 if ext_state.vtype().is_none() {
217 ::core::hint::cold_path();
218 return Err(ExecutionError::IllegalInstruction {
219 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
220 });
221 }
222 unsafe {
224 zvexx_mask_helpers::execute_mask_logical_op(ext_state, vd, vs2, vs1, |a, b| {
225 !(a ^ b)
226 });
227 }
228 }
229 Self::Vcpop { rd, vs2, vm } => {
231 if !ext_state.vector_instructions_allowed() {
232 ::core::hint::cold_path();
233 return Err(ExecutionError::IllegalInstruction {
234 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
235 });
236 }
237 if ext_state.vtype().is_none() {
239 ::core::hint::cold_path();
240 return Err(ExecutionError::IllegalInstruction {
241 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
242 });
243 }
244 let rd_value = unsafe { zvexx_mask_helpers::execute_vcpop(ext_state, vs2, vm) };
247
248 return Ok(ControlFlow::Continue((rd, rd_value)));
249 }
250 Self::Vfirst { rd, vs2, vm } => {
252 if !ext_state.vector_instructions_allowed() {
253 ::core::hint::cold_path();
254 return Err(ExecutionError::IllegalInstruction {
255 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
256 });
257 }
258 if ext_state.vtype().is_none() {
259 ::core::hint::cold_path();
260 return Err(ExecutionError::IllegalInstruction {
261 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
262 });
263 }
264 let rd_value = unsafe { zvexx_mask_helpers::execute_vfirst(ext_state, vs2, vm) };
266
267 return Ok(ControlFlow::Continue((rd, rd_value)));
268 }
269 Self::Vmsbf { vd, vs2, vm } => {
272 if !ext_state.vector_instructions_allowed() {
273 ::core::hint::cold_path();
274 return Err(ExecutionError::IllegalInstruction {
275 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
276 });
277 }
278 if ext_state.vtype().is_none() {
279 ::core::hint::cold_path();
280 return Err(ExecutionError::IllegalInstruction {
281 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
282 });
283 }
284 if ext_state.vstart() != 0 {
287 ::core::hint::cold_path();
288 return Err(ExecutionError::IllegalInstruction {
289 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
290 });
291 }
292 if vd == vs2 {
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 vl = ext_state.vl();
306 unsafe {
309 zvexx_mask_helpers::execute_vmsbf(ext_state, vd, vs2, vm, vl);
310 }
311 }
312 Self::Vmsof { vd, vs2, vm } => {
315 if !ext_state.vector_instructions_allowed() {
316 ::core::hint::cold_path();
317 return Err(ExecutionError::IllegalInstruction {
318 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
319 });
320 }
321 if ext_state.vtype().is_none() {
322 ::core::hint::cold_path();
323 return Err(ExecutionError::IllegalInstruction {
324 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
325 });
326 }
327 if ext_state.vstart() != 0 {
330 ::core::hint::cold_path();
331 return Err(ExecutionError::IllegalInstruction {
332 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
333 });
334 }
335 if vd == vs2 {
336 ::core::hint::cold_path();
337 return Err(ExecutionError::IllegalInstruction {
338 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
339 });
340 }
341 if !vm && vd == VReg::V0 {
342 ::core::hint::cold_path();
343 return Err(ExecutionError::IllegalInstruction {
344 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
345 });
346 }
347 let vl = ext_state.vl();
348 unsafe {
350 zvexx_mask_helpers::execute_vmsof(ext_state, vd, vs2, vm, vl);
351 }
352 }
353 Self::Vmsif { vd, vs2, vm } => {
356 if !ext_state.vector_instructions_allowed() {
357 ::core::hint::cold_path();
358 return Err(ExecutionError::IllegalInstruction {
359 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
360 });
361 }
362 if ext_state.vtype().is_none() {
363 ::core::hint::cold_path();
364 return Err(ExecutionError::IllegalInstruction {
365 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
366 });
367 }
368 if ext_state.vstart() != 0 {
371 ::core::hint::cold_path();
372 return Err(ExecutionError::IllegalInstruction {
373 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
374 });
375 }
376 if vd == vs2 {
377 ::core::hint::cold_path();
378 return Err(ExecutionError::IllegalInstruction {
379 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
380 });
381 }
382 if !vm && vd == VReg::V0 {
383 ::core::hint::cold_path();
384 return Err(ExecutionError::IllegalInstruction {
385 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
386 });
387 }
388 let vl = ext_state.vl();
389 unsafe {
391 zvexx_mask_helpers::execute_vmsif(ext_state, vd, vs2, vm, vl);
392 }
393 }
394 Self::Viota { vd, vs2, vm } => {
401 if !ext_state.vector_instructions_allowed() {
402 ::core::hint::cold_path();
403 return Err(ExecutionError::IllegalInstruction {
404 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
405 });
406 }
407 let Some(vtype) = ext_state.vtype() else {
408 ::core::hint::cold_path();
409 return Err(ExecutionError::IllegalInstruction {
410 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
411 });
412 };
413 if ext_state.vstart() != 0 {
415 ::core::hint::cold_path();
416 return Err(ExecutionError::IllegalInstruction {
417 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
418 });
419 }
420 let group_regs = vtype.vlmul().register_count();
421 let vd_idx = vd.to_bits();
422 if !vd_idx.is_multiple_of(group_regs) || vd_idx + group_regs > 32 {
423 ::core::hint::cold_path();
424 return Err(ExecutionError::IllegalInstruction {
425 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
426 });
427 }
428 let vd_start = u32::from(vd.to_bits());
430 let vs2_start = u32::from(vs2.to_bits());
431 if vd_start < vs2_start + 1 && vs2_start < vd_start + u32::from(group_regs) {
432 ::core::hint::cold_path();
433 return Err(ExecutionError::IllegalInstruction {
434 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
435 });
436 }
437 if !vm && vd == VReg::V0 {
438 ::core::hint::cold_path();
439 return Err(ExecutionError::IllegalInstruction {
440 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
441 });
442 }
443 let sew = vtype.vsew();
444 let vl = ext_state.vl();
445 unsafe {
449 zvexx_mask_helpers::execute_viota(ext_state, vd, vs2, vm, vl, sew);
450 }
451 }
452 Self::Vid { vd, vm } => {
455 if !ext_state.vector_instructions_allowed() {
456 ::core::hint::cold_path();
457 return Err(ExecutionError::IllegalInstruction {
458 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
459 });
460 }
461 let Some(vtype) = ext_state.vtype() else {
462 ::core::hint::cold_path();
463 return Err(ExecutionError::IllegalInstruction {
464 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
465 });
466 };
467 let group_regs = vtype.vlmul().register_count();
468 let vd_idx = vd.to_bits();
469 if !vd_idx.is_multiple_of(group_regs) || vd_idx + group_regs > 32 {
470 ::core::hint::cold_path();
471 return Err(ExecutionError::IllegalInstruction {
472 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
473 });
474 }
475 if !vm && vd == VReg::V0 {
476 ::core::hint::cold_path();
477 return Err(ExecutionError::IllegalInstruction {
478 address: program_counter.old_pc(zvexx_helpers::INSTRUCTION_SIZE),
479 });
480 }
481 let sew = vtype.vsew();
482 unsafe {
485 zvexx_mask_helpers::execute_vid(ext_state, vd, vm, sew);
486 }
487 }
488 }
489
490 Ok(ControlFlow::Continue(Default::default()))
491 }
492}