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