1#[cfg(test)]
4mod tests;
5
6use crate::instructions::Instruction;
7use crate::registers::general_purpose::Register;
8use ab_riscv_macros::instruction;
9use core::fmt;
10
11#[instruction]
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14#[rustfmt::skip]
15pub enum Rv64ZcaInstruction<Reg> {
16 CAddi4spn { rd: Reg, nzuimm: u16 },
19 CLw { rd: Reg, rs1: Reg, uimm: u8 },
21 CLd { rd: Reg, rs1: Reg, uimm: u8 },
23 CSw { rs1: Reg, rs2: Reg, uimm: u8 },
25 CSd { rs1: Reg, rs2: Reg, uimm: u8 },
27
28 CNop,
31 CAddi { rd: Reg, nzimm: i8 },
33 CAddiw { rd: Reg, imm: i8 },
35 CLi { rd: Reg, imm: i8 },
37 CAddi16sp { nzimm: i16 },
39 CLui { rd: Reg, nzimm: i32 },
41 CSrli { rd: Reg, shamt: u8 },
43 CSrai { rd: Reg, shamt: u8 },
45 CAndi { rd: Reg, imm: i8 },
47 CSub { rd: Reg, rs2: Reg },
49 CXor { rd: Reg, rs2: Reg },
51 COr { rd: Reg, rs2: Reg },
53 CAnd { rd: Reg, rs2: Reg },
55 CSubw { rd: Reg, rs2: Reg },
57 CAddw { rd: Reg, rs2: Reg },
59 CJ { imm: i16 },
61 CBeqz { rs1: Reg, imm: i16 },
63 CBnez { rs1: Reg, imm: i16 },
65
66 CSlli { rd: Reg, shamt: u8 },
69 CLwsp { rd: Reg, uimm: u8 },
71 CLdsp { rd: Reg, uimm: u16 },
73 CJr { rs1: Reg },
75 CMv { rd: Reg, rs2: Reg },
77 CEbreak,
79 CJalr { rs1: Reg },
81 CAdd { rd: Reg, rs2: Reg },
83 CSwsp { rs2: Reg, uimm: u8 },
85 CSdsp { rs2: Reg, uimm: u16 },
87
88 CUnimp,
90}
91
92#[instruction]
93impl<Reg> const Instruction for Rv64ZcaInstruction<Reg>
94where
95 Reg: [const] Register<Type = u64>,
96{
97 type Reg = Reg;
98
99 #[inline(always)]
100 fn try_decode(instruction: u32) -> Option<Self> {
101 #[inline(always)]
103 const fn prime_reg_bits(bits: u8) -> u8 {
104 bits + 8
105 }
106
107 #[inline(always)]
119 const fn decode_cb_branch_imm(inst: u16) -> i16 {
120 let imm8 = ((inst >> 12) & 1).cast_signed();
121 let imm4_3 = ((inst >> 10) & 0b11).cast_signed();
122 let imm7_6 = ((inst >> 5) & 0b11).cast_signed();
123 let imm2_1 = ((inst >> 3) & 0b11).cast_signed();
124 let imm5 = ((inst >> 2) & 1).cast_signed();
125 let raw = (imm8 << 8) | (imm7_6 << 6) | (imm5 << 5) | (imm4_3 << 3) | (imm2_1 << 1);
126 (raw << 7) >> 7
128 }
129
130 #[inline(always)]
145 const fn decode_cj_imm(inst: u16) -> i16 {
146 let imm11 = ((inst >> 12) & 1).cast_signed();
147 let imm4 = ((inst >> 11) & 1).cast_signed();
148 let imm9_8 = ((inst >> 9) & 0b11).cast_signed();
149 let imm10 = ((inst >> 8) & 1).cast_signed();
150 let imm6 = ((inst >> 7) & 1).cast_signed();
151 let imm7 = ((inst >> 6) & 1).cast_signed();
152 let imm3_1 = ((inst >> 3) & 0b111).cast_signed();
153 let imm5 = ((inst >> 2) & 1).cast_signed();
154 let raw = (imm11 << 11)
155 | (imm10 << 10)
156 | (imm9_8 << 8)
157 | (imm7 << 7)
158 | (imm6 << 6)
159 | (imm5 << 5)
160 | (imm4 << 4)
161 | (imm3_1 << 1);
162 (raw << 4) >> 4
164 }
165
166 let inst = instruction as u16;
167 let quadrant = inst & 0b11;
168 let funct3 = ((inst >> 13) & 0b111) as u8;
169
170 match quadrant {
171 0b00 => match funct3 {
173 0b000 => {
179 let imm5_4 = (inst >> 11) & 0b11;
180 let imm9_6 = (inst >> 7) & 0xf;
181 let imm2 = (inst >> 6) & 1;
182 let imm3 = (inst >> 5) & 1;
183 let nzuimm = (imm9_6 << 6) | (imm5_4 << 4) | (imm3 << 3) | (imm2 << 2);
184 if nzuimm == 0 {
185 if inst == 0 {
186 Some(Self::CUnimp)
187 } else {
188 None
190 }
191 } else {
192 let rd_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
193 let rd = Reg::from_bits(rd_bits)?;
194 Some(Self::CAddi4spn { rd, nzuimm })
195 }
196 }
197 0b010 => {
200 let uimm5_3 = ((inst >> 10) & 0b111) as u8;
201 let uimm2 = ((inst >> 6) & 1) as u8;
202 let uimm6 = ((inst >> 5) & 1) as u8;
203 let uimm = (uimm6 << 6) | (uimm5_3 << 3) | (uimm2 << 2);
204 let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
205 let rd_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
206 let rs1 = Reg::from_bits(rs1_bits)?;
207 let rd = Reg::from_bits(rd_bits)?;
208 Some(Self::CLw { rd, rs1, uimm })
209 }
210 0b011 => {
213 let uimm5_3 = ((inst >> 10) & 0b111) as u8;
214 let uimm7_6 = ((inst >> 5) & 0b11) as u8;
215 let uimm = (uimm7_6 << 6) | (uimm5_3 << 3);
216 let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
217 let rd_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
218 let rs1 = Reg::from_bits(rs1_bits)?;
219 let rd = Reg::from_bits(rd_bits)?;
220 Some(Self::CLd { rd, rs1, uimm })
221 }
222 0b110 => {
224 let uimm5_3 = ((inst >> 10) & 0b111) as u8;
225 let uimm2 = ((inst >> 6) & 1) as u8;
226 let uimm6 = ((inst >> 5) & 1) as u8;
227 let uimm = (uimm6 << 6) | (uimm5_3 << 3) | (uimm2 << 2);
228 let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
229 let rs2_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
230 let rs1 = Reg::from_bits(rs1_bits)?;
231 let rs2 = Reg::from_bits(rs2_bits)?;
232 Some(Self::CSw { rs1, rs2, uimm })
233 }
234 0b111 => {
236 let uimm5_3 = ((inst >> 10) & 0b111) as u8;
237 let uimm7_6 = ((inst >> 5) & 0b11) as u8;
238 let uimm = (uimm7_6 << 6) | (uimm5_3 << 3);
239 let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
240 let rs2_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
241 let rs1 = Reg::from_bits(rs1_bits)?;
242 let rs2 = Reg::from_bits(rs2_bits)?;
243 Some(Self::CSd { rs1, rs2, uimm })
244 }
245 _ => None,
247 },
248
249 0b01 => match funct3 {
251 0b000 => {
254 let rd_bits = ((inst >> 7) & 0x1f) as u8;
255 let imm5 = ((inst >> 12) & 1) as u8;
256 let imm4_0 = ((inst >> 2) & 0x1f) as u8;
257 let imm_raw = (imm5 << 5) | imm4_0;
258 let nzimm = ((imm_raw.cast_signed()) << 2) >> 2;
260 if rd_bits == 0 && nzimm == 0 {
261 Some(Self::CNop)
262 } else {
263 let rd = Reg::from_bits(rd_bits)?;
264 Some(Self::CAddi { rd, nzimm })
265 }
266 }
267 0b001 => {
270 let rd_bits = ((inst >> 7) & 0x1f) as u8;
271 if rd_bits == 0 {
273 None?;
274 }
275 let rd = Reg::from_bits(rd_bits)?;
276 let imm5 = ((inst >> 12) & 1) as u8;
277 let imm4_0 = ((inst >> 2) & 0x1f) as u8;
278 let imm_raw = (imm5 << 5) | imm4_0;
279 let imm = ((imm_raw.cast_signed()) << 2) >> 2;
280 Some(Self::CAddiw { rd, imm })
281 }
282 0b010 => {
285 let rd_bits = ((inst >> 7) & 0x1f) as u8;
286 let rd = Reg::from_bits(rd_bits)?;
287 let imm5 = ((inst >> 12) & 1) as u8;
288 let imm4_0 = ((inst >> 2) & 0x1f) as u8;
289 let imm_raw = (imm5 << 5) | imm4_0;
290 let imm = ((imm_raw.cast_signed()) << 2) >> 2;
291 Some(Self::CLi { rd, imm })
292 }
293 0b011 => {
295 let rd_bits = ((inst >> 7) & 0x1f) as u8;
296 if rd_bits == 2 {
297 let imm9 = ((inst >> 12) & 1).cast_signed();
304 let imm4 = ((inst >> 6) & 1).cast_signed();
305 let imm6 = ((inst >> 5) & 1).cast_signed();
306 let imm8_7 = ((inst >> 3) & 0b11).cast_signed();
307 let imm5 = ((inst >> 2) & 1).cast_signed();
308 let raw =
309 (imm9 << 9) | (imm8_7 << 7) | (imm6 << 6) | (imm5 << 5) | (imm4 << 4);
310 if raw == 0 {
311 None?;
312 }
313 let nzimm = (raw << 6) >> 6;
315 Some(Self::CAddi16sp { nzimm })
316 } else {
317 if rd_bits == 0 {
319 None?;
320 }
321 let rd = Reg::from_bits(rd_bits)?;
322 let imm17 = ((inst >> 12) & 1) as i32;
325 let imm16_12 = ((inst >> 2) & 0x1f) as i32;
326 let raw = (imm17 << 17) | (imm16_12 << 12);
327 if raw == 0 {
328 None?;
329 }
330 let nzimm = (raw << 14) >> 14;
332 Some(Self::CLui { rd, nzimm })
333 }
334 }
335 0b100 => {
337 let funct2 = ((inst >> 10) & 0b11) as u8;
338 let rd_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
339 match funct2 {
340 0b00 => {
343 let rd = Reg::from_bits(rd_bits)?;
344 let shamt5 = ((inst >> 12) & 1) as u8;
345 let shamt40 = ((inst >> 2) & 0x1f) as u8;
346 Some(Self::CSrli {
347 rd,
348 shamt: (shamt5 << 5) | shamt40,
349 })
350 }
351 0b01 => {
354 let rd = Reg::from_bits(rd_bits)?;
355 let shamt5 = ((inst >> 12) & 1) as u8;
356 let shamt40 = ((inst >> 2) & 0x1f) as u8;
357 Some(Self::CSrai {
358 rd,
359 shamt: (shamt5 << 5) | shamt40,
360 })
361 }
362 0b10 => {
364 let rd = Reg::from_bits(rd_bits)?;
365 let imm5 = ((inst >> 12) & 1) as u8;
366 let imm4_0 = ((inst >> 2) & 0x1f) as u8;
367 let imm_raw = (imm5 << 5) | imm4_0;
368 let imm = ((imm_raw.cast_signed()) << 2) >> 2;
369 Some(Self::CAndi { rd, imm })
370 }
371 0b11 => {
373 let bit12 = (inst >> 12) & 1;
374 let funct2b = ((inst >> 5) & 0b11) as u8;
375 let rs2_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
376 let rd = Reg::from_bits(rd_bits)?;
377 let rs2 = Reg::from_bits(rs2_bits)?;
378 if bit12 == 0 {
379 match funct2b {
380 0b00 => Some(Self::CSub { rd, rs2 }),
381 0b01 => Some(Self::CXor { rd, rs2 }),
382 0b10 => Some(Self::COr { rd, rs2 }),
383 0b11 => Some(Self::CAnd { rd, rs2 }),
384 _ => None,
385 }
386 } else {
387 match funct2b {
389 0b00 => Some(Self::CSubw { rd, rs2 }),
390 0b01 => Some(Self::CAddw { rd, rs2 }),
391 _ => None,
393 }
394 }
395 }
396 _ => None,
397 }
398 }
399 0b101 => Some(Self::CJ {
401 imm: decode_cj_imm(inst),
402 }),
403 0b110 => {
405 let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
406 let rs1 = Reg::from_bits(rs1_bits)?;
407 Some(Self::CBeqz {
408 rs1,
409 imm: decode_cb_branch_imm(inst),
410 })
411 }
412 0b111 => {
414 let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
415 let rs1 = Reg::from_bits(rs1_bits)?;
416 Some(Self::CBnez {
417 rs1,
418 imm: decode_cb_branch_imm(inst),
419 })
420 }
421 _ => None,
422 },
423
424 0b10 => match funct3 {
426 0b000 => {
429 let rd_bits = ((inst >> 7) & 0x1f) as u8;
430 let rd = Reg::from_bits(rd_bits)?;
431 let shamt5 = ((inst >> 12) & 1) as u8;
432 let shamt40 = ((inst >> 2) & 0x1f) as u8;
433 Some(Self::CSlli {
434 rd,
435 shamt: (shamt5 << 5) | shamt40,
436 })
437 }
438 0b010 => {
441 let rd_bits = ((inst >> 7) & 0x1f) as u8;
442 if rd_bits == 0 {
443 None?;
444 }
445 let rd = Reg::from_bits(rd_bits)?;
446 let uimm5 = ((inst >> 12) & 1) as u8;
447 let uimm42 = ((inst >> 4) & 0b111) as u8;
448 let uimm76 = ((inst >> 2) & 0b11) as u8;
449 let uimm = (uimm76 << 6) | (uimm5 << 5) | (uimm42 << 2);
450 Some(Self::CLwsp { rd, uimm })
451 }
452 0b011 => {
455 let rd_bits = ((inst >> 7) & 0x1f) as u8;
456 if rd_bits == 0 {
457 None?;
458 }
459 let rd = Reg::from_bits(rd_bits)?;
460 let uimm5 = (inst >> 12) & 1;
461 let uimm43 = (inst >> 5) & 0b11;
462 let uimm86 = (inst >> 2) & 0b111;
463 let uimm = (uimm86 << 6) | (uimm5 << 5) | (uimm43 << 3);
464 Some(Self::CLdsp { rd, uimm })
465 }
466 0b100 => {
468 let rs1_bits = ((inst >> 7) & 0x1f) as u8;
469 let rs2_bits = ((inst >> 2) & 0x1f) as u8;
470 let bit12 = (inst >> 12) & 1;
471 if bit12 == 0 {
472 if rs2_bits == 0 {
473 if rs1_bits == 0 {
475 None?;
476 }
477 let rs1 = Reg::from_bits(rs1_bits)?;
478 Some(Self::CJr { rs1 })
479 } else {
480 let rd = Reg::from_bits(rs1_bits)?;
482 let rs2 = Reg::from_bits(rs2_bits)?;
483 Some(Self::CMv { rd, rs2 })
484 }
485 } else if rs2_bits == 0 {
486 if rs1_bits == 0 {
487 Some(Self::CEbreak)
489 } else {
490 let rs1 = Reg::from_bits(rs1_bits)?;
492 Some(Self::CJalr { rs1 })
493 }
494 } else {
495 let rd = Reg::from_bits(rs1_bits)?;
497 let rs2 = Reg::from_bits(rs2_bits)?;
498 Some(Self::CAdd { rd, rs2 })
499 }
500 }
501 0b110 => {
503 let rs2_bits = ((inst >> 2) & 0x1f) as u8;
504 let rs2 = Reg::from_bits(rs2_bits)?;
505 let uimm52 = ((inst >> 9) & 0xf) as u8;
506 let uimm76 = ((inst >> 7) & 0b11) as u8;
507 let uimm = (uimm76 << 6) | (uimm52 << 2);
508 Some(Self::CSwsp { rs2, uimm })
509 }
510 0b111 => {
512 let rs2_bits = ((inst >> 2) & 0x1f) as u8;
513 let rs2 = Reg::from_bits(rs2_bits)?;
514 let uimm53 = (inst >> 10) & 0b111;
515 let uimm86 = (inst >> 7) & 0b111;
516 let uimm = (uimm86 << 6) | (uimm53 << 3);
517 Some(Self::CSdsp { rs2, uimm })
518 }
519 _ => None,
520 },
521
522 _ => None,
524 }
525 }
526
527 #[inline(always)]
528 fn alignment() -> u8 {
529 align_of::<u16>() as u8
530 }
531
532 #[inline(always)]
533 fn size(&self) -> u8 {
534 size_of::<u16>() as u8
535 }
536}
537
538impl<Reg> fmt::Display for Rv64ZcaInstruction<Reg>
539where
540 Reg: fmt::Display,
541{
542 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
543 match self {
544 Self::CAddi4spn { rd, nzuimm } => write!(f, "c.addi4spn {rd}, sp, {nzuimm}"),
545 Self::CLw { rd, rs1, uimm } => write!(f, "c.lw {rd}, {uimm}({rs1})"),
546 Self::CLd { rd, rs1, uimm } => write!(f, "c.ld {rd}, {uimm}({rs1})"),
547 Self::CSw { rs1, rs2, uimm } => write!(f, "c.sw {rs2}, {uimm}({rs1})"),
548 Self::CSd { rs1, rs2, uimm } => write!(f, "c.sd {rs2}, {uimm}({rs1})"),
549 Self::CNop => write!(f, "c.nop"),
550 Self::CAddi { rd, nzimm } => write!(f, "c.addi {rd}, {nzimm}"),
551 Self::CAddiw { rd, imm } => write!(f, "c.addiw {rd}, {imm}"),
552 Self::CLi { rd, imm } => write!(f, "c.li {rd}, {imm}"),
553 Self::CAddi16sp { nzimm } => write!(f, "c.addi16sp sp, {nzimm}"),
554 Self::CLui { rd, nzimm } => write!(f, "c.lui {rd}, 0x{:x}", nzimm >> 12),
555 Self::CSrli { rd, shamt } => write!(f, "c.srli {rd}, {shamt}"),
556 Self::CSrai { rd, shamt } => write!(f, "c.srai {rd}, {shamt}"),
557 Self::CAndi { rd, imm } => write!(f, "c.andi {rd}, {imm}"),
558 Self::CSub { rd, rs2 } => write!(f, "c.sub {rd}, {rs2}"),
559 Self::CXor { rd, rs2 } => write!(f, "c.xor {rd}, {rs2}"),
560 Self::COr { rd, rs2 } => write!(f, "c.or {rd}, {rs2}"),
561 Self::CAnd { rd, rs2 } => write!(f, "c.and {rd}, {rs2}"),
562 Self::CSubw { rd, rs2 } => write!(f, "c.subw {rd}, {rs2}"),
563 Self::CAddw { rd, rs2 } => write!(f, "c.addw {rd}, {rs2}"),
564 Self::CJ { imm } => write!(f, "c.j {imm}"),
565 Self::CBeqz { rs1, imm } => write!(f, "c.beqz {rs1}, {imm}"),
566 Self::CBnez { rs1, imm } => write!(f, "c.bnez {rs1}, {imm}"),
567 Self::CSlli { rd, shamt } => write!(f, "c.slli {rd}, {shamt}"),
568 Self::CLwsp { rd, uimm } => write!(f, "c.lwsp {rd}, {uimm}(sp)"),
569 Self::CLdsp { rd, uimm } => write!(f, "c.ldsp {rd}, {uimm}(sp)"),
570 Self::CJr { rs1 } => write!(f, "c.jr {rs1}"),
571 Self::CMv { rd, rs2 } => write!(f, "c.mv {rd}, {rs2}"),
572 Self::CEbreak => write!(f, "c.ebreak"),
573 Self::CJalr { rs1 } => write!(f, "c.jalr {rs1}"),
574 Self::CAdd { rd, rs2 } => write!(f, "c.add {rd}, {rs2}"),
575 Self::CSwsp { rs2, uimm } => write!(f, "c.swsp {rs2}, {uimm}(sp)"),
576 Self::CSdsp { rs2, uimm } => write!(f, "c.sdsp {rs2}, {uimm}(sp)"),
577 Self::CUnimp => write!(f, "c.unimp"),
578 }
579 }
580}