1#[cfg(test)]
4mod tests;
5
6use crate::hart::{HartConfig, VectorHartConfig};
7use crate::instructions::v::{Eew, V, VRegGroupSize};
8use crate::instructions::{ImplementedExtension, Instruction, IsaExtension};
9use crate::registers::general_purpose::Register;
10use crate::registers::vector::VReg;
11use ab_riscv_macros::instruction;
12use core::fmt;
13
14#[derive(Debug, Clone, Copy)]
16#[derive_const(PartialEq, Eq)]
17#[repr(u8)]
18pub enum Nf {
19 N1 = 1,
21 N2 = 2,
23 N3 = 3,
25 N4 = 4,
27 N5 = 5,
29 N6 = 6,
31 N7 = 7,
33 N8 = 8,
35}
36
37impl fmt::Display for Nf {
38 #[inline]
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 fmt::Display::fmt(&self.fields_per_segment(), f)
41 }
42}
43
44impl Nf {
45 pub const MAX: Self = Nf::N8;
47
48 #[inline(always)]
52 pub const fn new(nf: u8) -> Option<Self> {
53 match nf {
54 1 => Some(Nf::N1),
55 2 => Some(Nf::N2),
56 3 => Some(Nf::N3),
57 4 => Some(Nf::N4),
58 5 => Some(Nf::N5),
59 6 => Some(Nf::N6),
60 7 => Some(Nf::N7),
61 8 => Some(Nf::N8),
62 _ => None,
63 }
64 }
65
66 #[inline(always)]
70 pub const fn fields_per_segment(&self) -> u8 {
71 *self as u8
72 }
73}
74
75#[derive(Debug, Clone, Copy)]
80#[derive_const(PartialEq, Eq)]
81pub struct SegVmNf(u8);
82
83impl SegVmNf {
84 #[inline(always)]
86 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
87 pub const fn new(vm: bool, nf: Nf) -> Self {
88 Self((nf.fields_per_segment() << 1) | u8::from(vm))
89 }
90
91 #[inline(always)]
93 pub const fn vm(&self) -> bool {
94 self.0 & 1 == 1
95 }
96
97 #[inline(always)]
99 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
100 pub const fn nf(&self) -> Nf {
101 unsafe { Nf::new(self.0 >> 1).unwrap_unchecked() }
103 }
104}
105
106#[derive(Debug, Clone, Copy)]
108#[derive_const(PartialEq, Eq)]
109#[repr(u8)]
110pub enum LoadStoreNreg {
111 N1 = 1,
113 N2 = 2,
115 N4 = 4,
117 N8 = 8,
119}
120
121impl fmt::Display for LoadStoreNreg {
122 #[inline]
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 fmt::Display::fmt(&self.num_registers(), f)
125 }
126}
127
128impl LoadStoreNreg {
129 #[inline(always)]
131 pub const fn new(n: u8) -> Option<Self> {
132 match n {
133 1 => Some(Self::N1),
134 2 => Some(Self::N2),
135 4 => Some(Self::N4),
136 8 => Some(Self::N8),
137 _ => None,
138 }
139 }
140
141 #[inline(always)]
143 pub const fn num_registers(&self) -> VRegGroupSize {
144 match self {
145 Self::N1 => VRegGroupSize::R1,
146 Self::N2 => VRegGroupSize::R2,
147 Self::N4 => VRegGroupSize::R4,
148 Self::N8 => VRegGroupSize::R8,
149 }
150 }
151}
152
153#[instruction]
158#[derive(Debug, Clone, Copy)]
159#[derive_const(PartialEq, Eq)]
160#[rustfmt::skip]
161#[doc(hidden)]
162pub enum ZveXxLoadInstruction<Hart>
163where
164 Hart: HartConfig,
165{
166 Vle { vd: VReg, rs1: Hart::Reg, vm: bool, eew: Eew },
170 Vleff { vd: VReg, rs1: Hart::Reg, vm: bool, eew: Eew },
174 Vlm { vd: VReg, rs1: Hart::Reg },
178 Vlse { vd: VReg, rs1: Hart::Reg, rs2: Hart::Reg, vm: bool, eew: Eew },
182 Vluxei { vd: VReg, rs1: Hart::Reg, vs2: VReg, vm: bool, eew: Eew },
186 Vloxei { vd: VReg, rs1: Hart::Reg, vs2: VReg, vm: bool, eew: Eew },
190 Vlr { vd: VReg, rs1: Hart::Reg, nreg: LoadStoreNreg, eew: Eew },
194 Vlseg { vd: VReg, rs1: Hart::Reg, eew: Eew, vm_nf: SegVmNf },
198 Vlsegff { vd: VReg, rs1: Hart::Reg, eew: Eew, vm_nf: SegVmNf },
202 Vlsseg { vd: VReg, rs1: Hart::Reg, rs2: Hart::Reg, eew: Eew, vm_nf: SegVmNf },
206 Vluxseg { vd: VReg, rs1: Hart::Reg, vs2: VReg, eew: Eew, vm_nf: SegVmNf },
210 Vloxseg { vd: VReg, rs1: Hart::Reg, vs2: VReg, eew: Eew, vm_nf: SegVmNf },
214}
215
216#[instruction]
217const impl<Reg, Hart> Instruction for ZveXxLoadInstruction<Hart>
218where
219 Reg: [const] Register,
220 Hart: [const] VectorHartConfig<Reg = Reg>,
221{
222 const OWN_ISA_EXTENSIONS: &'static [IsaExtension] = &[];
223
224 const ALIGNMENT: u8 = align_of::<u32>() as u8;
225
226 type Hart = Hart;
227
228 #[inline(always)]
229 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
230 fn try_decode(instruction: u32) -> Option<Self> {
231 let opcode = (instruction & 0b111_1111) as u8;
232
233 if opcode != 0b000_0111 {
235 None?;
236 }
237
238 let vd_bits = ((instruction >> 7) & 0x1f) as u8;
239 let width = ((instruction >> 12) & 0b111) as u8;
240 let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
241 let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
242 let vm = ((instruction >> 25) & 1) != 0;
243 let mop = ((instruction >> 26) & 0b11) as u8;
244 let mew = ((instruction >> 28) & 1) as u8;
245 let nf = ((instruction >> 29) & 0b111) as u8;
246
247 if mew != 0 {
249 None?;
250 }
251
252 let vd = VReg::from_bits(vd_bits)?;
253 if vd.is_mask(vm) {
254 None?;
255 }
256 let rs1 = Reg::from_bits(rs1_bits)?;
257
258 let nf_val = nf + 1;
260
261 match mop {
262 0b00 => {
264 let lumop = rs2_bits;
265 match lumop {
266 0b0_0000 => {
268 let eew = Eew::from_width(width)?;
269 if !Hart::VECTOR_LENGTHS.elen.supports(eew) {
271 None?;
272 }
273 if nf == 0 {
274 Some(Self::Vle { vd, rs1, vm, eew })
275 } else {
276 Some(Self::Vlseg {
277 vd,
278 rs1,
279 eew,
280 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
281 })
282 }
283 }
284 0b0_1000 => {
286 if !vm {
288 None?;
289 }
290 let eew = Eew::from_width(width)?;
291 if !Hart::VECTOR_LENGTHS.elen.supports(eew) {
293 None?;
294 }
295 let nreg = LoadStoreNreg::new(nf_val)?;
296 Some(Self::Vlr { vd, rs1, nreg, eew })
297 }
298 0b0_1011 => {
300 if width != 0b000 || !vm || nf != 0 {
302 None?;
303 }
304 Some(Self::Vlm { vd, rs1 })
305 }
306 0b1_0000 => {
308 let eew = Eew::from_width(width)?;
309 if !Hart::VECTOR_LENGTHS.elen.supports(eew) {
311 None?;
312 }
313 if nf == 0 {
314 Some(Self::Vleff { vd, rs1, vm, eew })
315 } else {
316 Some(Self::Vlsegff {
317 vd,
318 rs1,
319 eew,
320 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
321 })
322 }
323 }
324 _ => None,
325 }
326 }
327 0b01 => {
329 let eew = Eew::from_width(width)?;
330 if !Hart::VECTOR_LENGTHS.elen.supports(eew) {
332 None?;
333 }
334 let vs2 = VReg::from_bits(rs2_bits)?;
335 if vs2.is_mask(vm) {
336 None?;
337 }
338
339 if !Self::implements_extension::<V<_>>()
340 && Reg::XLEN == u32::BITS as u8
341 && eew == Eew::E64
342 {
343 None?;
344 }
345
346 if nf == 0 {
347 Some(Self::Vluxei {
348 vd,
349 rs1,
350 vs2,
351 vm,
352 eew,
353 })
354 } else {
355 Some(Self::Vluxseg {
356 vd,
357 rs1,
358 vs2,
359 eew,
360 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
361 })
362 }
363 }
364 0b10 => {
366 let eew = Eew::from_width(width)?;
367 if !Hart::VECTOR_LENGTHS.elen.supports(eew) {
369 None?;
370 }
371 let rs2 = Reg::from_bits(rs2_bits)?;
372 if nf == 0 {
373 Some(Self::Vlse {
374 vd,
375 rs1,
376 rs2,
377 vm,
378 eew,
379 })
380 } else {
381 Some(Self::Vlsseg {
382 vd,
383 rs1,
384 rs2,
385 eew,
386 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
387 })
388 }
389 }
390 0b11 => {
392 let eew = Eew::from_width(width)?;
393 if !Hart::VECTOR_LENGTHS.elen.supports(eew) {
395 None?;
396 }
397 let vs2 = VReg::from_bits(rs2_bits)?;
398 if vs2.is_mask(vm) {
399 None?;
400 }
401
402 if !Self::implements_extension::<V<_>>()
403 && Reg::XLEN == u32::BITS as u8
404 && eew == Eew::E64
405 {
406 None?;
407 }
408
409 if nf == 0 {
410 Some(Self::Vloxei {
411 vd,
412 rs1,
413 vs2,
414 vm,
415 eew,
416 })
417 } else {
418 Some(Self::Vloxseg {
419 vd,
420 rs1,
421 vs2,
422 eew,
423 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
424 })
425 }
426 }
427 _ => None,
428 }
429 }
430
431 #[inline(always)]
432 fn size(&self) -> u8 {
433 size_of::<u32>() as u8
434 }
435}
436
437#[instruction]
438impl<Reg, Hart> fmt::Display for ZveXxLoadInstruction<Hart>
439where
440 Reg: fmt::Display,
441 Hart: HartConfig<Reg = Reg>,
442{
443 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
444 #[rustfmt::skip]
445 match self {
446 Self::Vle { vd, rs1, vm, eew } => write!(f, "vle{eew}.v {vd}, ({rs1}){}", mask_suffix(vm)),
447 Self::Vleff { vd, rs1, vm, eew } => write!(f, "vle{eew}ff.v {vd}, ({rs1}){}", mask_suffix(vm)),
448 Self::Vlm { vd, rs1 } => write!(f, "vlm.v {vd}, ({rs1})"),
449 Self::Vlse { vd, rs1, rs2, vm, eew } => write!(f, "vlse{eew}.v {vd}, ({rs1}), {rs2}{}", mask_suffix(vm)),
450 Self::Vluxei { vd, rs1, vs2, vm, eew } => write!(f, "vluxei{eew}.v {vd}, ({rs1}), {vs2}{}", mask_suffix(vm)),
451 Self::Vloxei { vd, rs1, vs2, vm, eew } => write!(f, "vloxei{eew}.v {vd}, ({rs1}), {vs2}{}", mask_suffix(vm)),
452 Self::Vlr { vd, rs1, nreg, eew } => write!(f, "vl{nreg}re{eew}.v {vd}, ({rs1})"),
453 Self::Vlseg { vd, rs1, eew, vm_nf } => write!(f, "vlseg{}e{eew}.v {vd}, ({rs1}){}", vm_nf.nf(), mask_suffix(&vm_nf.vm())),
454 Self::Vlsegff { vd, rs1, eew, vm_nf } => write!(f, "vlseg{}e{eew}ff.v {vd}, ({rs1}){}", vm_nf.nf(), mask_suffix(&vm_nf.vm())),
455 Self::Vlsseg { vd, rs1, rs2, eew, vm_nf } => write!(f, "vlsseg{}e{eew}.v {vd}, ({rs1}), {rs2}{}", vm_nf.nf(), mask_suffix(&vm_nf.vm())),
456 Self::Vluxseg { vd, rs1, vs2, eew, vm_nf } => write!(f, "vluxseg{}ei{eew}.v {vd}, ({rs1}), {vs2}{}", vm_nf.nf(), mask_suffix(&vm_nf.vm())),
457 Self::Vloxseg { vd, rs1, vs2, eew, vm_nf } => write!(f, "vloxseg{}ei{eew}.v {vd}, ({rs1}), {vs2}{}", vm_nf.nf(), mask_suffix(&vm_nf.vm())),
458 }
459 }
460}
461
462#[inline(always)]
464fn mask_suffix(vm: &bool) -> &'static str {
465 if *vm { "" } else { ", v0.t" }
466}