ckb_vm_definitions/
instructions.rs

1// For fast decoding and cache friendly, RISC-V instruction is decoded
2// into 64 bit unsigned integer in the following format:
3//
4// +-----+-----+-----+-----+-----+-----+-----+-----+
5// |           | rs2 | rs1 | flg | op2 | rd  | op  | R-type
6// +-----+-----+-----+-----+-----+-----+-----+-----+
7// |     | rs3 | rs2 | rs1 | flg | op2 | rd  | op  | R4-type
8// +-----------+-----------------------------------+
9// | rs4 | rs3 | rs2 | rs1 | flg | op2 | rd  | op  | R5-type
10// +-----------+-----------------------------------+
11// |    immediate    | rs1 | flg | op2 | rd  | op  | I-type
12// +-----------------------------------------------+
13// |    immediate    | rs1 | flg | op2 | rs2 | op  | S-type/B-type
14// +-----------------+-----------------------------+
15// |       immediate       | flg | op2 | rd  | op  | U-type/J-type
16// +-----+-----+-----+-----+-----+-----+-----+-----+
17//
18// +flg+ here means a combination of flags, Its format is as follows:
19//
20// +---+---+---+---+---+---+---+---+
21// | 7 | 6 | 5 | 4 | length >> 1   |
22// +---+---+---+---+---+---+---+---+
23//
24// This way each op and register index are in full byte, accessing them
25// will be much faster than the original compact form. Hence we will have
26// a fast path where the interpreter loop reads instruction directly in this
27// format, and a slow path where a full featured decoder decodes RISC-V
28// instruction into the internal form here(much like how traces/micro-ops work.)
29//
30// About +op+ and +op2+:
31// When the op value is 0x10-0xff, it expresses a first-level instruction under fast
32// path, at this time the value of op2 is ignored.
33// When the op value is 0x00-0x0f, op and op2 are combined to express a
34// second-level instruction under slow path.
35//
36// Notice that this module now uses macro-based techniques to define opcodes.
37// To see a full list of opcodes as plain Rust source code, install
38// [cargo-expand](https://github.com/dtolnay/cargo-expand) first, then use the
39// following command:
40//
41// cargo expand --manifest-path=definitions/Cargo.toml --lib instructions
42pub type Instruction = u64;
43
44pub type InstructionOpcode = u16;
45
46pub use paste::paste;
47
48#[doc(hidden)]
49#[macro_export]
50macro_rules! __apply {
51    ((0, $callback:ident), $(($name:ident, $code:expr)),*) => {
52        $crate::instructions::paste! {
53            $(
54                $callback!([< OP_ $name >], $name, $code);
55            )*
56        }
57    };
58    ((1, $x:ident, $callback:ident), $(($name:ident, $code:expr)),*) => {
59        $crate::instructions::paste! {
60            $(
61                $callback!([< OP_ $name >], $name, $code, $x);
62            )*
63        }
64    };
65    ((2, $x:ident, $y:ident, $callback:ident), $(($name:ident, $code:expr)),*) => {
66        $crate::instructions::paste! {
67            $(
68                $callback!([< OP_ $name >], $name, $code, $x, $y);
69            )*
70        }
71    };
72    ((100, $res:ident, $val:expr, $callback:ident, $others:expr), $(($name:ident, $code:expr)),*) => {
73        $crate::instructions::paste! {
74            let $res = match $val {
75                $( $code => $callback!([< OP_ $name >], $name, $code), )*
76                _ => $others
77            };
78        }
79    };
80    ((101, $x:ident, $res:ident, $val:expr, $callback:ident, $others:expr), $(($name:ident, $code:expr)),*) => {
81        $crate::instructions::paste! {
82            let $res = match $val {
83                $( $code => $callback!([< OP_ $name >], $name, $code, $x), )*
84                _ => $others
85            };
86        }
87    };
88    ((102, $x:ident, $y:ident, $res:ident, $val:expr, $callback:ident, $others:expr), $(($name:ident, $code:expr)),*) => {
89        $crate::instructions::paste! {
90            let $res = match $val {
91                $( $code => $callback!([< OP_ $name >], $name, $code, $x, $y), )*
92                _ => $others
93            };
94        }
95    };
96    ((200, $res:ident, $callback:ident), $(($name:ident, $code:expr)),*) => {
97        $crate::instructions::paste! {
98            let $res = [
99                $( $callback!([< OP_ $name >], $name, $code), )*
100            ];
101        }
102    };
103    ((201, $x:ident, $res:ident, $callback:ident), $(($name:ident, $code:expr)),*) => {
104        $crate::instructions::paste! {
105            let $res = [
106                $( $callback!([< OP_ $name >], $name, $code, $x), )*
107            ];
108        }
109    };
110    ((202, $x:ident, $y:ident, $res:ident, $callback:ident), $(($name:ident, $code:expr)),*) => {
111        $crate::instructions::paste! {
112            let $res = [
113                $( $callback!([< OP_ $name >], $name, $code, $x, $y), )*
114            ];
115        }
116    };
117}
118
119#[doc(hidden)]
120#[macro_export]
121macro_rules! __for_each_inst_inner {
122    ($callback:tt) => {
123        $crate::__apply!(
124            $callback,
125            // IMC
126            (UNLOADED, 0x10),
127            (ADD, 0x11),
128            (ADDI, 0x12),
129            (ADDIW, 0x13),
130            (ADDW, 0x14),
131            (AND, 0x15),
132            (ANDI, 0x16),
133            (DIV, 0x17),
134            (DIVU, 0x18),
135            (DIVUW, 0x19),
136            (DIVW, 0x1a),
137            (LB_VERSION0, 0x1b),
138            (LB_VERSION1, 0x1c),
139            (LBU_VERSION0, 0x1d),
140            (LBU_VERSION1, 0x1e),
141            (LD_VERSION0, 0x1f),
142            (LD_VERSION1, 0x20),
143            (LH_VERSION0, 0x21),
144            (LH_VERSION1, 0x22),
145            (LHU_VERSION0, 0x23),
146            (LHU_VERSION1, 0x24),
147            (LUI, 0x25),
148            (LW_VERSION0, 0x26),
149            (LW_VERSION1, 0x27),
150            (LWU_VERSION0, 0x28),
151            (LWU_VERSION1, 0x29),
152            (MUL, 0x2a),
153            (MULH, 0x2b),
154            (MULHSU, 0x2c),
155            (MULHU, 0x2d),
156            (MULW, 0x2e),
157            (OR, 0x2f),
158            (ORI, 0x30),
159            (REM, 0x31),
160            (REMU, 0x32),
161            (REMUW, 0x33),
162            (REMW, 0x34),
163            (SB, 0x35),
164            (SD, 0x36),
165            (SH, 0x37),
166            (SLL, 0x38),
167            (SLLI, 0x39),
168            (SLLIW, 0x3a),
169            (SLLW, 0x3b),
170            (SLT, 0x3c),
171            (SLTI, 0x3d),
172            (SLTIU, 0x3e),
173            (SLTU, 0x3f),
174            (SRA, 0x40),
175            (SRAI, 0x41),
176            (SRAIW, 0x42),
177            (SRAW, 0x43),
178            (SRL, 0x44),
179            (SRLI, 0x45),
180            (SRLIW, 0x46),
181            (SRLW, 0x47),
182            (SUB, 0x48),
183            (SUBW, 0x49),
184            (SW, 0x4a),
185            (XOR, 0x4b),
186            (XORI, 0x4c),
187            // A
188            (LR_W, 0x4d),
189            (SC_W, 0x4e),
190            (AMOSWAP_W, 0x4f),
191            (AMOADD_W, 0x50),
192            (AMOXOR_W, 0x51),
193            (AMOAND_W, 0x52),
194            (AMOOR_W, 0x53),
195            (AMOMIN_W, 0x54),
196            (AMOMAX_W, 0x55),
197            (AMOMINU_W, 0x56),
198            (AMOMAXU_W, 0x57),
199            (LR_D, 0x58),
200            (SC_D, 0x59),
201            (AMOSWAP_D, 0x5a),
202            (AMOADD_D, 0x5b),
203            (AMOXOR_D, 0x5c),
204            (AMOAND_D, 0x5d),
205            (AMOOR_D, 0x5e),
206            (AMOMIN_D, 0x5f),
207            (AMOMAX_D, 0x60),
208            (AMOMINU_D, 0x61),
209            (AMOMAXU_D, 0x62),
210            // B
211            (ADDUW, 0x63),
212            (ANDN, 0x64),
213            (BCLR, 0x65),
214            (BCLRI, 0x66),
215            (BEXT, 0x67),
216            (BEXTI, 0x68),
217            (BINV, 0x69),
218            (BINVI, 0x6a),
219            (BSET, 0x6b),
220            (BSETI, 0x6c),
221            (CLMUL, 0x6d),
222            (CLMULH, 0x6e),
223            (CLMULR, 0x6f),
224            (CLZ, 0x70),
225            (CLZW, 0x71),
226            (CPOP, 0x72),
227            (CPOPW, 0x73),
228            (CTZ, 0x74),
229            (CTZW, 0x75),
230            (MAX, 0x76),
231            (MAXU, 0x77),
232            (MIN, 0x78),
233            (MINU, 0x79),
234            (ORCB, 0x7a),
235            (ORN, 0x7b),
236            (REV8, 0x7c),
237            (ROL, 0x7d),
238            (ROLW, 0x7e),
239            (ROR, 0x7f),
240            (RORI, 0x80),
241            (RORIW, 0x81),
242            (RORW, 0x82),
243            (SEXTB, 0x83),
244            (SEXTH, 0x84),
245            (SH1ADD, 0x85),
246            (SH1ADDUW, 0x86),
247            (SH2ADD, 0x87),
248            (SH2ADDUW, 0x88),
249            (SH3ADD, 0x89),
250            (SH3ADDUW, 0x8a),
251            (SLLIUW, 0x8b),
252            (XNOR, 0x8c),
253            (ZEXTH, 0x8d),
254            // Mop
255            (WIDE_MUL, 0x8e),
256            (WIDE_MULU, 0x8f),
257            (WIDE_MULSU, 0x90),
258            (WIDE_DIV, 0x91),
259            (WIDE_DIVU, 0x92),
260            (ADC, 0x93),
261            (SBB, 0x94),
262            (ADCS, 0x95),
263            (SBBS, 0x96),
264            (ADD3A, 0x97),
265            (ADD3B, 0x98),
266            (ADD3C, 0x99),
267            (CUSTOM_LOAD_UIMM, 0x9a),
268            (CUSTOM_LOAD_IMM, 0x9b),
269            // All branches
270            (AUIPC, 0x9c),
271            (BEQ, 0x9d),
272            (BGE, 0x9e),
273            (BGEU, 0x9f),
274            (BLT, 0xa0),
275            (BLTU, 0xa1),
276            (BNE, 0xa2),
277            (EBREAK, 0xa3),
278            (ECALL, 0xa4),
279            (FENCE, 0xa5),
280            (FENCEI, 0xa6),
281            (JAL, 0xa7),
282            (JALR_VERSION0, 0xa8),
283            (JALR_VERSION1, 0xa9),
284            (FAR_JUMP_REL, 0xaa),
285            (FAR_JUMP_ABS, 0xab),
286            (CUSTOM_TRACE_END, 0xac)
287        );
288    };
289}
290
291/// Generates a possible definition for each instruction, it leverages
292/// a callback macro that takes (at least) 3 arguments:
293///
294/// 1. $name: an identifier containing the full defined opcode name,
295///    e.g., OP_ADD
296/// 2. $real_name: an identifier containing just the opcode part, e.g., ADD
297/// 3. $code: an expr containing the actual opcode number
298///
299/// Free variables are attached to the variants ending with inst1, inst2, etc.
300/// Those free variables will also be appended as arguments to the callback macro.
301#[macro_export]
302macro_rules! for_each_inst {
303    ($callback:ident) => {
304        $crate::__for_each_inst_inner!((0, $callback));
305    };
306}
307
308#[macro_export]
309macro_rules! for_each_inst1 {
310    ($callback:ident, $x:ident) => {
311        $crate::__for_each_inst_inner!((1, $x, $callback));
312    };
313}
314
315#[macro_export]
316macro_rules! for_each_inst2 {
317    ($callback:ident, $x:ident, $y:ident) => {
318        $crate::__for_each_inst_inner!((2, $x, $y, $callback));
319    };
320}
321
322/// Generates a match expression containing all instructions, it takes 3
323/// arguments:
324///
325/// * A callback macro that takes the exact same arguments as callback
326///   macro in +for_each_inst+
327/// * A value expression containing the actual value to match against.
328/// * An expression used as wildcard matches when the passed value does
329///   not match any opcode
330///
331/// * Free variables are attached to the variants ending with match1, match2, etc.
332#[macro_export]
333macro_rules! for_each_inst_match {
334    ($callback:ident, $val:expr, $others:expr) => {{
335        $crate::__for_each_inst_inner!((100, __res__, $val, $callback, $others));
336        __res__
337    }};
338}
339
340#[macro_export]
341macro_rules! for_each_inst_match1 {
342    ($callback:ident, $val:expr, $others:expr, $x:ident) => {{
343        $crate::__for_each_inst_inner!((101, $x, __res__, $val, $callback, $others));
344        __res__
345    }};
346}
347
348#[macro_export]
349macro_rules! for_each_inst_match2 {
350    ($callback:ident, $val:expr, $others:expr, $x:ident, $y:ident) => {{
351        $crate::__for_each_inst_inner!((102, $x, $y, __res__, $val, $callback, $others));
352        __res__
353    }};
354}
355
356/// Generates an array on all instructions
357///
358/// * A callback macro that takes the exact same arguments as callback
359///   macro in +for_each_inst+
360///
361/// * Free variables are attached to the variants ending with fold1, fold2, etc.
362#[macro_export]
363macro_rules! for_each_inst_array {
364    ($callback:ident) => {{
365        $crate::__for_each_inst_inner!((200, __res__, $callback));
366        __res__
367    }};
368}
369
370#[macro_export]
371macro_rules! for_each_inst_array1 {
372    ($callback:ident, $x:ident) => {{
373        $crate::__for_each_inst_inner!((201, $x, __res__, $callback));
374        __res__
375    }};
376}
377
378#[macro_export]
379macro_rules! for_each_inst_array2 {
380    ($callback:ident, $x:ident, $y:ident) => {{
381        $crate::__for_each_inst_inner!((202, $x, $y, __res__, $callback));
382        __res__
383    }};
384}
385
386// Define the actual opcodes
387macro_rules! define_instruction {
388    ($name:ident, $real_name:ident, $code:expr) => {
389        pub const $name: InstructionOpcode = $code;
390    };
391}
392for_each_inst!(define_instruction);
393
394pub const MINIMAL_OPCODE: InstructionOpcode = OP_UNLOADED;
395pub const MAXIMUM_OPCODE: InstructionOpcode = OP_CUSTOM_TRACE_END;
396
397pub const MINIMAL_BASIC_BLOCK_END_OPCODE: InstructionOpcode = OP_AUIPC;
398pub const MAXIMUM_BASIC_BLOCK_END_OPCODE: InstructionOpcode = OP_FAR_JUMP_ABS;
399
400macro_rules! inst_real_name {
401    ($name:ident, $real_name:ident, $code:expr) => {
402        stringify!($real_name)
403    };
404}
405
406pub fn instruction_opcode_name(i: InstructionOpcode) -> &'static str {
407    for_each_inst_match!(inst_real_name, i, "UNKNOWN_INSTRUCTION!")
408}