five32_instruction_set/rv32i/instr.rs
1use paste::paste;
2use strum_macros::EnumString;
3
4use crate::layout;
5use crate::rv32i::instr_masks::*;
6
7/// This macro is used to parse an Instruction if its corresponding bitmask matches the input word.
8macro_rules! define_parse_single_instruction {
9 ( $source:ident, $m_sym:ident, $m_layout:ty ) => {
10 {
11 paste!{
12 if ($source & [<MASK_ $m_sym>]) == [<MATCH_ $m_sym>] {
13 return Some(Instruction::$m_sym($m_layout::from($source)));
14 }
15 }
16 }
17 };
18}
19
20/// This macro is used to define an enum which organizes instructions and byte layouts.
21macro_rules! define_instruction_set_enum {
22 ($(($name:ident, $layout:ty)),*) => {
23 #[derive(Debug, PartialEq, EnumString)]
24 pub enum Instruction {
25 $(
26 $name($layout),
27 )*
28 }
29 }
30}
31
32/// This macro is used to define a function which parses (decodes) an Instruction from a given word.
33macro_rules! define_instruction_set_parser {
34 ($(($name:ident, $layout:ty)),*) => {
35 // This will generate a function 'parse_from_word' for the given set of instructions.
36 impl Instruction {
37 /// Returns the Instruction name (ex: "ADD")
38 pub fn get_name(&self) -> String {
39 match self {
40 $(
41 Self::$name(_) => String::from(stringify!($name)),
42 )*
43 }
44 }
45
46 /// Parses (decodes) the Instruction from a 32-bit word.
47 pub fn parse_from_word(word: u32) -> Option<Instruction>{
48 $(
49 define_parse_single_instruction!(word, $name, $layout);
50 )*
51 None
52 }
53 }
54 }
55}
56
57/// This macro is used to define an instruction set. It takes a collection of instruction names and
58/// corresponding binary layouts. It then defines an enum to encapsulate these instructions and
59/// writes associated helper functions.
60///
61/// note: The binary layout type must be fully-specified. This shortcoming is documented in
62/// https://rust-lang.github.io/api-guidelines/macros.html#type-fragments-are-flexible-c-macro-ty
63///
64/// ```rust
65///define_instruction_set!((ADD, layout::R));
66///
67/// // produces...
68/// pub enum Instruction {
69/// ADD(five32_instruction_set::layout::R)
70/// }
71///
72///impl Instruction {
73/// pub fn parse_from_word(word: u32) -> Option<Instruction> {
74/// if (word & MASK_AND) == MATCH_AND {
75/// return Some(Instruction::ADD(five32_instruction_set::R::from(word)));
76/// }
77/// None
78/// }
79///
80/// pub fn get_name(&self) -> String {
81/// match self {
82/// Instruction::ADD(_) => String::from("ADD")
83/// }
84/// }
85///}
86///
87/// ```
88macro_rules! define_instruction_set {
89 {$($x:tt)*} => {
90 define_instruction_set_enum!($($x)*);
91 define_instruction_set_parser!($($x)*);
92 }
93}
94
95define_instruction_set!{
96 // Arithmetic
97 (ADD, layout::R),
98 (SUB, layout::R),
99 (ADDI, layout::I),
100 (SLT, layout::R),
101 (SLTI, layout::I),
102 (SLTU, layout::R),
103 (SLTIU, layout::I),
104 (LUI, layout::U),
105 (AUIPC, layout::U),
106 // Logical
107 (AND, layout::R),
108 (OR, layout::R),
109 (XOR, layout::R),
110 (ANDI, layout::I),
111 (ORI, layout::I),
112 (XORI, layout::I),
113 (SLL, layout::R),
114 (SRL, layout::R),
115 (SRA, layout::R),
116 (SLLI, layout::I),
117 (SRLI, layout::I),
118 (SRAI, layout::I),
119 // IO
120 (LW, layout::I),
121 (LH, layout::I),
122 (LB, layout::I),
123 (LHU, layout::I),
124 (LBU, layout::S),
125 (SW, layout::S),
126 (SH, layout::S),
127 (SB, layout::S),
128 // Branching
129 (BEQ, layout::B),
130 (BNE, layout::B),
131 (BGE, layout::B),
132 (BGEU, layout::B),
133 (BLT, layout::B),
134 (BLTU, layout::B),
135 (JAL, layout::I),
136 (JALR, layout::I),
137 // Special Flags
138 (ECALL, layout::Raw),
139 (EBREAK, layout::Raw),
140 (FENCE, layout::Raw)
141}