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]
94impl<Reg> const Instruction for Rv64ZcaInstruction<Reg>
95where
96 Reg: [const] Register<Type = u64>,
97{
98 type Reg = Reg;
99
100 #[inline(always)]
101 fn try_decode(instruction: u32) -> Option<Self> {
102 #[inline(always)]
104 const fn prime_reg_bits(bits: u8) -> u8 {
105 bits + 8
106 }
107
108 #[inline(always)]
120 const fn decode_cb_branch_imm(inst: u16) -> i16 {
121 let imm8 = ((inst >> 12) & 1).cast_signed();
122 let imm4_3 = ((inst >> 10) & 0b11).cast_signed();
123 let imm7_6 = ((inst >> 5) & 0b11).cast_signed();
124 let imm2_1 = ((inst >> 3) & 0b11).cast_signed();
125 let imm5 = ((inst >> 2) & 1).cast_signed();
126 let raw = (imm8 << 8) | (imm7_6 << 6) | (imm5 << 5) | (imm4_3 << 3) | (imm2_1 << 1);
127 (raw << 7) >> 7
129 }
130
131 #[inline(always)]
146 const fn decode_cj_imm(inst: u16) -> i16 {
147 let imm11 = ((inst >> 12) & 1).cast_signed();
148 let imm4 = ((inst >> 11) & 1).cast_signed();
149 let imm9_8 = ((inst >> 9) & 0b11).cast_signed();
150 let imm10 = ((inst >> 8) & 1).cast_signed();
151 let imm6 = ((inst >> 7) & 1).cast_signed();
152 let imm7 = ((inst >> 6) & 1).cast_signed();
153 let imm3_1 = ((inst >> 3) & 0b111).cast_signed();
154 let imm5 = ((inst >> 2) & 1).cast_signed();
155 let raw = (imm11 << 11)
156 | (imm10 << 10)
157 | (imm9_8 << 8)
158 | (imm7 << 7)
159 | (imm6 << 6)
160 | (imm5 << 5)
161 | (imm4 << 4)
162 | (imm3_1 << 1);
163 (raw << 4) >> 4
165 }
166
167 let inst = instruction as u16;
168 let quadrant = inst & 0b11;
169 let funct3 = ((inst >> 13) & 0b111) as u8;
170
171 match quadrant {
172 0b00 => match funct3 {
174 0b000 => {
180 let imm5_4 = (inst >> 11) & 0b11;
181 let imm9_6 = (inst >> 7) & 0xf;
182 let imm2 = (inst >> 6) & 1;
183 let imm3 = (inst >> 5) & 1;
184 let nzuimm = (imm9_6 << 6) | (imm5_4 << 4) | (imm3 << 3) | (imm2 << 2);
185 if nzuimm == 0 {
186 if inst == 0 {
187 Some(Self::CUnimp)
188 } else {
189 None
191 }
192 } else {
193 let rd_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
194 let rd = Reg::from_bits(rd_bits)?;
195 Some(Self::CAddi4spn { rd, nzuimm })
196 }
197 }
198 0b010 => {
201 let uimm5_3 = ((inst >> 10) & 0b111) as u8;
202 let uimm2 = ((inst >> 6) & 1) as u8;
203 let uimm6 = ((inst >> 5) & 1) as u8;
204 let uimm = (uimm6 << 6) | (uimm5_3 << 3) | (uimm2 << 2);
205 let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
206 let rd_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
207 let rs1 = Reg::from_bits(rs1_bits)?;
208 let rd = Reg::from_bits(rd_bits)?;
209 Some(Self::CLw { rd, rs1, uimm })
210 }
211 0b011 => {
214 let uimm5_3 = ((inst >> 10) & 0b111) as u8;
215 let uimm7_6 = ((inst >> 5) & 0b11) as u8;
216 let uimm = (uimm7_6 << 6) | (uimm5_3 << 3);
217 let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
218 let rd_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
219 let rs1 = Reg::from_bits(rs1_bits)?;
220 let rd = Reg::from_bits(rd_bits)?;
221 Some(Self::CLd { rd, rs1, uimm })
222 }
223 0b110 => {
225 let uimm5_3 = ((inst >> 10) & 0b111) as u8;
226 let uimm2 = ((inst >> 6) & 1) as u8;
227 let uimm6 = ((inst >> 5) & 1) as u8;
228 let uimm = (uimm6 << 6) | (uimm5_3 << 3) | (uimm2 << 2);
229 let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
230 let rs2_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
231 let rs1 = Reg::from_bits(rs1_bits)?;
232 let rs2 = Reg::from_bits(rs2_bits)?;
233 Some(Self::CSw { rs1, rs2, uimm })
234 }
235 0b111 => {
237 let uimm5_3 = ((inst >> 10) & 0b111) as u8;
238 let uimm7_6 = ((inst >> 5) & 0b11) as u8;
239 let uimm = (uimm7_6 << 6) | (uimm5_3 << 3);
240 let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
241 let rs2_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
242 let rs1 = Reg::from_bits(rs1_bits)?;
243 let rs2 = Reg::from_bits(rs2_bits)?;
244 Some(Self::CSd { rs1, rs2, uimm })
245 }
246 _ => None,
248 },
249
250 0b01 => match funct3 {
252 0b000 => {
255 let rd_bits = ((inst >> 7) & 0x1f) as u8;
256 let imm5 = ((inst >> 12) & 1) as u8;
257 let imm4_0 = ((inst >> 2) & 0x1f) as u8;
258 let imm_raw = (imm5 << 5) | imm4_0;
259 let nzimm = ((imm_raw.cast_signed()) << 2) >> 2;
261 if rd_bits == 0 && nzimm == 0 {
262 Some(Self::CNop)
263 } else {
264 let rd = Reg::from_bits(rd_bits)?;
265 Some(Self::CAddi { rd, nzimm })
266 }
267 }
268 0b001 => {
271 let rd_bits = ((inst >> 7) & 0x1f) as u8;
272 if rd_bits == 0 {
274 None?;
275 }
276 let rd = Reg::from_bits(rd_bits)?;
277 let imm5 = ((inst >> 12) & 1) as u8;
278 let imm4_0 = ((inst >> 2) & 0x1f) as u8;
279 let imm_raw = (imm5 << 5) | imm4_0;
280 let imm = ((imm_raw.cast_signed()) << 2) >> 2;
281 Some(Self::CAddiw { rd, imm })
282 }
283 0b010 => {
286 let rd_bits = ((inst >> 7) & 0x1f) as u8;
287 let rd = Reg::from_bits(rd_bits)?;
288 let imm5 = ((inst >> 12) & 1) as u8;
289 let imm4_0 = ((inst >> 2) & 0x1f) as u8;
290 let imm_raw = (imm5 << 5) | imm4_0;
291 let imm = ((imm_raw.cast_signed()) << 2) >> 2;
292 Some(Self::CLi { rd, imm })
293 }
294 0b011 => {
296 let rd_bits = ((inst >> 7) & 0x1f) as u8;
297 if rd_bits == 2 {
298 let imm9 = ((inst >> 12) & 1).cast_signed();
305 let imm4 = ((inst >> 6) & 1).cast_signed();
306 let imm6 = ((inst >> 5) & 1).cast_signed();
307 let imm8_7 = ((inst >> 3) & 0b11).cast_signed();
308 let imm5 = ((inst >> 2) & 1).cast_signed();
309 let raw =
310 (imm9 << 9) | (imm8_7 << 7) | (imm6 << 6) | (imm5 << 5) | (imm4 << 4);
311 if raw == 0 {
312 None?;
313 }
314 let nzimm = (raw << 6) >> 6;
316 Some(Self::CAddi16sp { nzimm })
317 } else {
318 let rd = Reg::from_bits(rd_bits)?;
320 let imm17 = ((inst >> 12) & 1) as i32;
323 let imm16_12 = ((inst >> 2) & 0x1f) as i32;
324 let raw = (imm17 << 17) | (imm16_12 << 12);
325 if raw == 0 {
326 None?;
327 }
328 let nzimm = I24::from_i32((raw << 14) >> 14);
330 Some(Self::CLui { rd, nzimm })
331 }
332 }
333 0b100 => {
335 let funct2 = ((inst >> 10) & 0b11) as u8;
336 let rd_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
337 match funct2 {
338 0b00 => {
341 let rd = Reg::from_bits(rd_bits)?;
342 let shamt5 = ((inst >> 12) & 1) as u8;
343 let shamt40 = ((inst >> 2) & 0x1f) as u8;
344 Some(Self::CSrli {
345 rd,
346 shamt: (shamt5 << 5) | shamt40,
347 })
348 }
349 0b01 => {
352 let rd = Reg::from_bits(rd_bits)?;
353 let shamt5 = ((inst >> 12) & 1) as u8;
354 let shamt40 = ((inst >> 2) & 0x1f) as u8;
355 Some(Self::CSrai {
356 rd,
357 shamt: (shamt5 << 5) | shamt40,
358 })
359 }
360 0b10 => {
362 let rd = Reg::from_bits(rd_bits)?;
363 let imm5 = ((inst >> 12) & 1) as u8;
364 let imm4_0 = ((inst >> 2) & 0x1f) as u8;
365 let imm_raw = (imm5 << 5) | imm4_0;
366 let imm = ((imm_raw.cast_signed()) << 2) >> 2;
367 Some(Self::CAndi { rd, imm })
368 }
369 0b11 => {
371 let bit12 = (inst >> 12) & 1;
372 let funct2b = ((inst >> 5) & 0b11) as u8;
373 let rs2_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
374 let rd = Reg::from_bits(rd_bits)?;
375 let rs2 = Reg::from_bits(rs2_bits)?;
376 if bit12 == 0 {
377 match funct2b {
378 0b00 => Some(Self::CSub { rd, rs2 }),
379 0b01 => Some(Self::CXor { rd, rs2 }),
380 0b10 => Some(Self::COr { rd, rs2 }),
381 0b11 => Some(Self::CAnd { rd, rs2 }),
382 _ => None,
383 }
384 } else {
385 match funct2b {
387 0b00 => Some(Self::CSubw { rd, rs2 }),
388 0b01 => Some(Self::CAddw { rd, rs2 }),
389 _ => None,
391 }
392 }
393 }
394 _ => None,
395 }
396 }
397 0b101 => Some(Self::CJ {
399 imm: decode_cj_imm(inst),
400 }),
401 0b110 => {
403 let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
404 let rs1 = Reg::from_bits(rs1_bits)?;
405 Some(Self::CBeqz {
406 rs1,
407 imm: decode_cb_branch_imm(inst),
408 })
409 }
410 0b111 => {
412 let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
413 let rs1 = Reg::from_bits(rs1_bits)?;
414 Some(Self::CBnez {
415 rs1,
416 imm: decode_cb_branch_imm(inst),
417 })
418 }
419 _ => None,
420 },
421
422 0b10 => match funct3 {
424 0b000 => {
427 let rd_bits = ((inst >> 7) & 0x1f) as u8;
428 let rd = Reg::from_bits(rd_bits)?;
429 let shamt5 = ((inst >> 12) & 1) as u8;
430 let shamt40 = ((inst >> 2) & 0x1f) as u8;
431 Some(Self::CSlli {
432 rd,
433 shamt: (shamt5 << 5) | shamt40,
434 })
435 }
436 0b010 => {
439 let rd_bits = ((inst >> 7) & 0x1f) as u8;
440 if rd_bits == 0 {
441 None?;
442 }
443 let rd = Reg::from_bits(rd_bits)?;
444 let uimm5 = ((inst >> 12) & 1) as u8;
445 let uimm42 = ((inst >> 4) & 0b111) as u8;
446 let uimm76 = ((inst >> 2) & 0b11) as u8;
447 let uimm = (uimm76 << 6) | (uimm5 << 5) | (uimm42 << 2);
448 Some(Self::CLwsp { rd, uimm })
449 }
450 0b011 => {
453 let rd_bits = ((inst >> 7) & 0x1f) as u8;
454 if rd_bits == 0 {
455 None?;
456 }
457 let rd = Reg::from_bits(rd_bits)?;
458 let uimm5 = (inst >> 12) & 1;
459 let uimm43 = (inst >> 5) & 0b11;
460 let uimm86 = (inst >> 2) & 0b111;
461 let uimm = (uimm86 << 6) | (uimm5 << 5) | (uimm43 << 3);
462 Some(Self::CLdsp { rd, uimm })
463 }
464 0b100 => {
466 let rs1_bits = ((inst >> 7) & 0x1f) as u8;
467 let rs2_bits = ((inst >> 2) & 0x1f) as u8;
468 let bit12 = (inst >> 12) & 1;
469 if bit12 == 0 {
470 if rs2_bits == 0 {
471 if rs1_bits == 0 {
473 None?;
474 }
475 let rs1 = Reg::from_bits(rs1_bits)?;
476 Some(Self::CJr { rs1 })
477 } else {
478 let rd = Reg::from_bits(rs1_bits)?;
480 let rs2 = Reg::from_bits(rs2_bits)?;
481 Some(Self::CMv { rd, rs2 })
482 }
483 } else if rs2_bits == 0 {
484 if rs1_bits == 0 {
485 Some(Self::CEbreak)
487 } else {
488 let rs1 = Reg::from_bits(rs1_bits)?;
490 Some(Self::CJalr { rs1 })
491 }
492 } else {
493 let rd = Reg::from_bits(rs1_bits)?;
495 let rs2 = Reg::from_bits(rs2_bits)?;
496 Some(Self::CAdd { rd, rs2 })
497 }
498 }
499 0b110 => {
501 let rs2_bits = ((inst >> 2) & 0x1f) as u8;
502 let rs2 = Reg::from_bits(rs2_bits)?;
503 let uimm52 = ((inst >> 9) & 0xf) as u8;
504 let uimm76 = ((inst >> 7) & 0b11) as u8;
505 let uimm = (uimm76 << 6) | (uimm52 << 2);
506 Some(Self::CSwsp { rs2, uimm })
507 }
508 0b111 => {
510 let rs2_bits = ((inst >> 2) & 0x1f) as u8;
511 let rs2 = Reg::from_bits(rs2_bits)?;
512 let uimm53 = (inst >> 10) & 0b111;
513 let uimm86 = (inst >> 7) & 0b111;
514 let uimm = (uimm86 << 6) | (uimm53 << 3);
515 Some(Self::CSdsp { rs2, uimm })
516 }
517 _ => None,
518 },
519
520 _ => None,
522 }
523 }
524
525 #[inline(always)]
526 fn alignment() -> u8 {
527 align_of::<u16>() as u8
528 }
529
530 #[inline(always)]
531 fn size(&self) -> u8 {
532 size_of::<u16>() as u8
533 }
534}
535
536#[instruction]
537impl<Reg> fmt::Display for Rv64ZcaInstruction<Reg>
538where
539 Reg: fmt::Display,
540{
541 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
542 match self {
543 Self::CAddi4spn { rd, nzuimm } => write!(f, "c.addi4spn {rd}, sp, {nzuimm}"),
544 Self::CLw { rd, rs1, uimm } => write!(f, "c.lw {rd}, {uimm}({rs1})"),
545 Self::CLd { rd, rs1, uimm } => write!(f, "c.ld {rd}, {uimm}({rs1})"),
546 Self::CSw { rs1, rs2, uimm } => write!(f, "c.sw {rs2}, {uimm}({rs1})"),
547 Self::CSd { rs1, rs2, uimm } => write!(f, "c.sd {rs2}, {uimm}({rs1})"),
548 Self::CNop => write!(f, "c.nop"),
549 Self::CAddi { rd, nzimm } => write!(f, "c.addi {rd}, {nzimm}"),
550 Self::CAddiw { rd, imm } => write!(f, "c.addiw {rd}, {imm}"),
551 Self::CLi { rd, imm } => write!(f, "c.li {rd}, {imm}"),
552 Self::CAddi16sp { nzimm } => write!(f, "c.addi16sp sp, {nzimm}"),
553 Self::CLui { rd, nzimm } => write!(f, "c.lui {rd}, 0x{:x}", nzimm >> 12),
554 Self::CSrli { rd, shamt } => write!(f, "c.srli {rd}, {shamt}"),
555 Self::CSrai { rd, shamt } => write!(f, "c.srai {rd}, {shamt}"),
556 Self::CAndi { rd, imm } => write!(f, "c.andi {rd}, {imm}"),
557 Self::CSub { rd, rs2 } => write!(f, "c.sub {rd}, {rs2}"),
558 Self::CXor { rd, rs2 } => write!(f, "c.xor {rd}, {rs2}"),
559 Self::COr { rd, rs2 } => write!(f, "c.or {rd}, {rs2}"),
560 Self::CAnd { rd, rs2 } => write!(f, "c.and {rd}, {rs2}"),
561 Self::CSubw { rd, rs2 } => write!(f, "c.subw {rd}, {rs2}"),
562 Self::CAddw { rd, rs2 } => write!(f, "c.addw {rd}, {rs2}"),
563 Self::CJ { imm } => write!(f, "c.j {imm}"),
564 Self::CBeqz { rs1, imm } => write!(f, "c.beqz {rs1}, {imm}"),
565 Self::CBnez { rs1, imm } => write!(f, "c.bnez {rs1}, {imm}"),
566 Self::CSlli { rd, shamt } => write!(f, "c.slli {rd}, {shamt}"),
567 Self::CLwsp { rd, uimm } => write!(f, "c.lwsp {rd}, {uimm}(sp)"),
568 Self::CLdsp { rd, uimm } => write!(f, "c.ldsp {rd}, {uimm}(sp)"),
569 Self::CJr { rs1 } => write!(f, "c.jr {rs1}"),
570 Self::CMv { rd, rs2 } => write!(f, "c.mv {rd}, {rs2}"),
571 Self::CEbreak => write!(f, "c.ebreak"),
572 Self::CJalr { rs1 } => write!(f, "c.jalr {rs1}"),
573 Self::CAdd { rd, rs2 } => write!(f, "c.add {rd}, {rs2}"),
574 Self::CSwsp { rs2, uimm } => write!(f, "c.swsp {rs2}, {uimm}(sp)"),
575 Self::CSdsp { rs2, uimm } => write!(f, "c.sdsp {rs2}, {uimm}(sp)"),
576 Self::CUnimp => write!(f, "c.unimp"),
577 }
578 }
579}