rv32_asm/
instruction.rs

1use core::panic;
2use std::fmt::Display;
3use std::ops;
4
5type RegisterType = u32;
6pub const XLEN: u8 = 32;
7
8#[derive(Clone, PartialEq, Debug)]
9pub struct InstructionWithLabel {
10    pub inst: Instruction,
11    pub labels: Vec<Label>,
12    /// This normally contains corresponded IR. This field is outputted to dump file.
13    pub ir: Option<String>,
14}
15
16impl InstructionWithLabel {
17    pub fn new(inst: Instruction, labels: Vec<Label>, ir: Option<String>) -> Self {
18        Self { inst, labels, ir }
19    }
20
21    pub fn with_label(self, labels: Vec<Label>) -> Self {
22        Self { labels, ..self }
23    }
24}
25
26impl From<Instruction> for InstructionWithLabel {
27    fn from(value: Instruction) -> Self {
28        Self::new(value, vec![], None)
29    }
30}
31
32#[derive(Clone, PartialEq, Debug)]
33pub enum Instruction {
34    R(RInstruction),
35    I(IInstruction),
36    S(SInstruction),
37    J(JInstruction),
38    U(UInstruction),
39    SB(SBInstruction),
40}
41
42impl Instruction {
43    pub fn with_ir(self, ir: Option<String>) -> InstructionWithLabel {
44        InstructionWithLabel::new(self, vec![], ir)
45    }
46
47    // Pseudo instructions
48
49    pub fn mv(rd: Register, rs1: Register) -> Instruction {
50        Instruction::R(RInstruction {
51            op: RInstructionOp::Add,
52            rs1,
53            rs2: Register::zero(),
54            rd,
55        })
56    }
57
58    pub fn li(rd: Register, imm: Immediate) -> Instruction {
59        Instruction::I(IInstruction {
60            op: IInstructionOp::Addi,
61            imm,
62            rs1: Register::zero(),
63            rd,
64        })
65    }
66
67    pub fn ret() -> Instruction {
68        Instruction::I(IInstruction {
69            op: IInstructionOp::Jalr,
70            imm: Immediate::new(0),
71            rs1: Register::ra(),
72            rd: Register::zero(),
73        })
74    }
75
76    #[allow(dead_code)]
77    pub fn nop() -> Instruction {
78        Instruction::I(IInstruction {
79            op: IInstructionOp::Addi,
80            imm: Immediate::new(0),
81            rs1: Register::zero(),
82            rd: Register::zero(),
83        })
84    }
85
86    // Frequently used instructions
87
88    /// Store `rs2` to `mem[rs1 + imm]`
89    pub fn sw(rs2: Register, rs1: Register, imm: Immediate) -> Instruction {
90        Instruction::S(SInstruction {
91            op: SInstructionOp::Sw,
92            rs1,
93            rs2,
94            imm,
95        })
96    }
97
98    /// Load `mem[rs1 + imm]` to `rd`
99    pub fn lw(rd: Register, rs1: Register, imm: Immediate) -> Instruction {
100        Instruction::I(IInstruction {
101            op: IInstructionOp::Lw,
102            rs1,
103            rd,
104            imm,
105        })
106    }
107
108    pub fn addi(rd: Register, rs1: Register, imm: i32) -> Instruction {
109        Instruction::I(IInstruction {
110            op: IInstructionOp::Addi,
111            rs1,
112            rd,
113            imm: Immediate::for_i(imm),
114        })
115    }
116
117    pub fn add(rd: Register, rs1: Register, rs2: Register) -> Instruction {
118        Instruction::R(RInstruction {
119            op: RInstructionOp::Add,
120            rs1,
121            rs2,
122            rd,
123        })
124    }
125}
126
127impl Display for Instruction {
128    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129        use Instruction::*;
130        match self {
131            R(ri) => write!(f, "{}", ri.generate_asm()),
132            I(ii) => write!(f, "{}", ii.generate_asm()),
133            S(si) => write!(f, "{}", si.generate_asm()),
134            J(ji) => write!(f, "{}", ji.generate_asm()),
135            U(ui) => write!(f, "{}", ui.generate_asm()),
136            SB(sbi) => write!(f, "{}", sbi.generate_asm()),
137        }
138    }
139}
140
141// pub struct InstrWithIr(pub Instruction, pub Option<String>);
142
143// impl InstrWithIr {
144//     pub fn with_ir(self, ir: Option<String>) -> Self {
145//         let Self(inst, _) = self;
146//         Self(inst, ir)
147//     }
148
149//     pub fn set_ir(&mut self, ir: Option<String>) {
150//         self.1 = ir;
151//     }
152// }
153
154// impl From<Instruction> for InstrWithIr {
155//     fn from(inst: Instruction) -> Self {
156//         Self(inst, None)
157//     }
158// }
159
160#[derive(Clone, PartialEq, Debug)]
161pub struct RInstruction {
162    pub op: RInstructionOp,
163    pub rs1: Register,
164    pub rs2: Register,
165    pub rd: Register,
166}
167
168#[derive(Clone, PartialEq, Debug)]
169pub enum RInstructionOp {
170    Add,
171    Sub,
172    And,
173    Or,
174    ShiftLeft,
175    ShiftRight,
176    /// Set Less Than
177    Slt,
178
179    Mul,
180    Div,
181    Rem,
182}
183
184#[derive(Clone, PartialEq, Debug)]
185pub struct IInstruction {
186    pub op: IInstructionOp,
187    pub imm: Immediate,
188    pub rs1: Register,
189    pub rd: Register,
190}
191
192impl IInstruction {
193    pub fn is_nop(&self) -> bool {
194        self.op == IInstructionOp::Addi
195            && self.imm.value() == 0
196            && self.rs1.is_zero()
197            && self.rd.is_zero()
198    }
199}
200
201#[derive(Clone, PartialEq, Debug)]
202pub enum IInstructionOp {
203    Andi,
204    Ori,
205    Addi,
206    Jalr,
207    Ecall,
208    /// Load Word
209    Lw,
210    /// Load Byte
211    Lb,
212    Xori,
213    /// Set Less Than Immediate
214    Slti,
215    /// Set Less Than Immediate Unsigned
216    Sltiu,
217}
218
219#[derive(Clone, PartialEq, Debug)]
220pub struct SInstruction {
221    pub op: SInstructionOp,
222    pub imm: Immediate,
223    pub rs1: Register,
224    pub rs2: Register,
225}
226
227#[derive(Clone, PartialEq, Debug)]
228pub enum SInstructionOp {
229    /// Store Word
230    Sw,
231    /// Store Byte
232    Sb,
233}
234
235#[derive(Clone, PartialEq, Debug)]
236pub struct JInstruction {
237    pub op: JInstructionOp,
238    pub imm: RelAddress,
239    pub rd: Register,
240}
241
242#[derive(Clone, PartialEq, Debug)]
243pub enum JInstructionOp {
244    Jal,
245}
246
247#[derive(Clone, PartialEq, Debug)]
248pub struct UInstruction {
249    pub op: UInstructionOp,
250    pub imm: Immediate,
251    pub rd: Register,
252}
253
254#[derive(Clone, PartialEq, Debug)]
255pub enum UInstructionOp {
256    Lui,
257}
258
259#[derive(Clone, PartialEq, Debug)]
260pub struct SBInstruction {
261    pub op: SBInstructionOp,
262    pub imm: RelAddress,
263    pub rs1: Register,
264    pub rs2: Register,
265}
266
267#[derive(Clone, PartialEq, Debug)]
268pub enum SBInstructionOp {
269    /// Branch EQual
270    #[allow(dead_code)]
271    Beq,
272    /// Branch Not Equal
273    Bne,
274}
275
276pub trait GenerateCode {
277    fn generate_code(&self) -> RegisterType;
278    fn generate_asm(&self) -> String;
279}
280
281impl GenerateCode for RInstruction {
282    fn generate_code(&self) -> RegisterType {
283        use RInstructionOp::*;
284
285        let rs2 = self.rs2.as_int();
286        let rs1 = self.rs1.as_int();
287        let rd = self.rd.as_int();
288
289        let (funct7, funct3, opcode) = match self.op {
290            Add => (0b0000000, 0b000, 0b0110011),
291            Sub => (0b0100000, 0b000, 0b0110011),
292            And => (0b0000000, 0b111, 0b0110011),
293            Or => (0b0000000, 0b110, 0b0110011),
294            ShiftLeft => (0b0000000, 0b001, 0b0110011),
295            ShiftRight => (0b0000000, 0b101, 0b0110011),
296            Slt => (0b0000000, 0b010, 0b0110011),
297            Mul => (0b0000001, 0b000, 0b0110011),
298            Div => (0b0000001, 0b100, 0b0110011),
299            Rem => (0b0000001, 0b110, 0b0110011),
300        };
301
302        (funct7 << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode
303    }
304
305    fn generate_asm(&self) -> String {
306        use RInstructionOp::*;
307
308        let name = match self.op {
309            Add => "add",
310            Sub => "sub",
311            And => "and",
312            Or => "or",
313            ShiftLeft => "sll",
314            ShiftRight => "srl",
315            Slt => "slt",
316            Mul => "mul",
317            Div => "div",
318            Rem => "rem",
319        };
320
321        format!("{} {}, {}, {}", name, self.rd, self.rs1, self.rs2)
322    }
323}
324
325impl GenerateCode for IInstruction {
326    fn generate_code(&self) -> RegisterType {
327        use IInstructionOp::*;
328
329        assert!(
330            (self.imm.value() & !0xfff) == 0,
331            "Immediate of IInstruction must be under 0x1000. But the value is 0x{:x}.",
332            self.imm.value()
333        );
334
335        let imm = (self.imm.value() as u32) & 0xfff;
336        let rs1 = self.rs1.as_int();
337
338        let (funct3, opcode) = match self.op {
339            Andi => (0b111, 0b0010011),
340            Ori => (0b110, 0b0010011),
341            Addi => (0b000, 0b0010011),
342            Jalr => (0b000, 0b1100111),
343            Ecall => (0b000, 0b1110011),
344            Lw => (0b010, 0b0000011),
345            Lb => (0b000, 0b0000011),
346            Xori => (0b100, 0b0010011),
347            Slti => (0b010, 0b0010011),
348            Sltiu => (0b011, 0b0010011),
349        };
350
351        let rd = self.rd.as_int();
352
353        (imm << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode
354    }
355
356    fn generate_asm(&self) -> String {
357        use IInstructionOp::*;
358
359        if self.is_nop() {
360            return "nop".to_string();
361        }
362
363        match self.op {
364            Andi | Ori | Addi | Jalr | Xori | Slti | Sltiu => {
365                let mut imm = self.imm.value();
366                if imm >> 11 & 1 == 1 {
367                    // sign extension
368                    imm |= 0xffff_f000u32 as i32;
369                }
370                let name = match self.op {
371                    Andi => "andi",
372                    Ori => "ori",
373                    Addi => "addi",
374                    Jalr => "jalr",
375                    Xori => "xori",
376                    Slti => "slti",
377                    Sltiu => "sltiu",
378                    _ => panic!("Unknown op: {:?}", self.op),
379                };
380                format!("{} {}, {}, {}", name, self.rd, self.rs1, imm)
381            }
382            Ecall => "ecall".to_string(),
383            Lw => {
384                format!("lw {}, {}({})", self.rd, self.imm, self.rs1)
385            }
386            Lb => {
387                format!("lb {}, {}({})", self.rd, self.imm, self.rs1)
388            }
389        }
390    }
391}
392
393impl GenerateCode for SInstruction {
394    fn generate_code(&self) -> RegisterType {
395        use SInstructionOp::*;
396
397        let rs1 = self.rs1.as_int();
398        let rs2 = self.rs2.as_int();
399
400        let imm = self.imm.uvalue();
401        let imm1 = (imm >> 5) & 0b111_1111;
402        let imm2 = imm & 0b1_1111;
403
404        let (funct3, opcode) = match self.op {
405            Sw => (0b010, 0b0100011),
406            Sb => (0b000, 0b0100011),
407        };
408
409        (imm1 << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (imm2 << 7) | opcode
410    }
411
412    fn generate_asm(&self) -> String {
413        use SInstructionOp::*;
414
415        let name = match self.op {
416            Sw => "sw",
417            Sb => "sb",
418        };
419
420        format!("{} {}, {}({})", name, self.rs2, self.imm, self.rs1)
421    }
422}
423
424impl GenerateCode for JInstruction {
425    fn generate_code(&self) -> RegisterType {
426        use JInstructionOp::*;
427
428        let imm = self.imm.value();
429
430        assert!(imm & 1 == 0);
431        let imm = imm >> 1;
432
433        let imm = (imm & (0b1 << 19))
434            | ((imm & 0b11_1111_1111) << 9)
435            | ((imm & (0b1 << 10)) >> 2)
436            | ((imm & (0b1111_1111 << 11)) >> 11);
437
438        let rd = self.rd.as_int();
439
440        let opcode = match self.op {
441            Jal => 0b1101111,
442        };
443
444        (imm << 12) | (rd << 7) | opcode
445    }
446
447    fn generate_asm(&self) -> String {
448        use JInstructionOp::*;
449
450        match self.op {
451            Jal => {
452                format!("jal {}, {}", self.rd, self.imm)
453            }
454        }
455    }
456}
457
458impl GenerateCode for UInstruction {
459    fn generate_code(&self) -> RegisterType {
460        use UInstructionOp::*;
461
462        let imm = self.imm.uvalue() & 0xfffff000;
463        let rd = self.rd.as_int();
464
465        let opcode = match self.op {
466            Lui => 0b0110111,
467        };
468
469        imm | (rd << 7) | opcode
470    }
471
472    fn generate_asm(&self) -> String {
473        use UInstructionOp::*;
474
475        match self.op {
476            Lui => {
477                let imm = self.imm.uvalue() & 0xfffff000;
478                format!("lui {}, {}", self.rd, imm >> 12)
479            }
480        }
481    }
482}
483
484impl GenerateCode for SBInstruction {
485    fn generate_code(&self) -> RegisterType {
486        use SBInstructionOp::*;
487
488        let imm = self.imm.value();
489        assert!(imm & 1 == 0);
490        // 7 bits
491        let imm_upper = ((imm & (1 << 12)) >> 5) | ((imm >> 5) & 0b11111);
492        // 5 bits
493        let imm_lower = (imm & 0b11110) | ((imm >> 11) & 1);
494
495        let rs1 = self.rs1.as_int();
496        let rs2 = self.rs2.as_int();
497
498        let (opcode, funct3) = match self.op {
499            Beq => (0b1100011, 0b000),
500            Bne => (0b1100011, 0b001),
501        };
502
503        (imm_upper << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (imm_lower << 7) | opcode
504    }
505
506    fn generate_asm(&self) -> String {
507        use SBInstructionOp::*;
508
509        let name = match self.op {
510            Beq => "beq",
511            Bne => "bne",
512        };
513        format!("{} {}, {}, {}", name, self.rs1, self.rs2, self.imm)
514    }
515}
516
517#[derive(Clone, PartialEq, Debug)]
518pub struct Label {
519    pub name: String,
520}
521
522impl Label {
523    pub fn new(name: String) -> Self {
524        Self { name }
525    }
526}
527
528#[derive(Clone, PartialEq, Debug)]
529pub enum RelAddress {
530    Label(Label),
531    Immediate(Immediate),
532}
533
534impl RelAddress {
535    fn value(&self) -> RegisterType {
536        match self {
537            RelAddress::Label(_) => unimplemented!(),
538            RelAddress::Immediate(imm) => imm.uvalue(),
539        }
540    }
541}
542
543impl Display for RelAddress {
544    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
545        match self {
546            RelAddress::Label(label) => write!(f, "{}", label.name),
547            RelAddress::Immediate(imm) => write!(f, "{}", imm.value()),
548        }
549    }
550}
551
552#[derive(Clone, Copy, PartialEq, Debug)]
553pub enum Register {
554    Integer(u32),
555    // TODO: Support float registers
556    Float(u32),
557}
558
559impl Register {
560    pub fn zero() -> Register {
561        Register::Integer(0)
562    }
563
564    pub fn is_zero(&self) -> bool {
565        self.as_int() == 0
566    }
567
568    pub fn ra() -> Register {
569        Register::Integer(1)
570    }
571
572    pub fn sp() -> Register {
573        Register::Integer(2)
574    }
575
576    #[allow(dead_code)]
577    pub fn gp() -> Register {
578        Register::Integer(3)
579    }
580
581    #[allow(dead_code)]
582    pub fn tp() -> Register {
583        Register::Integer(4)
584    }
585
586    pub fn t(i: u32) -> Register {
587        match i {
588            0..=2 => Register::Integer(5 + i),
589            3.. => Register::Integer(28 - 3 + i),
590        }
591    }
592
593    #[allow(dead_code)]
594    pub fn fp() -> Register {
595        Self::s(0)
596    }
597
598    pub fn s(i: u32) -> Register {
599        match i {
600            0 | 1 => Register::Integer(8 + i),
601            2.. => Register::Integer(18 - 2 + i),
602        }
603    }
604
605    pub fn a(i: u32) -> Register {
606        Register::Integer(10 + i)
607    }
608
609    pub fn as_int(&self) -> u32 {
610        if let Register::Integer(i) = self {
611            if i >= &32u32 {
612                panic!("Register #{} is invalid!", *i)
613            } else {
614                *i
615            }
616        } else {
617            panic!("Register {} is invalid!", self)
618        }
619    }
620}
621
622impl Display for Register {
623    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
624        match self {
625            Register::Integer(i) => match i {
626                0 => write!(f, "zero"),
627                1 => write!(f, "ra"),
628                2 => write!(f, "sp"),
629                3 => write!(f, "gp"),
630                4 => write!(f, "tp"),
631                5..=7 => write!(f, "t{}", i - 5),
632                8 => write!(f, "s0"),
633                9 => write!(f, "s1"),
634                10..=17 => write!(f, "a{}", i - 10),
635                18..=27 => write!(f, "s{}", i - 16),
636                28..=31 => write!(f, "t{}", i - 25),
637                _ => write!(f, "(invalid register {})", i),
638            },
639            Register::Float(i) => {
640                write!(f, "f{}", i)
641            }
642        }
643    }
644}
645
646#[derive(Clone, PartialEq, Debug)]
647pub enum Immediate {
648    Value(i32),
649    Label(Label),
650}
651
652impl Immediate {
653    pub fn new(value: i32) -> Immediate {
654        Immediate::Value(value)
655    }
656
657    pub fn value(&self) -> i32 {
658        match self {
659            Immediate::Value(value) => *value,
660            Immediate::Label(_) => todo!(),
661        }
662    }
663
664    pub fn uvalue(&self) -> u32 {
665        self.value() as u32
666    }
667
668    /// Create an immediate for I-instruction.
669    pub fn for_i(value: i32) -> Self {
670        Self::new(value & 0xfff)
671    }
672}
673
674impl ops::Add<Immediate> for Immediate {
675    type Output = Immediate;
676
677    fn add(self, rhs: Immediate) -> Self::Output {
678        // TODO: Take care for label
679        Immediate::new(self.value() + rhs.value())
680    }
681}
682
683impl ops::MulAssign<i32> for Immediate {
684    fn mul_assign(&mut self, rhs: i32) {
685        match self {
686            Immediate::Value(value) => {
687                *value *= rhs;
688            }
689            Immediate::Label(_) => todo!(),
690        }
691    }
692}
693
694impl Display for Immediate {
695    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
696        write!(f, "{}", self.value())
697    }
698}