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