blob: d83aa8b5940ebde4828a64710452bf9504f3a69f [file] [log] [blame]
Damien826005c2013-10-05 23:17:28 +01001#include <stdint.h>
2#include <stdio.h>
3#include <string.h>
Damien Georgea26dc502014-04-12 17:54:52 +01004#include <stdarg.h>
Damien826005c2013-10-05 23:17:28 +01005#include <assert.h>
6
7#include "misc.h"
Damiend99b0522013-12-21 18:17:45 +00008#include "mpconfig.h"
Damien George55baff42014-01-21 21:40:13 +00009#include "qstr.h"
Damien826005c2013-10-05 23:17:28 +010010#include "lexer.h"
Damien826005c2013-10-05 23:17:28 +010011#include "parse.h"
Damien Georgedf8127a2014-04-13 11:04:33 +010012#include "obj.h"
13#include "emitglue.h"
Damien826005c2013-10-05 23:17:28 +010014#include "scope.h"
Damiend99b0522013-12-21 18:17:45 +000015#include "runtime0.h"
Damien826005c2013-10-05 23:17:28 +010016#include "emit.h"
17#include "asmthumb.h"
18
Damien3ef4abb2013-10-12 16:53:13 +010019#if MICROPY_EMIT_INLINE_THUMB
Damien826005c2013-10-05 23:17:28 +010020
Damien George87210872014-04-13 00:30:32 +010021typedef enum {
22 PN_none = 0,
23#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
24#include "grammar.h"
25#undef DEF_RULE
26 PN_maximum_number_of,
27} pn_kind_t;
28
Damien826005c2013-10-05 23:17:28 +010029struct _emit_inline_asm_t {
Damien Georgea26dc502014-04-12 17:54:52 +010030 uint16_t pass;
31 uint16_t success;
Damien826005c2013-10-05 23:17:28 +010032 scope_t *scope;
Damien George41d02b62014-01-24 22:42:28 +000033 uint max_num_labels;
Damien826005c2013-10-05 23:17:28 +010034 qstr *label_lookup;
35 asm_thumb_t *as;
36};
37
Damien Georgea26dc502014-04-12 17:54:52 +010038void emit_inline_thumb_error(emit_inline_asm_t *emit, const char *fmt, ...) {
39 printf("SyntaxError: ");
40 emit->success = false;
41 va_list ap;
42 va_start(ap, fmt);
43 vprintf(fmt, ap);
44 va_end(ap);
45}
46
Damien826005c2013-10-05 23:17:28 +010047emit_inline_asm_t *emit_inline_thumb_new(uint max_num_labels) {
Damien George41d02b62014-01-24 22:42:28 +000048 emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t);
Damien826005c2013-10-05 23:17:28 +010049 emit->max_num_labels = max_num_labels;
50 emit->label_lookup = m_new(qstr, max_num_labels);
51 memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr));
52 emit->as = asm_thumb_new(max_num_labels);
53 return emit;
54}
55
Damien George41d02b62014-01-24 22:42:28 +000056void emit_inline_thumb_free(emit_inline_asm_t *emit) {
57 m_del(qstr, emit->label_lookup, emit->max_num_labels);
58 asm_thumb_free(emit->as, false);
59 m_del_obj(emit_inline_asm_t, emit);
60}
61
Paul Sokolovsky520e2f52014-02-12 18:31:30 +020062STATIC void emit_inline_thumb_start_pass(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope) {
Damien826005c2013-10-05 23:17:28 +010063 emit->pass = pass;
Damien Georgea26dc502014-04-12 17:54:52 +010064 emit->success = true;
Damien826005c2013-10-05 23:17:28 +010065 emit->scope = scope;
66 asm_thumb_start_pass(emit->as, pass);
67 asm_thumb_entry(emit->as, 0);
68}
69
Damien Georgea26dc502014-04-12 17:54:52 +010070STATIC bool emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
Damien826005c2013-10-05 23:17:28 +010071 asm_thumb_exit(emit->as);
72 asm_thumb_end_pass(emit->as);
73
74 if (emit->pass == PASS_3) {
Damiend99b0522013-12-21 18:17:45 +000075 void *f = asm_thumb_get_code(emit->as);
Damien George2827d622014-04-27 15:50:52 +010076 mp_emit_glue_assign_inline_asm_code(emit->scope->raw_code, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args);
Damien826005c2013-10-05 23:17:28 +010077 }
Damien Georgea26dc502014-04-12 17:54:52 +010078
79 return emit->success;
Damien826005c2013-10-05 23:17:28 +010080}
81
Paul Sokolovsky520e2f52014-02-12 18:31:30 +020082STATIC int emit_inline_thumb_count_params(emit_inline_asm_t *emit, int n_params, mp_parse_node_t *pn_params) {
Damiena2f2f7d2013-10-06 00:14:13 +010083 if (n_params > 4) {
Damien Georgea26dc502014-04-12 17:54:52 +010084 emit_inline_thumb_error(emit, "can only have up to 4 parameters to inline thumb assembly\n");
Damiena2f2f7d2013-10-06 00:14:13 +010085 return 0;
86 }
87 for (int i = 0; i < n_params; i++) {
Damiend99b0522013-12-21 18:17:45 +000088 if (!MP_PARSE_NODE_IS_ID(pn_params[i])) {
Damien Georgea26dc502014-04-12 17:54:52 +010089 emit_inline_thumb_error(emit, "parameter to inline assembler must be an identifier\n");
Damiena2f2f7d2013-10-06 00:14:13 +010090 return 0;
91 }
Damiend99b0522013-12-21 18:17:45 +000092 const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i]));
Damiena2f2f7d2013-10-06 00:14:13 +010093 if (!(strlen(p) == 2 && p[0] == 'r' && p[1] == '0' + i)) {
Damien Georgea26dc502014-04-12 17:54:52 +010094 emit_inline_thumb_error(emit, "parameter %d to inline assembler must be r%d\n", i + 1, i);
Damiena2f2f7d2013-10-06 00:14:13 +010095 return 0;
96 }
97 }
98 return n_params;
99}
100
Damien George6f355fd2014-04-10 14:11:31 +0100101STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, uint label_num, qstr label_id) {
Damien826005c2013-10-05 23:17:28 +0100102 assert(label_num < emit->max_num_labels);
103 emit->label_lookup[label_num] = label_id;
104 asm_thumb_label_assign(emit->as, label_num);
105}
106
Damien Georgee5f8a772014-04-21 13:33:15 +0100107STATIC void emit_inline_thumb_align(emit_inline_asm_t *emit, uint align) {
108 asm_thumb_align(emit->as, align);
109}
110
111STATIC void emit_inline_thumb_data(emit_inline_asm_t *emit, uint bytesize, uint val) {
112 asm_thumb_data(emit->as, bytesize, val);
113}
114
Damien Georgea26dc502014-04-12 17:54:52 +0100115typedef struct _reg_name_t { byte reg; byte name[3]; } reg_name_t;
116STATIC const reg_name_t reg_name_table[] = {
117 {0, "r0\0"},
118 {1, "r1\0"},
119 {2, "r2\0"},
120 {3, "r3\0"},
121 {4, "r4\0"},
122 {5, "r5\0"},
123 {6, "r6\0"},
124 {7, "r7\0"},
125 {8, "r8\0"},
126 {9, "r9\0"},
127 {10, "r10"},
128 {11, "r11"},
129 {12, "r12"},
130 {13, "r13"},
131 {14, "r14"},
132 {15, "r15"},
133 {10, "sl\0"},
134 {11, "fp\0"},
135 {13, "sp\0"},
136 {14, "lr\0"},
137 {15, "pc\0"},
138};
139
Damien George87210872014-04-13 00:30:32 +0100140STATIC uint get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, uint max_reg) {
141 if (MP_PARSE_NODE_IS_ID(pn)) {
142 qstr reg_qstr = MP_PARSE_NODE_LEAF_ARG(pn);
Damien Georgea26dc502014-04-12 17:54:52 +0100143 const char *reg_str = qstr_str(reg_qstr);
Damien George6d3c5e42014-04-26 10:47:29 +0100144 for (uint i = 0; i < ARRAY_SIZE(reg_name_table); i++) {
Damien Georgea26dc502014-04-12 17:54:52 +0100145 const reg_name_t *r = &reg_name_table[i];
146 if (reg_str[0] == r->name[0] && reg_str[1] == r->name[1] && reg_str[2] == r->name[2] && (reg_str[2] == '\0' || reg_str[3] == '\0')) {
147 if (r->reg > max_reg) {
Damien George87210872014-04-13 00:30:32 +0100148 emit_inline_thumb_error(emit, "'%s' expects at most r%d\n", op, max_reg);
Damien Georgea26dc502014-04-12 17:54:52 +0100149 return 0;
150 } else {
151 return r->reg;
152 }
153 }
154 }
Damien826005c2013-10-05 23:17:28 +0100155 }
Damien George87210872014-04-13 00:30:32 +0100156 emit_inline_thumb_error(emit, "'%s' expects a register\n", op);
Damien Georgea26dc502014-04-12 17:54:52 +0100157 return 0;
Damien826005c2013-10-05 23:17:28 +0100158}
159
Damien George87210872014-04-13 00:30:32 +0100160STATIC int get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, int fit_mask) {
161 if (!MP_PARSE_NODE_IS_SMALL_INT(pn)) {
162 emit_inline_thumb_error(emit, "'%s' expects an integer\n", op);
Damien826005c2013-10-05 23:17:28 +0100163 return 0;
164 }
Damien George87210872014-04-13 00:30:32 +0100165 int i = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
Damien826005c2013-10-05 23:17:28 +0100166 if ((i & (~fit_mask)) != 0) {
Damien Georgea26dc502014-04-12 17:54:52 +0100167 emit_inline_thumb_error(emit, "'%s' integer 0x%x does not fit in mask 0x%x\n", op, i, fit_mask);
Damien826005c2013-10-05 23:17:28 +0100168 return 0;
169 }
170 return i;
171}
172
Damien George87210872014-04-13 00:30:32 +0100173STATIC bool get_arg_addr(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, mp_parse_node_t *pn_base, mp_parse_node_t *pn_offset) {
174 if (!MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_bracket)) {
175 goto bad_arg;
176 }
177 mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
178 if (!MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {
179 goto bad_arg;
180 }
181 pns = (mp_parse_node_struct_t*)pns->nodes[0];
182 if (MP_PARSE_NODE_STRUCT_NUM_NODES(pns) != 2) {
183 goto bad_arg;
184 }
185
186 *pn_base = pns->nodes[0];
187 *pn_offset = pns->nodes[1];
188 return true;
189
190bad_arg:
191 emit_inline_thumb_error(emit, "'%s' expects an address of the form [a, b]\n", op);
192 return false;
193}
194
195STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) {
196 if (!MP_PARSE_NODE_IS_ID(pn)) {
197 emit_inline_thumb_error(emit, "'%s' expects a label\n", op);
Damien826005c2013-10-05 23:17:28 +0100198 return 0;
199 }
Damien George87210872014-04-13 00:30:32 +0100200 qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn);
Damien826005c2013-10-05 23:17:28 +0100201 for (int i = 0; i < emit->max_num_labels; i++) {
202 if (emit->label_lookup[i] == label_qstr) {
203 return i;
204 }
205 }
Damiendc833822013-10-06 01:01:01 +0100206 // only need to have the labels on the last pass
207 if (emit->pass == PASS_3) {
Damien Georgea26dc502014-04-12 17:54:52 +0100208 emit_inline_thumb_error(emit, "label '%s' not defined\n", qstr_str(label_qstr));
Damiendc833822013-10-06 01:01:01 +0100209 }
Damien826005c2013-10-05 23:17:28 +0100210 return 0;
211}
212
Damien George47e1b852014-04-08 18:28:33 +0100213typedef struct _cc_name_t { byte cc; byte name[2]; } cc_name_t;
214STATIC const cc_name_t cc_name_table[] = {
215 {THUMB_CC_EQ, "eq"},
216 {THUMB_CC_NE, "ne"},
217 {THUMB_CC_CS, "cs"},
218 {THUMB_CC_CC, "cc"},
219 {THUMB_CC_MI, "mi"},
220 {THUMB_CC_PL, "pl"},
221 {THUMB_CC_VS, "vs"},
222 {THUMB_CC_VC, "vc"},
223 {THUMB_CC_HI, "hi"},
224 {THUMB_CC_LS, "ls"},
225 {THUMB_CC_GE, "ge"},
226 {THUMB_CC_LT, "lt"},
227 {THUMB_CC_GT, "gt"},
228 {THUMB_CC_LE, "le"},
229};
230
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200231STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, mp_parse_node_t *pn_args) {
Damien826005c2013-10-05 23:17:28 +0100232 // TODO perhaps make two tables:
Damien03d41242013-10-06 00:36:05 +0100233 // one_args =
234 // "b", LAB, asm_thumb_b_n,
235 // "bgt", LAB, asm_thumb_bgt_n,
Damien826005c2013-10-05 23:17:28 +0100236 // two_args =
237 // "movs", RLO, I8, asm_thumb_movs_reg_i8
238 // "movw", REG, REG, asm_thumb_movw_reg_i16
239 // three_args =
240 // "subs", RLO, RLO, I3, asm_thumb_subs_reg_reg_i3
241
Damien George47e1b852014-04-08 18:28:33 +0100242 const char *op_str = qstr_str(op);
243 uint op_len = strlen(op_str);
Damien826005c2013-10-05 23:17:28 +0100244
Damien George47e1b852014-04-08 18:28:33 +0100245 if (n_args == 0) {
Damien George90edf9e2014-04-18 16:56:54 +0100246 if (strcmp(op_str, "nop") == 0) {
247 asm_thumb_op16(emit->as, ASM_THUMB_OP_NOP);
248 } else if (strcmp(op_str, "wfi") == 0) {
249 asm_thumb_op16(emit->as, ASM_THUMB_OP_WFI);
250 } else if (strcmp(op_str, "ite.ge") == 0) { // TODO correct name for this op?
Damien George47e1b852014-04-08 18:28:33 +0100251 asm_thumb_ite_ge(emit->as);
252 } else {
253 goto unknown_op;
Damien826005c2013-10-05 23:17:28 +0100254 }
Damien826005c2013-10-05 23:17:28 +0100255
Damien George47e1b852014-04-08 18:28:33 +0100256 } else if (n_args == 1) {
257 if (strcmp(op_str, "b") == 0) {
Damien George87210872014-04-13 00:30:32 +0100258 int label_num = get_arg_label(emit, op_str, pn_args[0]);
Damien George47e1b852014-04-08 18:28:33 +0100259 // TODO check that this succeeded, ie branch was within range
260 asm_thumb_b_n(emit->as, label_num);
261 } else if (op_str[0] == 'b' && op_len == 3) {
262 uint cc = -1;
Damien George6d3c5e42014-04-26 10:47:29 +0100263 for (uint i = 0; i < ARRAY_SIZE(cc_name_table); i++) {
Damien George47e1b852014-04-08 18:28:33 +0100264 if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) {
265 cc = cc_name_table[i].cc;
266 }
267 }
268 if (cc == -1) {
269 goto unknown_op;
270 }
Damien George87210872014-04-13 00:30:32 +0100271 int label_num = get_arg_label(emit, op_str, pn_args[0]);
Damien George47e1b852014-04-08 18:28:33 +0100272 // TODO check that this succeeded, ie branch was within range
273 asm_thumb_bcc_n(emit->as, cc, label_num);
Damien George90edf9e2014-04-18 16:56:54 +0100274 } else if (strcmp(op_str, "cpsid")) {
275 // TODO check pn_args[0] == i
276 asm_thumb_op16(emit->as, ASM_THUMB_OP_CPSID_I);
277 } else if (strcmp(op_str, "cpsie")) {
278 // TODO check pn_args[0] == i
279 asm_thumb_op16(emit->as, ASM_THUMB_OP_CPSIE_I);
Damien George47e1b852014-04-08 18:28:33 +0100280 } else {
281 goto unknown_op;
Damien826005c2013-10-05 23:17:28 +0100282 }
Damien826005c2013-10-05 23:17:28 +0100283
Damien George47e1b852014-04-08 18:28:33 +0100284 } else if (n_args == 2) {
Damien George87210872014-04-13 00:30:32 +0100285 if (MP_PARSE_NODE_IS_ID(pn_args[1])) {
286 // second arg is a register (or should be)
287 uint op_code;
288 if (strcmp(op_str, "mov") == 0) {
289 uint reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
290 uint reg_src = get_arg_reg(emit, op_str, pn_args[1], 15);
291 asm_thumb_mov_reg_reg(emit->as, reg_dest, reg_src);
292 } else if (strcmp(op_str, "and") == 0) {
293 op_code = ASM_THUMB_FORMAT_4_AND;
294 uint reg_dest, reg_src;
295 op_format_4:
296 reg_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
297 reg_src = get_arg_reg(emit, op_str, pn_args[1], 7);
298 asm_thumb_format_4(emit->as, op_code, reg_dest, reg_src);
299 // TODO probably uses less ROM if these ops are in a lookup table
300 } else if (strcmp(op_str, "and") == 0) { op_code = ASM_THUMB_FORMAT_4_AND; goto op_format_4;
301 } else if (strcmp(op_str, "eor") == 0) { op_code = ASM_THUMB_FORMAT_4_EOR; goto op_format_4;
302 } else if (strcmp(op_str, "lsl") == 0) { op_code = ASM_THUMB_FORMAT_4_LSL; goto op_format_4;
303 } else if (strcmp(op_str, "lsr") == 0) { op_code = ASM_THUMB_FORMAT_4_LSR; goto op_format_4;
304 } else if (strcmp(op_str, "asr") == 0) { op_code = ASM_THUMB_FORMAT_4_ASR; goto op_format_4;
305 } else if (strcmp(op_str, "adc") == 0) { op_code = ASM_THUMB_FORMAT_4_ADC; goto op_format_4;
306 } else if (strcmp(op_str, "sbc") == 0) { op_code = ASM_THUMB_FORMAT_4_SBC; goto op_format_4;
307 } else if (strcmp(op_str, "ror") == 0) { op_code = ASM_THUMB_FORMAT_4_ROR; goto op_format_4;
308 } else if (strcmp(op_str, "tst") == 0) { op_code = ASM_THUMB_FORMAT_4_TST; goto op_format_4;
309 } else if (strcmp(op_str, "neg") == 0) { op_code = ASM_THUMB_FORMAT_4_NEG; goto op_format_4;
310 } else if (strcmp(op_str, "cmp") == 0) { op_code = ASM_THUMB_FORMAT_4_CMP; goto op_format_4;
311 } else if (strcmp(op_str, "cmn") == 0) { op_code = ASM_THUMB_FORMAT_4_CMN; goto op_format_4;
312 } else if (strcmp(op_str, "orr") == 0) { op_code = ASM_THUMB_FORMAT_4_ORR; goto op_format_4;
313 } else if (strcmp(op_str, "mul") == 0) { op_code = ASM_THUMB_FORMAT_4_MUL; goto op_format_4;
314 } else if (strcmp(op_str, "bic") == 0) { op_code = ASM_THUMB_FORMAT_4_BIC; goto op_format_4;
315 } else if (strcmp(op_str, "mvn") == 0) { op_code = ASM_THUMB_FORMAT_4_MVN; goto op_format_4;
316 } else {
317 goto unknown_op;
318 }
Damien George47e1b852014-04-08 18:28:33 +0100319 } else {
Damien George87210872014-04-13 00:30:32 +0100320 // second arg is not a register
321 uint op_code;
322 if (strcmp(op_str, "mov") == 0) {
323 op_code = ASM_THUMB_FORMAT_3_MOV;
324 uint rlo_dest, i8_src;
325 op_format_3:
326 rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
327 i8_src = get_arg_i(emit, op_str, pn_args[1], 0xff);
328 asm_thumb_format_3(emit->as, op_code, rlo_dest, i8_src);
329 } else if (strcmp(op_str, "cmp") == 0) {
330 op_code = ASM_THUMB_FORMAT_3_CMP;
331 goto op_format_3;
332 } else if (strcmp(op_str, "add") == 0) {
333 op_code = ASM_THUMB_FORMAT_3_ADD;
334 goto op_format_3;
335 } else if (strcmp(op_str, "sub") == 0) {
336 op_code = ASM_THUMB_FORMAT_3_SUB;
337 goto op_format_3;
338 } else if (strcmp(op_str, "movw") == 0) {
339 uint reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
340 int i_src = get_arg_i(emit, op_str, pn_args[1], 0xffff);
341 asm_thumb_movw_reg_i16(emit->as, reg_dest, i_src);
342 } else if (strcmp(op_str, "movt") == 0) {
343 uint reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
344 int i_src = get_arg_i(emit, op_str, pn_args[1], 0xffff);
345 asm_thumb_movt_reg_i16(emit->as, reg_dest, i_src);
346 } else if (strcmp(op_str, "movwt") == 0) {
347 // this is a convenience instruction
348 // we clear the MSB since it might be set from extracting the small int value
349 uint reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
350 int i_src = get_arg_i(emit, op_str, pn_args[1], 0xffffffff);
351 asm_thumb_movw_reg_i16(emit->as, reg_dest, i_src & 0xffff);
352 asm_thumb_movt_reg_i16(emit->as, reg_dest, (i_src >> 16) & 0x7fff);
353 } else if (strcmp(op_str, "ldr") == 0) {
354 op_code = ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER;
355 uint rlo_dest, rlo_base, i5;
356 mp_parse_node_t pn_base, pn_offset;
357 op_format_9_10:
358 rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
359 if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) {
360 rlo_base = get_arg_reg(emit, op_str, pn_base, 7);
361 if (op_code & ASM_THUMB_FORMAT_9_BYTE_TRANSFER) {
362 i5 = get_arg_i(emit, op_str, pn_offset, 0x1f);
363 } else if (op_code & ASM_THUMB_FORMAT_10_STRH) { // also catches LDRH
364 i5 = get_arg_i(emit, op_str, pn_offset, 0x3e) >> 1;
365 } else {
366 i5 = get_arg_i(emit, op_str, pn_offset, 0x7c) >> 2;
367 }
368 asm_thumb_format_9_10(emit->as, op_code, rlo_dest, rlo_base, i5);
369 }
370 } else if (strcmp(op_str, "ldrb") == 0) {
371 op_code = ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER;
372 goto op_format_9_10;
373 } else if (strcmp(op_str, "ldrh") == 0) {
374 op_code = ASM_THUMB_FORMAT_10_LDRH;
375 goto op_format_9_10;
376 } else if (strcmp(op_str, "str") == 0) {
377 op_code = ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_WORD_TRANSFER;
378 goto op_format_9_10;
379 } else if (strcmp(op_str, "strb") == 0) {
380 op_code = ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER;
381 goto op_format_9_10;
382 } else if (strcmp(op_str, "strh") == 0) {
383 op_code = ASM_THUMB_FORMAT_10_STRH;
384 goto op_format_9_10;
385 } else {
386 goto unknown_op;
387 }
Damien George47e1b852014-04-08 18:28:33 +0100388 }
389
390 } else if (n_args == 3) {
Damien George87210872014-04-13 00:30:32 +0100391 uint op_code;
Damien George47e1b852014-04-08 18:28:33 +0100392 if (strcmp(op_str, "add") == 0) {
Damien George87210872014-04-13 00:30:32 +0100393 op_code = ASM_THUMB_FORMAT_2_ADD;
394 uint rlo_dest, rlo_src;
395 op_format_2:
396 rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
397 rlo_src = get_arg_reg(emit, op_str, pn_args[1], 7);
398 int src_b;
399 if (MP_PARSE_NODE_IS_ID(pn_args[2])) {
400 op_code |= ASM_THUMB_FORMAT_2_REG_OPERAND;
401 src_b = get_arg_reg(emit, op_str, pn_args[2], 7);
402 } else {
403 op_code |= ASM_THUMB_FORMAT_2_IMM_OPERAND;
404 src_b = get_arg_i(emit, op_str, pn_args[2], 0x7);
405 }
406 asm_thumb_format_2(emit->as, op_code, rlo_dest, rlo_src, src_b);
407 } else if (strcmp(op_str, "sub") == 0) {
408 op_code = ASM_THUMB_FORMAT_2_SUB;
409 goto op_format_2;
Damien George47e1b852014-04-08 18:28:33 +0100410 } else {
411 goto unknown_op;
412 }
413
Damien826005c2013-10-05 23:17:28 +0100414 } else {
Damien George47e1b852014-04-08 18:28:33 +0100415 goto unknown_op;
Damien826005c2013-10-05 23:17:28 +0100416 }
Damien George47e1b852014-04-08 18:28:33 +0100417
418 return;
419
420unknown_op:
Damien Georgea26dc502014-04-12 17:54:52 +0100421 emit_inline_thumb_error(emit, "unsupported Thumb instruction '%s' with %d arguments\n", op_str, n_args);
Damien826005c2013-10-05 23:17:28 +0100422}
423
424const emit_inline_asm_method_table_t emit_inline_thumb_method_table = {
425 emit_inline_thumb_start_pass,
426 emit_inline_thumb_end_pass,
Damiena2f2f7d2013-10-06 00:14:13 +0100427 emit_inline_thumb_count_params,
Damien826005c2013-10-05 23:17:28 +0100428 emit_inline_thumb_label,
Damien Georgee5f8a772014-04-21 13:33:15 +0100429 emit_inline_thumb_align,
430 emit_inline_thumb_data,
Damien826005c2013-10-05 23:17:28 +0100431 emit_inline_thumb_op,
432};
433
Damien3ef4abb2013-10-12 16:53:13 +0100434#endif // MICROPY_EMIT_INLINE_THUMB