Skip to content

Commit 0d967b8

Browse files
committed
py: Implement push/pop for inline Thumb assembler.
1 parent dfe944c commit 0d967b8

File tree

3 files changed

+77
-2
lines changed

3 files changed

+77
-2
lines changed

py/emitinlinethumb.c

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,58 @@ STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_n
170170
return 0;
171171
}
172172

173+
STATIC mp_uint_t get_arg_reglist(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) {
174+
// a register list looks like {r0, r1, r2} and is parsed as a Python set
175+
176+
if (!MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_brace)) {
177+
goto bad_arg;
178+
}
179+
180+
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
181+
assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 1); // should always be
182+
pn = pns->nodes[0];
183+
184+
mp_uint_t reglist = 0;
185+
186+
if (MP_PARSE_NODE_IS_ID(pn)) {
187+
// set with one element
188+
reglist |= 1 << get_arg_reg(emit, op, pn, 15);
189+
} else if (MP_PARSE_NODE_IS_STRUCT(pn)) {
190+
pns = (mp_parse_node_struct_t*)pn;
191+
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker) {
192+
assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should succeed
193+
mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
194+
if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_dictorsetmaker_list) {
195+
// set with multiple elements
196+
197+
// get first element of set (we rely on get_arg_reg to catch syntax errors)
198+
reglist |= 1 << get_arg_reg(emit, op, pns->nodes[0], 15);
199+
200+
// get tail elements (2nd, 3rd, ...)
201+
mp_parse_node_t *nodes;
202+
int n = mp_parse_node_extract_list(&pns1->nodes[0], PN_dictorsetmaker_list2, &nodes);
203+
204+
// process rest of elements
205+
for (int i = 0; i < n; i++) {
206+
reglist |= 1 << get_arg_reg(emit, op, nodes[i], 15);
207+
}
208+
} else {
209+
goto bad_arg;
210+
}
211+
} else {
212+
goto bad_arg;
213+
}
214+
} else {
215+
goto bad_arg;
216+
}
217+
218+
return reglist;
219+
220+
bad_arg:
221+
emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects {r0, r1, ...}", op));
222+
return 0;
223+
}
224+
173225
STATIC int get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, int fit_mask) {
174226
if (!MP_PARSE_NODE_IS_SMALL_INT(pn)) {
175227
emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an integer", op));
@@ -284,12 +336,26 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
284336
int label_num = get_arg_label(emit, op_str, pn_args[0]);
285337
// TODO check that this succeeded, ie branch was within range
286338
asm_thumb_bcc_n(emit->as, cc, label_num);
287-
} else if (strcmp(op_str, "cpsid")) {
339+
} else if (strcmp(op_str, "cpsid") == 0) {
288340
// TODO check pn_args[0] == i
289341
asm_thumb_op16(emit->as, ASM_THUMB_OP_CPSID_I);
290-
} else if (strcmp(op_str, "cpsie")) {
342+
} else if (strcmp(op_str, "cpsie") == 0) {
291343
// TODO check pn_args[0] == i
292344
asm_thumb_op16(emit->as, ASM_THUMB_OP_CPSIE_I);
345+
} else if (strcmp(op_str, "push") == 0) {
346+
mp_uint_t reglist = get_arg_reglist(emit, op_str, pn_args[0]);
347+
if ((reglist & 0xff00) == 0) {
348+
asm_thumb_op16(emit->as, 0xb400 | reglist);
349+
} else {
350+
asm_thumb_op32(emit->as, 0xe92d, reglist);
351+
}
352+
} else if (strcmp(op_str, "pop") == 0) {
353+
mp_uint_t reglist = get_arg_reglist(emit, op_str, pn_args[0]);
354+
if ((reglist & 0xff00) == 0) {
355+
asm_thumb_op16(emit->as, 0xbc00 | reglist);
356+
} else {
357+
asm_thumb_op32(emit->as, 0xe8bd, reglist);
358+
}
293359
} else {
294360
goto unknown_op;
295361
}

tests/inlineasm/asmpushpop.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@micropython.asm_thumb
2+
def f(r0, r1, r2):
3+
push({r0})
4+
push({r1, r2})
5+
pop({r0})
6+
pop({r1, r2})
7+
8+
print(f(0, 1, 2))

tests/inlineasm/asmpushpop.py.exp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1

0 commit comments

Comments
 (0)