1use crate::{
2 error::Error,
3 instructions::{
4 extract_opcode, insts, Instruction, Itype, R4type, R5type, Rtype, Stype, Utype,
5 },
6};
7use core::convert::TryFrom;
8use core::fmt;
9
10#[derive(Debug, Clone, PartialEq)]
13pub enum TaggedInstruction {
14 Rtype(Rtype),
15 Itype(Itype),
16 Stype(Stype),
17 Utype(Utype),
18 R4type(R4type),
19 R5type(R5type),
20}
21
22impl fmt::Display for TaggedInstruction {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 match self {
25 TaggedInstruction::Rtype(i) => i.fmt(f),
26 TaggedInstruction::Itype(i) => i.fmt(f),
27 TaggedInstruction::Stype(i) => i.fmt(f),
28 TaggedInstruction::Utype(i) => i.fmt(f),
29 TaggedInstruction::R4type(i) => i.fmt(f),
30 TaggedInstruction::R5type(i) => i.fmt(f),
31 }
32 }
33}
34
35impl From<Rtype> for TaggedInstruction {
36 fn from(i: Rtype) -> Self {
37 TaggedInstruction::Rtype(i)
38 }
39}
40
41impl From<Itype> for TaggedInstruction {
42 fn from(i: Itype) -> Self {
43 TaggedInstruction::Itype(i)
44 }
45}
46
47impl From<Stype> for TaggedInstruction {
48 fn from(i: Stype) -> Self {
49 TaggedInstruction::Stype(i)
50 }
51}
52
53impl From<Utype> for TaggedInstruction {
54 fn from(i: Utype) -> Self {
55 TaggedInstruction::Utype(i)
56 }
57}
58
59impl From<R4type> for TaggedInstruction {
60 fn from(i: R4type) -> Self {
61 TaggedInstruction::R4type(i)
62 }
63}
64
65impl From<R5type> for TaggedInstruction {
66 fn from(i: R5type) -> Self {
67 TaggedInstruction::R5type(i)
68 }
69}
70
71impl From<TaggedInstruction> for Instruction {
72 fn from(t: TaggedInstruction) -> Self {
73 match t {
74 TaggedInstruction::Rtype(i) => i.0,
75 TaggedInstruction::Itype(i) => i.0,
76 TaggedInstruction::Stype(i) => i.0,
77 TaggedInstruction::Utype(i) => i.0,
78 TaggedInstruction::R4type(i) => i.0,
79 TaggedInstruction::R5type(i) => i.0,
80 }
81 }
82}
83
84impl TryFrom<Instruction> for TaggedInstruction {
85 type Error = Error;
86
87 fn try_from(i: Instruction) -> Result<Self, Self::Error> {
88 let op = extract_opcode(i);
89 let tagged_inst = match op {
90 insts::OP_UNLOADED => Rtype(i).into(),
91 insts::OP_ECALL => Rtype(i).into(),
92 insts::OP_EBREAK => Rtype(i).into(),
93 insts::OP_FENCEI => Rtype(i).into(),
94 insts::OP_FENCE => Rtype(i).into(),
95 insts::OP_CUSTOM_TRACE_END => Rtype(i).into(),
96 insts::OP_SUB => Rtype(i).into(),
97 insts::OP_SUBW => Rtype(i).into(),
98 insts::OP_ADD => Rtype(i).into(),
99 insts::OP_ADDW => Rtype(i).into(),
100 insts::OP_XOR => Rtype(i).into(),
101 insts::OP_OR => Rtype(i).into(),
102 insts::OP_AND => Rtype(i).into(),
103 insts::OP_SLL => Rtype(i).into(),
104 insts::OP_SLLW => Rtype(i).into(),
105 insts::OP_SRL => Rtype(i).into(),
106 insts::OP_SRLW => Rtype(i).into(),
107 insts::OP_SRA => Rtype(i).into(),
108 insts::OP_SRAW => Rtype(i).into(),
109 insts::OP_SLT => Rtype(i).into(),
110 insts::OP_SLTU => Rtype(i).into(),
111 insts::OP_LB_VERSION0 => Itype(i).into(),
112 insts::OP_LB_VERSION1 => Itype(i).into(),
113 insts::OP_LH_VERSION0 => Itype(i).into(),
114 insts::OP_LH_VERSION1 => Itype(i).into(),
115 insts::OP_LW_VERSION0 => Itype(i).into(),
116 insts::OP_LW_VERSION1 => Itype(i).into(),
117 insts::OP_LD_VERSION0 => Itype(i).into(),
118 insts::OP_LD_VERSION1 => Itype(i).into(),
119 insts::OP_LBU_VERSION0 => Itype(i).into(),
120 insts::OP_LBU_VERSION1 => Itype(i).into(),
121 insts::OP_LHU_VERSION0 => Itype(i).into(),
122 insts::OP_LHU_VERSION1 => Itype(i).into(),
123 insts::OP_LWU_VERSION0 => Itype(i).into(),
124 insts::OP_LWU_VERSION1 => Itype(i).into(),
125 insts::OP_ADDI => Itype(i).into(),
126 insts::OP_ADDIW => Itype(i).into(),
127 insts::OP_XORI => Itype(i).into(),
128 insts::OP_ORI => Itype(i).into(),
129 insts::OP_ANDI => Itype(i).into(),
130 insts::OP_SLTI => Itype(i).into(),
131 insts::OP_SLTIU => Itype(i).into(),
132 insts::OP_JALR_VERSION0 => Itype(i).into(),
133 insts::OP_JALR_VERSION1 => Itype(i).into(),
134 insts::OP_SLLI => Itype(i).into(),
135 insts::OP_SRLI => Itype(i).into(),
136 insts::OP_SRAI => Itype(i).into(),
137 insts::OP_SLLIW => Itype(i).into(),
138 insts::OP_SRLIW => Itype(i).into(),
139 insts::OP_SRAIW => Itype(i).into(),
140 insts::OP_SB => Stype(i).into(),
141 insts::OP_SH => Stype(i).into(),
142 insts::OP_SW => Stype(i).into(),
143 insts::OP_SD => Stype(i).into(),
144 insts::OP_BEQ => Stype(i).into(),
145 insts::OP_BNE => Stype(i).into(),
146 insts::OP_BLT => Stype(i).into(),
147 insts::OP_BGE => Stype(i).into(),
148 insts::OP_BLTU => Stype(i).into(),
149 insts::OP_BGEU => Stype(i).into(),
150 insts::OP_LUI => Utype(i).into(),
151 insts::OP_AUIPC => Utype(i).into(),
152 insts::OP_JAL => Utype(i).into(),
153 insts::OP_MUL => Rtype(i).into(),
154 insts::OP_MULW => Rtype(i).into(),
155 insts::OP_MULH => Rtype(i).into(),
156 insts::OP_MULHSU => Rtype(i).into(),
157 insts::OP_MULHU => Rtype(i).into(),
158 insts::OP_DIV => Rtype(i).into(),
159 insts::OP_DIVW => Rtype(i).into(),
160 insts::OP_DIVU => Rtype(i).into(),
161 insts::OP_DIVUW => Rtype(i).into(),
162 insts::OP_REM => Rtype(i).into(),
163 insts::OP_REMW => Rtype(i).into(),
164 insts::OP_REMU => Rtype(i).into(),
165 insts::OP_REMUW => Rtype(i).into(),
166 insts::OP_LR_W => Rtype(i).into(),
167 insts::OP_SC_W => Rtype(i).into(),
168 insts::OP_AMOSWAP_W => Rtype(i).into(),
169 insts::OP_AMOADD_W => Rtype(i).into(),
170 insts::OP_AMOXOR_W => Rtype(i).into(),
171 insts::OP_AMOAND_W => Rtype(i).into(),
172 insts::OP_AMOOR_W => Rtype(i).into(),
173 insts::OP_AMOMIN_W => Rtype(i).into(),
174 insts::OP_AMOMAX_W => Rtype(i).into(),
175 insts::OP_AMOMINU_W => Rtype(i).into(),
176 insts::OP_AMOMAXU_W => Rtype(i).into(),
177 insts::OP_LR_D => Rtype(i).into(),
178 insts::OP_SC_D => Rtype(i).into(),
179 insts::OP_AMOSWAP_D => Rtype(i).into(),
180 insts::OP_AMOADD_D => Rtype(i).into(),
181 insts::OP_AMOXOR_D => Rtype(i).into(),
182 insts::OP_AMOAND_D => Rtype(i).into(),
183 insts::OP_AMOOR_D => Rtype(i).into(),
184 insts::OP_AMOMIN_D => Rtype(i).into(),
185 insts::OP_AMOMAX_D => Rtype(i).into(),
186 insts::OP_AMOMINU_D => Rtype(i).into(),
187 insts::OP_AMOMAXU_D => Rtype(i).into(),
188 insts::OP_ADDUW => Rtype(i).into(),
189 insts::OP_ANDN => Rtype(i).into(),
190 insts::OP_BCLR => Rtype(i).into(),
191 insts::OP_BCLRI => Itype(i).into(),
192 insts::OP_BEXT => Rtype(i).into(),
193 insts::OP_BEXTI => Itype(i).into(),
194 insts::OP_BINV => Rtype(i).into(),
195 insts::OP_BINVI => Itype(i).into(),
196 insts::OP_BSET => Rtype(i).into(),
197 insts::OP_BSETI => Itype(i).into(),
198 insts::OP_CLMUL => Rtype(i).into(),
199 insts::OP_CLMULH => Rtype(i).into(),
200 insts::OP_CLMULR => Rtype(i).into(),
201 insts::OP_CLZ => Rtype(i).into(),
202 insts::OP_CLZW => Rtype(i).into(),
203 insts::OP_CPOP => Rtype(i).into(),
204 insts::OP_CPOPW => Rtype(i).into(),
205 insts::OP_CTZ => Rtype(i).into(),
206 insts::OP_CTZW => Rtype(i).into(),
207 insts::OP_MAX => Rtype(i).into(),
208 insts::OP_MAXU => Rtype(i).into(),
209 insts::OP_MIN => Rtype(i).into(),
210 insts::OP_MINU => Rtype(i).into(),
211 insts::OP_ORCB => Rtype(i).into(),
212 insts::OP_ORN => Rtype(i).into(),
213 insts::OP_REV8 => Rtype(i).into(),
214 insts::OP_ROL => Rtype(i).into(),
215 insts::OP_ROLW => Rtype(i).into(),
216 insts::OP_ROR => Rtype(i).into(),
217 insts::OP_RORI => Itype(i).into(),
218 insts::OP_RORIW => Itype(i).into(),
219 insts::OP_RORW => Rtype(i).into(),
220 insts::OP_SEXTB => Rtype(i).into(),
221 insts::OP_SEXTH => Rtype(i).into(),
222 insts::OP_SH1ADD => Rtype(i).into(),
223 insts::OP_SH1ADDUW => Rtype(i).into(),
224 insts::OP_SH2ADD => Rtype(i).into(),
225 insts::OP_SH2ADDUW => Rtype(i).into(),
226 insts::OP_SH3ADD => Rtype(i).into(),
227 insts::OP_SH3ADDUW => Rtype(i).into(),
228 insts::OP_SLLIUW => Itype(i).into(),
229 insts::OP_XNOR => Rtype(i).into(),
230 insts::OP_ZEXTH => Rtype(i).into(),
231 insts::OP_WIDE_MUL => R4type(i).into(),
232 insts::OP_WIDE_MULU => R4type(i).into(),
233 insts::OP_WIDE_MULSU => R4type(i).into(),
234 insts::OP_WIDE_DIV => R4type(i).into(),
235 insts::OP_WIDE_DIVU => R4type(i).into(),
236 insts::OP_FAR_JUMP_REL => Utype(i).into(),
237 insts::OP_FAR_JUMP_ABS => Utype(i).into(),
238 insts::OP_ADC => Rtype(i).into(),
239 insts::OP_SBB => R4type(i).into(),
240 insts::OP_ADCS => R4type(i).into(),
241 insts::OP_SBBS => R4type(i).into(),
242 insts::OP_ADD3A => R5type(i).into(),
243 insts::OP_ADD3B => R5type(i).into(),
244 insts::OP_ADD3C => R5type(i).into(),
245 insts::OP_CUSTOM_LOAD_UIMM => Utype(i).into(),
246 insts::OP_CUSTOM_LOAD_IMM => Utype(i).into(),
247 _ => return Err(Error::InvalidOp(op)),
248 };
249 Ok(tagged_inst)
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256 use crate::instructions::{blank_instruction, instruction_opcode_name};
257
258 #[test]
259 fn test_all_valid_opcodes_convert_to_tagged_instruction() {
260 for i in insts::OP_UNLOADED..=insts::OP_CUSTOM_TRACE_END {
261 let inst = blank_instruction(i);
262 let result = TaggedInstruction::try_from(inst);
263 assert!(
264 result.is_ok(),
265 "TaggedInstruction does not handle opcode {}({})!",
266 i,
267 instruction_opcode_name(i)
268 );
269 }
270 }
271}