blob: a539242b84d953633c11b2fdf179d2bcd6d87089 [file] [log] [blame]
Alessandro Gatti268acb72024-08-25 16:28:35 +02001/*
2 * This file is part of the MicroPython project, https://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2024 Alessandro Gatti
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
27#include <assert.h>
28#include <stdarg.h>
29#include <stdint.h>
30#include <stdio.h>
31#include <string.h>
32
Alessandro Gatti268acb72024-08-25 16:28:35 +020033#include "py/emit.h"
34#include "py/misc.h"
35
36#if MICROPY_EMIT_INLINE_RV32
37
Damien George9ee2ef52025-04-10 15:35:39 +100038#include "py/asmrv32.h"
39
Alessandro Gatti268acb72024-08-25 16:28:35 +020040typedef enum {
41// define rules with a compile function
42#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
43#define DEF_RULE_NC(rule, kind, ...)
44 #include "py/grammar.h"
45#undef DEF_RULE
46#undef DEF_RULE_NC
47 PN_const_object, // special node for a constant, generic Python object
48// define rules without a compile function
49#define DEF_RULE(rule, comp, kind, ...)
50#define DEF_RULE_NC(rule, kind, ...) PN_##rule,
51 #include "py/grammar.h"
52#undef DEF_RULE
53#undef DEF_RULE_NC
54} pn_kind_t;
55
56struct _emit_inline_asm_t {
57 asm_rv32_t as;
58 uint16_t pass;
59 mp_obj_t *error_slot;
60 mp_uint_t max_num_labels;
61 qstr *label_lookup;
62};
63
Alessandro Gatti8633abc2025-01-04 12:54:44 +010064static const qstr_short_t REGISTERS_QSTR_TABLE[] = {
Alessandro Gatti268acb72024-08-25 16:28:35 +020065 MP_QSTR_zero, MP_QSTR_ra, MP_QSTR_sp, MP_QSTR_gp, MP_QSTR_tp, MP_QSTR_t0, MP_QSTR_t1, MP_QSTR_t2,
66 MP_QSTR_s0, MP_QSTR_s1, MP_QSTR_a0, MP_QSTR_a1, MP_QSTR_a2, MP_QSTR_a3, MP_QSTR_a4, MP_QSTR_a5,
67 MP_QSTR_a6, MP_QSTR_a7, MP_QSTR_s2, MP_QSTR_s3, MP_QSTR_s4, MP_QSTR_s5, MP_QSTR_s6, MP_QSTR_s7,
68 MP_QSTR_s8, MP_QSTR_s9, MP_QSTR_s10, MP_QSTR_s11, MP_QSTR_t3, MP_QSTR_t4, MP_QSTR_t5, MP_QSTR_t6,
69 MP_QSTR_x0, MP_QSTR_x1, MP_QSTR_x2, MP_QSTR_x3, MP_QSTR_x4, MP_QSTR_x5, MP_QSTR_x6, MP_QSTR_x7,
70 MP_QSTR_x8, MP_QSTR_x9, MP_QSTR_x10, MP_QSTR_x11, MP_QSTR_x12, MP_QSTR_x13, MP_QSTR_x14, MP_QSTR_x15,
71 MP_QSTR_x16, MP_QSTR_x17, MP_QSTR_x18, MP_QSTR_x19, MP_QSTR_x20, MP_QSTR_x21, MP_QSTR_x22, MP_QSTR_x23,
72 MP_QSTR_x24, MP_QSTR_x25, MP_QSTR_x26, MP_QSTR_x27, MP_QSTR_x28, MP_QSTR_x29, MP_QSTR_x30, MP_QSTR_x31,
73};
74
75////////////////////////////////////////////////////////////////////////////////
76
77static inline void emit_inline_rv32_error_msg(emit_inline_asm_t *emit, mp_rom_error_text_t msg) {
78 *emit->error_slot = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg);
79}
80
81static inline void emit_inline_rv32_error_exc(emit_inline_asm_t *emit, mp_obj_t exc) {
82 *emit->error_slot = exc;
83}
84
85emit_inline_asm_t *emit_inline_rv32_new(mp_uint_t max_num_labels) {
86 emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t);
87 memset(&emit->as, 0, sizeof(emit->as));
88 mp_asm_base_init(&emit->as.base, max_num_labels);
89 emit->max_num_labels = max_num_labels;
90 emit->label_lookup = m_new(qstr, max_num_labels);
91 return emit;
92}
93
94void emit_inline_rv32_free(emit_inline_asm_t *emit) {
95 m_del(qstr, emit->label_lookup, emit->max_num_labels);
96 mp_asm_base_deinit(&emit->as.base, false);
97 m_del_obj(emit_inline_asm_t, emit);
98}
99
100static void emit_inline_rv32_start_pass(emit_inline_asm_t *emit, pass_kind_t pass, mp_obj_t *error_slot) {
101 emit->pass = pass;
102 emit->error_slot = error_slot;
103 if (emit->pass == MP_PASS_CODE_SIZE) {
104 memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr));
105 }
106 mp_asm_base_start_pass(&emit->as.base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE);
107}
108
109static void emit_inline_rv32_end_pass(emit_inline_asm_t *emit, mp_uint_t type_sig) {
110 // c.jr ra
111 asm_rv32_opcode_cjr(&emit->as, ASM_RV32_REG_RA);
112 asm_rv32_end_pass(&emit->as);
113}
114
115static bool parse_register_node(mp_parse_node_t node, mp_uint_t *register_number, bool compressed) {
116 assert(register_number != NULL && "Register number pointer is NULL.");
117
118 if (!MP_PARSE_NODE_IS_ID(node)) {
119 return false;
120 }
121
122 qstr node_qstr = MP_PARSE_NODE_LEAF_ARG(node);
123 for (mp_uint_t index = 0; index < MP_ARRAY_SIZE(REGISTERS_QSTR_TABLE); index++) {
124 if (node_qstr == REGISTERS_QSTR_TABLE[index]) {
125 mp_uint_t number = index % RV32_AVAILABLE_REGISTERS_COUNT;
126 if (!compressed || (compressed && RV32_IS_IN_C_REGISTER_WINDOW(number))) {
127 *register_number = compressed ? RV32_MAP_IN_C_REGISTER_WINDOW(number) : number;
128 return true;
129 }
130 break;
131 }
132 }
133
134 return false;
135}
136
137static mp_uint_t lookup_label(emit_inline_asm_t *emit, mp_parse_node_t node, qstr *qstring) {
138 assert(qstring && "qstring pointer is NULL");
139
140 *qstring = MP_PARSE_NODE_LEAF_ARG(node);
141 for (mp_uint_t label = 0; label < emit->max_num_labels; label++) {
142 if (emit->label_lookup[label] == *qstring) {
143 return label;
144 }
145 }
146
147 return emit->max_num_labels;
148}
149
150static inline ptrdiff_t label_code_offset(emit_inline_asm_t *emit, mp_uint_t label_index) {
151 return emit->as.base.label_offsets[label_index] - emit->as.base.code_offset;
152}
153
154static mp_uint_t emit_inline_rv32_count_params(emit_inline_asm_t *emit, mp_uint_t parameters_count, mp_parse_node_t *parameter_nodes) {
155 // TODO: Raise this up to 8? RV32I has 8 A-registers that are meant to
156 // be used for passing arguments.
157
158 if (parameters_count > 4) {
159 emit_inline_rv32_error_msg(emit, MP_ERROR_TEXT("can only have up to 4 parameters for RV32 assembly"));
160 return 0;
161 }
162
163 mp_uint_t register_index = 0;
164 for (mp_uint_t index = 0; index < parameters_count; index++) {
165 bool valid_register = parse_register_node(parameter_nodes[index], &register_index, false);
166 if (!valid_register || (register_index != (ASM_RV32_REG_A0 + index))) {
167 emit_inline_rv32_error_msg(emit, MP_ERROR_TEXT("parameters must be registers in sequence a0 to a3"));
168 return 0;
169 }
170 }
171
172 return parameters_count;
173}
174
175static bool emit_inline_rv32_label(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id) {
176 assert(label_num < emit->max_num_labels);
177 if (emit->pass == MP_PASS_CODE_SIZE) {
178 for (mp_uint_t index = 0; index < emit->max_num_labels; index++) {
179 if (emit->label_lookup[index] == label_id) {
180 return false;
181 }
182 }
183 }
184 emit->label_lookup[label_num] = label_id;
185 mp_asm_base_label_assign(&emit->as.base, label_num);
186 return true;
187}
188
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100189typedef enum {
190 CALL_RRR, // Opcode Register, Register, Register
191 CALL_RR, // Opcode Register, Register
192 CALL_RRI, // Opcode Register, Register, Immediate
193 CALL_RRL, // Opcode Register, Register, Label
194 CALL_RI, // Opcode Register, Immediate
195 CALL_L, // Opcode Label
196 CALL_R, // Opcode Register
197 CALL_RL, // Opcode Register, Label
198 CALL_N, // Opcode
199 CALL_I, // Opcode Immediate
200 CALL_RII, // Opcode Register, Register, Immediate
201 CALL_RIR, // Opcode Register, Immediate(Register)
202 CALL_COUNT
203} call_convention_t;
Alessandro Gatti268acb72024-08-25 16:28:35 +0200204
205#define N 0 // No argument
206#define R 1 // Register
207#define I 2 // Immediate
208#define L 3 // Label
209#define C (1 << 2) // Compressed register
210#define U (1 << 2) // Unsigned immediate
211#define Z (1 << 3) // Non-zero
212
213typedef void (*call_l_t)(asm_rv32_t *state, mp_uint_t label_index);
214typedef void (*call_ri_t)(asm_rv32_t *state, mp_uint_t rd, mp_int_t immediate);
215typedef void (*call_rri_t)(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_int_t immediate);
216typedef void (*call_rii_t)(asm_rv32_t *state, mp_uint_t rd, mp_uint_t immediate1, mp_int_t immediate2);
217typedef void (*call_rrr_t)(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2);
218typedef void (*call_rr_t)(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs);
219typedef void (*call_i_t)(asm_rv32_t *state, mp_int_t immediate);
220typedef void (*call_r_t)(asm_rv32_t *state, mp_uint_t rd);
221typedef void (*call_n_t)(asm_rv32_t *state);
222
223typedef struct _opcode_t {
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100224 qstr_short_t qstring;
225 uint16_t argument1_mask : 4;
226 uint16_t argument2_mask : 4;
227 uint16_t argument3_mask : 4;
228 uint16_t arguments_count : 2;
229 // 2 bits available here
Alessandro Gatti268acb72024-08-25 16:28:35 +0200230 uint32_t calling_convention : 4;
231 uint32_t argument1_kind : 4;
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100232 uint32_t argument1_shift : 4;
Alessandro Gatti268acb72024-08-25 16:28:35 +0200233 uint32_t argument2_kind : 4;
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100234 uint32_t argument2_shift : 4;
Alessandro Gatti268acb72024-08-25 16:28:35 +0200235 uint32_t argument3_kind : 4;
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100236 uint32_t argument3_shift : 4;
237 // 4 bits available here
238 void *emitter;
Alessandro Gatti268acb72024-08-25 16:28:35 +0200239} opcode_t;
240
241#define opcode_li asm_rv32_emit_optimised_load_immediate
242
243static void opcode_la(asm_rv32_t *state, mp_uint_t rd, mp_int_t displacement) {
244 // This cannot be optimised for size, otherwise label addresses would move around.
245 mp_uint_t upper = (mp_uint_t)displacement & 0xFFFFF000;
246 mp_uint_t lower = (mp_uint_t)displacement & 0x00000FFF;
247 if ((lower & 0x800) != 0) {
248 upper += 0x1000;
249 }
250 asm_rv32_opcode_auipc(state, rd, upper);
251 asm_rv32_opcode_addi(state, rd, rd, lower);
252}
253
254#define RC (R | C)
255#define IU (I | U)
256#define IZ (I | Z)
257#define IUZ (I | U | Z)
258
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100259#define MASK_NOT_USED 0
260
261enum {
262 MASK_FFFFFFFF,
263 MASK_00000FFF,
264 MASK_FFFFF000,
265 MASK_00001FFE,
266 MASK_0000001F,
267 MASK_FFFFFFFE,
268 MASK_0000003F,
269 MASK_0000FF00,
270 MASK_000003FC,
271 MASK_000001FE,
272 MASK_00000FFE,
273 MASK_FFFFFFFA,
274 MASK_0001F800,
275 MASK_0000007C,
276 MASK_000000FC,
277 MASK_001FFFFE,
278};
279
280static const uint32_t OPCODE_MASKS[] = {
281 [MASK_FFFFFFFF] = 0xFFFFFFFF,
282 [MASK_00000FFF] = 0x00000FFF,
283 [MASK_FFFFF000] = 0xFFFFF000,
284 [MASK_00001FFE] = 0x00001FFE,
285 [MASK_0000001F] = 0x0000001F,
286 [MASK_FFFFFFFE] = 0xFFFFFFFE,
287 [MASK_0000003F] = 0x0000003F,
288 [MASK_0000FF00] = 0x0000FF00,
289 [MASK_000003FC] = 0x000003FC,
290 [MASK_000001FE] = 0x000001FE,
291 [MASK_00000FFE] = 0x00000FFE,
292 [MASK_FFFFFFFA] = 0xFFFFFFFA,
293 [MASK_0001F800] = 0x0001F800,
294 [MASK_0000007C] = 0x0000007C,
295 [MASK_000000FC] = 0x000000FC,
296 [MASK_001FFFFE] = 0x001FFFFE,
297};
298
Alessandro Gatti268acb72024-08-25 16:28:35 +0200299static const opcode_t OPCODES[] = {
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100300 { MP_QSTR_add, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_add },
301 { MP_QSTR_addi, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_addi },
302 { MP_QSTR_and_, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_and },
303 { MP_QSTR_andi, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_andi },
304 { MP_QSTR_auipc, MASK_FFFFFFFF, MASK_FFFFF000, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 12, N, 0, asm_rv32_opcode_auipc },
305 { MP_QSTR_beq, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_beq },
306 { MP_QSTR_bge, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_bge },
307 { MP_QSTR_bgeu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_bgeu },
308 { MP_QSTR_blt, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_blt },
309 { MP_QSTR_bltu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_bltu },
310 { MP_QSTR_bne, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_bne },
311 { MP_QSTR_csrrc, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_csrrc },
312 { MP_QSTR_csrrs, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_csrrs },
313 { MP_QSTR_csrrw, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_csrrw },
314 { MP_QSTR_csrrci, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, asm_rv32_opcode_csrrci },
315 { MP_QSTR_csrrsi, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, asm_rv32_opcode_csrrsi },
316 { MP_QSTR_csrrwi, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, asm_rv32_opcode_csrrwi },
317 { MP_QSTR_c_add, MASK_FFFFFFFE, MASK_FFFFFFFE, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, asm_rv32_opcode_cadd },
318 { MP_QSTR_c_addi, MASK_FFFFFFFE, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, R, 0, IZ, 0, N, 0, asm_rv32_opcode_caddi },
319 { MP_QSTR_c_addi4spn, MASK_0000FF00, MASK_000003FC, MASK_NOT_USED, 2, CALL_RI, R, 0, IUZ, 0, N, 0, asm_rv32_opcode_caddi4spn },
320 { MP_QSTR_c_and, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, asm_rv32_opcode_cand },
321 { MP_QSTR_c_andi, MASK_0000FF00, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, RC, 0, I, 0, N, 0, asm_rv32_opcode_candi },
322 { MP_QSTR_c_beqz, MASK_0000FF00, MASK_000001FE, MASK_NOT_USED, 2, CALL_RL, RC, 0, L, 0, N, 0, asm_rv32_opcode_cbeqz },
323 { MP_QSTR_c_bnez, MASK_0000FF00, MASK_000001FE, MASK_NOT_USED, 2, CALL_RL, RC, 0, L, 0, N, 0, asm_rv32_opcode_cbnez },
324 { MP_QSTR_c_ebreak, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, asm_rv32_opcode_cebreak },
325 { MP_QSTR_c_j, MASK_00000FFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_L, L, 0, N, 0, N, 0, asm_rv32_opcode_cj },
326 { MP_QSTR_c_jal, MASK_00000FFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_L, L, 0, N, 0, N, 0, asm_rv32_opcode_cjal },
327 { MP_QSTR_c_jalr, MASK_FFFFFFFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_R, R, 0, N, 0, N, 0, asm_rv32_opcode_cjalr },
328 { MP_QSTR_c_jr, MASK_FFFFFFFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_R, R, 0, N, 0, N, 0, asm_rv32_opcode_cjr },
329 { MP_QSTR_c_li, MASK_FFFFFFFE, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, asm_rv32_opcode_cli },
330 { MP_QSTR_c_lui, MASK_FFFFFFFA, MASK_0001F800, MASK_NOT_USED, 2, CALL_RI, R, 0, IUZ, 12, N, 0, asm_rv32_opcode_clui },
331 { MP_QSTR_c_lw, MASK_0000FF00, MASK_0000007C, MASK_0000FF00, 3, CALL_RIR, RC, 0, I, 0, RC, 0, asm_rv32_opcode_clw },
332 { MP_QSTR_c_lwsp, MASK_FFFFFFFE, MASK_000000FC, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, asm_rv32_opcode_clwsp },
333 { MP_QSTR_c_mv, MASK_FFFFFFFE, MASK_FFFFFFFE, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, asm_rv32_opcode_cmv },
334 { MP_QSTR_c_nop, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, asm_rv32_opcode_cnop },
335 { MP_QSTR_c_or, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, asm_rv32_opcode_cor },
336 { MP_QSTR_c_slli, MASK_FFFFFFFE, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, R, 0, IU, 0, N, 0, asm_rv32_opcode_cslli },
337 { MP_QSTR_c_srai, MASK_0000FF00, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, RC, 0, IU, 0, N, 0, asm_rv32_opcode_csrai },
338 { MP_QSTR_c_srli, MASK_0000FF00, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, RC, 0, IU, 0, N, 0, asm_rv32_opcode_csrli },
339 { MP_QSTR_c_sub, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, asm_rv32_opcode_csub },
340 { MP_QSTR_c_sw, MASK_0000FF00, MASK_0000007C, MASK_0000FF00, 3, CALL_RIR, RC, 0, I, 0, RC, 0, asm_rv32_opcode_csw },
341 { MP_QSTR_c_swsp, MASK_FFFFFFFF, MASK_000000FC, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, asm_rv32_opcode_cswsp },
342 { MP_QSTR_c_xor, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, asm_rv32_opcode_cxor },
343 { MP_QSTR_div, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_div },
344 { MP_QSTR_divu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_divu },
345 { MP_QSTR_ebreak, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, asm_rv32_opcode_ebreak },
346 { MP_QSTR_ecall, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, asm_rv32_opcode_ecall },
347 { MP_QSTR_jal, MASK_FFFFFFFF, MASK_001FFFFE, MASK_NOT_USED, 2, CALL_RL, R, 0, L, 0, N, 0, asm_rv32_opcode_jal },
348 { MP_QSTR_jalr, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_jalr },
349 { MP_QSTR_la, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RL, R, 0, L, 0, N, 0, opcode_la },
350 { MP_QSTR_lb, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lb },
351 { MP_QSTR_lbu, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lbu },
352 { MP_QSTR_lh, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lh },
353 { MP_QSTR_lhu, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lhu },
354 { MP_QSTR_li, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, opcode_li },
355 { MP_QSTR_lui, MASK_FFFFFFFF, MASK_FFFFF000, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 12, N, 0, asm_rv32_opcode_lui },
356 { MP_QSTR_lw, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lw },
357 { MP_QSTR_mv, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, asm_rv32_opcode_cmv },
358 { MP_QSTR_mul, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_mul },
359 { MP_QSTR_mulh, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_mulh },
360 { MP_QSTR_mulhsu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_mulhsu },
361 { MP_QSTR_mulhu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_mulhu },
362 { MP_QSTR_or_, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_or },
363 { MP_QSTR_ori, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_ori },
364 { MP_QSTR_rem, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_rem },
365 { MP_QSTR_remu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_remu },
366 { MP_QSTR_sb, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_sb },
367 { MP_QSTR_sh, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_sh },
368 { MP_QSTR_sll, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_sll },
369 { MP_QSTR_slli, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_slli },
370 { MP_QSTR_slt, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_slt },
371 { MP_QSTR_slti, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_slti },
372 { MP_QSTR_sltiu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_sltiu },
373 { MP_QSTR_sltu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_sltu },
374 { MP_QSTR_sra, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_sra },
375 { MP_QSTR_srai, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_srai },
376 { MP_QSTR_srl, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_srl },
377 { MP_QSTR_srli, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_srli },
378 { MP_QSTR_sub, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_sub },
379 { MP_QSTR_sw, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_sw },
380 { MP_QSTR_xor, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_xor },
381 { MP_QSTR_xori, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_xori },
Alessandro Gatti268acb72024-08-25 16:28:35 +0200382};
383
384#undef RC
385#undef IU
386#undef IZ
387#undef IUZ
388
389// These two checks assume the bitmasks are contiguous.
390
391static bool is_in_signed_mask(mp_uint_t mask, mp_uint_t value) {
392 mp_uint_t leading_zeroes = mp_clz(mask);
393 if (leading_zeroes == 0 || leading_zeroes > 32) {
394 return true;
395 }
396 mp_uint_t positive_mask = ~(mask & ~(1U << (31 - leading_zeroes)));
397 if ((value & positive_mask) == 0) {
398 return true;
399 }
400 mp_uint_t negative_mask = ~(mask >> 1);
401 mp_uint_t trailing_zeroes = mp_ctz(mask);
402 if (trailing_zeroes > 0) {
403 mp_uint_t trailing_mask = (1U << trailing_zeroes) - 1;
404 if ((value & trailing_mask) != 0) {
405 return false;
406 }
407 negative_mask &= ~trailing_mask;
408 }
409 return (value & negative_mask) == negative_mask;
410}
411
412static inline bool is_in_unsigned_mask(mp_uint_t mask, mp_uint_t value) {
413 return (value & ~mask) == 0;
414}
415
416static bool validate_integer(mp_uint_t value, mp_uint_t mask, mp_uint_t flags) {
417 if (flags & U) {
418 if (!is_in_unsigned_mask(mask, value)) {
419 return false;
420 }
421 } else {
422 if (!is_in_signed_mask(mask, value)) {
423 return false;
424 }
425 }
426
427 if ((flags & Z) && (value == 0)) {
428 return false;
429 }
430
431 return true;
432}
433
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100434#define ET_WRONG_ARGUMENT_KIND MP_ERROR_TEXT("opcode '%q' argument %d: expecting %q")
435#define ET_WRONG_ARGUMENTS_COUNT MP_ERROR_TEXT("opcode '%q': expecting %d arguments")
436#define ET_OUT_OF_RANGE MP_ERROR_TEXT("opcode '%q' argument %d: out of range")
437
Alessandro Gatti268acb72024-08-25 16:28:35 +0200438static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr,
439 const opcode_t *opcode, mp_parse_node_t node, mp_uint_t node_index) {
440 assert((node_index < 3) && "Invalid argument node number.");
441
442 uint32_t kind = 0;
443 uint32_t shift = 0;
444 uint32_t mask = 0;
445
446 switch (node_index) {
447 case 0:
448 kind = opcode->argument1_kind;
449 shift = opcode->argument1_shift;
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100450 mask = OPCODE_MASKS[opcode->argument1_mask];
Alessandro Gatti268acb72024-08-25 16:28:35 +0200451 break;
452
453 case 1:
454 kind = opcode->argument2_kind;
455 shift = opcode->argument2_shift;
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100456 mask = OPCODE_MASKS[opcode->argument2_mask];
Alessandro Gatti268acb72024-08-25 16:28:35 +0200457 break;
458
459 case 2:
460 kind = opcode->argument3_kind;
461 shift = opcode->argument3_shift;
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100462 mask = OPCODE_MASKS[opcode->argument3_mask];
Alessandro Gatti268acb72024-08-25 16:28:35 +0200463 break;
464
465 default:
466 break;
467 }
468
469 switch (kind & 0x03) {
470 case N:
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100471 assert(mask == OPCODE_MASKS[MASK_NOT_USED] && "Invalid mask index for missing operand.");
Alessandro Gatti268acb72024-08-25 16:28:35 +0200472 return true;
473
474 case R: {
475 mp_uint_t register_index;
476 if (!parse_register_node(node, &register_index, false)) {
477 emit_inline_rv32_error_exc(emit,
478 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100479 ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_register));
Alessandro Gatti268acb72024-08-25 16:28:35 +0200480 return false;
481 }
482
483 if ((mask & (1U << register_index)) == 0) {
484 emit_inline_rv32_error_exc(emit,
485 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100486 MP_ERROR_TEXT("opcode '%q' argument %d: unknown register"),
Alessandro Gatti268acb72024-08-25 16:28:35 +0200487 opcode_qstr, node_index + 1));
488 return false;
489 }
490
491 return true;
492 }
493 break;
494
495 case I: {
496 mp_obj_t object;
497 if (!mp_parse_node_get_int_maybe(node, &object)) {
498 emit_inline_rv32_error_exc(emit,
499 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100500 ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_integer));
Alessandro Gatti268acb72024-08-25 16:28:35 +0200501 return false;
502 }
503
504 mp_uint_t immediate = mp_obj_get_int_truncated(object) << shift;
505 if (kind & U) {
506 if (!is_in_unsigned_mask(mask, immediate)) {
507 goto out_of_range;
508 }
509 } else {
510 if (!is_in_signed_mask(mask, immediate)) {
511 goto out_of_range;
512 }
513 }
514
515 if ((kind & Z) && (immediate == 0)) {
516 goto zero_immediate;
517 }
518
519 return true;
520 }
521 break;
522
523 case L: {
524 if (!MP_PARSE_NODE_IS_ID(node)) {
525 emit_inline_rv32_error_exc(emit,
526 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100527 ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_label));
Alessandro Gatti268acb72024-08-25 16:28:35 +0200528 return false;
529 }
530
531 qstr qstring;
532 mp_uint_t label_index = lookup_label(emit, node, &qstring);
533 if (label_index >= emit->max_num_labels && emit->pass == MP_PASS_EMIT) {
534 emit_inline_rv32_error_exc(emit,
535 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100536 MP_ERROR_TEXT("opcode '%q' argument %d: undefined label '%q'"),
Alessandro Gatti268acb72024-08-25 16:28:35 +0200537 opcode_qstr, node_index + 1, qstring));
538 return false;
539 }
540
541 mp_uint_t displacement = (mp_uint_t)(label_code_offset(emit, label_index));
542 if (kind & U) {
543 if (!is_in_unsigned_mask(mask, displacement)) {
544 goto out_of_range;
545 }
546 } else {
547 if (!is_in_signed_mask(mask, displacement)) {
548 goto out_of_range;
549 }
550 }
551 return true;
552 }
553 break;
554
555 default:
556 assert(!"Unknown argument kind");
557 break;
558 }
559
560 return false;
561
562out_of_range:
563 emit_inline_rv32_error_exc(emit,
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100564 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode_qstr, node_index + 1));
Alessandro Gatti268acb72024-08-25 16:28:35 +0200565 return false;
566
567zero_immediate:
568 emit_inline_rv32_error_exc(emit,
569 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100570 MP_ERROR_TEXT("opcode '%q' argument %d: must not be zero"),
Alessandro Gatti268acb72024-08-25 16:28:35 +0200571 opcode_qstr, node_index + 1));
572 return false;
573}
574
575static bool parse_register_offset_node(emit_inline_asm_t *emit, qstr opcode_qstr, const opcode_t *opcode_data, mp_parse_node_t node, mp_uint_t node_index, mp_parse_node_t *register_node, mp_parse_node_t *offset_node, bool *negative) {
576 assert(register_node != NULL && "Register node pointer is NULL.");
577 assert(offset_node != NULL && "Offset node pointer is NULL.");
578 assert(negative != NULL && "Negative pointer is NULL.");
579
580 if (!MP_PARSE_NODE_IS_STRUCT_KIND(node, PN_atom_expr_normal) && !MP_PARSE_NODE_IS_STRUCT_KIND(node, PN_factor_2)) {
581 goto invalid_structure;
582 }
583 mp_parse_node_struct_t *node_struct = (mp_parse_node_struct_t *)node;
584 *negative = false;
585 if (MP_PARSE_NODE_IS_STRUCT_KIND(node, PN_factor_2)) {
586 if (MP_PARSE_NODE_IS_TOKEN_KIND(node_struct->nodes[0], MP_TOKEN_OP_MINUS)) {
587 *negative = true;
588 } else {
589 if (!MP_PARSE_NODE_IS_TOKEN_KIND(node_struct->nodes[0], MP_TOKEN_OP_PLUS)) {
590 goto invalid_structure;
591 }
592 }
593 if (!MP_PARSE_NODE_IS_STRUCT_KIND(node_struct->nodes[1], PN_atom_expr_normal)) {
594 goto invalid_structure;
595 }
596 node_struct = (mp_parse_node_struct_t *)node_struct->nodes[1];
597 }
598
599 if (*negative) {
600 // If the value is negative, RULE_atom_expr_normal's first token will be the
601 // offset stripped of its negative marker; range check will then fail if the
602 // default method is used, so a custom check is used instead.
603 mp_obj_t object;
604 if (!mp_parse_node_get_int_maybe(node_struct->nodes[0], &object)) {
605 emit_inline_rv32_error_exc(emit,
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100606 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_WRONG_ARGUMENT_KIND, opcode_qstr, 2, MP_QSTR_integer));
Alessandro Gatti268acb72024-08-25 16:28:35 +0200607 return false;
608 }
609 mp_uint_t value = mp_obj_get_int_truncated(object);
610 value = (~value + 1) & (mp_uint_t)-1;
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100611 if (!validate_integer(value << opcode_data->argument2_shift, OPCODE_MASKS[opcode_data->argument2_mask], opcode_data->argument2_kind)) {
Alessandro Gatti268acb72024-08-25 16:28:35 +0200612 emit_inline_rv32_error_exc(emit,
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100613 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode_qstr, 2));
Alessandro Gatti268acb72024-08-25 16:28:35 +0200614 return false;
615 }
616 } else {
617 if (!validate_argument(emit, opcode_qstr, opcode_data, node_struct->nodes[0], 1)) {
618 return false;
619 }
620 }
621
622 *offset_node = node_struct->nodes[0];
623 node_struct = (mp_parse_node_struct_t *)node_struct->nodes[1];
624 if (!validate_argument(emit, opcode_qstr, opcode_data, node_struct->nodes[0], 2)) {
625 return false;
626 }
627 *register_node = node_struct->nodes[0];
628 return true;
629
630invalid_structure:
631 emit_inline_rv32_error_exc(emit,
632 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100633 ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_offset));
Alessandro Gatti268acb72024-08-25 16:28:35 +0200634 return false;
635}
636
637static void handle_opcode(emit_inline_asm_t *emit, qstr opcode, const opcode_t *opcode_data, mp_parse_node_t *arguments) {
638 mp_uint_t rd = 0;
639 mp_uint_t rs1 = 0;
640 mp_uint_t rs2 = 0;
641
642 switch (opcode_data->calling_convention) {
643 case CALL_RRR: {
644 parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
645 parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C);
646 parse_register_node(arguments[2], &rs2, opcode_data->argument3_kind & C);
647 ((call_rrr_t)opcode_data->emitter)(&emit->as, rd, rs1, rs2);
648 break;
649 }
650
651 case CALL_RR: {
652 parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
653 parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C);
654 ((call_rr_t)opcode_data->emitter)(&emit->as, rd, rs1);
655 break;
656 }
657
658 case CALL_RRI: {
659 parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
660 parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C);
661 mp_obj_t object;
662 mp_parse_node_get_int_maybe(arguments[2], &object);
663 mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument3_shift;
664 ((call_rri_t)opcode_data->emitter)(&emit->as, rd, rs1, immediate);
665 break;
666 }
667
668 case CALL_RI: {
669 parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
670 mp_obj_t object;
671 mp_parse_node_get_int_maybe(arguments[1], &object);
672 mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument2_shift;
673 ((call_ri_t)opcode_data->emitter)(&emit->as, rd, immediate);
674 break;
675 }
676
677 case CALL_R: {
678 parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
679 ((call_r_t)opcode_data->emitter)(&emit->as, rd);
680 break;
681 }
682
683 case CALL_RRL: {
684 parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
685 parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C);
686 qstr qstring;
687 mp_uint_t label_index = lookup_label(emit, arguments[2], &qstring);
688 ptrdiff_t displacement = label_code_offset(emit, label_index);
689 ((call_rri_t)opcode_data->emitter)(&emit->as, rd, rs1, displacement);
690 break;
691 }
692
693 case CALL_RL: {
694 parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
695 qstr qstring;
696 mp_uint_t label_index = lookup_label(emit, arguments[1], &qstring);
697 ptrdiff_t displacement = label_code_offset(emit, label_index);
698 ((call_ri_t)opcode_data->emitter)(&emit->as, rd, displacement);
699 break;
700 }
701
702 case CALL_L: {
703 qstr qstring;
704 mp_uint_t label_index = lookup_label(emit, arguments[0], &qstring);
705 ptrdiff_t displacement = label_code_offset(emit, label_index);
706 ((call_i_t)opcode_data->emitter)(&emit->as, displacement);
707 break;
708 }
709
710 case CALL_N:
711 ((call_n_t)opcode_data->emitter)(&emit->as);
712 break;
713
714 case CALL_I: {
715 mp_obj_t object;
716 mp_parse_node_get_int_maybe(arguments[0], &object);
717 mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument1_shift;
718 ((call_i_t)opcode_data->emitter)(&emit->as, immediate);
719 break;
720 }
721
722 case CALL_RII: {
723 parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
724 mp_obj_t object;
725 mp_parse_node_get_int_maybe(arguments[1], &object);
726 mp_uint_t immediate1 = mp_obj_get_int_truncated(object) << opcode_data->argument2_shift;
727 mp_parse_node_get_int_maybe(arguments[2], &object);
728 mp_uint_t immediate2 = mp_obj_get_int_truncated(object) << opcode_data->argument3_shift;
729 ((call_rii_t)opcode_data->emitter)(&emit->as, rd, immediate1, immediate2);
730 break;
731 }
732
733 case CALL_RIR:
734 assert(!"Should not get here.");
735 break;
736
737 default:
738 assert(!"Unhandled call convention.");
739 break;
740 }
741}
742
743static bool handle_load_store_opcode_with_offset(emit_inline_asm_t *emit, qstr opcode, const opcode_t *opcode_data, mp_parse_node_t *argument_nodes) {
744 mp_parse_node_t nodes[3] = {0};
745 if (!validate_argument(emit, opcode, opcode_data, argument_nodes[0], 0)) {
746 return false;
747 }
748 nodes[0] = argument_nodes[0];
749 bool negative = false;
750 if (!parse_register_offset_node(emit, opcode, opcode_data, argument_nodes[1], 1, &nodes[1], &nodes[2], &negative)) {
751 return false;
752 }
753
Alessandro Gattidc2c33b2025-01-04 12:51:18 +0100754 mp_uint_t rd = 0;
755 mp_uint_t rs1 = 0;
756 if (!parse_register_node(nodes[0], &rd, opcode_data->argument1_kind & C)) {
757 return false;
758 }
Alessandro Gatti268acb72024-08-25 16:28:35 +0200759 if (!parse_register_node(nodes[1], &rs1, opcode_data->argument3_kind & C)) {
760 return false;
761 }
762
763 mp_obj_t object;
764 mp_parse_node_get_int_maybe(nodes[2], &object);
765 mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument2_shift;
766 if (negative) {
767 immediate = (~immediate + 1) & (mp_uint_t)-1;
768 }
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100769 if (!is_in_signed_mask(OPCODE_MASKS[opcode_data->argument2_mask], immediate)) {
Alessandro Gatti268acb72024-08-25 16:28:35 +0200770 emit_inline_rv32_error_exc(emit,
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100771 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode, 2));
Alessandro Gatti268acb72024-08-25 16:28:35 +0200772 return false;
773 }
774
775 ((call_rri_t)opcode_data->emitter)(&emit->as, rd, rs1, immediate);
776 return true;
777}
778
779static void emit_inline_rv32_opcode(emit_inline_asm_t *emit, qstr opcode, mp_uint_t arguments_count, mp_parse_node_t *argument_nodes) {
780 const opcode_t *opcode_data = NULL;
781 for (mp_uint_t index = 0; index < MP_ARRAY_SIZE(OPCODES); index++) {
782 if (OPCODES[index].qstring == opcode) {
783 opcode_data = &OPCODES[index];
784 break;
785 }
786 }
787
788 if (!opcode_data) {
789 emit_inline_rv32_error_exc(emit,
790 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100791 MP_ERROR_TEXT("unknown RV32 instruction '%q'"), opcode));
Alessandro Gatti268acb72024-08-25 16:28:35 +0200792 return;
793 }
794
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100795 assert((opcode_data->argument1_mask < MP_ARRAY_SIZE(OPCODE_MASKS)) && "Argument #1 opcode mask index out of bounds.");
796 assert((opcode_data->argument2_mask < MP_ARRAY_SIZE(OPCODE_MASKS)) && "Argument #2 opcode mask index out of bounds.");
797 assert((opcode_data->argument3_mask < MP_ARRAY_SIZE(OPCODE_MASKS)) && "Argument #3 opcode mask index out of bounds.");
798 assert((opcode_data->calling_convention < CALL_COUNT) && "Calling convention index out of bounds.");
Alessandro Gatti268acb72024-08-25 16:28:35 +0200799 if (opcode_data->calling_convention != CALL_RIR) {
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100800 if (opcode_data->arguments_count != arguments_count) {
Alessandro Gatti268acb72024-08-25 16:28:35 +0200801 emit_inline_rv32_error_exc(emit,
802 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100803 ET_WRONG_ARGUMENTS_COUNT, opcode, opcode_data->arguments_count));
Alessandro Gatti268acb72024-08-25 16:28:35 +0200804 return;
805 }
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100806 if (opcode_data->arguments_count >= 1 && !validate_argument(emit, opcode, opcode_data, argument_nodes[0], 0)) {
Alessandro Gatti268acb72024-08-25 16:28:35 +0200807 return;
808 }
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100809 if (opcode_data->arguments_count >= 2 && !validate_argument(emit, opcode, opcode_data, argument_nodes[1], 1)) {
Alessandro Gatti268acb72024-08-25 16:28:35 +0200810 return;
811 }
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100812 if (opcode_data->arguments_count >= 3 && !validate_argument(emit, opcode, opcode_data, argument_nodes[2], 2)) {
Alessandro Gatti268acb72024-08-25 16:28:35 +0200813 return;
814 }
815 handle_opcode(emit, opcode, opcode_data, argument_nodes);
816 return;
817 }
818
Alessandro Gatti268acb72024-08-25 16:28:35 +0200819 assert((opcode_data->argument2_kind & U) == 0 && "Offset must not be unsigned.");
820 assert((opcode_data->argument2_kind & Z) == 0 && "Offset can be zero.");
821
822 if (arguments_count != 2) {
823 emit_inline_rv32_error_exc(emit,
Alessandro Gatti8633abc2025-01-04 12:54:44 +0100824 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_WRONG_ARGUMENTS_COUNT, opcode, 2));
Alessandro Gatti268acb72024-08-25 16:28:35 +0200825 return;
826 }
827
828 handle_load_store_opcode_with_offset(emit, opcode, opcode_data, argument_nodes);
829}
830
831#undef N
832#undef R
833#undef I
834#undef L
835#undef C
836#undef U
837
838const emit_inline_asm_method_table_t emit_inline_rv32_method_table = {
839 #if MICROPY_DYNAMIC_COMPILER
840 emit_inline_rv32_new,
841 emit_inline_rv32_free,
842 #endif
843
844 emit_inline_rv32_start_pass,
845 emit_inline_rv32_end_pass,
846 emit_inline_rv32_count_params,
847 emit_inline_rv32_label,
848 emit_inline_rv32_opcode,
849};
850
851#endif // MICROPY_EMIT_INLINE_RV32