Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the MicroPython project, http://micropython.org/ |
| 3 | * |
| 4 | * The MIT License (MIT) |
| 5 | * |
| 6 | * Copyright (c) 2013-2016 Damien P. George |
| 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 <stdint.h> |
| 28 | #include <stdio.h> |
| 29 | #include <string.h> |
| 30 | #include <stdarg.h> |
| 31 | #include <assert.h> |
| 32 | |
| 33 | #include "py/emit.h" |
| 34 | #include "py/asmxtensa.h" |
| 35 | |
| 36 | #if MICROPY_EMIT_INLINE_XTENSA |
| 37 | |
| 38 | struct _emit_inline_asm_t { |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 39 | asm_xtensa_t as; |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 40 | uint16_t pass; |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 41 | mp_obj_t *error_slot; |
| 42 | mp_uint_t max_num_labels; |
| 43 | qstr *label_lookup; |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 44 | }; |
| 45 | |
Angus Gratton | decf8e6 | 2024-02-27 15:32:29 +1100 | [diff] [blame] | 46 | static void emit_inline_xtensa_error_msg(emit_inline_asm_t *emit, mp_rom_error_text_t msg) { |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 47 | *emit->error_slot = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg); |
| 48 | } |
| 49 | |
Angus Gratton | decf8e6 | 2024-02-27 15:32:29 +1100 | [diff] [blame] | 50 | static void emit_inline_xtensa_error_exc(emit_inline_asm_t *emit, mp_obj_t exc) { |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 51 | *emit->error_slot = exc; |
| 52 | } |
| 53 | |
| 54 | emit_inline_asm_t *emit_inline_xtensa_new(mp_uint_t max_num_labels) { |
| 55 | emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t); |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 56 | memset(&emit->as, 0, sizeof(emit->as)); |
| 57 | mp_asm_base_init(&emit->as.base, max_num_labels); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 58 | emit->max_num_labels = max_num_labels; |
| 59 | emit->label_lookup = m_new(qstr, max_num_labels); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 60 | return emit; |
| 61 | } |
| 62 | |
| 63 | void emit_inline_xtensa_free(emit_inline_asm_t *emit) { |
| 64 | m_del(qstr, emit->label_lookup, emit->max_num_labels); |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 65 | mp_asm_base_deinit(&emit->as.base, false); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 66 | m_del_obj(emit_inline_asm_t, emit); |
| 67 | } |
| 68 | |
Angus Gratton | decf8e6 | 2024-02-27 15:32:29 +1100 | [diff] [blame] | 69 | static void emit_inline_xtensa_start_pass(emit_inline_asm_t *emit, pass_kind_t pass, mp_obj_t *error_slot) { |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 70 | emit->pass = pass; |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 71 | emit->error_slot = error_slot; |
| 72 | if (emit->pass == MP_PASS_CODE_SIZE) { |
| 73 | memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr)); |
| 74 | } |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 75 | mp_asm_base_start_pass(&emit->as.base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE); |
| 76 | asm_xtensa_entry(&emit->as, 0); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 77 | } |
| 78 | |
Angus Gratton | decf8e6 | 2024-02-27 15:32:29 +1100 | [diff] [blame] | 79 | static void emit_inline_xtensa_end_pass(emit_inline_asm_t *emit, mp_uint_t type_sig) { |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 80 | asm_xtensa_exit(&emit->as); |
| 81 | asm_xtensa_end_pass(&emit->as); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 82 | } |
| 83 | |
Angus Gratton | decf8e6 | 2024-02-27 15:32:29 +1100 | [diff] [blame] | 84 | static mp_uint_t emit_inline_xtensa_count_params(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params) { |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 85 | if (n_params > 4) { |
Jim Mussared | def76fe | 2020-03-02 22:35:22 +1100 | [diff] [blame] | 86 | emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT("can only have up to 4 parameters to Xtensa assembly")); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 87 | return 0; |
| 88 | } |
| 89 | for (mp_uint_t i = 0; i < n_params; i++) { |
| 90 | if (!MP_PARSE_NODE_IS_ID(pn_params[i])) { |
Jim Mussared | def76fe | 2020-03-02 22:35:22 +1100 | [diff] [blame] | 91 | emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT("parameters must be registers in sequence a2 to a5")); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 92 | return 0; |
| 93 | } |
| 94 | const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i])); |
Emil Renner Berthing | fdd6fa3 | 2020-10-03 10:51:59 +0200 | [diff] [blame] | 95 | if (!(strlen(p) == 2 && p[0] == 'a' && (mp_uint_t)p[1] == '2' + i)) { |
Jim Mussared | def76fe | 2020-03-02 22:35:22 +1100 | [diff] [blame] | 96 | emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT("parameters must be registers in sequence a2 to a5")); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 97 | return 0; |
| 98 | } |
| 99 | } |
| 100 | return n_params; |
| 101 | } |
| 102 | |
Angus Gratton | decf8e6 | 2024-02-27 15:32:29 +1100 | [diff] [blame] | 103 | static bool emit_inline_xtensa_label(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id) { |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 104 | assert(label_num < emit->max_num_labels); |
| 105 | if (emit->pass == MP_PASS_CODE_SIZE) { |
| 106 | // check for duplicate label on first pass |
| 107 | for (uint i = 0; i < emit->max_num_labels; i++) { |
| 108 | if (emit->label_lookup[i] == label_id) { |
| 109 | return false; |
| 110 | } |
| 111 | } |
| 112 | } |
| 113 | emit->label_lookup[label_num] = label_id; |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 114 | mp_asm_base_label_assign(&emit->as.base, label_num); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 115 | return true; |
| 116 | } |
| 117 | |
Damien George | 69661f3 | 2020-02-27 15:36:53 +1100 | [diff] [blame] | 118 | typedef struct _reg_name_t { byte reg; |
| 119 | byte name[3]; |
| 120 | } reg_name_t; |
Angus Gratton | decf8e6 | 2024-02-27 15:32:29 +1100 | [diff] [blame] | 121 | static const reg_name_t reg_name_table[] = { |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 122 | {0, "a0\0"}, |
| 123 | {1, "a1\0"}, |
| 124 | {2, "a2\0"}, |
| 125 | {3, "a3\0"}, |
| 126 | {4, "a4\0"}, |
| 127 | {5, "a5\0"}, |
| 128 | {6, "a6\0"}, |
| 129 | {7, "a7\0"}, |
| 130 | {8, "a8\0"}, |
| 131 | {9, "a9\0"}, |
| 132 | {10, "a10"}, |
| 133 | {11, "a11"}, |
| 134 | {12, "a12"}, |
| 135 | {13, "a13"}, |
| 136 | {14, "a14"}, |
| 137 | {15, "a15"}, |
| 138 | }; |
| 139 | |
| 140 | // return empty string in case of error, so we can attempt to parse the string |
| 141 | // without a special check if it was in fact a string |
Angus Gratton | decf8e6 | 2024-02-27 15:32:29 +1100 | [diff] [blame] | 142 | static const char *get_arg_str(mp_parse_node_t pn) { |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 143 | if (MP_PARSE_NODE_IS_ID(pn)) { |
| 144 | qstr qst = MP_PARSE_NODE_LEAF_ARG(pn); |
| 145 | return qstr_str(qst); |
| 146 | } else { |
| 147 | return ""; |
| 148 | } |
| 149 | } |
| 150 | |
Angus Gratton | decf8e6 | 2024-02-27 15:32:29 +1100 | [diff] [blame] | 151 | static mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 152 | const char *reg_str = get_arg_str(pn); |
| 153 | for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) { |
| 154 | const reg_name_t *r = ®_name_table[i]; |
| 155 | if (reg_str[0] == r->name[0] |
| 156 | && reg_str[1] == r->name[1] |
| 157 | && reg_str[2] == r->name[2] |
| 158 | && (reg_str[2] == '\0' || reg_str[3] == '\0')) { |
| 159 | return r->reg; |
| 160 | } |
| 161 | } |
| 162 | emit_inline_xtensa_error_exc(emit, |
| 163 | mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, |
Jim Mussared | def76fe | 2020-03-02 22:35:22 +1100 | [diff] [blame] | 164 | MP_ERROR_TEXT("'%s' expects a register"), op)); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 165 | return 0; |
| 166 | } |
| 167 | |
Angus Gratton | decf8e6 | 2024-02-27 15:32:29 +1100 | [diff] [blame] | 168 | static uint32_t get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, int min, int max) { |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 169 | mp_obj_t o; |
| 170 | if (!mp_parse_node_get_int_maybe(pn, &o)) { |
Jim Mussared | def76fe | 2020-03-02 22:35:22 +1100 | [diff] [blame] | 171 | emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("'%s' expects an integer"), op)); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 172 | return 0; |
| 173 | } |
| 174 | uint32_t i = mp_obj_get_int_truncated(o); |
| 175 | if (min != max && ((int)i < min || (int)i > max)) { |
Jim Mussared | def76fe | 2020-03-02 22:35:22 +1100 | [diff] [blame] | 176 | emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("'%s' integer %d isn't within range %d..%d"), op, i, min, max)); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 177 | return 0; |
| 178 | } |
| 179 | return i; |
| 180 | } |
| 181 | |
Angus Gratton | decf8e6 | 2024-02-27 15:32:29 +1100 | [diff] [blame] | 182 | static int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 183 | if (!MP_PARSE_NODE_IS_ID(pn)) { |
Jim Mussared | def76fe | 2020-03-02 22:35:22 +1100 | [diff] [blame] | 184 | emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("'%s' expects a label"), op)); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 185 | return 0; |
| 186 | } |
| 187 | qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn); |
| 188 | for (uint i = 0; i < emit->max_num_labels; i++) { |
| 189 | if (emit->label_lookup[i] == label_qstr) { |
| 190 | return i; |
| 191 | } |
| 192 | } |
| 193 | // only need to have the labels on the last pass |
| 194 | if (emit->pass == MP_PASS_EMIT) { |
Jim Mussared | def76fe | 2020-03-02 22:35:22 +1100 | [diff] [blame] | 195 | emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("label '%q' not defined"), label_qstr)); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 196 | } |
| 197 | return 0; |
| 198 | } |
| 199 | |
| 200 | #define RRR (0) |
| 201 | #define RRI8 (1) |
| 202 | #define RRI8_B (2) |
| 203 | |
| 204 | typedef struct _opcode_table_3arg_t { |
| 205 | uint16_t name; // actually a qstr, which should fit in 16 bits |
| 206 | uint8_t type; |
| 207 | uint8_t a0 : 4; |
| 208 | uint8_t a1 : 4; |
| 209 | } opcode_table_3arg_t; |
| 210 | |
Angus Gratton | decf8e6 | 2024-02-27 15:32:29 +1100 | [diff] [blame] | 211 | static const opcode_table_3arg_t opcode_table_3arg[] = { |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 212 | // arithmetic opcodes: reg, reg, reg |
| 213 | {MP_QSTR_and_, RRR, 0, 1}, |
| 214 | {MP_QSTR_or_, RRR, 0, 2}, |
| 215 | {MP_QSTR_xor, RRR, 0, 3}, |
| 216 | {MP_QSTR_add, RRR, 0, 8}, |
| 217 | {MP_QSTR_sub, RRR, 0, 12}, |
| 218 | {MP_QSTR_mull, RRR, 2, 8}, |
| 219 | |
| 220 | // load/store/addi opcodes: reg, reg, imm |
| 221 | // upper nibble of type encodes the range of the immediate arg |
| 222 | {MP_QSTR_l8ui, RRI8 | 0x10, 2, 0}, |
| 223 | {MP_QSTR_l16ui, RRI8 | 0x30, 2, 1}, |
| 224 | {MP_QSTR_l32i, RRI8 | 0x50, 2, 2}, |
| 225 | {MP_QSTR_s8i, RRI8 | 0x10, 2, 4}, |
| 226 | {MP_QSTR_s16i, RRI8 | 0x30, 2, 5}, |
| 227 | {MP_QSTR_s32i, RRI8 | 0x50, 2, 6}, |
| 228 | {MP_QSTR_l16si, RRI8 | 0x30, 2, 9}, |
| 229 | {MP_QSTR_addi, RRI8 | 0x00, 2, 12}, |
| 230 | |
| 231 | // branch opcodes: reg, reg, label |
| 232 | {MP_QSTR_ball, RRI8_B, ASM_XTENSA_CC_ALL, 0}, |
| 233 | {MP_QSTR_bany, RRI8_B, ASM_XTENSA_CC_ANY, 0}, |
| 234 | {MP_QSTR_bbc, RRI8_B, ASM_XTENSA_CC_BC, 0}, |
| 235 | {MP_QSTR_bbs, RRI8_B, ASM_XTENSA_CC_BS, 0}, |
| 236 | {MP_QSTR_beq, RRI8_B, ASM_XTENSA_CC_EQ, 0}, |
| 237 | {MP_QSTR_bge, RRI8_B, ASM_XTENSA_CC_GE, 0}, |
| 238 | {MP_QSTR_bgeu, RRI8_B, ASM_XTENSA_CC_GEU, 0}, |
| 239 | {MP_QSTR_blt, RRI8_B, ASM_XTENSA_CC_LT, 0}, |
| 240 | {MP_QSTR_bnall, RRI8_B, ASM_XTENSA_CC_NALL, 0}, |
| 241 | {MP_QSTR_bne, RRI8_B, ASM_XTENSA_CC_NE, 0}, |
| 242 | {MP_QSTR_bnone, RRI8_B, ASM_XTENSA_CC_NONE, 0}, |
| 243 | }; |
| 244 | |
Angus Gratton | decf8e6 | 2024-02-27 15:32:29 +1100 | [diff] [blame] | 245 | static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args) { |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 246 | size_t op_len; |
Damien George | 69661f3 | 2020-02-27 15:36:53 +1100 | [diff] [blame] | 247 | const char *op_str = (const char *)qstr_data(op, &op_len); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 248 | |
| 249 | if (n_args == 0) { |
| 250 | if (op == MP_QSTR_ret_n) { |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 251 | asm_xtensa_op_ret_n(&emit->as); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 252 | } else { |
| 253 | goto unknown_op; |
| 254 | } |
| 255 | |
| 256 | } else if (n_args == 1) { |
| 257 | if (op == MP_QSTR_callx0) { |
| 258 | uint r0 = get_arg_reg(emit, op_str, pn_args[0]); |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 259 | asm_xtensa_op_callx0(&emit->as, r0); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 260 | } else if (op == MP_QSTR_j) { |
| 261 | int label = get_arg_label(emit, op_str, pn_args[0]); |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 262 | asm_xtensa_j_label(&emit->as, label); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 263 | } else if (op == MP_QSTR_jx) { |
| 264 | uint r0 = get_arg_reg(emit, op_str, pn_args[0]); |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 265 | asm_xtensa_op_jx(&emit->as, r0); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 266 | } else { |
| 267 | goto unknown_op; |
| 268 | } |
| 269 | |
| 270 | } else if (n_args == 2) { |
| 271 | uint r0 = get_arg_reg(emit, op_str, pn_args[0]); |
| 272 | if (op == MP_QSTR_beqz) { |
| 273 | int label = get_arg_label(emit, op_str, pn_args[1]); |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 274 | asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_EQ, r0, label); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 275 | } else if (op == MP_QSTR_bnez) { |
| 276 | int label = get_arg_label(emit, op_str, pn_args[1]); |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 277 | asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_NE, r0, label); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 278 | } else if (op == MP_QSTR_mov || op == MP_QSTR_mov_n) { |
| 279 | // we emit mov.n for both "mov" and "mov_n" opcodes |
| 280 | uint r1 = get_arg_reg(emit, op_str, pn_args[1]); |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 281 | asm_xtensa_op_mov_n(&emit->as, r0, r1); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 282 | } else if (op == MP_QSTR_movi) { |
| 283 | // for convenience we emit l32r if the integer doesn't fit in movi |
| 284 | uint32_t imm = get_arg_i(emit, op_str, pn_args[1], 0, 0); |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 285 | asm_xtensa_mov_reg_i32(&emit->as, r0, imm); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 286 | } else { |
| 287 | goto unknown_op; |
| 288 | } |
| 289 | |
| 290 | } else if (n_args == 3) { |
| 291 | // search table for 3 arg instructions |
| 292 | for (uint i = 0; i < MP_ARRAY_SIZE(opcode_table_3arg); i++) { |
| 293 | const opcode_table_3arg_t *o = &opcode_table_3arg[i]; |
| 294 | if (op == o->name) { |
| 295 | uint r0 = get_arg_reg(emit, op_str, pn_args[0]); |
| 296 | uint r1 = get_arg_reg(emit, op_str, pn_args[1]); |
| 297 | if (o->type == RRR) { |
| 298 | uint r2 = get_arg_reg(emit, op_str, pn_args[2]); |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 299 | asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, o->a0, o->a1, r0, r1, r2)); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 300 | } else if (o->type == RRI8_B) { |
| 301 | int label = get_arg_label(emit, op_str, pn_args[2]); |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 302 | asm_xtensa_bcc_reg_reg_label(&emit->as, o->a0, r0, r1, label); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 303 | } else { |
| 304 | int shift, min, max; |
| 305 | if ((o->type & 0xf0) == 0) { |
| 306 | shift = 0; |
| 307 | min = -128; |
| 308 | max = 127; |
| 309 | } else { |
| 310 | shift = (o->type & 0xf0) >> 5; |
| 311 | min = 0; |
| 312 | max = 0xff << shift; |
| 313 | } |
| 314 | uint32_t imm = get_arg_i(emit, op_str, pn_args[2], min, max); |
Damien George | a7fd786 | 2016-12-09 20:35:21 +1100 | [diff] [blame] | 315 | asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRI8(o->a0, o->a1, r1, r0, (imm >> shift) & 0xff)); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 316 | } |
| 317 | return; |
| 318 | } |
| 319 | } |
| 320 | goto unknown_op; |
| 321 | |
| 322 | } else { |
| 323 | goto unknown_op; |
| 324 | } |
| 325 | |
| 326 | return; |
| 327 | |
| 328 | unknown_op: |
Jim Mussared | def76fe | 2020-03-02 22:35:22 +1100 | [diff] [blame] | 329 | emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("unsupported Xtensa instruction '%s' with %d arguments"), op_str, n_args)); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 330 | return; |
| 331 | |
| 332 | /* |
| 333 | branch_not_in_range: |
Jim Mussared | def76fe | 2020-03-02 22:35:22 +1100 | [diff] [blame] | 334 | emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT("branch not in range")); |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 335 | return; |
| 336 | */ |
| 337 | } |
| 338 | |
| 339 | const emit_inline_asm_method_table_t emit_inline_xtensa_method_table = { |
Damien George | 55fcb83 | 2019-03-09 12:32:09 +1100 | [diff] [blame] | 340 | #if MICROPY_DYNAMIC_COMPILER |
| 341 | emit_inline_xtensa_new, |
| 342 | emit_inline_xtensa_free, |
| 343 | #endif |
| 344 | |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 345 | emit_inline_xtensa_start_pass, |
| 346 | emit_inline_xtensa_end_pass, |
| 347 | emit_inline_xtensa_count_params, |
| 348 | emit_inline_xtensa_label, |
Damien George | f76b1bf | 2016-12-09 17:03:33 +1100 | [diff] [blame] | 349 | emit_inline_xtensa_op, |
| 350 | }; |
| 351 | |
| 352 | #endif // MICROPY_EMIT_INLINE_XTENSA |