Skip to content

Commit 47e1b85

Browse files
committed
py: Improve inline assembler; add a few more opcodes.
1 parent 495d781 commit 47e1b85

3 files changed

Lines changed: 118 additions & 84 deletions

File tree

py/asmthumb.c

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,12 @@ void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) {
275275
asm_thumb_write_op16(as, 0x4600 | op_lo);
276276
}
277277

278+
#define OP_ADD_REG_REG_REG(rlo_dest, rlo_src_a, rlo_src_b) (0x1800 | ((rlo_src_b) << 6) | ((rlo_src_a) << 3) | (rlo_dest))
279+
280+
void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) {
281+
asm_thumb_write_op16(as, OP_ADD_REG_REG_REG(rlo_dest, rlo_src_a, rlo_src_b));
282+
}
283+
278284
#define OP_SUBS_RLO_RLO_I3(rlo_dest, rlo_src, i3_src) (0x1e00 | ((i3_src) << 6) | ((rlo_src) << 3) | (rlo_dest))
279285

280286
void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int i3_src) {
@@ -283,13 +289,23 @@ void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int
283289
asm_thumb_write_op16(as, OP_SUBS_RLO_RLO_I3(rlo_dest, rlo_src, i3_src));
284290
}
285291

292+
#define OP_CMP_REG_REG(rlo_a, rlo_b) (0x4280 | ((rlo_b) << 3) | (rlo_a))
293+
294+
void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b) {
295+
asm_thumb_write_op16(as, OP_CMP_REG_REG(rlo_a, rlo_b));
296+
}
297+
286298
#define OP_CMP_RLO_I8(rlo, i8) (0x2800 | ((rlo) << 8) | (i8))
287299

288300
void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8) {
289301
assert(rlo < REG_R8);
290302
asm_thumb_write_op16(as, OP_CMP_RLO_I8(rlo, i8));
291303
}
292304

305+
void asm_thumb_ite_ge(asm_thumb_t *as) {
306+
asm_thumb_write_op16(as, 0xbfac);
307+
}
308+
293309
#define OP_B_N(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff))
294310

295311
void asm_thumb_b_n(asm_thumb_t *as, int label) {
@@ -360,22 +376,6 @@ void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num)
360376
asm_thumb_write_op16(as, OP_ADD_REG_SP_OFFSET(rlo_dest, word_offset));
361377
}
362378

363-
#define OP_ADD_REG_REG_REG(rlo_dest, rlo_src_a, rlo_src_b) (0x1800 | ((rlo_src_b) << 6) | ((rlo_src_a) << 3) | (rlo_dest))
364-
365-
void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) {
366-
asm_thumb_write_op16(as, OP_ADD_REG_REG_REG(rlo_dest, rlo_src_a, rlo_src_b));
367-
}
368-
369-
#define OP_CMP_REG_REG(rlo_a, rlo_b) (0x4280 | ((rlo_b) << 3) | (rlo_a))
370-
371-
void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b) {
372-
asm_thumb_write_op16(as, OP_CMP_REG_REG(rlo_a, rlo_b));
373-
}
374-
375-
void asm_thumb_ite_ge(asm_thumb_t *as) {
376-
asm_thumb_write_op16(as, 0xbfac);
377-
}
378-
379379
// this could be wrong, because it should have a range of +/- 16MiB...
380380
#define OP_BW_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff))
381381
#define OP_BW_LO(byte_offset) (0xb800 | (((byte_offset) >> 1) & 0x07ff))

py/asmthumb.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,11 @@ void asm_thumb_movs_rlo_i8(asm_thumb_t *as, uint rlo_dest, int i8_src);
6262
void asm_thumb_movw_reg_i16(asm_thumb_t *as, uint reg_dest, int i16_src);
6363
void asm_thumb_movt_reg_i16(asm_thumb_t *as, uint reg_dest, int i16_src);
6464
void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src);
65+
void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b);
6566
void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int i3_src);
67+
void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b);
6668
void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8);
69+
void asm_thumb_ite_ge(asm_thumb_t *as);
6770
void asm_thumb_b_n(asm_thumb_t *as, int label);
6871
void asm_thumb_bcc_n(asm_thumb_t *as, int cond, int label);
6972

