1#[cfg(test)]
4mod tests;
5
6use crate::instructions::Instruction;
7use crate::instructions::v::Eew;
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, PartialEq, Eq)]
15#[repr(u8)]
16pub enum Nf {
17 N1 = 1,
19 N2 = 2,
21 N3 = 3,
23 N4 = 4,
25 N5 = 5,
27 N6 = 6,
29 N7 = 7,
31 N8 = 8,
33}
34
35impl fmt::Display for Nf {
36 #[inline]
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 fmt::Display::fmt(&self.fields_per_segment(), f)
39 }
40}
41
42impl Nf {
43 pub const MAX: Self = Nf::N8;
45
46 #[inline(always)]
50 pub const fn new(nf: u8) -> Option<Self> {
51 match nf {
52 1 => Some(Nf::N1),
53 2 => Some(Nf::N2),
54 3 => Some(Nf::N3),
55 4 => Some(Nf::N4),
56 5 => Some(Nf::N5),
57 6 => Some(Nf::N6),
58 7 => Some(Nf::N7),
59 8 => Some(Nf::N8),
60 _ => None,
61 }
62 }
63
64 #[inline(always)]
68 pub const fn fields_per_segment(&self) -> u8 {
69 *self as u8
70 }
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub struct SegVmNf(u8);
79
80impl SegVmNf {
81 #[inline(always)]
83 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
84 pub const fn new(vm: bool, nf: Nf) -> Self {
85 Self((nf.fields_per_segment() << 1) | u8::from(vm))
86 }
87
88 #[inline(always)]
90 pub const fn vm(&self) -> bool {
91 self.0 & 1 == 1
92 }
93
94 #[inline(always)]
96 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
97 pub const fn nf(&self) -> Nf {
98 unsafe { Nf::new(self.0 >> 1).unwrap_unchecked() }
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105#[repr(u8)]
106pub enum LoadStoreNreg {
107 N1 = 1,
109 N2 = 2,
111 N4 = 4,
113 N8 = 8,
115}
116
117impl fmt::Display for LoadStoreNreg {
118 #[inline]
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 fmt::Display::fmt(&self.num_registers(), f)
121 }
122}
123
124impl LoadStoreNreg {
125 #[inline(always)]
127 pub const fn new(n: u8) -> Option<Self> {
128 match n {
129 1 => Some(Self::N1),
130 2 => Some(Self::N2),
131 4 => Some(Self::N4),
132 8 => Some(Self::N8),
133 _ => None,
134 }
135 }
136
137 #[inline(always)]
139 pub const fn num_registers(&self) -> u8 {
140 *self as u8
141 }
142}
143
144#[instruction]
149#[derive(Debug, Clone, Copy, PartialEq, Eq)]
150#[rustfmt::skip]
151#[doc(hidden)]
152pub enum ZveXxLoadInstruction<Reg> {
153 Vle { vd: VReg, rs1: Reg, vm: bool, eew: Eew },
157 Vleff { vd: VReg, rs1: Reg, vm: bool, eew: Eew },
161 Vlm { vd: VReg, rs1: Reg },
165 Vlse { vd: VReg, rs1: Reg, rs2: Reg, vm: bool, eew: Eew },
169 Vluxei { vd: VReg, rs1: Reg, vs2: VReg, vm: bool, eew: Eew },
173 Vloxei { vd: VReg, rs1: Reg, vs2: VReg, vm: bool, eew: Eew },
177 Vlr { vd: VReg, rs1: Reg, nreg: LoadStoreNreg, eew: Eew },
181 Vlseg { vd: VReg, rs1: Reg, eew: Eew, vm_nf: SegVmNf },
185 Vlsegff { vd: VReg, rs1: Reg, eew: Eew, vm_nf: SegVmNf },
189 Vlsseg { vd: VReg, rs1: Reg, rs2: Reg, eew: Eew, vm_nf: SegVmNf },
193 Vluxseg { vd: VReg, rs1: Reg, vs2: VReg, eew: Eew, vm_nf: SegVmNf },
197 Vloxseg { vd: VReg, rs1: Reg, vs2: VReg, eew: Eew, vm_nf: SegVmNf },
201}
202
203#[instruction]
204const impl<Reg> Instruction for ZveXxLoadInstruction<Reg>
205where
206 Reg: [const] Register,
207{
208 type Reg = Reg;
209
210 #[inline(always)]
211 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
212 fn try_decode(instruction: u32) -> Option<Self> {
213 let opcode = (instruction & 0b111_1111) as u8;
214
215 if opcode != 0b000_0111 {
217 None?;
218 }
219
220 let vd_bits = ((instruction >> 7) & 0x1f) as u8;
221 let width = ((instruction >> 12) & 0b111) as u8;
222 let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
223 let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
224 let vm = ((instruction >> 25) & 1) != 0;
225 let mop = ((instruction >> 26) & 0b11) as u8;
226 let mew = ((instruction >> 28) & 1) as u8;
227 let nf = ((instruction >> 29) & 0b111) as u8;
228
229 if mew != 0 {
231 None?;
232 }
233
234 let vd = VReg::from_bits(vd_bits)?;
235 let rs1 = Reg::from_bits(rs1_bits)?;
236
237 let nf_val = nf + 1;
239
240 match mop {
241 0b00 => {
243 let lumop = rs2_bits;
244 match lumop {
245 0b0_0000 => {
247 let eew = Eew::from_width(width)?;
248 if nf == 0 {
249 Some(Self::Vle { vd, rs1, vm, eew })
250 } else {
251 Some(Self::Vlseg {
252 vd,
253 rs1,
254 eew,
255 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
256 })
257 }
258 }
259 0b0_1000 => {
261 if !vm {
263 None?;
264 }
265 let eew = Eew::from_width(width)?;
266 let nreg = LoadStoreNreg::new(nf_val)?;
267 Some(Self::Vlr { vd, rs1, nreg, eew })
268 }
269 0b0_1011 => {
271 if width != 0b000 || !vm || nf != 0 {
273 None?;
274 }
275 Some(Self::Vlm { vd, rs1 })
276 }
277 0b1_0000 => {
279 let eew = Eew::from_width(width)?;
280 if nf == 0 {
281 Some(Self::Vleff { vd, rs1, vm, eew })
282 } else {
283 Some(Self::Vlsegff {
284 vd,
285 rs1,
286 eew,
287 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
288 })
289 }
290 }
291 _ => None,
292 }
293 }
294 0b01 => {
296 let eew = Eew::from_width(width)?;
297 let vs2 = VReg::from_bits(rs2_bits)?;
298 if nf == 0 {
299 Some(Self::Vluxei {
300 vd,
301 rs1,
302 vs2,
303 vm,
304 eew,
305 })
306 } else {
307 Some(Self::Vluxseg {
308 vd,
309 rs1,
310 vs2,
311 eew,
312 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
313 })
314 }
315 }
316 0b10 => {
318 let eew = Eew::from_width(width)?;
319 let rs2 = Reg::from_bits(rs2_bits)?;
320 if nf == 0 {
321 Some(Self::Vlse {
322 vd,
323 rs1,
324 rs2,
325 vm,
326 eew,
327 })
328 } else {
329 Some(Self::Vlsseg {
330 vd,
331 rs1,
332 rs2,
333 eew,
334 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
335 })
336 }
337 }
338 0b11 => {
340 let eew = Eew::from_width(width)?;
341 let vs2 = VReg::from_bits(rs2_bits)?;
342 if nf == 0 {
343 Some(Self::Vloxei {
344 vd,
345 rs1,
346 vs2,
347 vm,
348 eew,
349 })
350 } else {
351 Some(Self::Vloxseg {
352 vd,
353 rs1,
354 vs2,
355 eew,
356 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
357 })
358 }
359 }
360 _ => None,
361 }
362 }
363
364 #[inline(always)]
365 fn alignment() -> u8 {
366 align_of::<u32>() as u8
367 }
368
369 #[inline(always)]
370 fn size(&self) -> u8 {
371 size_of::<u32>() as u8
372 }
373}
374
375#[instruction]
376impl<Reg> fmt::Display for ZveXxLoadInstruction<Reg>
377where
378 Reg: fmt::Display,
379{
380 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
381 #[rustfmt::skip]
382 match self {
383 Self::Vle { vd, rs1, vm, eew } => write!(f, "vle{eew}.v {vd}, ({rs1}){}", mask_suffix(vm)),
384 Self::Vleff { vd, rs1, vm, eew } => write!(f, "vle{eew}ff.v {vd}, ({rs1}){}", mask_suffix(vm)),
385 Self::Vlm { vd, rs1 } => write!(f, "vlm.v {vd}, ({rs1})"),
386 Self::Vlse { vd, rs1, rs2, vm, eew } => write!(f, "vlse{eew}.v {vd}, ({rs1}), {rs2}{}", mask_suffix(vm)),
387 Self::Vluxei { vd, rs1, vs2, vm, eew } => write!(f, "vluxei{eew}.v {vd}, ({rs1}), {vs2}{}", mask_suffix(vm)),
388 Self::Vloxei { vd, rs1, vs2, vm, eew } => write!(f, "vloxei{eew}.v {vd}, ({rs1}), {vs2}{}", mask_suffix(vm)),
389 Self::Vlr { vd, rs1, nreg, eew } => write!(f, "vl{nreg}re{eew}.v {vd}, ({rs1})"),
390 Self::Vlseg { vd, rs1, eew, vm_nf } => write!(f, "vlseg{}e{eew}.v {vd}, ({rs1}){}", vm_nf.nf(), mask_suffix(&vm_nf.vm())),
391 Self::Vlsegff { vd, rs1, eew, vm_nf } => write!(f, "vlseg{}e{eew}ff.v {vd}, ({rs1}){}", vm_nf.nf(), mask_suffix(&vm_nf.vm())),
392 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())),
393 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())),
394 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())),
395 }
396 }
397}
398
399#[inline(always)]
401fn mask_suffix(vm: &bool) -> &'static str {
402 if *vm { "" } else { ", v0.t" }
403}