Skip to content

Commit 4249539

Browse files
committed
py: Implement "it" instruction for inline Thumb assembler.
1 parent 3d7bf5d commit 4249539

2 files changed

Lines changed: 65 additions & 15 deletions

File tree

py/asmthumb.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ void asm_thumb_data(asm_thumb_t* as, uint bytesize, uint val);
8484
// argument order follows ARM, in general dest is first
8585
// note there is a difference between movw and mov.w, and many others!
8686

87+
#define ASM_THUMB_OP_IT (0xbf00)
8788
#define ASM_THUMB_OP_ITE_EQ (0xbf0c)
8889
#define ASM_THUMB_OP_ITE_CS (0xbf2c)
8990
#define ASM_THUMB_OP_ITE_MI (0xbf4c)
@@ -100,6 +101,9 @@ void asm_thumb_data(asm_thumb_t* as, uint bytesize, uint val);
100101
void asm_thumb_op16(asm_thumb_t *as, uint op);
101102
void asm_thumb_op32(asm_thumb_t *as, uint op1, uint op2);
102103

104+
static inline void asm_thumb_it_cc(asm_thumb_t *as, uint cc, uint mask)
105+
{ asm_thumb_op16(as, ASM_THUMB_OP_IT | (cc << 4) | mask); }
106+
103107
// FORMAT 2: add/subtract
104108

105109
#define ASM_THUMB_FORMAT_2_ADD (0x1800)

py/emitinlinethumb.c

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -150,23 +150,38 @@ STATIC const reg_name_t reg_name_table[] = {
150150
{15, "pc\0"},
151151
};
152152

153-
STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, mp_uint_t max_reg) {
153+
// return empty string in case of error, so we can attempt to parse the string
154+
// without a special check if it was in fact a string
155+
STATIC const char *get_arg_str(mp_parse_node_t pn) {
154156
if (MP_PARSE_NODE_IS_ID(pn)) {
155-
qstr reg_qstr = MP_PARSE_NODE_LEAF_ARG(pn);
156-
const char *reg_str = qstr_str(reg_qstr);
157-
for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) {
158-
const reg_name_t *r = &reg_name_table[i];
159-
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')) {
160-
if (r->reg > max_reg) {
161-
emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects at most r%d", op, max_reg));
162-
return 0;
163-
} else {
164-
return r->reg;
165-
}
157+
qstr qst = MP_PARSE_NODE_LEAF_ARG(pn);
158+
return qstr_str(qst);
159+
} else {
160+
return "";
161+
}
162+
}
163+
164+
STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, mp_uint_t max_reg) {
165+
const char *reg_str = get_arg_str(pn);
166+
for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) {
167+
const reg_name_t *r = &reg_name_table[i];
168+
if (reg_str[0] == r->name[0]
169+
&& reg_str[1] == r->name[1]
170+
&& reg_str[2] == r->name[2]
171+
&& (reg_str[2] == '\0' || reg_str[3] == '\0')) {
172+
if (r->reg > max_reg) {
173+
emit_inline_thumb_error_exc(emit,
174+
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
175+
"'%s' expects at most r%d", op, max_reg));
176+
return 0;
177+
} else {
178+
return r->reg;
166179
}
167180
}
168181
}
169-
emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects a register", op));
182+
emit_inline_thumb_error_exc(emit,
183+
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
184+
"'%s' expects a register", op));
170185
return 0;
171186
}
172187

@@ -312,8 +327,6 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
312327
asm_thumb_op16(emit->as, ASM_THUMB_OP_NOP);
313328
} else if (strcmp(op_str, "wfi") == 0) {
314329
asm_thumb_op16(emit->as, ASM_THUMB_OP_WFI);
315-
} else if (strcmp(op_str, "ite.ge") == 0) { // TODO correct name for this op?
316-
asm_thumb_op16(emit->as, ASM_THUMB_OP_ITE_GE);
317330
} else {
318331
goto unknown_op;
319332
}
@@ -336,6 +349,39 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
336349
int label_num = get_arg_label(emit, op_str, pn_args[0]);
337350
// TODO check that this succeeded, ie branch was within range
338351
asm_thumb_bcc_n(emit->as, cc, label_num);
352+
} else if (op_str[0] == 'i' && op_str[1] == 't') {
353+
const char *arg_str = get_arg_str(pn_args[0]);
354+
mp_uint_t cc = -1;
355+
for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) {
356+
if (arg_str[0] == cc_name_table[i].name[0]
357+
&& arg_str[1] == cc_name_table[i].name[1]
358+
&& arg_str[2] == '\0') {
359+
cc = cc_name_table[i].cc;
360+
break;
361+
}
362+
}
363+
if (cc == -1) {
364+
goto unknown_op;
365+
}
366+
const char *os = op_str + 2;
367+
while (*os != '\0') {
368+
os++;
369+
}
370+
if (os > op_str + 5) {
371+
goto unknown_op;
372+
}
373+
mp_uint_t it_mask = 8;
374+
while (--os >= op_str + 2) {
375+
it_mask >>= 1;
376+
if (*os == 't') {
377+
it_mask |= (cc & 1) << 3;
378+
} else if (*os == 'e') {
379+
it_mask |= ((~cc) & 1) << 3;
380+
} else {
381+
goto unknown_op;
382+
}
383+
}
384+
asm_thumb_it_cc(emit->as, cc, it_mask);
339385
} else if (strcmp(op_str, "cpsid") == 0) {
340386
// TODO check pn_args[0] == i
341387
asm_thumb_op16(emit->as, ASM_THUMB_OP_CPSID_I);

0 commit comments

Comments
 (0)