1#[cfg(test)]
4mod tests;
5
6use crate::hart::HartConfig;
7use crate::instructions::utils::{I24, Shamt};
8use crate::instructions::{ImplementedExtension, Instruction, IsaExtension};
9use crate::registers::general_purpose::Register;
10use ab_riscv_macros::instruction;
11use core::fmt;
12
13#[instruction]
15#[derive(Debug, Clone, Copy)]
16#[derive_const(PartialEq, Eq)]
17#[rustfmt::skip]
18pub enum Rv64ZcaInstruction<Hart>
19where
20 Hart: HartConfig,
21{
22 CAddi4spn { rd: Hart::Reg, nzuimm: u16 },
25 CLw { rd: Hart::Reg, rs1: Hart::Reg, uimm: u8 },
27 CLd { rd: Hart::Reg, rs1: Hart::Reg, uimm: u8 },
29 CSw { rs1: Hart::Reg, rs2: Hart::Reg, uimm: u8 },
31 CSd { rs1: Hart::Reg, rs2: Hart::Reg, uimm: u8 },
33
34 CNop,
37 CAddi { rd: Hart::Reg, nzimm: i8 },
39 CAddiw { rd: Hart::Reg, imm: i8 },
41 CLi { rd: Hart::Reg, imm: i8 },
43 CAddi16sp { nzimm: i16 },
45 CLui { rd: Hart::Reg, nzimm: I24 },
47 CSrli { rd: Hart::Reg, shamt: Shamt<u64> },
49 CSrai { rd: Hart::Reg, shamt: Shamt<u64> },
51 CAndi { rd: Hart::Reg, imm: i8 },
53 CSub { rd: Hart::Reg, rs2: Hart::Reg },
55 CXor { rd: Hart::Reg, rs2: Hart::Reg },
57 COr { rd: Hart::Reg, rs2: Hart::Reg },
59 CAnd { rd: Hart::Reg, rs2: Hart::Reg },
61 CSubw { rd: Hart::Reg, rs2: Hart::Reg },
63 CAddw { rd: Hart::Reg, rs2: Hart::Reg },
65 CJ { imm: i16 },
67 CBeqz { rs1: Hart::Reg, imm: i16 },
69 CBnez { rs1: Hart::Reg, imm: i16 },
71
72 CSlli { rd: Hart::Reg, shamt: Shamt<u64> },
75 CLwsp { rd: Hart::Reg, uimm: u8 },
77 CLdsp { rd: Hart::Reg, uimm: u16 },
79 CJr { rs1: Hart::Reg },
81 CMv { rd: Hart::Reg, rs2: Hart::Reg },
83 CEbreak,
85 CJalr { rs1: Hart::Reg },
87 CAdd { rd: Hart::Reg, rs2: Hart::Reg },
89 CSwsp { rs2: Hart::Reg, uimm: u8 },
91 CSdsp { rs2: Hart::Reg, uimm: u16 },
93
94 CUnimp,
96}
97
98#[instruction]
99const impl<Reg, Hart> Instruction for Rv64ZcaInstruction<Hart>
100where
101 Reg: [const] Register<Type = u64>,
102 Hart: [const] HartConfig<Reg = Reg>,
103{
104 const OWN_ISA_EXTENSIONS: &'static [IsaExtension] = &[IsaExtension::new("zca", 1, 0)];
105
106 const ALIGNMENT: u8 = align_of::<u16>() as u8;
107
108 type Hart = Hart;
109
110 #[inline(always)]
111 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
112 fn try_decode(instruction: u32) -> Option<Self> {
113 #[inline(always)]
115 const fn prime_reg_bits(bits: u8) -> u8 {
116 bits + 8
117 }
118
119 #[inline(always)]
131 const fn decode_cb_branch_imm(inst: u16) -> i16 {
132 let imm8 = ((inst >> 12u8) & 1).cast_signed();
133 let imm4_3 = ((inst >> 10u8) & 0b11).cast_signed();
134 let imm7_6 = ((inst >> 5u8) & 0b11).cast_signed();
135 let imm2_1 = ((inst >> 3u8) & 0b11).cast_signed();
136 let imm5 = ((inst >> 2u8) & 1).cast_signed();
137 let raw =
138 (imm8 << 8u8) | (imm7_6 << 6u8) | (imm5 << 5u8) | (imm4_3 << 3u8) | (imm2_1 << 1u8);
139 (raw << 7u8) >> 7u8
141 }
142
143 #[inline(always)]
158 const fn decode_cj_imm(inst: u16) -> i16 {
159 let imm11 = ((inst >> 12u8) & 1).cast_signed();
160 let imm4 = ((inst >> 11u8) & 1).cast_signed();
161 let imm9_8 = ((inst >> 9u8) & 0b11).cast_signed();
162 let imm10 = ((inst >> 8u8) & 1).cast_signed();
163 let imm6 = ((inst >> 7u8) & 1).cast_signed();
164 let imm7 = ((inst >> 6u8) & 1).cast_signed();
165 let imm3_1 = ((inst >> 3u8) & 0b111).cast_signed();
166 let imm5 = ((inst >> 2u8) & 1).cast_signed();
167 let raw = (imm11 << 11u8)
168 | (imm10 << 10u8)
169 | (imm9_8 << 8u8)
170 | (imm7 << 7u8)
171 | (imm6 << 6u8)
172 | (imm5 << 5u8)
173 | (imm4 << 4u8)
174 | (imm3_1 << 1u8);
175 (raw << 4u8) >> 4u8
177 }
178
179 let inst = instruction as u16;
180 let quadrant = inst & 0b11;
181 let funct3 = ((inst >> 13u8) & 0b111) as u8;
182
183 match quadrant {
184 0b00 => match funct3 {
186 0b000 => {
192 let imm5_4 = (inst >> 11u8) & 0b11;
193 let imm9_6 = (inst >> 7u8) & 0xf;
194 let imm2 = (inst >> 6u8) & 1;
195 let imm3 = (inst >> 5u8) & 1;
196 let nzuimm = (imm9_6 << 6u8) | (imm5_4 << 4u8) | (imm3 << 3u8) | (imm2 << 2u8);
197 if nzuimm == 0 {
198 if inst == 0 {
199 Some(Self::CUnimp)
200 } else {
201 None
203 }
204 } else {
205 let rd_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
206 let rd = Reg::from_bits(rd_bits)?;
207 Some(Self::CAddi4spn { rd, nzuimm })
208 }
209 }
210 0b010 => {
213 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
214 let uimm2 = ((inst >> 6u8) & 1) as u8;
215 let uimm6 = ((inst >> 5u8) & 1) as u8;
216 let uimm = (uimm6 << 6u8) | (uimm5_3 << 3u8) | (uimm2 << 2u8);
217 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
218 let rd_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
219 let rs1 = Reg::from_bits(rs1_bits)?;
220 let rd = Reg::from_bits(rd_bits)?;
221 Some(Self::CLw { rd, rs1, uimm })
222 }
223 0b011 => {
226 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
227 let uimm7_6 = ((inst >> 5u8) & 0b11) as u8;
228 let uimm = (uimm7_6 << 6u8) | (uimm5_3 << 3u8);
229 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
230 let rd_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
231 let rs1 = Reg::from_bits(rs1_bits)?;
232 let rd = Reg::from_bits(rd_bits)?;
233 Some(Self::CLd { rd, rs1, uimm })
234 }
235 0b110 => {
237 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
238 let uimm2 = ((inst >> 6u8) & 1) as u8;
239 let uimm6 = ((inst >> 5u8) & 1) as u8;
240 let uimm = (uimm6 << 6u8) | (uimm5_3 << 3u8) | (uimm2 << 2u8);
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::CSw { rs1, rs2, uimm })
246 }
247 0b111 => {
249 let uimm5_3 = ((inst >> 10u8) & 0b111) as u8;
250 let uimm7_6 = ((inst >> 5u8) & 0b11) as u8;
251 let uimm = (uimm7_6 << 6u8) | (uimm5_3 << 3u8);
252 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
253 let rs2_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
254 let rs1 = Reg::from_bits(rs1_bits)?;
255 let rs2 = Reg::from_bits(rs2_bits)?;
256 Some(Self::CSd { rs1, rs2, uimm })
257 }
258 _ => None,
260 },
261
262 0b01 => match funct3 {
264 0b000 => {
267 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
268 let imm5 = ((inst >> 12u8) & 1) as u8;
269 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
270 let imm_raw = (imm5 << 5u8) | imm4_0;
271 let nzimm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
273 if rd_bits == 0 && nzimm == 0 {
274 Some(Self::CNop)
275 } else {
276 let rd = Reg::from_bits(rd_bits)?;
277 Some(Self::CAddi { rd, nzimm })
278 }
279 }
280 0b001 => {
283 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
284 if rd_bits == 0 {
286 None?;
287 }
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::CAddiw { rd, imm })
294 }
295 0b010 => {
298 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
299 let rd = Reg::from_bits(rd_bits)?;
300 let imm5 = ((inst >> 12u8) & 1) as u8;
301 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
302 let imm_raw = (imm5 << 5u8) | imm4_0;
303 let imm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
304 Some(Self::CLi { rd, imm })
305 }
306 0b011 => {
308 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
309 if rd_bits == 2 {
310 let imm9 = ((inst >> 12u8) & 1).cast_signed();
317 let imm4 = ((inst >> 6u8) & 1).cast_signed();
318 let imm6 = ((inst >> 5u8) & 1).cast_signed();
319 let imm8_7 = ((inst >> 3u8) & 0b11).cast_signed();
320 let imm5 = ((inst >> 2u8) & 1).cast_signed();
321 let raw = (imm9 << 9u8)
322 | (imm8_7 << 7u8)
323 | (imm6 << 6u8)
324 | (imm5 << 5u8)
325 | (imm4 << 4u8);
326 if raw == 0 {
327 None?;
328 }
329 let nzimm = (raw << 6u8) >> 6u8;
331 Some(Self::CAddi16sp { nzimm })
332 } else {
333 let rd = Reg::from_bits(rd_bits)?;
335 let imm17 = ((inst >> 12u8) & 1) as i32;
338 let imm16_12 = ((inst >> 2u8) & 0x1f) as i32;
339 let raw = (imm17 << 17u8) | (imm16_12 << 12u8);
340 if raw == 0 {
341 None?;
342 }
343 let nzimm = I24::from_i32((raw << 14u8) >> 14u8);
345 Some(Self::CLui { rd, nzimm })
346 }
347 }
348 0b100 => {
350 let funct2 = ((inst >> 10u8) & 0b11) as u8;
351 let rd_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
352 match funct2 {
353 0b00 => {
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::CSrli {
360 rd,
361 shamt: Shamt::<u64>::new((shamt5 << 5u8) | shamt40)?,
362 })
363 }
364 0b01 => {
367 let rd = Reg::from_bits(rd_bits)?;
368 let shamt5 = ((inst >> 12u8) & 1) as u8;
369 let shamt40 = ((inst >> 2u8) & 0x1f) as u8;
370 Some(Self::CSrai {
371 rd,
372 shamt: Shamt::<u64>::new((shamt5 << 5u8) | shamt40)?,
373 })
374 }
375 0b10 => {
377 let rd = Reg::from_bits(rd_bits)?;
378 let imm5 = ((inst >> 12u8) & 1) as u8;
379 let imm4_0 = ((inst >> 2u8) & 0x1f) as u8;
380 let imm_raw = (imm5 << 5u8) | imm4_0;
381 let imm = ((imm_raw.cast_signed()) << 2u8) >> 2u8;
382 Some(Self::CAndi { rd, imm })
383 }
384 0b11 => {
386 let bit12 = (inst >> 12u8) & 1;
387 let funct2b = ((inst >> 5u8) & 0b11) as u8;
388 let rs2_bits = prime_reg_bits(((inst >> 2u8) & 0b111) as u8);
389 let rd = Reg::from_bits(rd_bits)?;
390 let rs2 = Reg::from_bits(rs2_bits)?;
391 if bit12 == 0 {
392 match funct2b {
393 0b00 => Some(Self::CSub { rd, rs2 }),
394 0b01 => Some(Self::CXor { rd, rs2 }),
395 0b10 => Some(Self::COr { rd, rs2 }),
396 0b11 => Some(Self::CAnd { rd, rs2 }),
397 _ => None,
398 }
399 } else {
400 match funct2b {
402 0b00 => Some(Self::CSubw { rd, rs2 }),
403 0b01 => Some(Self::CAddw { rd, rs2 }),
404 _ => None,
406 }
407 }
408 }
409 _ => None,
410 }
411 }
412 0b101 => Some(Self::CJ {
414 imm: decode_cj_imm(inst),
415 }),
416 0b110 => {
418 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
419 let rs1 = Reg::from_bits(rs1_bits)?;
420 Some(Self::CBeqz {
421 rs1,
422 imm: decode_cb_branch_imm(inst),
423 })
424 }
425 0b111 => {
427 let rs1_bits = prime_reg_bits(((inst >> 7u8) & 0b111) as u8);
428 let rs1 = Reg::from_bits(rs1_bits)?;
429 Some(Self::CBnez {
430 rs1,
431 imm: decode_cb_branch_imm(inst),
432 })
433 }
434 _ => None,
435 },
436
437 0b10 => match funct3 {
439 0b000 => {
442 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
443 let rd = Reg::from_bits(rd_bits)?;
444 let shamt5 = ((inst >> 12u8) & 1) as u8;
445 let shamt40 = ((inst >> 2u8) & 0x1f) as u8;
446 Some(Self::CSlli {
447 rd,
448 shamt: Shamt::<u64>::new((shamt5 << 5u8) | shamt40)?,
449 })
450 }
451 0b010 => {
454 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
455 if rd_bits == 0 {
456 None?;
457 }
458 let rd = Reg::from_bits(rd_bits)?;
459 let uimm5 = ((inst >> 12u8) & 1) as u8;
460 let uimm42 = ((inst >> 4u8) & 0b111) as u8;
461 let uimm76 = ((inst >> 2u8) & 0b11) as u8;
462 let uimm = (uimm76 << 6u8) | (uimm5 << 5u8) | (uimm42 << 2u8);
463 Some(Self::CLwsp { rd, uimm })
464 }
465 0b011 => {
468 let rd_bits = ((inst >> 7u8) & 0x1f) as u8;
469 if rd_bits == 0 {
470 None?;
471 }
472 let rd = Reg::from_bits(rd_bits)?;
473 let uimm5 = (inst >> 12u8) & 1;
474 let uimm43 = (inst >> 5u8) & 0b11;
475 let uimm86 = (inst >> 2u8) & 0b111;
476 let uimm = (uimm86 << 6u8) | (uimm5 << 5u8) | (uimm43 << 3u8);
477 Some(Self::CLdsp { rd, uimm })
478 }
479 0b100 => {
481 let rs1_bits = ((inst >> 7u8) & 0x1f) as u8;
482 let rs2_bits = ((inst >> 2u8) & 0x1f) as u8;
483 let bit12 = (inst >> 12u8) & 1;
484 if bit12 == 0 {
485 if rs2_bits == 0 {
486 if rs1_bits == 0 {
488 None?;
489 }
490 let rs1 = Reg::from_bits(rs1_bits)?;
491 Some(Self::CJr { rs1 })
492 } else {
493 let rd = Reg::from_bits(rs1_bits)?;
495 let rs2 = Reg::from_bits(rs2_bits)?;
496 Some(Self::CMv { rd, rs2 })
497 }
498 } else if rs2_bits == 0 {
499 if rs1_bits == 0 {
500 Some(Self::CEbreak)
502 } else {
503 let rs1 = Reg::from_bits(rs1_bits)?;
505 Some(Self::CJalr { rs1 })
506 }
507 } else {
508 let rd = Reg::from_bits(rs1_bits)?;
510 let rs2 = Reg::from_bits(rs2_bits)?;
511 Some(Self::CAdd { rd, rs2 })
512 }
513 }
514 0b110 => {
516 let rs2_bits = ((inst >> 2u8) & 0x1f) as u8;
517 let rs2 = Reg::from_bits(rs2_bits)?;
518 let uimm52 = ((inst >> 9u8) & 0xf) as u8;
519 let uimm76 = ((inst >> 7u8) & 0b11) as u8;
520 let uimm = (uimm76 << 6u8) | (uimm52 << 2u8);
521 Some(Self::CSwsp { rs2, uimm })
522 }
523 0b111 => {
525 let rs2_bits = ((inst >> 2u8) & 0x1f) as u8;
526 let rs2 = Reg::from_bits(rs2_bits)?;
527 let uimm53 = (inst >> 10u8) & 0b111;
528 let uimm86 = (inst >> 7u8) & 0b111;
529 let uimm = (uimm86 << 6u8) | (uimm53 << 3u8);
530 Some(Self::CSdsp { rs2, uimm })
531 }
532 _ => None,
533 },
534
535 _ => None,
537 }
538 }
539
540 #[inline(always)]
541 fn size(&self) -> u8 {
542 size_of::<u16>() as u8
543 }
544}
545
546#[instruction]
547impl<Reg, Hart> fmt::Display for Rv64ZcaInstruction<Hart>
548where
549 Reg: fmt::Display,
550 Hart: HartConfig<Reg = Reg>,
551{
552 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
553 match self {
554 Self::CAddi4spn { rd, nzuimm } => write!(f, "c.addi4spn {rd}, sp, {nzuimm}"),
555 Self::CLw { rd, rs1, uimm } => write!(f, "c.lw {rd}, {uimm}({rs1})"),
556 Self::CLd { rd, rs1, uimm } => write!(f, "c.ld {rd}, {uimm}({rs1})"),
557 Self::CSw { rs1, rs2, uimm } => write!(f, "c.sw {rs2}, {uimm}({rs1})"),
558 Self::CSd { rs1, rs2, uimm } => write!(f, "c.sd {rs2}, {uimm}({rs1})"),
559 Self::CNop => write!(f, "c.nop"),
560 Self::CAddi { rd, nzimm } => write!(f, "c.addi {rd}, {nzimm}"),
561 Self::CAddiw { rd, imm } => write!(f, "c.addiw {rd}, {imm}"),
562 Self::CLi { rd, imm } => write!(f, "c.li {rd}, {imm}"),
563 Self::CAddi16sp { nzimm } => write!(f, "c.addi16sp sp, {nzimm}"),
564 Self::CLui { rd, nzimm } => write!(f, "c.lui {rd}, 0x{:x}", nzimm >> 12u8),
565 Self::CSrli { rd, shamt } => write!(f, "c.srli {rd}, {shamt}"),
566 Self::CSrai { rd, shamt } => write!(f, "c.srai {rd}, {shamt}"),
567 Self::CAndi { rd, imm } => write!(f, "c.andi {rd}, {imm}"),
568 Self::CSub { rd, rs2 } => write!(f, "c.sub {rd}, {rs2}"),
569 Self::CXor { rd, rs2 } => write!(f, "c.xor {rd}, {rs2}"),
570 Self::COr { rd, rs2 } => write!(f, "c.or {rd}, {rs2}"),
571 Self::CAnd { rd, rs2 } => write!(f, "c.and {rd}, {rs2}"),
572 Self::CSubw { rd, rs2 } => write!(f, "c.subw {rd}, {rs2}"),
573 Self::CAddw { rd, rs2 } => write!(f, "c.addw {rd}, {rs2}"),
574 Self::CJ { imm } => write!(f, "c.j {imm}"),
575 Self::CBeqz { rs1, imm } => write!(f, "c.beqz {rs1}, {imm}"),
576 Self::CBnez { rs1, imm } => write!(f, "c.bnez {rs1}, {imm}"),
577 Self::CSlli { rd, shamt } => write!(f, "c.slli {rd}, {shamt}"),
578 Self::CLwsp { rd, uimm } => write!(f, "c.lwsp {rd}, {uimm}(sp)"),
579 Self::CLdsp { rd, uimm } => write!(f, "c.ldsp {rd}, {uimm}(sp)"),
580 Self::CJr { rs1 } => write!(f, "c.jr {rs1}"),
581 Self::CMv { rd, rs2 } => write!(f, "c.mv {rd}, {rs2}"),
582 Self::CEbreak => write!(f, "c.ebreak"),
583 Self::CJalr { rs1 } => write!(f, "c.jalr {rs1}"),
584 Self::CAdd { rd, rs2 } => write!(f, "c.add {rd}, {rs2}"),
585 Self::CSwsp { rs2, uimm } => write!(f, "c.swsp {rs2}, {uimm}(sp)"),
586 Self::CSdsp { rs2, uimm } => write!(f, "c.sdsp {rs2}, {uimm}(sp)"),
587 Self::CUnimp => write!(f, "c.unimp"),
588 }
589 }
590}