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