1#[cfg(test)]
4mod tests;
5
6use crate::instructions::Instruction;
7use crate::instructions::v::{Eew, V, VRegGroupSize};
8use crate::registers::general_purpose::Register;
9use crate::registers::vector::VReg;
10use ab_riscv_macros::instruction;
11use core::fmt;
12
13#[derive(Debug, Clone, Copy)]
15#[derive_const(PartialEq, Eq)]
16#[repr(u8)]
17pub enum Nf {
18 N1 = 1,
20 N2 = 2,
22 N3 = 3,
24 N4 = 4,
26 N5 = 5,
28 N6 = 6,
30 N7 = 7,
32 N8 = 8,
34}
35
36impl fmt::Display for Nf {
37 #[inline]
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 fmt::Display::fmt(&self.fields_per_segment(), f)
40 }
41}
42
43impl Nf {
44 pub const MAX: Self = Nf::N8;
46
47 #[inline(always)]
51 pub const fn new(nf: u8) -> Option<Self> {
52 match nf {
53 1 => Some(Nf::N1),
54 2 => Some(Nf::N2),
55 3 => Some(Nf::N3),
56 4 => Some(Nf::N4),
57 5 => Some(Nf::N5),
58 6 => Some(Nf::N6),
59 7 => Some(Nf::N7),
60 8 => Some(Nf::N8),
61 _ => None,
62 }
63 }
64
65 #[inline(always)]
69 pub const fn fields_per_segment(&self) -> u8 {
70 *self as u8
71 }
72}
73
74#[derive(Debug, Clone, Copy)]
79#[derive_const(PartialEq, Eq)]
80pub struct SegVmNf(u8);
81
82impl SegVmNf {
83 #[inline(always)]
85 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
86 pub const fn new(vm: bool, nf: Nf) -> Self {
87 Self((nf.fields_per_segment() << 1) | u8::from(vm))
88 }
89
90 #[inline(always)]
92 pub const fn vm(&self) -> bool {
93 self.0 & 1 == 1
94 }
95
96 #[inline(always)]
98 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
99 pub const fn nf(&self) -> Nf {
100 unsafe { Nf::new(self.0 >> 1).unwrap_unchecked() }
102 }
103}
104
105#[derive(Debug, Clone, Copy)]
107#[derive_const(PartialEq, Eq)]
108#[repr(u8)]
109pub enum LoadStoreNreg {
110 N1 = 1,
112 N2 = 2,
114 N4 = 4,
116 N8 = 8,
118}
119
120impl fmt::Display for LoadStoreNreg {
121 #[inline]
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 fmt::Display::fmt(&self.num_registers(), f)
124 }
125}
126
127impl LoadStoreNreg {
128 #[inline(always)]
130 pub const fn new(n: u8) -> Option<Self> {
131 match n {
132 1 => Some(Self::N1),
133 2 => Some(Self::N2),
134 4 => Some(Self::N4),
135 8 => Some(Self::N8),
136 _ => None,
137 }
138 }
139
140 #[inline(always)]
142 pub const fn num_registers(&self) -> VRegGroupSize {
143 match self {
144 Self::N1 => VRegGroupSize::R1,
145 Self::N2 => VRegGroupSize::R2,
146 Self::N4 => VRegGroupSize::R4,
147 Self::N8 => VRegGroupSize::R8,
148 }
149 }
150}
151
152#[instruction]
157#[derive(Debug, Clone, Copy)]
158#[derive_const(PartialEq, Eq)]
159#[rustfmt::skip]
160#[doc(hidden)]
161pub enum ZveXxLoadInstruction<Reg> {
162 Vle { vd: VReg, rs1: Reg, vm: bool, eew: Eew },
166 Vleff { vd: VReg, rs1: Reg, vm: bool, eew: Eew },
170 Vlm { vd: VReg, rs1: Reg },
174 Vlse { vd: VReg, rs1: Reg, rs2: Reg, vm: bool, eew: Eew },
178 Vluxei { vd: VReg, rs1: Reg, vs2: VReg, vm: bool, eew: Eew },
182 Vloxei { vd: VReg, rs1: Reg, vs2: VReg, vm: bool, eew: Eew },
186 Vlr { vd: VReg, rs1: Reg, nreg: LoadStoreNreg, eew: Eew },
190 Vlseg { vd: VReg, rs1: Reg, eew: Eew, vm_nf: SegVmNf },
194 Vlsegff { vd: VReg, rs1: Reg, eew: Eew, vm_nf: SegVmNf },
198 Vlsseg { vd: VReg, rs1: Reg, rs2: Reg, eew: Eew, vm_nf: SegVmNf },
202 Vluxseg { vd: VReg, rs1: Reg, vs2: VReg, eew: Eew, vm_nf: SegVmNf },
206 Vloxseg { vd: VReg, rs1: Reg, vs2: VReg, eew: Eew, vm_nf: SegVmNf },
210}
211
212#[instruction]
213const impl<Reg> Instruction for ZveXxLoadInstruction<Reg>
214where
215 Reg: [const] Register,
216{
217 const ALIGNMENT: u8 = align_of::<u32>() as u8;
218
219 type Reg = Reg;
220
221 #[inline(always)]
222 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
223 fn try_decode(instruction: u32) -> Option<Self> {
224 let opcode = (instruction & 0b111_1111) as u8;
225
226 if opcode != 0b000_0111 {
228 None?;
229 }
230
231 let vd_bits = ((instruction >> 7) & 0x1f) as u8;
232 let width = ((instruction >> 12) & 0b111) as u8;
233 let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
234 let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
235 let vm = ((instruction >> 25) & 1) != 0;
236 let mop = ((instruction >> 26) & 0b11) as u8;
237 let mew = ((instruction >> 28) & 1) as u8;
238 let nf = ((instruction >> 29) & 0b111) as u8;
239
240 if mew != 0 {
242 None?;
243 }
244
245 let vd = VReg::from_bits(vd_bits)?;
246 let rs1 = Reg::from_bits(rs1_bits)?;
247
248 let nf_val = nf + 1;
250
251 match mop {
252 0b00 => {
254 let lumop = rs2_bits;
255 match lumop {
256 0b0_0000 => {
258 let eew = Eew::from_width(width)?;
259 if nf == 0 {
260 Some(Self::Vle { vd, rs1, vm, eew })
261 } else {
262 Some(Self::Vlseg {
263 vd,
264 rs1,
265 eew,
266 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
267 })
268 }
269 }
270 0b0_1000 => {
272 if !vm {
274 None?;
275 }
276 let eew = Eew::from_width(width)?;
277 let nreg = LoadStoreNreg::new(nf_val)?;
278 Some(Self::Vlr { vd, rs1, nreg, eew })
279 }
280 0b0_1011 => {
282 if width != 0b000 || !vm || nf != 0 {
284 None?;
285 }
286 Some(Self::Vlm { vd, rs1 })
287 }
288 0b1_0000 => {
290 let eew = Eew::from_width(width)?;
291 if nf == 0 {
292 Some(Self::Vleff { vd, rs1, vm, eew })
293 } else {
294 Some(Self::Vlsegff {
295 vd,
296 rs1,
297 eew,
298 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
299 })
300 }
301 }
302 _ => None,
303 }
304 }
305 0b01 => {
307 let eew = Eew::from_width(width)?;
308 let vs2 = VReg::from_bits(rs2_bits)?;
309
310 if !Self::implements_extension::<V<_>>()
311 && Reg::XLEN == u32::BITS as u8
312 && eew == Eew::E64
313 {
314 None?;
315 }
316
317 if nf == 0 {
318 Some(Self::Vluxei {
319 vd,
320 rs1,
321 vs2,
322 vm,
323 eew,
324 })
325 } else {
326 Some(Self::Vluxseg {
327 vd,
328 rs1,
329 vs2,
330 eew,
331 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
332 })
333 }
334 }
335 0b10 => {
337 let eew = Eew::from_width(width)?;
338 let rs2 = Reg::from_bits(rs2_bits)?;
339 if nf == 0 {
340 Some(Self::Vlse {
341 vd,
342 rs1,
343 rs2,
344 vm,
345 eew,
346 })
347 } else {
348 Some(Self::Vlsseg {
349 vd,
350 rs1,
351 rs2,
352 eew,
353 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
354 })
355 }
356 }
357 0b11 => {
359 let eew = Eew::from_width(width)?;
360 let vs2 = VReg::from_bits(rs2_bits)?;
361
362 if !Self::implements_extension::<V<_>>()
363 && Reg::XLEN == u32::BITS as u8
364 && eew == Eew::E64
365 {
366 None?;
367 }
368
369 if nf == 0 {
370 Some(Self::Vloxei {
371 vd,
372 rs1,
373 vs2,
374 vm,
375 eew,
376 })
377 } else {
378 Some(Self::Vloxseg {
379 vd,
380 rs1,
381 vs2,
382 eew,
383 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
384 })
385 }
386 }
387 _ => None,
388 }
389 }
390
391 #[inline(always)]
392 fn size(&self) -> u8 {
393 size_of::<u32>() as u8
394 }
395}
396
397#[instruction]
398impl<Reg> fmt::Display for ZveXxLoadInstruction<Reg>
399where
400 Reg: fmt::Display,
401{
402 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
403 #[rustfmt::skip]
404 match self {
405 Self::Vle { vd, rs1, vm, eew } => write!(f, "vle{eew}.v {vd}, ({rs1}){}", mask_suffix(vm)),
406 Self::Vleff { vd, rs1, vm, eew } => write!(f, "vle{eew}ff.v {vd}, ({rs1}){}", mask_suffix(vm)),
407 Self::Vlm { vd, rs1 } => write!(f, "vlm.v {vd}, ({rs1})"),
408 Self::Vlse { vd, rs1, rs2, vm, eew } => write!(f, "vlse{eew}.v {vd}, ({rs1}), {rs2}{}", mask_suffix(vm)),
409 Self::Vluxei { vd, rs1, vs2, vm, eew } => write!(f, "vluxei{eew}.v {vd}, ({rs1}), {vs2}{}", mask_suffix(vm)),
410 Self::Vloxei { vd, rs1, vs2, vm, eew } => write!(f, "vloxei{eew}.v {vd}, ({rs1}), {vs2}{}", mask_suffix(vm)),
411 Self::Vlr { vd, rs1, nreg, eew } => write!(f, "vl{nreg}re{eew}.v {vd}, ({rs1})"),
412 Self::Vlseg { vd, rs1, eew, vm_nf } => write!(f, "vlseg{}e{eew}.v {vd}, ({rs1}){}", vm_nf.nf(), mask_suffix(&vm_nf.vm())),
413 Self::Vlsegff { vd, rs1, eew, vm_nf } => write!(f, "vlseg{}e{eew}ff.v {vd}, ({rs1}){}", vm_nf.nf(), mask_suffix(&vm_nf.vm())),
414 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())),
415 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())),
416 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())),
417 }
418 }
419}
420
421#[inline(always)]
423fn mask_suffix(vm: &bool) -> &'static str {
424 if *vm { "" } else { ", v0.t" }
425}