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 pub const fn new(vm: bool, nf: Nf) -> Self {
84 Self((nf.fields_per_segment() << 1) | u8::from(vm))
85 }
86
87 #[inline(always)]
89 pub const fn vm(&self) -> bool {
90 self.0 & 1 == 1
91 }
92
93 #[inline(always)]
95 pub const fn nf(&self) -> Nf {
96 unsafe { Nf::new(self.0 >> 1).unwrap_unchecked() }
98 }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103#[repr(u8)]
104pub enum LoadStoreNreg {
105 N1 = 1,
107 N2 = 2,
109 N4 = 4,
111 N8 = 8,
113}
114
115impl fmt::Display for LoadStoreNreg {
116 #[inline]
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 fmt::Display::fmt(&self.num_registers(), f)
119 }
120}
121
122impl LoadStoreNreg {
123 #[inline(always)]
125 pub const fn new(n: u8) -> Option<Self> {
126 match n {
127 1 => Some(Self::N1),
128 2 => Some(Self::N2),
129 4 => Some(Self::N4),
130 8 => Some(Self::N8),
131 _ => None,
132 }
133 }
134
135 #[inline(always)]
137 pub const fn num_registers(&self) -> u8 {
138 *self as u8
139 }
140}
141
142#[instruction]
147#[derive(Debug, Clone, Copy, PartialEq, Eq)]
148#[rustfmt::skip]
149#[doc(hidden)]
150pub enum ZveXxLoadInstruction<Reg> {
151 Vle { vd: VReg, rs1: Reg, vm: bool, eew: Eew },
155 Vleff { vd: VReg, rs1: Reg, vm: bool, eew: Eew },
159 Vlm { vd: VReg, rs1: Reg },
163 Vlse { vd: VReg, rs1: Reg, rs2: Reg, vm: bool, eew: Eew },
167 Vluxei { vd: VReg, rs1: Reg, vs2: VReg, vm: bool, eew: Eew },
171 Vloxei { vd: VReg, rs1: Reg, vs2: VReg, vm: bool, eew: Eew },
175 Vlr { vd: VReg, rs1: Reg, nreg: LoadStoreNreg, eew: Eew },
179 Vlseg { vd: VReg, rs1: Reg, eew: Eew, vm_nf: SegVmNf },
183 Vlsegff { vd: VReg, rs1: Reg, eew: Eew, vm_nf: SegVmNf },
187 Vlsseg { vd: VReg, rs1: Reg, rs2: Reg, eew: Eew, vm_nf: SegVmNf },
191 Vluxseg { vd: VReg, rs1: Reg, vs2: VReg, eew: Eew, vm_nf: SegVmNf },
195 Vloxseg { vd: VReg, rs1: Reg, vs2: VReg, eew: Eew, vm_nf: SegVmNf },
199}
200
201#[instruction]
202impl<Reg> const Instruction for ZveXxLoadInstruction<Reg>
203where
204 Reg: [const] Register,
205{
206 type Reg = Reg;
207
208 #[inline(always)]
209 fn try_decode(instruction: u32) -> Option<Self> {
210 let opcode = (instruction & 0b111_1111) as u8;
211
212 if opcode != 0b000_0111 {
214 None?;
215 }
216
217 let vd_bits = ((instruction >> 7) & 0x1f) as u8;
218 let width = ((instruction >> 12) & 0b111) as u8;
219 let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
220 let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
221 let vm = ((instruction >> 25) & 1) != 0;
222 let mop = ((instruction >> 26) & 0b11) as u8;
223 let mew = ((instruction >> 28) & 1) as u8;
224 let nf = ((instruction >> 29) & 0b111) as u8;
225
226 if mew != 0 {
228 None?;
229 }
230
231 let vd = VReg::from_bits(vd_bits)?;
232 let rs1 = Reg::from_bits(rs1_bits)?;
233
234 let nf_val = nf + 1;
236
237 match mop {
238 0b00 => {
240 let lumop = rs2_bits;
241 match lumop {
242 0b0_0000 => {
244 let eew = Eew::from_width(width)?;
245 if nf == 0 {
246 Some(Self::Vle { vd, rs1, vm, eew })
247 } else {
248 Some(Self::Vlseg {
249 vd,
250 rs1,
251 eew,
252 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
253 })
254 }
255 }
256 0b0_1000 => {
258 if !vm {
260 None?;
261 }
262 let eew = Eew::from_width(width)?;
263 let nreg = LoadStoreNreg::new(nf_val)?;
264 Some(Self::Vlr { vd, rs1, nreg, eew })
265 }
266 0b0_1011 => {
268 if width != 0b000 || !vm || nf != 0 {
270 None?;
271 }
272 Some(Self::Vlm { vd, rs1 })
273 }
274 0b1_0000 => {
276 let eew = Eew::from_width(width)?;
277 if nf == 0 {
278 Some(Self::Vleff { vd, rs1, vm, eew })
279 } else {
280 Some(Self::Vlsegff {
281 vd,
282 rs1,
283 eew,
284 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
285 })
286 }
287 }
288 _ => None,
289 }
290 }
291 0b01 => {
293 let eew = Eew::from_width(width)?;
294 let vs2 = VReg::from_bits(rs2_bits)?;
295 if nf == 0 {
296 Some(Self::Vluxei {
297 vd,
298 rs1,
299 vs2,
300 vm,
301 eew,
302 })
303 } else {
304 Some(Self::Vluxseg {
305 vd,
306 rs1,
307 vs2,
308 eew,
309 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
310 })
311 }
312 }
313 0b10 => {
315 let eew = Eew::from_width(width)?;
316 let rs2 = Reg::from_bits(rs2_bits)?;
317 if nf == 0 {
318 Some(Self::Vlse {
319 vd,
320 rs1,
321 rs2,
322 vm,
323 eew,
324 })
325 } else {
326 Some(Self::Vlsseg {
327 vd,
328 rs1,
329 rs2,
330 eew,
331 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
332 })
333 }
334 }
335 0b11 => {
337 let eew = Eew::from_width(width)?;
338 let vs2 = VReg::from_bits(rs2_bits)?;
339 if nf == 0 {
340 Some(Self::Vloxei {
341 vd,
342 rs1,
343 vs2,
344 vm,
345 eew,
346 })
347 } else {
348 Some(Self::Vloxseg {
349 vd,
350 rs1,
351 vs2,
352 eew,
353 vm_nf: SegVmNf::new(vm, Nf::new(nf_val)?),
354 })
355 }
356 }
357 _ => None,
358 }
359 }
360
361 #[inline(always)]
362 fn alignment() -> u8 {
363 align_of::<u32>() as u8
364 }
365
366 #[inline(always)]
367 fn size(&self) -> u8 {
368 size_of::<u32>() as u8
369 }
370}
371
372#[instruction]
373impl<Reg> fmt::Display for ZveXxLoadInstruction<Reg>
374where
375 Reg: fmt::Display,
376{
377 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378 #[rustfmt::skip]
379 match self {
380 Self::Vle { vd, rs1, vm, eew } => write!(f, "vle{eew}.v {vd}, ({rs1}){}", mask_suffix(vm)),
381 Self::Vleff { vd, rs1, vm, eew } => write!(f, "vle{eew}ff.v {vd}, ({rs1}){}", mask_suffix(vm)),
382 Self::Vlm { vd, rs1 } => write!(f, "vlm.v {vd}, ({rs1})"),
383 Self::Vlse { vd, rs1, rs2, vm, eew } => write!(f, "vlse{eew}.v {vd}, ({rs1}), {rs2}{}", mask_suffix(vm)),
384 Self::Vluxei { vd, rs1, vs2, vm, eew } => write!(f, "vluxei{eew}.v {vd}, ({rs1}), {vs2}{}", mask_suffix(vm)),
385 Self::Vloxei { vd, rs1, vs2, vm, eew } => write!(f, "vloxei{eew}.v {vd}, ({rs1}), {vs2}{}", mask_suffix(vm)),
386 Self::Vlr { vd, rs1, nreg, eew } => write!(f, "vl{nreg}re{eew}.v {vd}, ({rs1})"),
387 Self::Vlseg { vd, rs1, eew, vm_nf } => write!(f, "vlseg{}e{eew}.v {vd}, ({rs1}){}", vm_nf.nf(), mask_suffix(&vm_nf.vm())),
388 Self::Vlsegff { vd, rs1, eew, vm_nf } => write!(f, "vlseg{}e{eew}ff.v {vd}, ({rs1}){}", vm_nf.nf(), mask_suffix(&vm_nf.vm())),
389 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())),
390 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())),
391 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())),
392 }
393 }
394}
395
396#[inline(always)]
398fn mask_suffix(vm: &bool) -> &'static str {
399 if *vm { "" } else { ", v0.t" }
400}