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, PartialEq, Eq)]
15#[rustfmt::skip]
16pub enum Rv64ZcaInstruction<Reg> {
17 CAddi4spn { rd: Reg, nzuimm: u16 },
20 CLw { rd: Reg, rs1: Reg, uimm: u8 },
22 CLd { rd: Reg, rs1: Reg, uimm: u8 },
24 CSw { rs1: Reg, rs2: Reg, uimm: u8 },
26 CSd { rs1: Reg, rs2: Reg, uimm: u8 },
28
29 CNop,
32 CAddi { rd: Reg, nzimm: i8 },
34 CAddiw { rd: Reg, imm: i8 },
36 CLi { rd: Reg, imm: i8 },
38 CAddi16sp { nzimm: i16 },
40 CLui { rd: Reg, nzimm: I24 },
42 CSrli { rd: Reg, shamt: u8 },
44 CSrai { rd: Reg, shamt: u8 },
46 CAndi { rd: Reg, imm: i8 },
48 CSub { rd: Reg, rs2: Reg },
50 CXor { rd: Reg, rs2: Reg },
52 COr { rd: Reg, rs2: Reg },
54 CAnd { rd: Reg, rs2: Reg },
56 CSubw { rd: Reg, rs2: Reg },
58 CAddw { rd: Reg, rs2: Reg },
60 CJ { imm: i16 },
62 CBeqz { rs1: Reg, imm: i16 },
64 CBnez { rs1: Reg, imm: i16 },
66
67 CSlli { rd: Reg, shamt: u8 },
70 CLwsp { rd: Reg, uimm: u8 },
72 CLdsp { rd: Reg, uimm: u16 },
74 CJr { rs1: Reg },
76 CMv { rd: Reg, rs2: Reg },
78 CEbreak,
80 CJalr { rs1: Reg },
82 CAdd { rd: Reg, rs2: Reg },
84 CSwsp { rs2: Reg, uimm: u8 },
86 CSdsp { rs2: Reg, uimm: u16 },
88
89 CUnimp,
91}
92
93#[instruction]
94const impl<Reg> Instruction for Rv64ZcaInstruction<Reg>
95where
96 Reg: [const] Register<Type = u64>,
97{
98 type Reg = Reg;
99
100 #[inline(always)]
101 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
102 fn try_decode(instruction: u32) -> Option<Self> {
103 #[inline(always)]
105 const fn prime_reg_bits(bits: u8) -> u8 {
106 bits + 8
107 }
108
109 #[inline(always)]
121 const fn decode_cb_branch_imm(inst: u16) -> i16 {
122 let imm8 = ((inst >> 12u8) & 1).cast_signed();
123 let imm4_3 = ((inst >> 10u8) & 0b11).cast_signed();
124 let imm7_6 = ((inst >> 5u8) & 0b11).cast_signed();
125 let imm2_1 = ((inst >> 3u8) & 0b11).cast_signed();
126 let imm5 = ((inst >> 2u8) & 1).cast_signed();
127 let raw =
128 (imm8 << 8u8) | (imm7_6 << 6u8) | (imm5 << 5u8) | (imm4_3 << 3u8) | (imm2_1 << 1u8);
129 (raw << 7u8) >> 7u8
131 }
132
133 #[inline(always)]
148 const fn decode_cj_imm(inst: u16) -> i16 {
149 let imm11 = ((inst >> 12u8) & 1).cast_signed();
150 let imm4 = ((inst >> 11u8) & 1).cast_signed();
151 let imm9_8 = ((inst >> 9u8) & 0b11).cast_signed();
152 let imm10 = ((inst >> 8u8) & 1).cast_signed();
153 let imm6 = ((inst >> 7u8) & 1).cast_signed();
154 let imm7 = ((inst >> 6u8) & 1).cast_signed();
155 let imm3_1 = ((inst >> 3u8) & 0b111).cast_signed();
156 let imm5 = ((inst >> 2u8) & 1).cast_signed();
157 let raw = (imm11 << 11u8)
158 | (imm10 << 10u8)
159 | (imm9_8 << 8u8)
160 | (imm7 << 7u8)
161 | (imm6 << 6u8)
162 | (imm5 << 5u8)
163 | (imm4 << 4u8)
164 | (imm3_1 << 1u8);
165 (raw << 4u8) >> 4u8
167 }
168
169 let inst = instruction as u16;
170 let quadrant = inst & 0b11;
171 let funct3 = ((inst >> 13u8) & 0b111) as u8;
172
173 match quadrant {
174 0b00 => match funct3 {
176 0b000 => {
182 let imm5_4 = (inst >> 11u8) & 0b11;
183 let imm9_6 = (inst >> 7u8) & 0xf;
184 let imm2 = (inst >> 6u8) & 1;
185 let imm3 = (inst >> 5u8) & 1;
186 let nzuimm = (imm9_6 << 6u8) | (imm5_4 << 4u8) | (imm3 << 3u8) | (imm2 << 2u8);
187 if nzuimm == 0 {
188 if inst == 0 {
189 Some(Self::CUnimp)
190 } else {
191 None
193 }
194 } else {
195 let rd_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
196 let rd = Reg::from_bits(rd_bits)?;
197 Some(Self::CAddi4spn { rd, nzuimm })
198 }
199 }
200 0b010 => {
203 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
204 let uimm2 = ((inst >> 6u8) & 1) as u8;
205 let uimm6 = ((inst >> 5u8) & 1) as u8;
206 let uimm = (uimm6 << 6u8) | (uimm5_3 << 3u8) | (uimm2 << 2u8);
207 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
208 let rd_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
209 let rs1 = Reg::from_bits(rs1_bits)?;
210 let rd = Reg::from_bits(rd_bits)?;
211 Some(Self::CLw { rd, rs1, uimm })
212 }
213 0b011 => {
216 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
217 let uimm7_6 = ((inst >> 5u8) & 0b11) as u8;
218 let uimm = (uimm7_6 << 6u8) | (uimm5_3 << 3u8);
219 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
220 let rd_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
221 let rs1 = Reg::from_bits(rs1_bits)?;
222 let rd = Reg::from_bits(rd_bits)?;
223 Some(Self::CLd { rd, rs1, uimm })
224 }
225 0b110 => {
227 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
228 let uimm2 = ((inst >> 6u8) & 1) as u8;
229 let uimm6 = ((inst >> 5u8) & 1) as u8;
230 let uimm = (uimm6 << 6u8) | (uimm5_3 << 3u8) | (uimm2 << 2u8);
231 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
232 let rs2_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
233 let rs1 = Reg::from_bits(rs1_bits)?;
234 let rs2 = Reg::from_bits(rs2_bits)?;
235 Some(Self::CSw { rs1, rs2, uimm })
236 }
237 0b111 => {
239 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
240 let uimm7_6 = ((inst >> 5u8) & 0b11) as u8;
241 let uimm = (uimm7_6 << 6u8) | (uimm5_3 << 3u8);
242 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
243 let rs2_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
244 let rs1 = Reg::from_bits(rs1_bits)?;
245 let rs2 = Reg::from_bits(rs2_bits)?;
246 Some(Self::CSd { rs1, rs2, uimm })
247 }
248 _ => None,
250 },
251
252 0b01 => match funct3 {
254 0b000 => {
257 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
258 let imm5 = ((inst >> 12u8) & 1) as u8;
259 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
260 let imm_raw = (imm5 << 5u8) | imm4_0;
261 let nzimm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
263 if rd_bits == 0 && nzimm == 0 {
264 Some(Self::CNop)
265 } else {
266 let rd = Reg::from_bits(rd_bits)?;
267 Some(Self::CAddi { rd, nzimm })
268 }
269 }
270 0b001 => {
273 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
274 if rd_bits == 0 {
276 None?;
277 }
278 let rd = Reg::from_bits(rd_bits)?;
279 let imm5 = ((inst >> 12u8) & 1) as u8;
280 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
281 let imm_raw = (imm5 << 5u8) | imm4_0;
282 let imm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
283 Some(Self::CAddiw { rd, imm })
284 }
285 0b010 => {
288 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
289 let rd = Reg::from_bits(rd_bits)?;
290 let imm5 = ((inst >> 12u8) & 1) as u8;
291 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
292 let imm_raw = (imm5 << 5u8) | imm4_0;
293 let imm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
294 Some(Self::CLi { rd, imm })
295 }
296 0b011 => {
298 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
299 if rd_bits == 2 {
300 let imm9 = ((inst >> 12u8) & 1).cast_signed();
307 let imm4 = ((inst >> 6u8) & 1).cast_signed();
308 let imm6 = ((inst >> 5u8) & 1).cast_signed();
309 let imm8_7 = ((inst >> 3u8) & 0b11).cast_signed();
310 let imm5 = ((inst >> 2u8) & 1).cast_signed();
311 let raw = (imm9 << 9u8)
312 | (imm8_7 << 7u8)
313 | (imm6 << 6u8)
314 | (imm5 << 5u8)
315 | (imm4 << 4u8);
316 if raw == 0 {
317 None?;
318 }
319 let nzimm = (raw << 6u8) >> 6u8;
321 Some(Self::CAddi16sp { nzimm })
322 } else {
323 let rd = Reg::from_bits(rd_bits)?;
325 let imm17 = ((inst >> 12u8) & 1) as i32;
328 let imm16_12 = ((inst >> 2u8) & 0x1f) as i32;
329 let raw = (imm17 << 17u8) | (imm16_12 << 12u8);
330 if raw == 0 {
331 None?;
332 }
333 let nzimm = I24::from_i32((raw << 14u8) >> 14u8);
335 Some(Self::CLui { rd, nzimm })
336 }
337 }
338 0b100 => {
340 let funct2 = ((inst >> 10u8) & 0b11) as u8;
341 let rd_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
342 match funct2 {
343 0b00 => {
346 let rd = Reg::from_bits(rd_bits)?;
347 let shamt5 = ((inst >> 12u8) & 1) as u8;
348 let shamt40 = ((inst >> 2u8) & 0x1f) as u8;
349 Some(Self::CSrli {
350 rd,
351 shamt: (shamt5 << 5u8) | shamt40,
352 })
353 }
354 0b01 => {
357 let rd = Reg::from_bits(rd_bits)?;
358 let shamt5 = ((inst >> 12u8) & 1) as u8;
359 let shamt40 = ((inst >> 2u8) & 0x1f) as u8;
360 Some(Self::CSrai {
361 rd,
362 shamt: (shamt5 << 5u8) | shamt40,
363 })
364 }
365 0b10 => {
367 let rd = Reg::from_bits(rd_bits)?;
368 let imm5 = ((inst >> 12u8) & 1) as u8;
369 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
370 let imm_raw = (imm5 << 5u8) | imm4_0;
371 let imm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
372 Some(Self::CAndi { rd, imm })
373 }
374 0b11 => {
376 let bit12 = (inst >> 12u8) & 1;
377 let funct2b = ((inst >> 5u8) & 0b11) as u8;
378 let rs2_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
379 let rd = Reg::from_bits(rd_bits)?;
380 let rs2 = Reg::from_bits(rs2_bits)?;
381 if bit12 == 0 {
382 match funct2b {
383 0b00 => Some(Self::CSub { rd, rs2 }),
384 0b01 => Some(Self::CXor { rd, rs2 }),
385 0b10 => Some(Self::COr { rd, rs2 }),
386 0b11 => Some(Self::CAnd { rd, rs2 }),
387 _ => None,
388 }
389 } else {
390 match funct2b {
392 0b00 => Some(Self::CSubw { rd, rs2 }),
393 0b01 => Some(Self::CAddw { rd, rs2 }),
394 _ => None,
396 }
397 }
398 }
399 _ => None,
400 }
401 }
402 0b101 => Some(Self::CJ {
404 imm: decode_cj_imm(inst),
405 }),
406 0b110 => {
408 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
409 let rs1 = Reg::from_bits(rs1_bits)?;
410 Some(Self::CBeqz {
411 rs1,
412 imm: decode_cb_branch_imm(inst),
413 })
414 }
415 0b111 => {
417 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
418 let rs1 = Reg::from_bits(rs1_bits)?;
419 Some(Self::CBnez {
420 rs1,
421 imm: decode_cb_branch_imm(inst),
422 })
423 }
424 _ => None,
425 },
426
427 0b10 => match funct3 {
429 0b000 => {
432 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
433 let rd = Reg::from_bits(rd_bits)?;
434 let shamt5 = ((inst >> 12u8) & 1) as u8;
435 let shamt40 = ((inst >> 2u8) & 0x1f) as u8;
436 Some(Self::CSlli {
437 rd,
438 shamt: (shamt5 << 5u8) | shamt40,
439 })
440 }
441 0b010 => {
444 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
445 if rd_bits == 0 {
446 None?;
447 }
448 let rd = Reg::from_bits(rd_bits)?;
449 let uimm5 = ((inst >> 12u8) & 1) as u8;
450 let uimm42 = ((inst >> 4u8) & 0b111) as u8;
451 let uimm76 = ((inst >> 2u8) & 0b11) as u8;
452 let uimm = (uimm76 << 6u8) | (uimm5 << 5u8) | (uimm42 << 2u8);
453 Some(Self::CLwsp { rd, uimm })
454 }
455 0b011 => {
458 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
459 if rd_bits == 0 {
460 None?;
461 }
462 let rd = Reg::from_bits(rd_bits)?;
463 let uimm5 = (inst >> 12u8) & 1;
464 let uimm43 = (inst >> 5u8) & 0b11;
465 let uimm86 = (inst >> 2u8) & 0b111;
466 let uimm = (uimm86 << 6u8) | (uimm5 << 5u8) | (uimm43 << 3u8);
467 Some(Self::CLdsp { rd, uimm })
468 }
469 0b100 => {
471 let rs1_bits = ((inst >> 7u8) & 0x1f) as u8;
472 let rs2_bits = ((inst >> 2u8) & 0x1f) as u8;
473 let bit12 = (inst >> 12u8) & 1;
474 if bit12 == 0 {
475 if rs2_bits == 0 {
476 if rs1_bits == 0 {
478 None?;
479 }
480 let rs1 = Reg::from_bits(rs1_bits)?;
481 Some(Self::CJr { rs1 })
482 } else {
483 let rd = Reg::from_bits(rs1_bits)?;
485 let rs2 = Reg::from_bits(rs2_bits)?;
486 Some(Self::CMv { rd, rs2 })
487 }
488 } else if rs2_bits == 0 {
489 if rs1_bits == 0 {
490 Some(Self::CEbreak)
492 } else {
493 let rs1 = Reg::from_bits(rs1_bits)?;
495 Some(Self::CJalr { rs1 })
496 }
497 } else {
498 let rd = Reg::from_bits(rs1_bits)?;
500 let rs2 = Reg::from_bits(rs2_bits)?;
501 Some(Self::CAdd { rd, rs2 })
502 }
503 }
504 0b110 => {
506 let rs2_bits = ((inst >> 2u8) & 0x1f) as u8;
507 let rs2 = Reg::from_bits(rs2_bits)?;
508 let uimm52 = ((inst >> 9u8) & 0xf) as u8;
509 let uimm76 = ((inst >> 7u8) & 0b11) as u8;
510 let uimm = (uimm76 << 6u8) | (uimm52 << 2u8);
511 Some(Self::CSwsp { rs2, uimm })
512 }
513 0b111 => {
515 let rs2_bits = ((inst >> 2u8) & 0x1f) as u8;
516 let rs2 = Reg::from_bits(rs2_bits)?;
517 let uimm53 = (inst >> 10u8) & 0b111;
518 let uimm86 = (inst >> 7u8) & 0b111;
519 let uimm = (uimm86 << 6u8) | (uimm53 << 3u8);
520 Some(Self::CSdsp { rs2, uimm })
521 }
522 _ => None,
523 },
524
525 _ => None,
527 }
528 }
529
530 #[inline(always)]
531 fn alignment() -> u8 {
532 align_of::<u16>() as u8
533 }
534
535 #[inline(always)]
536 fn size(&self) -> u8 {
537 size_of::<u16>() as u8
538 }
539}
540
541#[instruction]
542impl<Reg> fmt::Display for Rv64ZcaInstruction<Reg>
543where
544 Reg: fmt::Display,
545{
546 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
547 match self {
548 Self::CAddi4spn { rd, nzuimm } => write!(f, "c.addi4spn {rd}, sp, {nzuimm}"),
549 Self::CLw { rd, rs1, uimm } => write!(f, "c.lw {rd}, {uimm}({rs1})"),
550 Self::CLd { rd, rs1, uimm } => write!(f, "c.ld {rd}, {uimm}({rs1})"),
551 Self::CSw { rs1, rs2, uimm } => write!(f, "c.sw {rs2}, {uimm}({rs1})"),
552 Self::CSd { rs1, rs2, uimm } => write!(f, "c.sd {rs2}, {uimm}({rs1})"),
553 Self::CNop => write!(f, "c.nop"),
554 Self::CAddi { rd, nzimm } => write!(f, "c.addi {rd}, {nzimm}"),
555 Self::CAddiw { rd, imm } => write!(f, "c.addiw {rd}, {imm}"),
556 Self::CLi { rd, imm } => write!(f, "c.li {rd}, {imm}"),
557 Self::CAddi16sp { nzimm } => write!(f, "c.addi16sp sp, {nzimm}"),
558 Self::CLui { rd, nzimm } => write!(f, "c.lui {rd}, 0x{:x}", nzimm >> 12u8),
559 Self::CSrli { rd, shamt } => write!(f, "c.srli {rd}, {shamt}"),
560 Self::CSrai { rd, shamt } => write!(f, "c.srai {rd}, {shamt}"),
561 Self::CAndi { rd, imm } => write!(f, "c.andi {rd}, {imm}"),
562 Self::CSub { rd, rs2 } => write!(f, "c.sub {rd}, {rs2}"),
563 Self::CXor { rd, rs2 } => write!(f, "c.xor {rd}, {rs2}"),
564 Self::COr { rd, rs2 } => write!(f, "c.or {rd}, {rs2}"),
565 Self::CAnd { rd, rs2 } => write!(f, "c.and {rd}, {rs2}"),
566 Self::CSubw { rd, rs2 } => write!(f, "c.subw {rd}, {rs2}"),
567 Self::CAddw { rd, rs2 } => write!(f, "c.addw {rd}, {rs2}"),
568 Self::CJ { imm } => write!(f, "c.j {imm}"),
569 Self::CBeqz { rs1, imm } => write!(f, "c.beqz {rs1}, {imm}"),
570 Self::CBnez { rs1, imm } => write!(f, "c.bnez {rs1}, {imm}"),
571 Self::CSlli { rd, shamt } => write!(f, "c.slli {rd}, {shamt}"),
572 Self::CLwsp { rd, uimm } => write!(f, "c.lwsp {rd}, {uimm}(sp)"),
573 Self::CLdsp { rd, uimm } => write!(f, "c.ldsp {rd}, {uimm}(sp)"),
574 Self::CJr { rs1 } => write!(f, "c.jr {rs1}"),
575 Self::CMv { rd, rs2 } => write!(f, "c.mv {rd}, {rs2}"),
576 Self::CEbreak => write!(f, "c.ebreak"),
577 Self::CJalr { rs1 } => write!(f, "c.jalr {rs1}"),
578 Self::CAdd { rd, rs2 } => write!(f, "c.add {rd}, {rs2}"),
579 Self::CSwsp { rs2, uimm } => write!(f, "c.swsp {rs2}, {uimm}(sp)"),
580 Self::CSdsp { rs2, uimm } => write!(f, "c.sdsp {rs2}, {uimm}(sp)"),
581 Self::CUnimp => write!(f, "c.unimp"),
582 }
583 }
584}