@@ -73,10 +76,6 @@ void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src);
7376
void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience
7477
void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience
7578

76-
void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b); // convenience ?
77-
void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b); // convenience ?
78-
void asm_thumb_ite_ge(asm_thumb_t *as); // convenience ?
79-
8079
void asm_thumb_b_label(asm_thumb_t *as, int label); // convenience ?
8180
void asm_thumb_bcc_label(asm_thumb_t *as, int cc, int label); // convenience: picks narrow or wide branch
8281
void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp); // convenience ?

py/emitinlinethumb.c

Lines changed: 99 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -81,45 +81,36 @@ STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, int label_num, qstr
8181
asm_thumb_label_assign(emit->as, label_num);
8282
}
8383

84-
STATIC bool check_n_arg(qstr op, int n_args, int wanted_n_args) {
85-
if (wanted_n_args == n_args) {
86-
return true;
87-
} else {
88-
printf("SyntaxError: '%s' expects %d arguments'\n", qstr_str(op), wanted_n_args);
89-
return false;
90-
}
91-
}
92-
93-
STATIC uint get_arg_rlo(qstr op, mp_parse_node_t *pn_args, int wanted_arg_num) {
84+
STATIC uint get_arg_rlo(const char *op, mp_parse_node_t *pn_args, int wanted_arg_num) {
9485
if (!MP_PARSE_NODE_IS_ID(pn_args[wanted_arg_num])) {
95-
printf("SyntaxError: '%s' expects a register in position %d\n", qstr_str(op), wanted_arg_num);
86+
printf("SyntaxError: '%s' expects a register in position %d\n", op, wanted_arg_num);
9687
return 0;
9788
}
9889
qstr reg_qstr = MP_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]);
9990
const char *reg_str = qstr_str(reg_qstr);
10091
if (!(strlen(reg_str) == 2 && reg_str[0] == 'r' && ('0' <= reg_str[1] && reg_str[1] <= '7'))) {
101-
printf("SyntaxError: '%s' expects a register in position %d\n", qstr_str(op), wanted_arg_num);
92+
printf("SyntaxError: '%s' expects a register in position %d\n", op, wanted_arg_num);
10293
return 0;
10394
}
10495
return reg_str[1] - '0';
10596
}
10697

107-
STATIC int get_arg_i(qstr op, mp_parse_node_t *pn_args, int wanted_arg_num, int fit_mask) {
98+
STATIC int get_arg_i(const char *op, mp_parse_node_t *pn_args, int wanted_arg_num, int fit_mask) {
10899
if (!MP_PARSE_NODE_IS_SMALL_INT(pn_args[wanted_arg_num])) {
109-
printf("SyntaxError: '%s' expects an integer in position %d\n", qstr_str(op), wanted_arg_num);
100+
printf("SyntaxError: '%s' expects an integer in position %d\n", op, wanted_arg_num);
110101
return 0;
111102
}
112103
int i = MP_PARSE_NODE_LEAF_SMALL_INT(pn_args[wanted_arg_num]);
113104
if ((i & (~fit_mask)) != 0) {
114-
printf("SyntaxError: '%s' integer 0x%x does not fit in mask 0x%x\n", qstr_str(op), i, fit_mask);
105+
printf("SyntaxError: '%s' integer 0x%x does not fit in mask 0x%x\n", op, i, fit_mask);
115106
return 0;
116107
}
117108
return i;
118109
}
119110

120-
STATIC int get_arg_label(emit_inline_asm_t *emit, qstr op, mp_parse_node_t *pn_args, int wanted_arg_num) {
111+
STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t *pn_args, int wanted_arg_num) {
121112
if (!MP_PARSE_NODE_IS_ID(pn_args[wanted_arg_num])) {
122-
printf("SyntaxError: '%s' expects a label in position %d\n", qstr_str(op), wanted_arg_num);
113+
printf("SyntaxError: '%s' expects a label in position %d\n", op, wanted_arg_num);
123114
return 0;
124115
}
125116
qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]);
@@ -135,6 +126,24 @@ STATIC int get_arg_label(emit_inline_asm_t *emit, qstr op, mp_parse_node_t *pn_a
135126
return 0;
136127
}
137128

