Skip to main content

ab_riscv_primitives/instructions/rv32/c/
zca.rs

1//! RV32 Zca extension
2
3#[cfg(test)]
4mod tests;
5
6use crate::instructions::Instruction;
7use crate::registers::general_purpose::Register;
8use ab_riscv_macros::instruction;
9use core::fmt;
10
11/// RISC-V RV32 Zca compressed instruction set
12#[instruction]
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14#[rustfmt::skip]
15pub enum Rv32ZcaInstruction<Reg> {
16    // Quadrant 00
17    /// C.ADDI4SPN  rd' = sp + nzuimm  (nzuimm != 0)
18    CAddi4spn { rd: Reg, nzuimm: u16 },
19    /// C.LW  rd' = sext(mem32\[rs1' + uimm])
20    CLw { rd: Reg, rs1: Reg, uimm: u8 },
21    /// C.SW  mem32\[rs1' + uimm] = rs2'
22    CSw { rs1: Reg, rs2: Reg, uimm: u8 },
23
24    // Quadrant 01
25    /// C.NOP  (ADDI x0, x0, 0 with rd==x0 and nzimm==0)
26    CNop,
27    /// C.ADDI  rd += nzimm  (rd != x0)
28    CAddi { rd: Reg, nzimm: i8 },
29    /// C.JAL  ra = pc+2; pc += imm
30    CJal { imm: i16 },
31    /// C.LI  rd = sext(imm)  (rd=x0 is a HINT)
32    CLi { rd: Reg, imm: i8 },
33    /// C.ADDI16SP  sp += nzimm  (nzimm != 0)
34    CAddi16sp { nzimm: i16 },
35    /// C.LUI  rd = sext(nzimm << 12)  (rd != x0, rd != x2, nzimm != 0)
36    CLui { rd: Reg, nzimm: i32 },
37    /// C.SRLI  rd' >>= shamt  (logical, 5-bit shamt; shamt=0 is a HINT)
38    CSrli { rd: Reg, shamt: u8 },
39    /// C.SRAI  rd' >>= shamt  (arithmetic, 5-bit shamt; shamt=0 is a HINT)
40    CSrai { rd: Reg, shamt: u8 },
41    /// C.ANDI  rd' &= sext(imm)
42    CAndi { rd: Reg, imm: i8 },
43    /// C.SUB  rd' -= rs2'
44    CSub { rd: Reg, rs2: Reg },
45    /// C.XOR  rd' ^= rs2'
46    CXor { rd: Reg, rs2: Reg },
47    /// C.OR   rd' |= rs2'
48    COr { rd: Reg, rs2: Reg },
49    /// C.AND  rd' &= rs2'
50    CAnd { rd: Reg, rs2: Reg },
51    /// C.J  pc += sext(imm)
52    CJ { imm: i16 },
53    /// C.BEQZ  if rs1' == 0: pc += sext(imm)
54    CBeqz { rs1: Reg, imm: i16 },
55    /// C.BNEZ  if rs1' != 0: pc += sext(imm)
56    CBnez { rs1: Reg, imm: i16 },
57
58    // Quadrant 10
59    /// C.SLLI  rd <<= shamt  (5-bit shamt; rd=x0 or shamt=0 is a HINT)
60    CSlli { rd: Reg, shamt: u8 },
61    /// C.LWSP  rd = sext(mem32\[sp + uimm])  (rd != x0)
62    CLwsp { rd: Reg, uimm: u8 },
63    /// C.JR  pc = rs1  (rs1 != x0)
64    CJr { rs1: Reg },
65    /// C.MV  rd = rs2  (rs2 != x0; rd=x0 is a HINT)
66    CMv { rd: Reg, rs2: Reg },
67    /// C.EBREAK
68    CEbreak,
69    /// C.JALR  ra = pc+2; pc = rs1  (rs1 != x0)
70    CJalr { rs1: Reg },
71    /// C.ADD  rd += rs2  (rs2 != x0; rd=x0 is a HINT)
72    CAdd { rd: Reg, rs2: Reg },
73    /// C.SWSP  mem32\[sp + uimm] = rs2
74    CSwsp { rs2: Reg, uimm: u8 },
75
76    // Unimplemented/illegal
77    CUnimp,
78}
79
80#[instruction]
81impl<Reg> const Instruction for Rv32ZcaInstruction<Reg>
82where
83    Reg: [const] Register<Type = u32>,
84{
85    type Reg = Reg;
86
87    #[inline(always)]
88    fn try_decode(instruction: u32) -> Option<Self> {
89        /// Map a 3-bit "prime" register field to an absolute register number
90        #[inline(always)]
91        const fn prime_reg_bits(bits: u8) -> u8 {
92            bits + 8
93        }
94
95        /// Reconstruct the CB-type branch offset used by C.BEQZ / C.BNEZ.
96        ///
97        /// Bit layout in the 16-bit instruction word:
98        /// ```text
99        ///   imm[8]   = inst[12]
100        ///   imm[4:3] = inst[11:10]
101        ///   imm[7:6] = inst[6:5]
102        ///   imm[2:1] = inst[4:3]
103        ///   imm[5]   = inst[2]
104        /// imm[0] is always 0 (2-byte aligned).
105        /// ```
106        #[inline(always)]
107        const fn decode_cb_branch_imm(inst: u16) -> i16 {
108            let imm8 = ((inst >> 12) & 1).cast_signed();
109            let imm4_3 = ((inst >> 10) & 0b11).cast_signed();
110            let imm7_6 = ((inst >> 5) & 0b11).cast_signed();
111            let imm2_1 = ((inst >> 3) & 0b11).cast_signed();
112            let imm5 = ((inst >> 2) & 1).cast_signed();
113            let raw = (imm8 << 8) | (imm7_6 << 6) | (imm5 << 5) | (imm4_3 << 3) | (imm2_1 << 1);
114            // Sign-extend from bit 8 (9-bit immediate -> i16)
115            (raw << 7) >> 7
116        }
117
118        /// Decode CJ-type jump offset (C.J / C.JAL).
119        ///
120        /// Bit layout:
121        /// ```text
122        ///   imm[11]  = inst[12]
123        ///   imm[4]   = inst[11]
124        ///   imm[9:8] = inst[10:9]
125        ///   imm[10]  = inst[8]
126        ///   imm[6]   = inst[7]
127        ///   imm[7]   = inst[6]
128        ///   imm[3:1] = inst[5:3]
129        ///   imm[5]   = inst[2]
130        /// imm[0] is always 0 (2-byte aligned).
131        /// ```
132        #[inline(always)]
133        const fn decode_cj_imm(inst: u16) -> i16 {
134            let imm11 = ((inst >> 12) & 1).cast_signed();
135            let imm4 = ((inst >> 11) & 1).cast_signed();
136            let imm9_8 = ((inst >> 9) & 0b11).cast_signed();
137            let imm10 = ((inst >> 8) & 1).cast_signed();
138            let imm6 = ((inst >> 7) & 1).cast_signed();
139            let imm7 = ((inst >> 6) & 1).cast_signed();
140            let imm3_1 = ((inst >> 3) & 0b111).cast_signed();
141            let imm5 = ((inst >> 2) & 1).cast_signed();
142            let raw = (imm11 << 11)
143                | (imm10 << 10)
144                | (imm9_8 << 8)
145                | (imm7 << 7)
146                | (imm6 << 6)
147                | (imm5 << 5)
148                | (imm4 << 4)
149                | (imm3_1 << 1);
150            // Sign-extend from bit 11 (12-bit immediate -> i16)
151            (raw << 4) >> 4
152        }
153
154        let inst = instruction as u16;
155        let quadrant = inst & 0b11;
156        let funct3 = ((inst >> 13) & 0b111) as u8;
157
158        match quadrant {
159            // Quadrant 00
160            0b00 => match funct3 {
161                // C.ADDI4SPN
162                // nzuimm[5:4]  = inst[12:11]
163                // nzuimm[9:6]  = inst[10:7]
164                // nzuimm[2]    = inst[6]
165                // nzuimm[3]    = inst[5]
166                0b000 => {
167                    let imm5_4 = (inst >> 11) & 0b11;
168                    let imm9_6 = (inst >> 7) & 0xf;
169                    let imm2 = (inst >> 6) & 1;
170                    let imm3 = (inst >> 5) & 1;
171                    let nzuimm = (imm9_6 << 6) | (imm5_4 << 4) | (imm3 << 3) | (imm2 << 2);
172                    if nzuimm == 0 {
173                        if inst == 0 {
174                            Some(Self::CUnimp)
175                        } else {
176                            // Reserved encoding
177                            None
178                        }
179                    } else {
180                        let rd_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
181                        let rd = Reg::from_bits(rd_bits)?;
182                        Some(Self::CAddi4spn { rd, nzuimm })
183                    }
184                }
185                // C.LW
186                // uimm[5:3] = inst[12:10], uimm[2] = inst[6], uimm[6] = inst[5]
187                0b010 => {
188                    let uimm5_3 = ((inst >> 10) & 0b111) as u8;
189                    let uimm2 = ((inst >> 6) & 1) as u8;
190                    let uimm6 = ((inst >> 5) & 1) as u8;
191                    let uimm = (uimm6 << 6) | (uimm5_3 << 3) | (uimm2 << 2);
192                    let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
193                    let rd_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
194                    let rs1 = Reg::from_bits(rs1_bits)?;
195                    let rd = Reg::from_bits(rd_bits)?;
196                    Some(Self::CLw { rd, rs1, uimm })
197                }
198                // C.SW  (same uimm layout as C.LW)
199                0b110 => {
200                    let uimm5_3 = ((inst >> 10) & 0b111) as u8;
201                    let uimm2 = ((inst >> 6) & 1) as u8;
202                    let uimm6 = ((inst >> 5) & 1) as u8;
203                    let uimm = (uimm6 << 6) | (uimm5_3 << 3) | (uimm2 << 2);
204                    let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
205                    let rs2_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
206                    let rs1 = Reg::from_bits(rs1_bits)?;
207                    let rs2 = Reg::from_bits(rs2_bits)?;
208                    Some(Self::CSw { rs1, rs2, uimm })
209                }
210                // funct3=001: C.FLD (Zcd) - not in Zca, reserved
211                // funct3=011: C.FLD (Zcd) - not in Zca, reserved
212                // funct3=100: used by Zcb
213                // funct3=101: C.FSD (Zcd) - not in Zca, reserved
214                // funct3=111: C.FSD (Zcd) - not in Zca, reserved
215                _ => None,
216            },
217
218            // Quadrant 01
219            0b01 => match funct3 {
220                // C.NOP (rd=x0) / C.ADDI (rd!=x0)
221                // nzimm[5] = inst[12], nzimm[4:0] = inst[6:2]
222                0b000 => {
223                    let rd_bits = ((inst >> 7) & 0x1f) as u8;
224                    let imm5 = ((inst >> 12) & 1) as u8;
225                    let imm4_0 = ((inst >> 2) & 0x1f) as u8;
226                    let imm_raw = (imm5 << 5) | imm4_0;
227                    // Sign-extend 6-bit immediate to i8
228                    let nzimm = ((imm_raw.cast_signed()) << 2) >> 2;
229                    if rd_bits == 0 && nzimm == 0 {
230                        Some(Self::CNop)
231                    } else {
232                        let rd = Reg::from_bits(rd_bits)?;
233                        Some(Self::CAddi { rd, nzimm })
234                    }
235                }
236                // C.JAL  (same CJ immediate encoding as C.J)
237                0b001 => Some(Self::CJal {
238                    imm: decode_cj_imm(inst),
239                }),
240                // C.LI  rd = sext(imm)  (rd=x0 is a HINT, still decoded)
241                // imm[5] = inst[12], imm[4:0] = inst[6:2]
242                0b010 => {
243                    let rd_bits = ((inst >> 7) & 0x1f) as u8;
244                    let rd = Reg::from_bits(rd_bits)?;
245                    let imm5 = ((inst >> 12) & 1) as u8;
246                    let imm4_0 = ((inst >> 2) & 0x1f) as u8;
247                    let imm_raw = (imm5 << 5) | imm4_0;
248                    let imm = ((imm_raw.cast_signed()) << 2) >> 2;
249                    Some(Self::CLi { rd, imm })
250                }
251                // C.ADDI16SP (rd=x2) / C.LUI (rd!=x0, rd!=x2)
252                0b011 => {
253                    let rd_bits = ((inst >> 7) & 0x1f) as u8;
254                    if rd_bits == 2 {
255                        // C.ADDI16SP
256                        // nzimm[9]   = inst[12]
257                        // nzimm[4]   = inst[6]
258                        // nzimm[6]   = inst[5]
259                        // nzimm[8:7] = inst[4:3]
260                        // nzimm[5]   = inst[2]
261                        let imm9 = ((inst >> 12) & 1).cast_signed();
262                        let imm4 = ((inst >> 6) & 1).cast_signed();
263                        let imm6 = ((inst >> 5) & 1).cast_signed();
264                        let imm8_7 = ((inst >> 3) & 0b11).cast_signed();
265                        let imm5 = ((inst >> 2) & 1).cast_signed();
266                        let raw =
267                            (imm9 << 9) | (imm8_7 << 7) | (imm6 << 6) | (imm5 << 5) | (imm4 << 4);
268                        if raw == 0 {
269                            None?;
270                        }
271                        // Sign-extend from bit 9 (10-bit nzimm -> i16)
272                        let nzimm = (raw << 6) >> 6;
273                        Some(Self::CAddi16sp { nzimm })
274                    } else {
275                        // C.LUI  (rd=x0 is reserved)
276                        if rd_bits == 0 {
277                            None?;
278                        }
279                        let rd = Reg::from_bits(rd_bits)?;
280                        // nzimm[17]    = inst[12]
281                        // nzimm[16:12] = inst[6:2]
282                        let imm17 = ((inst >> 12) & 1) as i32;
283                        let imm16_12 = ((inst >> 2) & 0x1f) as i32;
284                        let raw = (imm17 << 17) | (imm16_12 << 12);
285                        if raw == 0 {
286                            None?;
287                        }
288                        // Sign-extend from bit 17 (18-bit nzimm -> i32)
289                        let nzimm = (raw << 14) >> 14;
290                        Some(Self::CLui { rd, nzimm })
291                    }
292                }
293                // C.SRLI / C.SRAI / C.ANDI / arithmetic
294                // RV32: shamt is 5-bit only (inst[12] must be 0 for shifts, else reserved)
295                0b100 => {
296                    let funct2 = ((inst >> 10) & 0b11) as u8;
297                    let rd_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
298                    match funct2 {
299                        // C.SRLI  shamt[4:0]=inst[6:2]
300                        // RV32: shamt[5]=inst[12] must be 0, else reserved (NSE)
301                        // shamt=0 is a HINT, still decoded
302                        0b00 => {
303                            let rd = Reg::from_bits(rd_bits)?;
304                            let shamt5 = ((inst >> 12) & 1) as u8;
305                            let shamt40 = ((inst >> 2) & 0x1f) as u8;
306                            if shamt5 != 0 {
307                                None?;
308                            }
309                            Some(Self::CSrli { rd, shamt: shamt40 })
310                        }
311                        // C.SRAI  (same shamt layout as C.SRLI)
312                        // RV32: shamt[5]=inst[12] must be 0, else reserved (NSE)
313                        // shamt=0 is a HINT, still decoded
314                        0b01 => {
315                            let rd = Reg::from_bits(rd_bits)?;
316                            let shamt5 = ((inst >> 12) & 1) as u8;
317                            let shamt40 = ((inst >> 2) & 0x1f) as u8;
318                            if shamt5 != 0 {
319                                None?;
320                            }
321                            Some(Self::CSrai { rd, shamt: shamt40 })
322                        }
323                        // C.ANDI  imm[5]=inst[12], imm[4:0]=inst[6:2]
324                        0b10 => {
325                            let rd = Reg::from_bits(rd_bits)?;
326                            let imm5 = ((inst >> 12) & 1) as u8;
327                            let imm4_0 = ((inst >> 2) & 0x1f) as u8;
328                            let imm_raw = (imm5 << 5) | imm4_0;
329                            let imm = ((imm_raw.cast_signed()) << 2) >> 2;
330                            Some(Self::CAndi { rd, imm })
331                        }
332                        // Arithmetic: only bit12=0 variants valid in RV32
333                        // bit12=1 (C.SUBW/C.ADDW) does not exist in RV32, reserved
334                        0b11 => {
335                            let bit12 = (inst >> 12) & 1;
336                            if bit12 != 0 {
337                                None?;
338                            }
339                            let funct2b = ((inst >> 5) & 0b11) as u8;
340                            let rs2_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
341                            let rd = Reg::from_bits(rd_bits)?;
342                            let rs2 = Reg::from_bits(rs2_bits)?;
343                            match funct2b {
344                                0b00 => Some(Self::CSub { rd, rs2 }),
345                                0b01 => Some(Self::CXor { rd, rs2 }),
346                                0b10 => Some(Self::COr { rd, rs2 }),
347                                0b11 => Some(Self::CAnd { rd, rs2 }),
348                                _ => None,
349                            }
350                        }
351                        _ => None,
352                    }
353                }
354                // C.J
355                0b101 => Some(Self::CJ {
356                    imm: decode_cj_imm(inst),
357                }),
358                // C.BEQZ
359                0b110 => {
360                    let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
361                    let rs1 = Reg::from_bits(rs1_bits)?;
362                    Some(Self::CBeqz {
363                        rs1,
364                        imm: decode_cb_branch_imm(inst),
365                    })
366                }
367                // C.BNEZ
368                0b111 => {
369                    let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
370                    let rs1 = Reg::from_bits(rs1_bits)?;
371                    Some(Self::CBnez {
372                        rs1,
373                        imm: decode_cb_branch_imm(inst),
374                    })
375                }
376                _ => None,
377            },
378
379            // Quadrant 10
380            0b10 => match funct3 {
381                // C.SLLI  shamt[4:0]=inst[6:2]
382                // RV32: shamt[5]=inst[12] must be 0, else reserved (NSE)
383                // rd=x0 or shamt=0 is a HINT, still decoded
384                0b000 => {
385                    let rd_bits = ((inst >> 7) & 0x1f) as u8;
386                    let rd = Reg::from_bits(rd_bits)?;
387                    let shamt5 = ((inst >> 12) & 1) as u8;
388                    let shamt40 = ((inst >> 2) & 0x1f) as u8;
389                    if shamt5 != 0 {
390                        None?;
391                    }
392                    Some(Self::CSlli { rd, shamt: shamt40 })
393                }
394                // C.LWSP  uimm[5]=inst[12], uimm[4:2]=inst[6:4], uimm[7:6]=inst[3:2]
395                // rd=x0 is reserved
396                0b010 => {
397                    let rd_bits = ((inst >> 7) & 0x1f) as u8;
398                    if rd_bits == 0 {
399                        None?;
400                    }
401                    let rd = Reg::from_bits(rd_bits)?;
402                    let uimm5 = ((inst >> 12) & 1) as u8;
403                    let uimm42 = ((inst >> 4) & 0b111) as u8;
404                    let uimm76 = ((inst >> 2) & 0b11) as u8;
405                    let uimm = (uimm76 << 6) | (uimm5 << 5) | (uimm42 << 2);
406                    Some(Self::CLwsp { rd, uimm })
407                }
408                // funct3=001: C.FLWSP (Zcf, not Zca) - reserved
409                // funct3=011: C.FLDSP (Zcd, not Zca) - reserved
410                // C.JR / C.MV / C.EBREAK / C.JALR / C.ADD
411                0b100 => {
412                    let rs1_bits = ((inst >> 7) & 0x1f) as u8;
413                    let rs2_bits = ((inst >> 2) & 0x1f) as u8;
414                    let bit12 = (inst >> 12) & 1;
415                    if bit12 == 0 {
416                        if rs2_bits == 0 {
417                            // C.JR  (rs1=x0 is reserved)
418                            if rs1_bits == 0 {
419                                None?;
420                            }
421                            let rs1 = Reg::from_bits(rs1_bits)?;
422                            Some(Self::CJr { rs1 })
423                        } else {
424                            // C.MV  (rs2!=x0; rd=x0 is a HINT, still decoded)
425                            let rd = Reg::from_bits(rs1_bits)?;
426                            let rs2 = Reg::from_bits(rs2_bits)?;
427                            Some(Self::CMv { rd, rs2 })
428                        }
429                    } else if rs2_bits == 0 {
430                        if rs1_bits == 0 {
431                            // C.EBREAK
432                            Some(Self::CEbreak)
433                        } else {
434                            // C.JALR  (rs1!=x0)
435                            let rs1 = Reg::from_bits(rs1_bits)?;
436                            Some(Self::CJalr { rs1 })
437                        }
438                    } else {
439                        // C.ADD  (rs2!=x0; rd=x0 is a HINT, still decoded)
440                        let rd = Reg::from_bits(rs1_bits)?;
441                        let rs2 = Reg::from_bits(rs2_bits)?;
442                        Some(Self::CAdd { rd, rs2 })
443                    }
444                }
445                // C.SWSP  uimm[5:2]=inst[12:9], uimm[7:6]=inst[8:7]
446                0b110 => {
447                    let rs2_bits = ((inst >> 2) & 0x1f) as u8;
448                    let rs2 = Reg::from_bits(rs2_bits)?;
449                    let uimm52 = ((inst >> 9) & 0xf) as u8;
450                    let uimm76 = ((inst >> 7) & 0b11) as u8;
451                    let uimm = (uimm76 << 6) | (uimm52 << 2);
452                    Some(Self::CSwsp { rs2, uimm })
453                }
454                // funct3=111: C.FSWSP (Zcf, not Zca) - reserved
455                _ => None,
456            },
457
458            // Quadrant 11 = 32-bit instructions
459            _ => None,
460        }
461    }
462
463    #[inline(always)]
464    fn alignment() -> u8 {
465        align_of::<u16>() as u8
466    }
467
468    #[inline(always)]
469    fn size(&self) -> u8 {
470        size_of::<u16>() as u8
471    }
472}
473
474impl<Reg> fmt::Display for Rv32ZcaInstruction<Reg>
475where
476    Reg: fmt::Display,
477{
478    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
479        match self {
480            Self::CAddi4spn { rd, nzuimm } => write!(f, "c.addi4spn {rd}, sp, {nzuimm}"),
481            Self::CLw { rd, rs1, uimm } => write!(f, "c.lw {rd}, {uimm}({rs1})"),
482            Self::CSw { rs1, rs2, uimm } => write!(f, "c.sw {rs2}, {uimm}({rs1})"),
483            Self::CNop => write!(f, "c.nop"),
484            Self::CAddi { rd, nzimm } => write!(f, "c.addi {rd}, {nzimm}"),
485            Self::CJal { imm } => write!(f, "c.jal {imm}"),
486            Self::CLi { rd, imm } => write!(f, "c.li {rd}, {imm}"),
487            Self::CAddi16sp { nzimm } => write!(f, "c.addi16sp sp, {nzimm}"),
488            Self::CLui { rd, nzimm } => write!(f, "c.lui {rd}, 0x{:x}", nzimm >> 12),
489            Self::CSrli { rd, shamt } => write!(f, "c.srli {rd}, {shamt}"),
490            Self::CSrai { rd, shamt } => write!(f, "c.srai {rd}, {shamt}"),
491            Self::CAndi { rd, imm } => write!(f, "c.andi {rd}, {imm}"),
492            Self::CSub { rd, rs2 } => write!(f, "c.sub {rd}, {rs2}"),
493            Self::CXor { rd, rs2 } => write!(f, "c.xor {rd}, {rs2}"),
494            Self::COr { rd, rs2 } => write!(f, "c.or {rd}, {rs2}"),
495            Self::CAnd { rd, rs2 } => write!(f, "c.and {rd}, {rs2}"),
496            Self::CJ { imm } => write!(f, "c.j {imm}"),
497            Self::CBeqz { rs1, imm } => write!(f, "c.beqz {rs1}, {imm}"),
498            Self::CBnez { rs1, imm } => write!(f, "c.bnez {rs1}, {imm}"),
499            Self::CSlli { rd, shamt } => write!(f, "c.slli {rd}, {shamt}"),
500            Self::CLwsp { rd, uimm } => write!(f, "c.lwsp {rd}, {uimm}(sp)"),
501            Self::CJr { rs1 } => write!(f, "c.jr {rs1}"),
502            Self::CMv { rd, rs2 } => write!(f, "c.mv {rd}, {rs2}"),
503            Self::CEbreak => write!(f, "c.ebreak"),
504            Self::CJalr { rs1 } => write!(f, "c.jalr {rs1}"),
505            Self::CAdd { rd, rs2 } => write!(f, "c.add {rd}, {rs2}"),
506            Self::CSwsp { rs2, uimm } => write!(f, "c.swsp {rs2}, {uimm}(sp)"),
507            Self::CUnimp => write!(f, "c.unimp"),
508        }
509    }
510}