1use std::fmt::Display;
4
5use deepsize2::DeepSizeOf;
6use enum_map::Enum;
7use rrs_lib::instruction_formats::{
8 OPCODE_AUIPC, OPCODE_BRANCH, OPCODE_JAL, OPCODE_JALR, OPCODE_LOAD, OPCODE_LUI, OPCODE_OP,
9 OPCODE_OP_32, OPCODE_OP_IMM, OPCODE_OP_IMM_32, OPCODE_STORE, OPCODE_SYSTEM,
10};
11use serde::{Deserialize, Serialize};
12use slop_algebra::Field;
13
14use crate::InstructionType;
15
16#[allow(non_camel_case_types)]
31#[derive(
32 Debug,
33 Clone,
34 Copy,
35 PartialEq,
36 Eq,
37 Hash,
38 Serialize,
39 Deserialize,
40 PartialOrd,
41 Ord,
42 Enum,
43 DeepSizeOf,
44)]
45#[repr(u8)]
46pub enum Opcode {
47 ADD = 0,
49 ADDI = 1,
51 SUB = 2,
53 XOR = 3,
55 OR = 4,
57 AND = 5,
59 SLL = 6,
61 SRL = 7,
63 SRA = 8,
65 SLT = 9,
67 SLTU = 10,
69 MUL = 11,
71 MULH = 12,
73 MULHU = 13,
75 MULHSU = 14,
77 DIV = 15,
79 DIVU = 16,
81 REM = 17,
83 REMU = 18,
85 LB = 19,
87 LH = 20,
89 LW = 21,
91 LBU = 22,
93 LHU = 23,
95 SB = 24,
97 SH = 25,
99 SW = 26,
101 BEQ = 27,
103 BNE = 28,
105 BLT = 29,
107 BGE = 30,
109 BLTU = 31,
111 BGEU = 32,
113 JAL = 33,
115 JALR = 34,
117 AUIPC = 35,
119 LUI = 36,
121 ECALL = 37,
123 EBREAK = 38,
125 ADDW = 39,
128 SUBW = 40,
130 SLLW = 41,
132 SRLW = 42,
134 SRAW = 43,
136 LWU = 44,
138 LD = 45,
140 SD = 46,
142 MULW = 47,
144 DIVW = 48,
146 DIVUW = 49,
148 REMW = 50,
150 REMUW = 51,
152 UNIMP = 52,
154}
155#[derive(
161 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, DeepSizeOf,
162)]
163#[allow(clippy::upper_case_acronyms)]
164pub enum ByteOpcode {
165 AND = 0,
167 OR = 1,
169 XOR = 2,
171 U8Range = 3,
173 LTU = 4,
175 MSB = 5,
177 Range = 6,
179}
180
181impl Opcode {
182 #[must_use]
184 pub const fn mnemonic(&self) -> &str {
185 match self {
186 Opcode::ADD => "add",
187 Opcode::ADDI => "addi",
188 Opcode::SUB => "sub",
189 Opcode::XOR => "xor",
190 Opcode::OR => "or",
191 Opcode::AND => "and",
192 Opcode::SLL => "sll",
193 Opcode::SRL => "srl",
194 Opcode::SRA => "sra",
195 Opcode::SLT => "slt",
196 Opcode::SLTU => "sltu",
197 Opcode::LB => "lb",
198 Opcode::LH => "lh",
199 Opcode::LW => "lw",
200 Opcode::LBU => "lbu",
201 Opcode::LHU => "lhu",
202 Opcode::SB => "sb",
203 Opcode::SH => "sh",
204 Opcode::SW => "sw",
205 Opcode::BEQ => "beq",
206 Opcode::BNE => "bne",
207 Opcode::BLT => "blt",
208 Opcode::BGE => "bge",
209 Opcode::BLTU => "bltu",
210 Opcode::BGEU => "bgeu",
211 Opcode::JAL => "jal",
212 Opcode::JALR => "jalr",
213 Opcode::AUIPC => "auipc",
214 Opcode::LUI => "lui",
215 Opcode::ECALL => "ecall",
216 Opcode::EBREAK => "ebreak",
217 Opcode::MUL => "mul",
218 Opcode::MULH => "mulh",
219 Opcode::MULHU => "mulhu",
220 Opcode::MULHSU => "mulhsu",
221 Opcode::DIV => "div",
222 Opcode::DIVU => "divu",
223 Opcode::REM => "rem",
224 Opcode::REMU => "remu",
225 Opcode::ADDW => "addw",
226 Opcode::SUBW => "subw",
227 Opcode::SLLW => "sllw",
228 Opcode::SRLW => "srlw",
229 Opcode::SRAW => "sraw",
230 Opcode::LWU => "lwu",
231 Opcode::LD => "ld",
232 Opcode::SD => "sd",
233 Opcode::MULW => "mulw",
234 Opcode::DIVW => "divw",
235 Opcode::DIVUW => "divuw",
236 Opcode::REMW => "remw",
237 Opcode::REMUW => "remuw",
238 Opcode::UNIMP => "unimp",
239 }
240 }
241
242 #[must_use]
244 pub fn as_field<F: Field>(self) -> F {
245 F::from_canonical_u32(self as u32)
246 }
247
248 #[must_use]
250 #[allow(clippy::match_same_arms)]
251 pub fn funct3(self: Opcode) -> Option<u8> {
252 Some(match self {
253 Opcode::ADD | Opcode::SUB | Opcode::ADDI => 0b000,
255 Opcode::SLL => 0b001,
256 Opcode::SLT => 0b010,
257 Opcode::SLTU => 0b011,
258 Opcode::XOR => 0b100,
259 Opcode::SRL | Opcode::SRA => 0b101,
260 Opcode::OR => 0b110,
261 Opcode::AND => 0b111,
262 Opcode::ADDW => 0b000,
263 Opcode::SUBW => 0b000,
264 Opcode::SLLW => 0b001,
265 Opcode::SRLW => 0b101,
266 Opcode::SRAW => 0b101,
267 Opcode::LWU => 0b110,
268 Opcode::LD => 0b011,
269 Opcode::SD => 0b011,
270 Opcode::MULW => 0b000,
271 Opcode::DIVW => 0b100,
272 Opcode::DIVUW => 0b101,
273 Opcode::REMW => 0b110,
274 Opcode::REMUW => 0b111,
275
276 Opcode::MUL => 0b000,
278 Opcode::MULH => 0b001,
279 Opcode::MULHSU => 0b010,
280 Opcode::MULHU => 0b011,
281 Opcode::DIV => 0b100,
282 Opcode::DIVU => 0b101,
283 Opcode::REM => 0b110,
284 Opcode::REMU => 0b111,
285
286 Opcode::LB => 0b000,
288 Opcode::LH => 0b001,
289 Opcode::LW => 0b010,
290 Opcode::LBU => 0b100,
291 Opcode::LHU => 0b101,
292
293 Opcode::SB => 0b000,
295 Opcode::SH => 0b001,
296 Opcode::SW => 0b010,
297
298 Opcode::BEQ => 0b000,
300 Opcode::BNE => 0b001,
301 Opcode::BLT => 0b100,
302 Opcode::BGE => 0b101,
303 Opcode::BLTU => 0b110,
304 Opcode::BGEU => 0b111,
305
306 Opcode::JALR => 0b000, Opcode::ECALL | Opcode::EBREAK => 0b000,
311
312 Opcode::JAL | Opcode::AUIPC | Opcode::LUI | Opcode::UNIMP => return None,
314 })
315 }
316
317 #[must_use]
319 #[allow(clippy::match_same_arms)]
320 pub fn funct7(self: Opcode) -> Option<u8> {
321 use Opcode::{
322 ADD, ADDI, ADDW, AND, AUIPC, BEQ, BGE, BGEU, BLT, BLTU, BNE, DIV, DIVU, DIVUW, DIVW,
323 EBREAK, ECALL, JAL, JALR, LB, LBU, LD, LH, LHU, LUI, LW, LWU, MUL, MULH, MULHSU, MULHU,
324 MULW, OR, REM, REMU, REMUW, REMW, SB, SD, SH, SLL, SLLW, SLT, SLTU, SRA, SRAW, SRL,
325 SRLW, SUB, SUBW, SW, UNIMP, XOR,
326 };
327 Some(match self {
328 ADD | SLL | SLT | SLTU | XOR | SRL | OR | AND | ADDW | SLLW | SRLW => 0b0000000,
329 SUB | SRA | SUBW | SRAW => 0b0100000,
330 MUL | MULH | MULHSU | MULHU | DIV | DIVU | REM | REMU | MULW | DIVW | DIVUW | REMW
331 | REMUW => 0b0000001,
332 ECALL | EBREAK => 0b0000000,
333 ADDI | LB | LH | LW | LBU | LHU | SB | SH | SW | BEQ | BNE | BLT | BGE | BLTU
334 | BGEU | JAL | JALR | AUIPC | LUI | UNIMP | LWU | LD | SD => return None,
335 })
336 }
337
338 #[must_use]
340 pub fn funct12(self: Opcode) -> Option<u32> {
341 use Opcode::ECALL;
342 Some(match self {
343 ECALL => 0x000,
344 _ => return None,
345 })
346 }
347
348 #[must_use]
349 pub fn base_opcode(self: Opcode) -> (u32, Option<u32>) {
351 match self {
352 Opcode::SLL
353 | Opcode::SRL
354 | Opcode::SRA
355 | Opcode::XOR
356 | Opcode::OR
357 | Opcode::AND
358 | Opcode::SLT
359 | Opcode::SLTU => (OPCODE_OP, Some(OPCODE_OP_IMM)),
360
361 Opcode::ADD
362 | Opcode::SUB
363 | Opcode::MUL
364 | Opcode::MULH
365 | Opcode::MULHU
366 | Opcode::MULHSU
367 | Opcode::DIV
368 | Opcode::DIVU
369 | Opcode::REM
370 | Opcode::REMU => (OPCODE_OP, Some(OPCODE_OP)),
371
372 Opcode::ADDI => (OPCODE_OP_IMM, Some(OPCODE_OP_IMM)),
373
374 Opcode::ECALL => (OPCODE_SYSTEM, None),
375
376 Opcode::JALR => (OPCODE_JALR, Some(OPCODE_JALR)),
377
378 Opcode::LB
379 | Opcode::LH
380 | Opcode::LW
381 | Opcode::LBU
382 | Opcode::LHU
383 | Opcode::LWU
384 | Opcode::LD => (OPCODE_LOAD, Some(OPCODE_LOAD)),
385
386 Opcode::SB | Opcode::SH | Opcode::SW | Opcode::SD => (OPCODE_STORE, Some(OPCODE_STORE)),
387
388 Opcode::BEQ | Opcode::BNE | Opcode::BLT | Opcode::BGE | Opcode::BLTU | Opcode::BGEU => {
389 (OPCODE_BRANCH, Some(OPCODE_BRANCH))
390 }
391
392 Opcode::AUIPC => (OPCODE_AUIPC, Some(OPCODE_AUIPC)),
393
394 Opcode::LUI => (OPCODE_LUI, Some(OPCODE_LUI)),
395
396 Opcode::JAL => (OPCODE_JAL, Some(OPCODE_JAL)),
397
398 Opcode::ADDW | Opcode::SLLW | Opcode::SRLW | Opcode::SRAW => {
400 (OPCODE_OP_32, Some(OPCODE_OP_IMM_32))
401 }
402
403 Opcode::SUBW
404 | Opcode::MULW
405 | Opcode::DIVW
406 | Opcode::DIVUW
407 | Opcode::REMW
408 | Opcode::REMUW => (OPCODE_OP_32, None),
409
410 _ => unreachable!("Opcode {:?} has no base opcode", self),
411 }
412 }
413
414 #[must_use]
415 pub fn instruction_type(self) -> (InstructionType, Option<InstructionType>) {
417 match self {
418 Opcode::SLL | Opcode::SRL | Opcode::SRA => {
419 (InstructionType::RType, Some(InstructionType::ITypeShamt))
420 }
421
422 Opcode::SLLW | Opcode::SRLW | Opcode::SRAW => {
423 (InstructionType::RType, Some(InstructionType::ITypeShamt32))
424 }
425
426 Opcode::ADDW | Opcode::XOR | Opcode::OR | Opcode::AND | Opcode::SLT | Opcode::SLTU => {
427 (InstructionType::RType, Some(InstructionType::IType))
428 }
429
430 Opcode::ADD
431 | Opcode::SUB
432 | Opcode::SUBW
433 | Opcode::MUL
434 | Opcode::MULH
435 | Opcode::MULHU
436 | Opcode::MULHSU
437 | Opcode::DIV
438 | Opcode::DIVU
439 | Opcode::REM
440 | Opcode::REMU
441 | Opcode::MULW
442 | Opcode::DIVW
443 | Opcode::DIVUW
444 | Opcode::REMW
445 | Opcode::REMUW => (InstructionType::RType, None),
446
447 Opcode::ADDI => (InstructionType::IType, Some(InstructionType::IType)),
448
449 Opcode::ECALL => (InstructionType::ECALL, None),
450
451 Opcode::JALR
452 | Opcode::LB
453 | Opcode::LH
454 | Opcode::LW
455 | Opcode::LBU
456 | Opcode::LHU
457 | Opcode::LWU
458 | Opcode::LD => (InstructionType::IType, None),
459
460 Opcode::SB | Opcode::SH | Opcode::SW | Opcode::SD => (InstructionType::SType, None),
461
462 Opcode::BEQ | Opcode::BNE | Opcode::BLT | Opcode::BGE | Opcode::BLTU | Opcode::BGEU => {
463 (InstructionType::BType, None)
464 }
465
466 Opcode::AUIPC | Opcode::LUI => (InstructionType::UType, None),
467
468 Opcode::JAL => (InstructionType::JType, None),
469
470 _ => unreachable!("Opcode {:?} has no instruction type", self),
471 }
472 }
473}
474
475impl Display for Opcode {
476 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
477 f.write_str(self.mnemonic())
478 }
479}