129+
typedef struct _cc_name_t { byte cc; byte name[2]; } cc_name_t;
130+
STATIC const cc_name_t cc_name_table[] = {
131+
{THUMB_CC_EQ, "eq"},
132+
{THUMB_CC_NE, "ne"},
133+
{THUMB_CC_CS, "cs"},
134+
{THUMB_CC_CC, "cc"},
135+
{THUMB_CC_MI, "mi"},
136+
{THUMB_CC_PL, "pl"},
137+
{THUMB_CC_VS, "vs"},
138+
{THUMB_CC_VC, "vc"},
139+
{THUMB_CC_HI, "hi"},
140+
{THUMB_CC_LS, "ls"},
141+
{THUMB_CC_GE, "ge"},
142+
{THUMB_CC_LT, "lt"},
143+
{THUMB_CC_GT, "gt"},
144+
{THUMB_CC_LE, "le"},
145+
};
146+
138147
STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, mp_parse_node_t *pn_args) {
139148
// TODO perhaps make two tables:
140149
// one_args =
@@ -146,60 +155,86 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
146155
// three_args =
147156
// "subs", RLO, RLO, I3, asm_thumb_subs_reg_reg_i3
148157

149-
// 1 arg
150-
if (strcmp(qstr_str(op), "b") == 0) {
151-
if (!check_n_arg(op, n_args, 1)) {
152-
return;
153-
}
154-
int label_num = get_arg_label(emit, op, pn_args, 0);
155-
// TODO check that this succeeded, ie branch was within range
156-
asm_thumb_b_n(emit->as, label_num);
157-
} else if (strcmp(qstr_str(op), "bgt") == 0) {
158-
if (!check_n_arg(op, n_args, 1)) {
159-
return;
160-
}
161-
int label_num = get_arg_label(emit, op, pn_args, 0);
162-
// TODO check that this succeeded, ie branch was within range
163-
asm_thumb_bcc_n(emit->as, THUMB_CC_GT, label_num);
164-
165-
// 2 args
166-
} else if (strcmp(qstr_str(op), "movs") == 0) {
167-
if (!check_n_arg(op, n_args, 2)) {
168-
return;
158+
const char *op_str = qstr_str(op);
159+
uint op_len = strlen(op_str);
160+
161+
if (n_args == 0) {
162+
if (strcmp(op_str, "ite.ge") == 0) { // TODO correct name for this op?
163+
asm_thumb_ite_ge(emit->as);
164+
} else {
165+
goto unknown_op;
169166
}
170-
uint rlo_dest = get_arg_rlo(op, pn_args, 0);
171-
int i_src = get_arg_i(op, pn_args, 1, 0xff);
172-
asm_thumb_movs_rlo_i8(emit->as, rlo_dest, i_src);
173-
} else if (strcmp(qstr_str(op), "movw") == 0) {
174-
if (!check_n_arg(op, n_args, 2)) {
175-
return;
167+
168+
} else if (n_args == 1) {
169+
if (strcmp(op_str, "b") == 0) {
170+
int label_num = get_arg_label(emit, op_str, pn_args, 0);
171+
// TODO check that this succeeded, ie branch was within range
172+
asm_thumb_b_n(emit->as, label_num);
173+
} else if (op_str[0] == 'b' && op_len == 3) {
174+
uint cc = -1;
175+
for (uint i = 0; i < (sizeof cc_name_table) / (sizeof cc_name_table[0]); i++) {
176+
if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) {
177+
cc = cc_name_table[i].cc;
178+
}
179+
}
180+
if (cc == -1) {
181+
goto unknown_op;
182+
}
183+
int label_num = get_arg_label(emit, op_str, pn_args, 0);
184+
// TODO check that this succeeded, ie branch was within range
185+
asm_thumb_bcc_n(emit->as, cc, label_num);
186+
} else {
187+
goto unknown_op;
176188
}
177-
uint rlo_dest = get_arg_rlo(op, pn_args, 0); // TODO can be reg lo or hi
178-
int i_src = get_arg_i(op, pn_args, 1, 0xffff);
179-
asm_thumb_movw_reg_i16(emit->as, rlo_dest, i_src);
180-
} else if (strcmp(qstr_str(op), "cmp") == 0) {
181-
if (!check_n_arg(op, n_args, 2)) {
182-
return;
189+
190+
} else if (n_args == 2) {
191+
if (strcmp(op_str, "mov") == 0) {
192+
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0);
193+
uint rlo_src = get_arg_rlo(op_str, pn_args, 1);
194+
asm_thumb_mov_reg_reg(emit->as, rlo_dest, rlo_src);
195+
} else if (strcmp(op_str, "movs") == 0) {
196+
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0);
197+
int i_src = get_arg_i(op_str, pn_args, 1, 0xff);
198+
asm_thumb_movs_rlo_i8(emit->as, rlo_dest, i_src);
199+
} else if (strcmp(op_str, "movw") == 0) {
200+
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); // TODO can be reg lo or hi
201+
int i_src = get_arg_i(op_str, pn_args, 1, 0xffff);
202+
asm_thumb_movw_reg_i16(emit->as, rlo_dest, i_src);
203+
} else if (strcmp(op_str, "movt") == 0) {
204+
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); // TODO can be reg lo or hi
205+
int i_src = get_arg_i(op_str, pn_args, 1, 0xffff);
206+
asm_thumb_movt_reg_i16(emit->as, rlo_dest, i_src);
207+
} else if (strcmp(op_str, "cmp") == 0) {
208+
uint rlo = get_arg_rlo(op_str, pn_args, 0);
209+
int i8 = get_arg_i(op_str, pn_args, 1, 0xff);
210+
asm_thumb_cmp_rlo_i8(emit->as, rlo, i8);
211+
} else {
212+
goto unknown_op;
183213
}
184-
uint rlo = get_arg_rlo(op, pn_args, 0);
185-
int i8 = get_arg_i(op, pn_args, 1, 0xff);
186-
asm_thumb_cmp_rlo_i8(emit->as, rlo, i8);
187-
188-
// 3 args
189-
} else if (strcmp(qstr_str(op), "subs") == 0) {
190-
if (!check_n_arg(op, n_args, 3)) {
191-
return;
214+
215+
} else if (n_args == 3) {
216+
if (strcmp(op_str, "add") == 0) {
217+
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0);
218+
uint rlo_src_a = get_arg_rlo(op_str, pn_args, 1);
219+
uint rlo_src_b = get_arg_rlo(op_str, pn_args, 2);
220+
asm_thumb_add_reg_reg_reg(emit->as, rlo_dest, rlo_src_a, rlo_src_b);
221+
} else if (strcmp(op_str, "subs") == 0) {
222+
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0);
223+
uint rlo_src = get_arg_rlo(op_str, pn_args, 1);
224+
int i3_src = get_arg_i(op_str, pn_args, 2, 0x7);
225+
asm_thumb_subs_rlo_rlo_i3(emit->as, rlo_dest, rlo_src, i3_src);
226+
} else {
227+
goto unknown_op;
192228
}
193-
uint rlo_dest = get_arg_rlo(op, pn_args, 0);
194-
uint rlo_src = get_arg_rlo(op, pn_args, 1);
195-
int i3_src = get_arg_i(op, pn_args, 2, 0x7);
196-
asm_thumb_subs_rlo_rlo_i3(emit->as, rlo_dest, rlo_src, i3_src);
197229

198-
// unknown op
199230
} else {
200-
printf("SyntaxError: unsupported ARM Thumb instruction '%s'\n", qstr_str(op));
201-
return;
231+
goto unknown_op;
202232
}
233+
234+
return;
235+
236+
unknown_op:
237+
printf("SyntaxError: unsupported ARM Thumb instruction '%s' with %d arguments\n", op_str, n_args);
203238
}
204239

205240
const emit_inline_asm_method_table_t emit_inline_thumb_method_table = {

0 commit comments

Comments
 (0)