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