riscv_codec/
cinstruction.rs

1use std::fmt::{Display, Formatter};
2
3use crate::{
4    immediates::{
5        BImmediate, C16SPImmediate, CBImmediate, CDImmediate, CDSPImmediate, CIImmediate,
6        CJImmediate, CSDSPImmediate, CSWSPImmediate, CShamt, CWImmediate, CWSPImmediate,
7        CWideImmediate, IImmediate, JImmediate, SImmediate, Shamt,
8    },
9    instruction::Instruction,
10    register::{CFRegister, CIRegister, FRegister, IRegister},
11};
12
13#[derive(Debug, PartialEq)]
14pub enum CInstruction {
15    //
16    // Instructions in C extension
17    //
18    ADDI4SPN {
19        dest: CIRegister,
20        imm: CWideImmediate,
21    },
22    FLD {
23        dest: CFRegister,
24        base: CIRegister,
25        offset: CDImmediate,
26    },
27    LW {
28        dest: CIRegister,
29        base: CIRegister,
30        offset: CWImmediate,
31    },
32    LD {
33        dest: CIRegister,
34        base: CIRegister,
35        offset: CDImmediate,
36    },
37    FSD {
38        src: CFRegister,
39        base: CIRegister,
40        offset: CDImmediate,
41    },
42    SW {
43        src: CIRegister,
44        base: CIRegister,
45        offset: CWImmediate,
46    },
47    SD {
48        src: CIRegister,
49        base: CIRegister,
50        offset: CDImmediate,
51    },
52    ADDI {
53        dest: IRegister,
54        imm: CIImmediate,
55    },
56    ADDIW {
57        dest: IRegister,
58        imm: CIImmediate,
59    },
60    LI {
61        dest: IRegister,
62        imm: CIImmediate,
63    },
64    ADDI16SP {
65        imm: C16SPImmediate,
66    },
67    LUI {
68        dest: IRegister,
69        imm: CIImmediate,
70    },
71    SRLI {
72        dest: CIRegister,
73        shamt: CShamt,
74    },
75    SRAI {
76        dest: CIRegister,
77        shamt: CShamt,
78    },
79    ANDI {
80        dest: CIRegister,
81        imm: CIImmediate,
82    },
83    SUB {
84        dest: CIRegister,
85        src: CIRegister,
86    },
87    XOR {
88        dest: CIRegister,
89        src: CIRegister,
90    },
91    OR {
92        dest: CIRegister,
93        src: CIRegister,
94    },
95    AND {
96        dest: CIRegister,
97        src: CIRegister,
98    },
99    SUBW {
100        dest: CIRegister,
101        src: CIRegister,
102    },
103    ADDW {
104        dest: CIRegister,
105        src: CIRegister,
106    },
107    J {
108        offset: CJImmediate,
109    },
110    BEQZ {
111        src: CIRegister,
112        offset: CBImmediate,
113    },
114    BNEZ {
115        src: CIRegister,
116        offset: CBImmediate,
117    },
118    SLLI {
119        dest: IRegister,
120        shamt: CShamt,
121    },
122    FLDSP {
123        dest: FRegister,
124        offset: CDSPImmediate,
125    },
126    LWSP {
127        dest: IRegister,
128        offset: CWSPImmediate,
129    },
130    LDSP {
131        dest: IRegister,
132        offset: CDSPImmediate,
133    },
134    JR {
135        src: IRegister,
136    },
137    MV {
138        dest: IRegister,
139        src: IRegister,
140    },
141    EBREAK,
142    JALR {
143        src: IRegister,
144    },
145    ADD {
146        dest: IRegister,
147        src: IRegister,
148    },
149    FSDSP {
150        src: FRegister,
151        offset: CSDSPImmediate,
152    },
153    SWSP {
154        src: IRegister,
155        offset: CSWSPImmediate,
156    },
157    SDSP {
158        src: IRegister,
159        offset: CSDSPImmediate,
160    },
161}
162
163impl Display for CInstruction {
164    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
165        match self {
166            CInstruction::ADDI4SPN { dest, imm } => write!(f, "c.addi4spn {dest},{imm}"),
167            CInstruction::FLD {
168                dest: rd,
169                base,
170                offset,
171            } => write!(f, "c.fld {rd},{offset}({base})"),
172            CInstruction::LW {
173                dest: rd,
174                base,
175                offset,
176            } => write!(f, "c.lw {rd},{offset}({base})"),
177            CInstruction::LD {
178                dest: rd,
179                base,
180                offset,
181            } => write!(f, "c.ld {rd},{offset}({base})"),
182            CInstruction::FSD { src, base, offset } => write!(f, "c.fsd {src},{offset}({base})"),
183            CInstruction::SW { src, base, offset } => write!(f, "c.sw {src},{offset}({base})"),
184            CInstruction::SD { src, base, offset } => write!(f, "c.sd {src},{offset}({base})"),
185            CInstruction::ADDI { dest, imm } => write!(f, "c.addi {dest},{imm}"),
186            CInstruction::ADDIW { dest, imm } => write!(f, "c.addiw {dest},{imm}"),
187            CInstruction::LI { dest, imm } => write!(f, "c.li {dest},{imm}"),
188            CInstruction::ADDI16SP { imm } => write!(f, "c.addi16sp {imm}"),
189            CInstruction::LUI { dest, imm } => write!(f, "c.lui {dest},{imm}"),
190            CInstruction::SRLI { dest, shamt } => write!(f, "c.srli {dest},{shamt}"),
191            CInstruction::SRAI { dest, shamt } => write!(f, "c.srai {dest},{shamt}"),
192            CInstruction::ANDI { dest, imm } => write!(f, "c.andi {dest},{imm}"),
193            CInstruction::SUB { dest: rd, src: rs2 } => write!(f, "c.sub {rd},{rs2}"),
194            CInstruction::XOR { dest: rd, src: rs2 } => write!(f, "c.xor {rd},{rs2}"),
195            CInstruction::OR { dest: rd, src: rs2 } => write!(f, "c.or {rd},{rs2}"),
196            CInstruction::AND { dest: rd, src: rs2 } => write!(f, "c.and {rd},{rs2}"),
197            CInstruction::SUBW { dest: rd, src: rs2 } => write!(f, "c.subw {rd},{rs2}"),
198            CInstruction::ADDW { dest: rd, src: rs2 } => write!(f, "c.addw {rd},{rs2}"),
199            CInstruction::J { offset } => write!(f, "c.j {offset}"),
200            CInstruction::BEQZ { src, offset } => write!(f, "c.beqz {src},{offset}"),
201            CInstruction::BNEZ { src, offset } => write!(f, "c.bnez {src},{offset}"),
202            CInstruction::SLLI { dest, shamt } => write!(f, "c.slli {dest},{shamt}"),
203            CInstruction::FLDSP { dest, offset } => write!(f, "c.fldsp {dest},{offset}"),
204            CInstruction::LWSP { dest, offset } => write!(f, "c.lwsp {dest},{offset}"),
205            CInstruction::LDSP { dest, offset } => write!(f, "c.ldsp {dest},{offset}"),
206            CInstruction::JR { src } => write!(f, "c.jr {src}"),
207            CInstruction::MV { dest, src } => write!(f, "c.mv {dest},{src}"),
208            CInstruction::EBREAK => write!(f, "c.ebreak"),
209            CInstruction::JALR { src } => write!(f, "c.jalr {src}"),
210            CInstruction::ADD { dest: rd, src: rs2 } => write!(f, "c.add {rd},{rs2}"),
211            CInstruction::FSDSP { src, offset } => write!(f, "c.fsdsp {src},{offset}"),
212            CInstruction::SWSP { src, offset } => write!(f, "c.swsp {src},{offset}"),
213            CInstruction::SDSP { src, offset } => write!(f, "c.sdsp {src},{offset}"),
214        }
215    }
216}
217
218impl CInstruction {
219    /// Decodes a u16 into a `CInstruction`.
220    pub fn decode(instruction: u16) -> Result<Self, String> {
221        let crs2 = CIRegister::try_from((instruction >> 2) & 0b111).unwrap();
222        let cfrd = CFRegister::try_from((instruction >> 2) & 0b111).unwrap();
223
224        let crs1 = CIRegister::from((instruction >> 7) & 0b111);
225
226        let ciimmediate = CIImmediate::from_u16(instruction);
227
228        let cshamt = CShamt::from_u16(instruction);
229
230        let rd = IRegister::from_int(((instruction >> 7) & 0b1_1111) as u32);
231        let frd = FRegister::try_from(((instruction >> 7) & 0b1_1111) as u32).unwrap();
232        let rs2 = IRegister::from_int(((instruction >> 2) & 0b1_1111) as u32);
233        let frs2 = FRegister::try_from(((instruction >> 2) & 0b1_1111) as u32).unwrap();
234
235        match instruction & 0b11 {
236            0b00 => match instruction >> 13 {
237                0b000 => {
238                    let imm = CWideImmediate::from_u16(instruction);
239                    if imm.val() == 0 {
240                        Err("compressed illegal instruction".to_owned())
241                    } else {
242                        Ok(CInstruction::ADDI4SPN { dest: crs2, imm })
243                    }
244                }
245                0b001 => Ok(CInstruction::FLD {
246                    dest: cfrd,
247                    base: crs1,
248                    offset: CDImmediate::from_u16(instruction),
249                }),
250                0b010 => Ok(CInstruction::LW {
251                    dest: crs2,
252                    base: crs1,
253                    offset: CWImmediate::from_u16(instruction),
254                }),
255                0b011 => Ok(CInstruction::LD {
256                    dest: crs2,
257                    base: crs1,
258                    offset: CDImmediate::from_u16(instruction),
259                }),
260                0b100 => Err("reserved opcode in C instruction".to_owned()),
261                0b101 => Ok(CInstruction::FSD {
262                    src: cfrd,
263                    base: crs1,
264                    offset: CDImmediate::from_u16(instruction),
265                }),
266                0b110 => Ok(CInstruction::SW {
267                    src: crs2,
268                    base: crs1,
269                    offset: CWImmediate::from_u16(instruction),
270                }),
271                0b111 => Ok(CInstruction::SD {
272                    src: crs2,
273                    base: crs1,
274                    offset: CDImmediate::from_u16(instruction),
275                }),
276                _ => unreachable!(),
277            },
278            0b01 => match instruction >> 13 {
279                0b000 => Ok(CInstruction::ADDI {
280                    dest: rd,
281                    imm: ciimmediate,
282                }),
283                0b001 => Ok(CInstruction::ADDIW {
284                    dest: rd,
285                    imm: ciimmediate,
286                }),
287                0b010 => Ok(CInstruction::LI {
288                    dest: rd,
289                    imm: ciimmediate,
290                }),
291                0b011 => {
292                    if (instruction >> 7) & 0b111 == 2 {
293                        Ok(CInstruction::ADDI16SP {
294                            imm: C16SPImmediate::from_u16(instruction),
295                        })
296                    } else {
297                        Ok(CInstruction::LUI {
298                            dest: rd,
299                            imm: ciimmediate,
300                        })
301                    }
302                }
303                0b100 => match (instruction >> 10) & 0b11 {
304                    0b00 => Ok(CInstruction::SRLI {
305                        dest: crs1,
306                        shamt: cshamt,
307                    }),
308                    0b01 => Ok(CInstruction::SRAI {
309                        dest: crs1,
310                        shamt: cshamt,
311                    }),
312                    0b10 => Ok(CInstruction::ANDI {
313                        dest: crs1,
314                        imm: ciimmediate,
315                    }),
316                    0b11 => match ((instruction >> 5) & 0b11, (instruction >> 12) & 0b1) {
317                        (0b00, 0b0) => Ok(CInstruction::SUB {
318                            dest: crs1,
319                            src: crs2,
320                        }),
321                        (0b01, 0b0) => Ok(CInstruction::XOR {
322                            dest: crs1,
323                            src: crs2,
324                        }),
325                        (0b10, 0b0) => Ok(CInstruction::OR {
326                            dest: crs1,
327                            src: crs2,
328                        }),
329                        (0b11, 0b0) => Ok(CInstruction::AND {
330                            dest: crs1,
331                            src: crs2,
332                        }),
333                        (0b00, 0b1) => Ok(CInstruction::SUBW {
334                            dest: crs1,
335                            src: crs2,
336                        }),
337                        (0b01, 0b1) => Ok(CInstruction::ADDW {
338                            dest: crs1,
339                            src: crs2,
340                        }),
341                        _ => Err("Reserved instruction".to_owned()),
342                    },
343                    _ => unreachable!(),
344                },
345                0b101 => Ok(CInstruction::J {
346                    offset: CJImmediate::from_u16(instruction),
347                }),
348                0b110 => Ok(CInstruction::BEQZ {
349                    src: crs1,
350                    offset: CBImmediate::from_u16(instruction),
351                }),
352                0b111 => Ok(CInstruction::BNEZ {
353                    src: crs1,
354                    offset: CBImmediate::from_u16(instruction),
355                }),
356                _ => unreachable!(),
357            },
358            0b10 => match instruction >> 13 {
359                0b000 => Ok(CInstruction::SLLI {
360                    dest: rd,
361                    shamt: cshamt,
362                }),
363                0b001 => Ok(CInstruction::FLDSP {
364                    dest: frd,
365                    offset: CDSPImmediate::from_u16(instruction),
366                }),
367                0b010 => Ok(CInstruction::LWSP {
368                    dest: rd,
369                    offset: CWSPImmediate::from_u16(instruction),
370                }),
371                0b011 => Ok(CInstruction::LDSP {
372                    dest: rd,
373                    offset: CDSPImmediate::from_u16(instruction),
374                }),
375                0b100 => {
376                    match (
377                        (instruction >> 12) & 0b1,
378                        (instruction >> 7) & 0b1_1111,
379                        (instruction >> 2) & 0b1_1111,
380                    ) {
381                        (0, _, 0) => Ok(CInstruction::JR { src: rd }),
382                        (0, _, _) => Ok(CInstruction::MV { dest: rd, src: rs2 }),
383                        (1, 0, 0) => Ok(CInstruction::EBREAK),
384                        (1, _, 0) => Ok(CInstruction::JALR { src: rd }),
385                        (1, _, _) => Ok(CInstruction::ADD { dest: rd, src: rs2 }),
386                        _ => unreachable!(),
387                    }
388                }
389                0b101 => Ok(CInstruction::FSDSP {
390                    src: frs2,
391                    offset: CSDSPImmediate::from_u16(instruction),
392                }),
393                0b110 => Ok(CInstruction::SWSP {
394                    src: rs2,
395                    offset: CSWSPImmediate::from_u16(instruction),
396                }),
397                0b111 => Ok(CInstruction::SDSP {
398                    src: rs2,
399                    offset: CSDSPImmediate::from_u16(instruction),
400                }),
401                _ => unreachable!(),
402            },
403            0b11 => {
404                Err("attempting to decode larger instruction as though it were 16 bits".to_owned())
405            }
406            _ => unreachable!(),
407        }
408    }
409
410    pub fn disassemble(instruction: &CInstruction) -> String {
411        format!("{}", instruction)
412    }
413
414    /// Converts a compressed instruction into the corresponding 32-bit `Instruction`.
415    ///
416    /// Note that C.JALR does not have exactly the same effect as the corresponding JALR as described in the manual:
417    /// > Strictly speaking, C.JALR does not expand exactly to a base RVI instruction as the value added to the PC to
418    /// > form the link address is 2 rather than 4 as in the base ISA, but supporting both offsets of 2 and 4 bytes
419    /// > is only a very minor change to the base microarchitecture.
420    pub fn expand(&self) -> Instruction {
421        match self {
422            CInstruction::ADDI4SPN { dest, imm } => Instruction::ADDI {
423                dest: dest.expand(),
424                src: IRegister::StackPointer,
425                imm: IImmediate::try_from(imm.val()).unwrap(),
426            },
427            CInstruction::FLD { .. } => todo!(), // needs unimplemented double extension
428            CInstruction::LW { dest, base, offset } => Instruction::LW {
429                dest: dest.expand(),
430                base: base.expand(),
431                offset: IImmediate::try_from(offset.val()).unwrap(),
432            },
433            CInstruction::LD { dest, base, offset } => Instruction::LD {
434                dest: dest.expand(),
435                base: base.expand(),
436                offset: IImmediate::try_from(offset.val()).unwrap(),
437            },
438            CInstruction::FSD { .. } => todo!(), // needs unimplemented double extension
439            CInstruction::SW { src, base, offset } => Instruction::SW {
440                src: src.expand(),
441                base: base.expand(),
442                offset: SImmediate::try_from(offset.val()).unwrap(),
443            },
444            CInstruction::SD { src, base, offset } => Instruction::SD {
445                src: src.expand(),
446                base: base.expand(),
447                offset: SImmediate::try_from(offset.val()).unwrap(),
448            },
449            CInstruction::ADDI { dest, imm } => Instruction::ADDI {
450                dest: *dest,
451                src: *dest,
452                imm: IImmediate::try_from(imm.val()).unwrap(),
453            },
454            CInstruction::ADDIW { dest, imm } => Instruction::ADDIW {
455                dest: *dest,
456                src: *dest,
457                imm: IImmediate::try_from(imm.val()).unwrap(),
458            },
459            CInstruction::LI { dest, imm } => Instruction::ADDI {
460                dest: *dest,
461                src: IRegister::Zero,
462                imm: IImmediate::try_from(imm.val()).unwrap(),
463            },
464            CInstruction::ADDI16SP { imm } => Instruction::ADDI {
465                dest: IRegister::StackPointer,
466                src: IRegister::StackPointer,
467                imm: IImmediate::try_from(imm.val()).unwrap(),
468            },
469            CInstruction::LUI { dest, imm } => Instruction::ADDI {
470                dest: *dest,
471                src: IRegister::Zero,
472                imm: IImmediate::try_from(imm.val()).unwrap(),
473            },
474            CInstruction::SRLI { dest, shamt } => Instruction::SRLI {
475                dest: dest.expand(),
476                src: dest.expand(),
477                shamt: Shamt::try_from(shamt.val()).unwrap(),
478            },
479            CInstruction::SRAI { dest, shamt } => Instruction::SRAI {
480                dest: dest.expand(),
481                src: dest.expand(),
482                shamt: Shamt::try_from(shamt.val()).unwrap(),
483            },
484            CInstruction::ANDI { dest, imm } => Instruction::ANDI {
485                dest: dest.expand(),
486                src: dest.expand(),
487                imm: IImmediate::try_from(imm.val()).unwrap(),
488            },
489            CInstruction::SUB { dest, src } => Instruction::SUB {
490                dest: dest.expand(),
491                src1: dest.expand(),
492                src2: src.expand(),
493            },
494            CInstruction::XOR { dest, src } => Instruction::XOR {
495                dest: dest.expand(),
496                src1: dest.expand(),
497                src2: src.expand(),
498            },
499            CInstruction::OR { dest, src } => Instruction::OR {
500                dest: dest.expand(),
501                src1: dest.expand(),
502                src2: src.expand(),
503            },
504            CInstruction::AND { dest, src } => Instruction::AND {
505                dest: dest.expand(),
506                src1: dest.expand(),
507                src2: src.expand(),
508            },
509            CInstruction::SUBW { dest, src } => Instruction::SUBW {
510                dest: dest.expand(),
511                src1: dest.expand(),
512                src2: src.expand(),
513            },
514            CInstruction::ADDW { dest, src } => Instruction::ADDW {
515                dest: dest.expand(),
516                src1: dest.expand(),
517                src2: src.expand(),
518            },
519            CInstruction::J { offset } => Instruction::JAL {
520                dest: IRegister::Zero,
521                offset: JImmediate::try_from(offset.val()).unwrap(),
522            },
523            CInstruction::BEQZ { src, offset } => Instruction::BEQ {
524                src1: src.expand(),
525                src2: IRegister::Zero,
526                offset: BImmediate::try_from(offset.val()).unwrap(),
527            },
528            CInstruction::BNEZ { src, offset } => Instruction::BNE {
529                src1: src.expand(),
530                src2: IRegister::Zero,
531                offset: BImmediate::try_from(offset.val()).unwrap(),
532            },
533            CInstruction::SLLI { dest, shamt } => Instruction::SLLI {
534                dest: *dest,
535                src: *dest,
536                shamt: Shamt::try_from(shamt.val()).unwrap(),
537            },
538            CInstruction::FLDSP { .. } => todo!(), // needs unimplemented double extension
539            CInstruction::LWSP { dest, offset } => Instruction::LW {
540                dest: *dest,
541                base: IRegister::StackPointer,
542                offset: IImmediate::try_from(offset.val()).unwrap(),
543            },
544            CInstruction::LDSP { dest, offset } => Instruction::LD {
545                dest: *dest,
546                base: IRegister::StackPointer,
547                offset: IImmediate::try_from(offset.val()).unwrap(),
548            },
549            CInstruction::JR { src } => Instruction::JALR {
550                dest: IRegister::Zero,
551                base: *src,
552                offset: IImmediate::try_from(0).unwrap(),
553            },
554            CInstruction::MV { dest, src } => Instruction::ADD {
555                dest: *dest,
556                src1: IRegister::Zero,
557                src2: *src,
558            },
559            CInstruction::EBREAK => Instruction::EBREAK,
560            CInstruction::JALR { src } => Instruction::JALR {
561                dest: IRegister::ReturnAddress,
562                base: *src,
563                offset: IImmediate::try_from(0).unwrap(),
564            },
565            // CInstruction::JALR { .. } => todo!(), // not exactly the same as the expanded version (see manual)
566            CInstruction::ADD { dest, src } => Instruction::ADD {
567                dest: *dest,
568                src1: *dest,
569                src2: *src,
570            },
571            CInstruction::FSDSP { .. } => todo!(), // needs unimplemented double extension
572            CInstruction::SWSP { src, offset } => Instruction::SW {
573                src: *src,
574                base: IRegister::StackPointer,
575                offset: SImmediate::try_from(offset.val()).unwrap(),
576            },
577            CInstruction::SDSP { src, offset } => Instruction::SD {
578                src: *src,
579                base: IRegister::StackPointer,
580                offset: SImmediate::try_from(offset.val()).unwrap(),
581            },
582        }
583    }
584
585    /// Encodes a `CInstruction` into a `u16`.
586    pub fn encode(instruction: &CInstruction) -> u16 {
587        match instruction {
588            CInstruction::ADDI4SPN { dest, imm } => 0b000 << 13 | imm.to_u16() | dest.rs2(),
589            CInstruction::FLD { dest, base, offset } => {
590                0b001 << 13 | offset.to_u16() | base.rs1() | dest.rs2()
591            }
592            CInstruction::LW { dest, base, offset } => {
593                0b010 << 13 | offset.to_u16() | base.rs1() | dest.rs2()
594            }
595            CInstruction::LD { dest, base, offset } => {
596                0b011 << 13 | offset.to_u16() | base.rs1() | dest.rs2()
597            }
598            CInstruction::FSD { src, base, offset } => {
599                0b101 << 13 | offset.to_u16() | base.rs1() | src.rs2()
600            }
601            CInstruction::SW { src, base, offset } => {
602                0b0110 << 13 | offset.to_u16() | base.rs1() | src.rs2()
603            }
604            CInstruction::SD { src, base, offset } => {
605                0b111 << 13 | offset.to_u16() | base.rs1() | src.rs2()
606            }
607            CInstruction::ADDI { dest, imm } => {
608                0b000 << 13 | imm.to_u16() | dest.rd() as u16 | 0b01
609            }
610            CInstruction::ADDIW { dest, imm } => {
611                0b001 << 13 | imm.to_u16() | dest.rd() as u16 | 0b01
612            }
613            CInstruction::LI { dest, imm } => 0b010 << 13 | imm.to_u16() | dest.rd() as u16 | 0b01,
614            CInstruction::ADDI16SP { imm } => 0b011 << 13 | imm.to_u16() | 0b10 << 7 | 0b01,
615            CInstruction::LUI { dest, imm } => 0b011 << 13 | imm.to_u16() | dest.rd() as u16 | 0b01,
616            CInstruction::SRLI { dest, shamt } => {
617                0b100 << 13 | shamt.to_u16() | 0b00 << 10 | dest.rs1() | 0b01
618            }
619            CInstruction::SRAI { dest, shamt } => {
620                0b100 << 13 | shamt.to_u16() | 0b01 << 10 | dest.rs1() | 0b01
621            }
622            CInstruction::ANDI { dest, imm } => {
623                0b100 << 13 | imm.to_u16() | 0b10 << 10 | dest.rs1() | 0b01
624            }
625            CInstruction::SUB { dest, src } => {
626                0b100 << 13 | 0b11 << 10 | dest.rs1() | 0b00 << 5 | src.rs2() | 0b01
627            }
628            CInstruction::XOR { dest, src } => {
629                0b100 << 13 | 0b11 << 10 | dest.rs1() | 0b01 << 5 | src.rs2() | 0b01
630            }
631            CInstruction::OR { dest, src } => {
632                0b100 << 13 | 0b11 << 10 | dest.rs1() | 0b10 << 5 | src.rs2() | 0b01
633            }
634            CInstruction::AND { dest, src } => {
635                0b100 << 13 | 0b11 << 10 | dest.rs1() | 0b11 << 5 | src.rs2() | 0b01
636            }
637            CInstruction::SUBW { dest, src } => {
638                0b100 << 13 | 1 << 12 | 0b11 << 10 | dest.rs1() | 0b00 << 5 | src.rs2() | 0b01
639            }
640            CInstruction::ADDW { dest, src } => {
641                0b100 << 13 | 1 << 12 | 0b11 << 10 | dest.rs1() | 0b01 << 5 | src.rs2() | 0b01
642            }
643            CInstruction::J { offset } => 0b101 << 13 | offset.to_u16() | 0b01,
644            CInstruction::BEQZ { src, offset } => 0b110 << 13 | offset.to_u16() | src.rs1() | 0b01,
645            CInstruction::BNEZ { src, offset } => 0b111 << 13 | offset.to_u16() | src.rs1() | 0b01,
646            CInstruction::SLLI { dest, shamt } => {
647                0b000 << 13 | shamt.to_u16() | dest.rd() as u16 | 0b10
648            }
649            CInstruction::FLDSP { dest, offset } => {
650                0b001 << 13 | offset.to_u16() | dest.rd() as u16 | 0b10
651            }
652            CInstruction::LWSP { dest, offset } => {
653                0b010 << 13 | offset.to_u16() | dest.rd() as u16 | 0b10
654            }
655            CInstruction::LDSP { dest, offset } => {
656                0b011 << 13 | offset.to_u16() | dest.rd() as u16 | 0b10
657            }
658            CInstruction::JR { src } => 0b100 << 13 | src.rd() as u16 | 0b10,
659            CInstruction::MV { dest, src } => {
660                0b100 << 13 | dest.rd() as u16 | (src.rd() >> 5) as u16 | 0b10
661            }
662            CInstruction::EBREAK => 0b100 << 13 | 0b1 << 12 | 0b10,
663            CInstruction::JALR { src } => 0b100 << 13 | 0b1 << 12 | src.rd() as u16 | 0b10,
664            CInstruction::ADD { dest, src } => {
665                0b100 << 13 | 0b1 << 12 | dest.rd() as u16 | (src.rd() >> 5) as u16 | 0b10
666            }
667            CInstruction::FSDSP { src, offset } => {
668                0b101 << 13 | offset.to_u16() | (src.rd() >> 5) as u16 | 0b10
669            }
670            CInstruction::SWSP { src, offset } => {
671                0b110 << 13 | offset.to_u16() | (src.rd() >> 5) as u16 | 0b10
672            }
673            CInstruction::SDSP { src, offset } => {
674                0b111 << 13 | offset.to_u16() | (src.rd() >> 5) as u16 | 0b10
675            }
676        }
677    }
678}