1#[cfg(test)]
4mod tests;
5
6use crate::instructions::Instruction;
7use crate::instructions::utils::I24;
8use crate::registers::general_purpose::Register;
9use ab_riscv_macros::instruction;
10use core::fmt;
11
12#[instruction]
14#[derive(Debug, Clone, Copy)]
15#[derive_const(PartialEq, Eq)]
16#[rustfmt::skip]
17pub enum Rv64ZcaInstruction<Reg> {
18 CAddi4spn { rd: Reg, nzuimm: u16 },
21 CLw { rd: Reg, rs1: Reg, uimm: u8 },
23 CLd { rd: Reg, rs1: Reg, uimm: u8 },
25 CSw { rs1: Reg, rs2: Reg, uimm: u8 },
27 CSd { rs1: Reg, rs2: Reg, uimm: u8 },
29
30 CNop,
33 CAddi { rd: Reg, nzimm: i8 },
35 CAddiw { rd: Reg, imm: i8 },
37 CLi { rd: Reg, imm: i8 },
39 CAddi16sp { nzimm: i16 },
41 CLui { rd: Reg, nzimm: I24 },
43 CSrli { rd: Reg, shamt: u8 },
45 CSrai { rd: Reg, shamt: u8 },
47 CAndi { rd: Reg, imm: i8 },
49 CSub { rd: Reg, rs2: Reg },
51 CXor { rd: Reg, rs2: Reg },
53 COr { rd: Reg, rs2: Reg },
55 CAnd { rd: Reg, rs2: Reg },
57 CSubw { rd: Reg, rs2: Reg },
59 CAddw { rd: Reg, rs2: Reg },
61 CJ { imm: i16 },
63 CBeqz { rs1: Reg, imm: i16 },
65 CBnez { rs1: Reg, imm: i16 },
67
68 CSlli { rd: Reg, shamt: u8 },
71 CLwsp { rd: Reg, uimm: u8 },
73 CLdsp { rd: Reg, uimm: u16 },
75 CJr { rs1: Reg },
77 CMv { rd: Reg, rs2: Reg },
79 CEbreak,
81 CJalr { rs1: Reg },
83 CAdd { rd: Reg, rs2: Reg },
85 CSwsp { rs2: Reg, uimm: u8 },
87 CSdsp { rs2: Reg, uimm: u16 },
89
90 CUnimp,
92}
93
94#[instruction]
95const impl<Reg> Instruction for Rv64ZcaInstruction<Reg>
96where
97 Reg: [const] Register<Type = u64>,
98{
99 type Reg = Reg;
100
101 #[inline(always)]
102 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
103 fn try_decode(instruction: u32) -> Option<Self> {
104 #[inline(always)]
106 const fn prime_reg_bits(bits: u8) -> u8 {
107 bits + 8
108 }
109
110 #[inline(always)]
122 const fn decode_cb_branch_imm(inst: u16) -> i16 {
123 let imm8 = ((inst >> 12u8) & 1).cast_signed();
124 let imm4_3 = ((inst >> 10u8) & 0b11).cast_signed();
125 let imm7_6 = ((inst >> 5u8) & 0b11).cast_signed();
126 let imm2_1 = ((inst >> 3u8) & 0b11).cast_signed();
127 let imm5 = ((inst >> 2u8) & 1).cast_signed();
128 let raw =
129 (imm8 << 8u8) | (imm7_6 << 6u8) | (imm5 << 5u8) | (imm4_3 << 3u8) | (imm2_1 << 1u8);
130 (raw << 7u8) >> 7u8
132 }
133
134 #[inline(always)]
149 const fn decode_cj_imm(inst: u16) -> i16 {
150 let imm11 = ((inst >> 12u8) & 1).cast_signed();
151 let imm4 = ((inst >> 11u8) & 1).cast_signed();
152 let imm9_8 = ((inst >> 9u8) & 0b11).cast_signed();
153 let imm10 = ((inst >> 8u8) & 1).cast_signed();
154 let imm6 = ((inst >> 7u8) & 1).cast_signed();
155 let imm7 = ((inst >> 6u8) & 1).cast_signed();
156 let imm3_1 = ((inst >> 3u8) & 0b111).cast_signed();
157 let imm5 = ((inst >> 2u8) & 1).cast_signed();
158 let raw = (imm11 << 11u8)
159 | (imm10 << 10u8)
160 | (imm9_8 << 8u8)
161 | (imm7 << 7u8)
162 | (imm6 << 6u8)
163 | (imm5 << 5u8)
164 | (imm4 << 4u8)
165 | (imm3_1 << 1u8);
166 (raw << 4u8) >> 4u8
168 }
169
170 let inst = instruction as u16;
171 let quadrant = inst & 0b11;
172 let funct3 = ((inst >> 13u8) & 0b111) as u8;
173
174 match quadrant {
175 0b00 => match funct3 {
177 0b000 => {
183 let imm5_4 = (inst >> 11u8) & 0b11;
184 let imm9_6 = (inst >> 7u8) & 0xf;
185 let imm2 = (inst >> 6u8) & 1;
186 let imm3 = (inst >> 5u8) & 1;
187 let nzuimm = (imm9_6 << 6u8) | (imm5_4 << 4u8) | (imm3 << 3u8) | (imm2 << 2u8);
188 if nzuimm == 0 {
189 if inst == 0 {
190 Some(Self::CUnimp)
191 } else {
192 None
194 }
195 } else {
196 let rd_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
197 let rd = Reg::from_bits(rd_bits)?;
198 Some(Self::CAddi4spn { rd, nzuimm })
199 }
200 }
201 0b010 => {
204 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
205 let uimm2 = ((inst >> 6u8) & 1) as u8;
206 let uimm6 = ((inst >> 5u8) & 1) as u8;
207 let uimm = (uimm6 << 6u8) | (uimm5_3 << 3u8) | (uimm2 << 2u8);
208 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
209 let rd_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
210 let rs1 = Reg::from_bits(rs1_bits)?;
211 let rd = Reg::from_bits(rd_bits)?;
212 Some(Self::CLw { rd, rs1, uimm })
213 }
214 0b011 => {
217 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
218 let uimm7_6 = ((inst >> 5u8) & 0b11) as u8;
219 let uimm = (uimm7_6 << 6u8) | (uimm5_3 << 3u8);
220 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
221 let rd_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
222 let rs1 = Reg::from_bits(rs1_bits)?;
223 let rd = Reg::from_bits(rd_bits)?;
224 Some(Self::CLd { rd, rs1, uimm })
225 }
226 0b110 => {
228 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
229 let uimm2 = ((inst >> 6u8) & 1) as u8;
230 let uimm6 = ((inst >> 5u8) & 1) as u8;
231 let uimm = (uimm6 << 6u8) | (uimm5_3 << 3u8) | (uimm2 << 2u8);
232 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
233 let rs2_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
234 let rs1 = Reg::from_bits(rs1_bits)?;
235 let rs2 = Reg::from_bits(rs2_bits)?;
236 Some(Self::CSw { rs1, rs2, uimm })
237 }
238 0b111 => {
240 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
241 let uimm7_6 = ((inst >> 5u8) & 0b11) as u8;
242 let uimm = (uimm7_6 << 6u8) | (uimm5_3 << 3u8);
243 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
244 let rs2_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
245 let rs1 = Reg::from_bits(rs1_bits)?;
246 let rs2 = Reg::from_bits(rs2_bits)?;
247 Some(Self::CSd { rs1, rs2, uimm })
248 }
249 _ => None,
251 },
252
253 0b01 => match funct3 {
255 0b000 => {
258 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
259 let imm5 = ((inst >> 12u8) & 1) as u8;
260 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
261 let imm_raw = (imm5 << 5u8) | imm4_0;
262 let nzimm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
264 if rd_bits == 0 && nzimm == 0 {
265 Some(Self::CNop)
266 } else {
267 let rd = Reg::from_bits(rd_bits)?;
268 Some(Self::CAddi { rd, nzimm })
269 }
270 }
271 0b001 => {
274 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
275 if rd_bits == 0 {
277 None?;
278 }
279 let rd = Reg::from_bits(rd_bits)?;
280 let imm5 = ((inst >> 12u8) & 1) as u8;
281 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
282 let imm_raw = (imm5 << 5u8) | imm4_0;
283 let imm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
284 Some(Self::CAddiw { rd, imm })
285 }
286 0b010 => {
289 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
290 let rd = Reg::from_bits(rd_bits)?;
291 let imm5 = ((inst >> 12u8) & 1) as u8;
292 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
293 let imm_raw = (imm5 << 5u8) | imm4_0;
294 let imm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
295 Some(Self::CLi { rd, imm })
296 }
297 0b011 => {
299 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
300 if rd_bits == 2 {
301 let imm9 = ((inst >> 12u8) & 1).cast_signed();
308 let imm4 = ((inst >> 6u8) & 1).cast_signed();
309 let imm6 = ((inst >> 5u8) & 1).cast_signed();
310 let imm8_7 = ((inst >> 3u8) & 0b11).cast_signed();
311 let imm5 = ((inst >> 2u8) & 1).cast_signed();
312 let raw = (imm9 << 9u8)
313 | (imm8_7 << 7u8)
314 | (imm6 << 6u8)
315 | (imm5 << 5u8)
316 | (imm4 << 4u8);
317 if raw == 0 {
318 None?;
319 }
320 let nzimm = (raw << 6u8) >> 6u8;
322 Some(Self::CAddi16sp { nzimm })
323 } else {
324 let rd = Reg::from_bits(rd_bits)?;
326 let imm17 = ((inst >> 12u8) & 1) as i32;
329 let imm16_12 = ((inst >> 2u8) & 0x1f) as i32;
330 let raw = (imm17 << 17u8) | (imm16_12 << 12u8);
331 if raw == 0 {
332 None?;
333 }
334 let nzimm = I24::from_i32((raw << 14u8) >> 14u8);
336 Some(Self::CLui { rd, nzimm })
337 }
338 }
339 0b100 => {
341 let funct2 = ((inst >> 10u8) & 0b11) as u8;
342 let rd_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
343 match funct2 {
344 0b00 => {
347 let rd = Reg::from_bits(rd_bits)?;
348 let shamt5 = ((inst >> 12u8) & 1) as u8;
349 let shamt40 = ((inst >> 2u8) & 0x1f) as u8;
350 Some(Self::CSrli {
351 rd,
352 shamt: (shamt5 << 5u8) | shamt40,
353 })
354 }
355 0b01 => {
358 let rd = Reg::from_bits(rd_bits)?;
359 let shamt5 = ((inst >> 12u8) & 1) as u8;
360 let shamt40 = ((inst >> 2u8) & 0x1f) as u8;
361 Some(Self::CSrai {
362 rd,
363 shamt: (shamt5 << 5u8) | shamt40,
364 })
365 }
366 0b10 => {
368 let rd = Reg::from_bits(rd_bits)?;
369 let imm5 = ((inst >> 12u8) & 1) as u8;
370 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
371 let imm_raw = (imm5 << 5u8) | imm4_0;
372 let imm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
373 Some(Self::CAndi { rd, imm })
374 }
375 0b11 => {
377 let bit12 = (inst >> 12u8) & 1;
378 let funct2b = ((inst >> 5u8) & 0b11) as u8;
379 let rs2_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
380 let rd = Reg::from_bits(rd_bits)?;
381 let rs2 = Reg::from_bits(rs2_bits)?;
382 if bit12 == 0 {
383 match funct2b {
384 0b00 => Some(Self::CSub { rd, rs2 }),
385 0b01 => Some(Self::CXor { rd, rs2 }),
386 0b10 => Some(Self::COr { rd, rs2 }),
387 0b11 => Some(Self::CAnd { rd, rs2 }),
388 _ => None,
389 }
390 } else {
391 match funct2b {
393 0b00 => Some(Self::CSubw { rd, rs2 }),
394 0b01 => Some(Self::CAddw { rd, rs2 }),
395 _ => None,
397 }
398 }
399 }
400 _ => None,
401 }
402 }
403 0b101 => Some(Self::CJ {
405 imm: decode_cj_imm(inst),
406 }),
407 0b110 => {
409 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
410 let rs1 = Reg::from_bits(rs1_bits)?;
411 Some(Self::CBeqz {
412 rs1,
413 imm: decode_cb_branch_imm(inst),
414 })
415 }
416 0b111 => {
418 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
419 let rs1 = Reg::from_bits(rs1_bits)?;
420 Some(Self::CBnez {
421 rs1,
422 imm: decode_cb_branch_imm(inst),
423 })
424 }
425 _ => None,
426 },
427
428 0b10 => match funct3 {
430 0b000 => {
433 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
434 let rd = Reg::from_bits(rd_bits)?;
435 let shamt5 = ((inst >> 12u8) & 1) as u8;
436 let shamt40 = ((inst >> 2u8) & 0x1f) as u8;
437 Some(Self::CSlli {
438 rd,
439 shamt: (shamt5 << 5u8) | shamt40,
440 })
441 }
442 0b010 => {
445 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
446 if rd_bits == 0 {
447 None?;
448 }
449 let rd = Reg::from_bits(rd_bits)?;
450 let uimm5 = ((inst >> 12u8) & 1) as u8;
451 let uimm42 = ((inst >> 4u8) & 0b111) as u8;
452 let uimm76 = ((inst >> 2u8) & 0b11) as u8;
453 let uimm = (uimm76 << 6u8) | (uimm5 << 5u8) | (uimm42 << 2u8);
454 Some(Self::CLwsp { rd, uimm })
455 }
456 0b011 => {
459 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
460 if rd_bits == 0 {
461 None?;
462 }
463 let rd = Reg::from_bits(rd_bits)?;
464 let uimm5 = (inst >> 12u8) & 1;
465 let uimm43 = (inst >> 5u8) & 0b11;
466 let uimm86 = (inst >> 2u8) & 0b111;
467 let uimm = (uimm86 << 6u8) | (uimm5 << 5u8) | (uimm43 << 3u8);
468 Some(Self::CLdsp { rd, uimm })
469 }
470 0b100 => {
472 let rs1_bits = ((inst >> 7u8) & 0x1f) as u8;
473 let rs2_bits = ((inst >> 2u8) & 0x1f) as u8;
474 let bit12 = (inst >> 12u8) & 1;
475 if bit12 == 0 {
476 if rs2_bits == 0 {
477 if rs1_bits == 0 {
479 None?;
480 }
481 let rs1 = Reg::from_bits(rs1_bits)?;
482 Some(Self::CJr { rs1 })
483 } else {
484 let rd = Reg::from_bits(rs1_bits)?;
486 let rs2 = Reg::from_bits(rs2_bits)?;
487 Some(Self::CMv { rd, rs2 })
488 }
489 } else if rs2_bits == 0 {
490 if rs1_bits == 0 {
491 Some(Self::CEbreak)
493 } else {
494 let rs1 = Reg::from_bits(rs1_bits)?;
496 Some(Self::CJalr { rs1 })
497 }
498 } else {
499 let rd = Reg::from_bits(rs1_bits)?;
501 let rs2 = Reg::from_bits(rs2_bits)?;
502 Some(Self::CAdd { rd, rs2 })
503 }
504 }
505 0b110 => {
507 let rs2_bits = ((inst >> 2u8) & 0x1f) as u8;
508 let rs2 = Reg::from_bits(rs2_bits)?;
509 let uimm52 = ((inst >> 9u8) & 0xf) as u8;
510 let uimm76 = ((inst >> 7u8) & 0b11) as u8;
511 let uimm = (uimm76 << 6u8) | (uimm52 << 2u8);
512 Some(Self::CSwsp { rs2, uimm })
513 }
514 0b111 => {
516 let rs2_bits = ((inst >> 2u8) & 0x1f) as u8;
517 let rs2 = Reg::from_bits(rs2_bits)?;
518 let uimm53 = (inst >> 10u8) & 0b111;
519 let uimm86 = (inst >> 7u8) & 0b111;
520 let uimm = (uimm86 << 6u8) | (uimm53 << 3u8);
521 Some(Self::CSdsp { rs2, uimm })
522 }
523 _ => None,
524 },
525
526 _ => None,
528 }
529 }
530
531 #[inline(always)]
532 fn alignment() -> u8 {
533 align_of::<u16>() as u8
534 }
535
536 #[inline(always)]
537 fn size(&self) -> u8 {
538 size_of::<u16>() as u8
539 }
540}
541
542#[instruction]
543impl<Reg> fmt::Display for Rv64ZcaInstruction<Reg>
544where
545 Reg: fmt::Display,
546{
547 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
548 match self {
549 Self::CAddi4spn { rd, nzuimm } => write!(f, "c.addi4spn {rd}, sp, {nzuimm}"),
550 Self::CLw { rd, rs1, uimm } => write!(f, "c.lw {rd}, {uimm}({rs1})"),
551 Self::CLd { rd, rs1, uimm } => write!(f, "c.ld {rd}, {uimm}({rs1})"),
552 Self::CSw { rs1, rs2, uimm } => write!(f, "c.sw {rs2}, {uimm}({rs1})"),
553 Self::CSd { rs1, rs2, uimm } => write!(f, "c.sd {rs2}, {uimm}({rs1})"),
554 Self::CNop => write!(f, "c.nop"),
555 Self::CAddi { rd, nzimm } => write!(f, "c.addi {rd}, {nzimm}"),
556 Self::CAddiw { rd, imm } => write!(f, "c.addiw {rd}, {imm}"),
557 Self::CLi { rd, imm } => write!(f, "c.li {rd}, {imm}"),
558 Self::CAddi16sp { nzimm } => write!(f, "c.addi16sp sp, {nzimm}"),
559 Self::CLui { rd, nzimm } => write!(f, "c.lui {rd}, 0x{:x}", nzimm >> 12u8),
560 Self::CSrli { rd, shamt } => write!(f, "c.srli {rd}, {shamt}"),
561 Self::CSrai { rd, shamt } => write!(f, "c.srai {rd}, {shamt}"),
562 Self::CAndi { rd, imm } => write!(f, "c.andi {rd}, {imm}"),
563 Self::CSub { rd, rs2 } => write!(f, "c.sub {rd}, {rs2}"),
564 Self::CXor { rd, rs2 } => write!(f, "c.xor {rd}, {rs2}"),
565 Self::COr { rd, rs2 } => write!(f, "c.or {rd}, {rs2}"),
566 Self::CAnd { rd, rs2 } => write!(f, "c.and {rd}, {rs2}"),
567 Self::CSubw { rd, rs2 } => write!(f, "c.subw {rd}, {rs2}"),
568 Self::CAddw { rd, rs2 } => write!(f, "c.addw {rd}, {rs2}"),
569 Self::CJ { imm } => write!(f, "c.j {imm}"),
570 Self::CBeqz { rs1, imm } => write!(f, "c.beqz {rs1}, {imm}"),
571 Self::CBnez { rs1, imm } => write!(f, "c.bnez {rs1}, {imm}"),
572 Self::CSlli { rd, shamt } => write!(f, "c.slli {rd}, {shamt}"),
573 Self::CLwsp { rd, uimm } => write!(f, "c.lwsp {rd}, {uimm}(sp)"),
574 Self::CLdsp { rd, uimm } => write!(f, "c.ldsp {rd}, {uimm}(sp)"),
575 Self::CJr { rs1 } => write!(f, "c.jr {rs1}"),
576 Self::CMv { rd, rs2 } => write!(f, "c.mv {rd}, {rs2}"),
577 Self::CEbreak => write!(f, "c.ebreak"),
578 Self::CJalr { rs1 } => write!(f, "c.jalr {rs1}"),
579 Self::CAdd { rd, rs2 } => write!(f, "c.add {rd}, {rs2}"),
580 Self::CSwsp { rs2, uimm } => write!(f, "c.swsp {rs2}, {uimm}(sp)"),
581 Self::CSdsp { rs2, uimm } => write!(f, "c.sdsp {rs2}, {uimm}(sp)"),
582 Self::CUnimp => write!(f, "c.unimp"),
583 }
584 }
585}