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 const ALIGNMENT: u8 = align_of::<u16>() as u8;
100
101 type Reg = Reg;
102
103 #[inline(always)]
104 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
105 fn try_decode(instruction: u32) -> Option<Self> {
106 #[inline(always)]
108 const fn prime_reg_bits(bits: u8) -> u8 {
109 bits + 8
110 }
111
112 #[inline(always)]
124 const fn decode_cb_branch_imm(inst: u16) -> i16 {
125 let imm8 = ((inst >> 12u8) & 1).cast_signed();
126 let imm4_3 = ((inst >> 10u8) & 0b11).cast_signed();
127 let imm7_6 = ((inst >> 5u8) & 0b11).cast_signed();
128 let imm2_1 = ((inst >> 3u8) & 0b11).cast_signed();
129 let imm5 = ((inst >> 2u8) & 1).cast_signed();
130 let raw =
131 (imm8 << 8u8) | (imm7_6 << 6u8) | (imm5 << 5u8) | (imm4_3 << 3u8) | (imm2_1 << 1u8);
132 (raw << 7u8) >> 7u8
134 }
135
136 #[inline(always)]
151 const fn decode_cj_imm(inst: u16) -> i16 {
152 let imm11 = ((inst >> 12u8) & 1).cast_signed();
153 let imm4 = ((inst >> 11u8) & 1).cast_signed();
154 let imm9_8 = ((inst >> 9u8) & 0b11).cast_signed();
155 let imm10 = ((inst >> 8u8) & 1).cast_signed();
156 let imm6 = ((inst >> 7u8) & 1).cast_signed();
157 let imm7 = ((inst >> 6u8) & 1).cast_signed();
158 let imm3_1 = ((inst >> 3u8) & 0b111).cast_signed();
159 let imm5 = ((inst >> 2u8) & 1).cast_signed();
160 let raw = (imm11 << 11u8)
161 | (imm10 << 10u8)
162 | (imm9_8 << 8u8)
163 | (imm7 << 7u8)
164 | (imm6 << 6u8)
165 | (imm5 << 5u8)
166 | (imm4 << 4u8)
167 | (imm3_1 << 1u8);
168 (raw << 4u8) >> 4u8
170 }
171
172 let inst = instruction as u16;
173 let quadrant = inst & 0b11;
174 let funct3 = ((inst >> 13u8) & 0b111) as u8;
175
176 match quadrant {
177 0b00 => match funct3 {
179 0b000 => {
185 let imm5_4 = (inst >> 11u8) & 0b11;
186 let imm9_6 = (inst >> 7u8) & 0xf;
187 let imm2 = (inst >> 6u8) & 1;
188 let imm3 = (inst >> 5u8) & 1;
189 let nzuimm = (imm9_6 << 6u8) | (imm5_4 << 4u8) | (imm3 << 3u8) | (imm2 << 2u8);
190 if nzuimm == 0 {
191 if inst == 0 {
192 Some(Self::CUnimp)
193 } else {
194 None
196 }
197 } else {
198 let rd_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
199 let rd = Reg::from_bits(rd_bits)?;
200 Some(Self::CAddi4spn { rd, nzuimm })
201 }
202 }
203 0b010 => {
206 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
207 let uimm2 = ((inst >> 6u8) & 1) as u8;
208 let uimm6 = ((inst >> 5u8) & 1) as u8;
209 let uimm = (uimm6 << 6u8) | (uimm5_3 << 3u8) | (uimm2 << 2u8);
210 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
211 let rd_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
212 let rs1 = Reg::from_bits(rs1_bits)?;
213 let rd = Reg::from_bits(rd_bits)?;
214 Some(Self::CLw { rd, rs1, uimm })
215 }
216 0b011 => {
219 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
220 let uimm7_6 = ((inst >> 5u8) & 0b11) as u8;
221 let uimm = (uimm7_6 << 6u8) | (uimm5_3 << 3u8);
222 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
223 let rd_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
224 let rs1 = Reg::from_bits(rs1_bits)?;
225 let rd = Reg::from_bits(rd_bits)?;
226 Some(Self::CLd { rd, rs1, uimm })
227 }
228 0b110 => {
230 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
231 let uimm2 = ((inst >> 6u8) & 1) as u8;
232 let uimm6 = ((inst >> 5u8) & 1) as u8;
233 let uimm = (uimm6 << 6u8) | (uimm5_3 << 3u8) | (uimm2 << 2u8);
234 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
235 let rs2_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
236 let rs1 = Reg::from_bits(rs1_bits)?;
237 let rs2 = Reg::from_bits(rs2_bits)?;
238 Some(Self::CSw { rs1, rs2, uimm })
239 }
240 0b111 => {
242 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
243 let uimm7_6 = ((inst >> 5u8) & 0b11) as u8;
244 let uimm = (uimm7_6 << 6u8) | (uimm5_3 << 3u8);
245 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
246 let rs2_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
247 let rs1 = Reg::from_bits(rs1_bits)?;
248 let rs2 = Reg::from_bits(rs2_bits)?;
249 Some(Self::CSd { rs1, rs2, uimm })
250 }
251 _ => None,
253 },
254
255 0b01 => match funct3 {
257 0b000 => {
260 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
261 let imm5 = ((inst >> 12u8) & 1) as u8;
262 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
263 let imm_raw = (imm5 << 5u8) | imm4_0;
264 let nzimm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
266 if rd_bits == 0 && nzimm == 0 {
267 Some(Self::CNop)
268 } else {
269 let rd = Reg::from_bits(rd_bits)?;
270 Some(Self::CAddi { rd, nzimm })
271 }
272 }
273 0b001 => {
276 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
277 if rd_bits == 0 {
279 None?;
280 }
281 let rd = Reg::from_bits(rd_bits)?;
282 let imm5 = ((inst >> 12u8) & 1) as u8;
283 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
284 let imm_raw = (imm5 << 5u8) | imm4_0;
285 let imm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
286 Some(Self::CAddiw { rd, imm })
287 }
288 0b010 => {
291 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
292 let rd = Reg::from_bits(rd_bits)?;
293 let imm5 = ((inst >> 12u8) & 1) as u8;
294 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
295 let imm_raw = (imm5 << 5u8) | imm4_0;
296 let imm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
297 Some(Self::CLi { rd, imm })
298 }
299 0b011 => {
301 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
302 if rd_bits == 2 {
303 let imm9 = ((inst >> 12u8) & 1).cast_signed();
310 let imm4 = ((inst >> 6u8) & 1).cast_signed();
311 let imm6 = ((inst >> 5u8) & 1).cast_signed();
312 let imm8_7 = ((inst >> 3u8) & 0b11).cast_signed();
313 let imm5 = ((inst >> 2u8) & 1).cast_signed();
314 let raw = (imm9 << 9u8)
315 | (imm8_7 << 7u8)
316 | (imm6 << 6u8)
317 | (imm5 << 5u8)
318 | (imm4 << 4u8);
319 if raw == 0 {
320 None?;
321 }
322 let nzimm = (raw << 6u8) >> 6u8;
324 Some(Self::CAddi16sp { nzimm })
325 } else {
326 let rd = Reg::from_bits(rd_bits)?;
328 let imm17 = ((inst >> 12u8) & 1) as i32;
331 let imm16_12 = ((inst >> 2u8) & 0x1f) as i32;
332 let raw = (imm17 << 17u8) | (imm16_12 << 12u8);
333 if raw == 0 {
334 None?;
335 }
336 let nzimm = I24::from_i32((raw << 14u8) >> 14u8);
338 Some(Self::CLui { rd, nzimm })
339 }
340 }
341 0b100 => {
343 let funct2 = ((inst >> 10u8) & 0b11) as u8;
344 let rd_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
345 match funct2 {
346 0b00 => {
349 let rd = Reg::from_bits(rd_bits)?;
350 let shamt5 = ((inst >> 12u8) & 1) as u8;
351 let shamt40 = ((inst >> 2u8) & 0x1f) as u8;
352 Some(Self::CSrli {
353 rd,
354 shamt: (shamt5 << 5u8) | shamt40,
355 })
356 }
357 0b01 => {
360 let rd = Reg::from_bits(rd_bits)?;
361 let shamt5 = ((inst >> 12u8) & 1) as u8;
362 let shamt40 = ((inst >> 2u8) & 0x1f) as u8;
363 Some(Self::CSrai {
364 rd,
365 shamt: (shamt5 << 5u8) | shamt40,
366 })
367 }
368 0b10 => {
370 let rd = Reg::from_bits(rd_bits)?;
371 let imm5 = ((inst >> 12u8) & 1) as u8;
372 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
373 let imm_raw = (imm5 << 5u8) | imm4_0;
374 let imm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
375 Some(Self::CAndi { rd, imm })
376 }
377 0b11 => {
379 let bit12 = (inst >> 12u8) & 1;
380 let funct2b = ((inst >> 5u8) & 0b11) as u8;
381 let rs2_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
382 let rd = Reg::from_bits(rd_bits)?;
383 let rs2 = Reg::from_bits(rs2_bits)?;
384 if bit12 == 0 {
385 match funct2b {
386 0b00 => Some(Self::CSub { rd, rs2 }),
387 0b01 => Some(Self::CXor { rd, rs2 }),
388 0b10 => Some(Self::COr { rd, rs2 }),
389 0b11 => Some(Self::CAnd { rd, rs2 }),
390 _ => None,
391 }
392 } else {
393 match funct2b {
395 0b00 => Some(Self::CSubw { rd, rs2 }),
396 0b01 => Some(Self::CAddw { rd, rs2 }),
397 _ => None,
399 }
400 }
401 }
402 _ => None,
403 }
404 }
405 0b101 => Some(Self::CJ {
407 imm: decode_cj_imm(inst),
408 }),
409 0b110 => {
411 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
412 let rs1 = Reg::from_bits(rs1_bits)?;
413 Some(Self::CBeqz {
414 rs1,
415 imm: decode_cb_branch_imm(inst),
416 })
417 }
418 0b111 => {
420 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
421 let rs1 = Reg::from_bits(rs1_bits)?;
422 Some(Self::CBnez {
423 rs1,
424 imm: decode_cb_branch_imm(inst),
425 })
426 }
427 _ => None,
428 },
429
430 0b10 => match funct3 {
432 0b000 => {
435 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
436 let rd = Reg::from_bits(rd_bits)?;
437 let shamt5 = ((inst >> 12u8) & 1) as u8;
438 let shamt40 = ((inst >> 2u8) & 0x1f) as u8;
439 Some(Self::CSlli {
440 rd,
441 shamt: (shamt5 << 5u8) | shamt40,
442 })
443 }
444 0b010 => {
447 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
448 if rd_bits == 0 {
449 None?;
450 }
451 let rd = Reg::from_bits(rd_bits)?;
452 let uimm5 = ((inst >> 12u8) & 1) as u8;
453 let uimm42 = ((inst >> 4u8) & 0b111) as u8;
454 let uimm76 = ((inst >> 2u8) & 0b11) as u8;
455 let uimm = (uimm76 << 6u8) | (uimm5 << 5u8) | (uimm42 << 2u8);
456 Some(Self::CLwsp { rd, uimm })
457 }
458 0b011 => {
461 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
462 if rd_bits == 0 {
463 None?;
464 }
465 let rd = Reg::from_bits(rd_bits)?;
466 let uimm5 = (inst >> 12u8) & 1;
467 let uimm43 = (inst >> 5u8) & 0b11;
468 let uimm86 = (inst >> 2u8) & 0b111;
469 let uimm = (uimm86 << 6u8) | (uimm5 << 5u8) | (uimm43 << 3u8);
470 Some(Self::CLdsp { rd, uimm })
471 }
472 0b100 => {
474 let rs1_bits = ((inst >> 7u8) & 0x1f) as u8;
475 let rs2_bits = ((inst >> 2u8) & 0x1f) as u8;
476 let bit12 = (inst >> 12u8) & 1;
477 if bit12 == 0 {
478 if rs2_bits == 0 {
479 if rs1_bits == 0 {
481 None?;
482 }
483 let rs1 = Reg::from_bits(rs1_bits)?;
484 Some(Self::CJr { rs1 })
485 } else {
486 let rd = Reg::from_bits(rs1_bits)?;
488 let rs2 = Reg::from_bits(rs2_bits)?;
489 Some(Self::CMv { rd, rs2 })
490 }
491 } else if rs2_bits == 0 {
492 if rs1_bits == 0 {
493 Some(Self::CEbreak)
495 } else {
496 let rs1 = Reg::from_bits(rs1_bits)?;
498 Some(Self::CJalr { rs1 })
499 }
500 } else {
501 let rd = Reg::from_bits(rs1_bits)?;
503 let rs2 = Reg::from_bits(rs2_bits)?;
504 Some(Self::CAdd { rd, rs2 })
505 }
506 }
507 0b110 => {
509 let rs2_bits = ((inst >> 2u8) & 0x1f) as u8;
510 let rs2 = Reg::from_bits(rs2_bits)?;
511 let uimm52 = ((inst >> 9u8) & 0xf) as u8;
512 let uimm76 = ((inst >> 7u8) & 0b11) as u8;
513 let uimm = (uimm76 << 6u8) | (uimm52 << 2u8);
514 Some(Self::CSwsp { rs2, uimm })
515 }
516 0b111 => {
518 let rs2_bits = ((inst >> 2u8) & 0x1f) as u8;
519 let rs2 = Reg::from_bits(rs2_bits)?;
520 let uimm53 = (inst >> 10u8) & 0b111;
521 let uimm86 = (inst >> 7u8) & 0b111;
522 let uimm = (uimm86 << 6u8) | (uimm53 << 3u8);
523 Some(Self::CSdsp { rs2, uimm })
524 }
525 _ => None,
526 },
527
528 _ => None,
530 }
531 }
532
533 #[inline(always)]
534 fn size(&self) -> u8 {
535 size_of::<u16>() as u8
536 }
537}
538
539#[instruction]
540impl<Reg> fmt::Display for Rv64ZcaInstruction<Reg>
541where
542 Reg: fmt::Display,
543{
544 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
545 match self {
546 Self::CAddi4spn { rd, nzuimm } => write!(f, "c.addi4spn {rd}, sp, {nzuimm}"),
547 Self::CLw { rd, rs1, uimm } => write!(f, "c.lw {rd}, {uimm}({rs1})"),
548 Self::CLd { rd, rs1, uimm } => write!(f, "c.ld {rd}, {uimm}({rs1})"),
549 Self::CSw { rs1, rs2, uimm } => write!(f, "c.sw {rs2}, {uimm}({rs1})"),
550 Self::CSd { rs1, rs2, uimm } => write!(f, "c.sd {rs2}, {uimm}({rs1})"),
551 Self::CNop => write!(f, "c.nop"),
552 Self::CAddi { rd, nzimm } => write!(f, "c.addi {rd}, {nzimm}"),
553 Self::CAddiw { rd, imm } => write!(f, "c.addiw {rd}, {imm}"),
554 Self::CLi { rd, imm } => write!(f, "c.li {rd}, {imm}"),
555 Self::CAddi16sp { nzimm } => write!(f, "c.addi16sp sp, {nzimm}"),
556 Self::CLui { rd, nzimm } => write!(f, "c.lui {rd}, 0x{:x}", nzimm >> 12u8),
557 Self::CSrli { rd, shamt } => write!(f, "c.srli {rd}, {shamt}"),
558 Self::CSrai { rd, shamt } => write!(f, "c.srai {rd}, {shamt}"),
559 Self::CAndi { rd, imm } => write!(f, "c.andi {rd}, {imm}"),
560 Self::CSub { rd, rs2 } => write!(f, "c.sub {rd}, {rs2}"),
561 Self::CXor { rd, rs2 } => write!(f, "c.xor {rd}, {rs2}"),
562 Self::COr { rd, rs2 } => write!(f, "c.or {rd}, {rs2}"),
563 Self::CAnd { rd, rs2 } => write!(f, "c.and {rd}, {rs2}"),
564 Self::CSubw { rd, rs2 } => write!(f, "c.subw {rd}, {rs2}"),
565 Self::CAddw { rd, rs2 } => write!(f, "c.addw {rd}, {rs2}"),
566 Self::CJ { imm } => write!(f, "c.j {imm}"),
567 Self::CBeqz { rs1, imm } => write!(f, "c.beqz {rs1}, {imm}"),
568 Self::CBnez { rs1, imm } => write!(f, "c.bnez {rs1}, {imm}"),
569 Self::CSlli { rd, shamt } => write!(f, "c.slli {rd}, {shamt}"),
570 Self::CLwsp { rd, uimm } => write!(f, "c.lwsp {rd}, {uimm}(sp)"),
571 Self::CLdsp { rd, uimm } => write!(f, "c.ldsp {rd}, {uimm}(sp)"),
572 Self::CJr { rs1 } => write!(f, "c.jr {rs1}"),
573 Self::CMv { rd, rs2 } => write!(f, "c.mv {rd}, {rs2}"),
574 Self::CEbreak => write!(f, "c.ebreak"),
575 Self::CJalr { rs1 } => write!(f, "c.jalr {rs1}"),
576 Self::CAdd { rd, rs2 } => write!(f, "c.add {rd}, {rs2}"),
577 Self::CSwsp { rs2, uimm } => write!(f, "c.swsp {rs2}, {uimm}(sp)"),
578 Self::CSdsp { rs2, uimm } => write!(f, "c.sdsp {rs2}, {uimm}(sp)"),
579 Self::CUnimp => write!(f, "c.unimp"),
580 }
581 }
582}