summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--py/asmthumb.c20
-rw-r--r--py/asmthumb.h4
-rw-r--r--py/compile.c78
-rw-r--r--py/emit.h2
-rw-r--r--py/emitglue.c1
-rw-r--r--py/emitinlinethumb.c145
-rw-r--r--py/emitnative.c2
7 files changed, 191 insertions, 61 deletions
diff --git a/py/asmthumb.c b/py/asmthumb.c
index e8c8927a9c..1cd971c76b 100644
--- a/py/asmthumb.c
+++ b/py/asmthumb.c
@@ -275,10 +275,10 @@ void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) {
asm_thumb_write_op16(as, 0x4600 | op_lo);
}
-#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))
+#define OP_ADD_RLO_RLO_RLO(rlo_dest, rlo_src_a, rlo_src_b) (0x1800 | ((rlo_src_b) << 6) | ((rlo_src_a) << 3) | (rlo_dest))
-void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) {
- asm_thumb_write_op16(as, OP_ADD_REG_REG_REG(rlo_dest, rlo_src_a, rlo_src_b));
+void asm_thumb_add_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) {
+ asm_thumb_write_op16(as, OP_ADD_RLO_RLO_RLO(rlo_dest, rlo_src_a, rlo_src_b));
}
#define OP_SUBS_RLO_RLO_I3(rlo_dest, rlo_src, i3_src) (0x1e00 | ((i3_src) << 6) | ((rlo_src) << 3) | (rlo_dest))
@@ -302,6 +302,17 @@ void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8) {
asm_thumb_write_op16(as, OP_CMP_RLO_I8(rlo, i8));
}
+#define OP_LDR_RLO_RLO_I5(rlo_dest, rlo_base, word_offset) (0x6800 | (((word_offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest))
+#define OP_STR_RLO_RLO_I5(rlo_dest, rlo_base, word_offset) (0x6000 | (((word_offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest))
+
+void asm_thumb_ldr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint word_offset) {
+ asm_thumb_write_op16(as, OP_LDR_RLO_RLO_I5(rlo_dest, rlo_base, word_offset));
+}
+
+void asm_thumb_str_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint word_offset) {
+ asm_thumb_write_op16(as, OP_STR_RLO_RLO_I5(rlo_src, rlo_base, word_offset));
+}
+
void asm_thumb_ite_ge(asm_thumb_t *as) {
asm_thumb_write_op16(as, 0xbfac);
}
@@ -424,7 +435,6 @@ void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) {
#define OP_BLX(reg) (0x4780 | ((reg) << 3))
#define OP_SVC(arg) (0xdf00 | (arg))
-#define OP_LDR_FROM_BASE_OFFSET(rlo_dest, rlo_base, word_offset) (0x6800 | (((word_offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest))
void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp) {
/* TODO make this use less bytes
@@ -442,7 +452,7 @@ void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp
asm_thumb_mov_reg_i32(as, reg_temp, (machine_uint_t)fun_ptr);
asm_thumb_write_op16(as, OP_BLX(reg_temp));
} else if (1) {
- asm_thumb_write_op16(as, OP_LDR_FROM_BASE_OFFSET(reg_temp, REG_R7, fun_id));
+ asm_thumb_write_op16(as, OP_LDR_RLO_RLO_I5(reg_temp, REG_R7, fun_id));
asm_thumb_write_op16(as, OP_BLX(reg_temp));
} else {
// use SVC
diff --git a/py/asmthumb.h b/py/asmthumb.h
index f9226f1eb0..de376fd2ce 100644
--- a/py/asmthumb.h
+++ b/py/asmthumb.h
@@ -62,10 +62,12 @@ void asm_thumb_movs_rlo_i8(asm_thumb_t *as, uint rlo_dest, int i8_src);
void asm_thumb_movw_reg_i16(asm_thumb_t *as, uint reg_dest, int i16_src);
void asm_thumb_movt_reg_i16(asm_thumb_t *as, uint reg_dest, int i16_src);
void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src);
-void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b);
+void asm_thumb_add_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b);
void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int i3_src);
void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b);
void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8);
+void asm_thumb_ldr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint word_offset);
+void asm_thumb_str_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint word_offset);
void asm_thumb_ite_ge(asm_thumb_t *as);
void asm_thumb_b_n(asm_thumb_t *as, uint label);
void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label);
diff --git a/py/compile.c b/py/compile.c
index 8d9d5fa52b..f397501f17 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -17,6 +17,7 @@
#include "obj.h"
#include "compile.h"
#include "runtime.h"
+#include "builtin.h"
#include "smallint.h"
// TODO need to mangle __attr names
@@ -100,17 +101,44 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
pns->nodes[i] = fold_constants(pns->nodes[i]);
}
+ // now try to fold this parse node
switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
+ case PN_atom_paren:
+ if (n == 1 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0])) {
+ // (int)
+ pn = pns->nodes[0];
+ }
+ break;
+
+ case PN_expr:
+ if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
+ // int | int
+ machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
+ machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
+ pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 | arg1);
+ }
+ break;
+
+ case PN_and_expr:
+ if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
+ // int & int
+ machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
+ machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
+ pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 & arg1);
+ }
+ break;
+
case PN_shift_expr:
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
- int arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
- int arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
+ machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
+ machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) {
-#if MICROPY_EMIT_CPYTHON
- // can overflow; enabled only to compare with CPython
- pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 << arg1);
-#endif
+ // int << int
+ if (!(arg1 >= BITS_PER_WORD || arg0 > (MP_SMALL_INT_MAX >> arg1) || arg0 < (MP_SMALL_INT_MIN >> arg1))) {
+ pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 << arg1);
+ }
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_MORE)) {
+ // int >> int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 >> arg1);
} else {
// shouldn't happen
@@ -125,14 +153,17 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PLUS)) {
+ // int + int
arg0 += arg1;
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_MINUS)) {
+ // int - int
arg0 -= arg1;
} else {
// shouldn't happen
assert(0);
}
if (MP_PARSE_FITS_SMALL_INT(arg0)) {
+ //printf("%ld + %ld\n", arg0, arg1);
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
}
}
@@ -143,6 +174,7 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
+ // int * int
if (!mp_small_int_mul_overflow(arg0, arg1)) {
arg0 *= arg1;
if (MP_PARSE_FITS_SMALL_INT(arg0)) {
@@ -150,11 +182,14 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
}
}
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_SLASH)) {
- ; // pass
+ // int / int
+ // pass
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PERCENT)) {
+ // int%int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_modulo(arg0, arg1));
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_SLASH)) {
if (arg1 != 0) {
+ // int // int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_floor_divide(arg0, arg1));
}
} else {
@@ -168,10 +203,13 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_PLUS)) {
+ // +int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg);
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_MINUS)) {
+ // -int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, -arg);
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_TILDE)) {
+ // ~int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ~arg);
} else {
// shouldn't happen
@@ -184,7 +222,7 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
if (0) {
#if MICROPY_EMIT_CPYTHON
} else if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_NULL(pns->nodes[1]) && !MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
- // int**x
+ // int ** x
// can overflow; enabled only to compare with CPython
mp_parse_node_struct_t* pns2 = (mp_parse_node_struct_t*)pns->nodes[2];
if (MP_PARSE_NODE_IS_SMALL_INT(pns2->nodes[0])) {
@@ -3121,7 +3159,16 @@ void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass
for (int i = 0; i < num; i++) {
assert(MP_PARSE_NODE_IS_STRUCT(nodes[i]));
mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)nodes[i];
- assert(MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_expr_stmt);
+ if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_pass_stmt) {
+ // no instructions
+ continue;
+ } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_expr_stmt) {
+ // an instruction; fall through
+ } else {
+ // not an instruction; error
+ compile_syntax_error(comp, nodes[i], "inline assembler expecting an instruction");
+ return;
+ }
assert(MP_PARSE_NODE_IS_STRUCT(pns2->nodes[0]));
assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[1]));
pns2 = (mp_parse_node_struct_t*)pns2->nodes[0];
@@ -3152,7 +3199,10 @@ void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass
}
if (comp->pass > PASS_1) {
- EMIT_INLINE_ASM(end_pass);
+ bool success = EMIT_INLINE_ASM(end_pass);
+ if (!success) {
+ comp->had_error = true;
+ }
}
}
#endif
@@ -3330,7 +3380,9 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
comp->emit_inline_asm = emit_inline_thumb;
comp->emit_inline_asm_method_table = &emit_inline_thumb_method_table;
compile_scope_inline_asm(comp, s, PASS_2);
- compile_scope_inline_asm(comp, s, PASS_3);
+ if (!comp->had_error) {
+ compile_scope_inline_asm(comp, s, PASS_3);
+ }
#endif
} else {
@@ -3374,7 +3426,9 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
// compile pass 2 and pass 3
compile_scope(comp, s, PASS_2);
- compile_scope(comp, s, PASS_3);
+ if (!comp->had_error) {
+ compile_scope(comp, s, PASS_3);
+ }
}
}
diff --git a/py/emit.h b/py/emit.h
index 738150c656..54837c0d82 100644
--- a/py/emit.h
+++ b/py/emit.h
@@ -133,7 +133,7 @@ typedef struct _emit_inline_asm_t emit_inline_asm_t;
typedef struct _emit_inline_asm_method_table_t {
void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope);
- void (*end_pass)(emit_inline_asm_t *emit);
+ bool (*end_pass)(emit_inline_asm_t *emit);
int (*count_params)(emit_inline_asm_t *emit, int n_params, mp_parse_node_t *pn_params);
void (*label)(emit_inline_asm_t *emit, uint label_num, qstr label_id);
void (*op)(emit_inline_asm_t *emit, qstr op, int n_args, mp_parse_node_t *pn_args);
diff --git a/py/emitglue.c b/py/emitglue.c
index 90c9b77cf8..bcc9b2cca1 100644
--- a/py/emitglue.c
+++ b/py/emitglue.c
@@ -185,6 +185,7 @@ void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint le
#ifdef WRITE_CODE
if (fp_write_code != NULL) {
fwrite(fun_data, len, 1, fp_write_code);
+ fflush(fp_write_code);
}
#endif
#endif
diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c
index db1525672f..58aeed1f64 100644
--- a/py/emitinlinethumb.c
+++ b/py/emitinlinethumb.c
@@ -1,6 +1,7 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
+#include <stdarg.h>
#include <assert.h>
#include "misc.h"
@@ -17,13 +18,23 @@
#if MICROPY_EMIT_INLINE_THUMB
struct _emit_inline_asm_t {
- int pass;
+ uint16_t pass;
+ uint16_t success;
scope_t *scope;
uint max_num_labels;
qstr *label_lookup;
asm_thumb_t *as;
};
+void emit_inline_thumb_error(emit_inline_asm_t *emit, const char *fmt, ...) {
+ printf("SyntaxError: ");
+ emit->success = false;
+ va_list ap;
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+
emit_inline_asm_t *emit_inline_thumb_new(uint max_num_labels) {
emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t);
emit->max_num_labels = max_num_labels;
@@ -41,12 +52,13 @@ void emit_inline_thumb_free(emit_inline_asm_t *emit) {
STATIC void emit_inline_thumb_start_pass(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope) {
emit->pass = pass;
+ emit->success = true;
emit->scope = scope;
asm_thumb_start_pass(emit->as, pass);
asm_thumb_entry(emit->as, 0);
}
-STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
+STATIC bool emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
asm_thumb_exit(emit->as);
asm_thumb_end_pass(emit->as);
@@ -54,21 +66,23 @@ STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
void *f = asm_thumb_get_code(emit->as);
mp_emit_glue_assign_inline_asm_code(emit->scope->unique_code_id, f, asm_thumb_get_code_size(emit->as), emit->scope->num_params);
}
+
+ return emit->success;
}
STATIC int emit_inline_thumb_count_params(emit_inline_asm_t *emit, int n_params, mp_parse_node_t *pn_params) {
if (n_params > 4) {
- printf("SyntaxError: can only have up to 4 parameters to inline thumb assembly\n");
+ emit_inline_thumb_error(emit, "can only have up to 4 parameters to inline thumb assembly\n");
return 0;
}
for (int i = 0; i < n_params; i++) {
if (!MP_PARSE_NODE_IS_ID(pn_params[i])) {
- printf("SyntaxError: parameter to inline assembler must be an identifier\n");
+ emit_inline_thumb_error(emit, "parameter to inline assembler must be an identifier\n");
return 0;
}
const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i]));
if (!(strlen(p) == 2 && p[0] == 'r' && p[1] == '0' + i)) {
- printf("SyntaxError: parameter %d to inline assembler must be r%d\n", i + 1, i);
+ emit_inline_thumb_error(emit, "parameter %d to inline assembler must be r%d\n", i + 1, i);
return 0;
}
}
@@ -81,28 +95,59 @@ STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, uint label_num, qst
asm_thumb_label_assign(emit->as, label_num);
}
-STATIC uint get_arg_rlo(const char *op, mp_parse_node_t *pn_args, int wanted_arg_num) {
- if (!MP_PARSE_NODE_IS_ID(pn_args[wanted_arg_num])) {
- printf("SyntaxError: '%s' expects a register in position %d\n", op, wanted_arg_num);
- return 0;
- }
- qstr reg_qstr = MP_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]);
- const char *reg_str = qstr_str(reg_qstr);
- if (!(strlen(reg_str) == 2 && reg_str[0] == 'r' && ('0' <= reg_str[1] && reg_str[1] <= '7'))) {
- printf("SyntaxError: '%s' expects a register in position %d\n", op, wanted_arg_num);
- return 0;
+typedef struct _reg_name_t { byte reg; byte name[3]; } reg_name_t;
+STATIC const reg_name_t reg_name_table[] = {
+ {0, "r0\0"},
+ {1, "r1\0"},
+ {2, "r2\0"},
+ {3, "r3\0"},
+ {4, "r4\0"},
+ {5, "r5\0"},
+ {6, "r6\0"},
+ {7, "r7\0"},
+ {8, "r8\0"},
+ {9, "r9\0"},
+ {10, "r10"},
+ {11, "r11"},
+ {12, "r12"},
+ {13, "r13"},
+ {14, "r14"},
+ {15, "r15"},
+ {10, "sl\0"},
+ {11, "fp\0"},
+ {13, "sp\0"},
+ {14, "lr\0"},
+ {15, "pc\0"},
+};
+
+STATIC uint get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t *pn_args, uint wanted_arg_num, uint max_reg) {
+ if (MP_PARSE_NODE_IS_ID(pn_args[wanted_arg_num])) {
+ qstr reg_qstr = MP_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]);
+ const char *reg_str = qstr_str(reg_qstr);
+ for (uint i = 0; i < sizeof(reg_name_table) / sizeof(reg_name_table[0]); i++) {
+ const reg_name_t *r = &reg_name_table[i];
+ 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')) {
+ if (r->reg > max_reg) {
+ emit_inline_thumb_error(emit, "'%s' expects at most r%d in position %d\n", op, max_reg, wanted_arg_num);
+ return 0;
+ } else {
+ return r->reg;
+ }
+ }
+ }
}
- return reg_str[1] - '0';
+ emit_inline_thumb_error(emit, "'%s' expects a register in position %d\n", op, wanted_arg_num);
+ return 0;
}
-STATIC int get_arg_i(const char *op, mp_parse_node_t *pn_args, int wanted_arg_num, int fit_mask) {
+STATIC int get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t *pn_args, int wanted_arg_num, int fit_mask) {
if (!MP_PARSE_NODE_IS_SMALL_INT(pn_args[wanted_arg_num])) {
- printf("SyntaxError: '%s' expects an integer in position %d\n", op, wanted_arg_num);
+ emit_inline_thumb_error(emit, "'%s' expects an integer in position %d\n", op, wanted_arg_num);
return 0;
}
int i = MP_PARSE_NODE_LEAF_SMALL_INT(pn_args[wanted_arg_num]);
if ((i & (~fit_mask)) != 0) {
- printf("SyntaxError: '%s' integer 0x%x does not fit in mask 0x%x\n", op, i, fit_mask);
+ emit_inline_thumb_error(emit, "'%s' integer 0x%x does not fit in mask 0x%x\n", op, i, fit_mask);
return 0;
}
return i;
@@ -110,7 +155,7 @@ STATIC int get_arg_i(const char *op, mp_parse_node_t *pn_args, int wanted_arg_nu
STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t *pn_args, int wanted_arg_num) {
if (!MP_PARSE_NODE_IS_ID(pn_args[wanted_arg_num])) {
- printf("SyntaxError: '%s' expects a label in position %d\n", op, wanted_arg_num);
+ emit_inline_thumb_error(emit, "'%s' expects a label in position %d\n", op, wanted_arg_num);
return 0;
}
qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]);
@@ -121,7 +166,7 @@ STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_
}
// only need to have the labels on the last pass
if (emit->pass == PASS_3) {
- printf("SyntaxError: label '%s' not defined\n", qstr_str(label_qstr));
+ emit_inline_thumb_error(emit, "label '%s' not defined\n", qstr_str(label_qstr));
}
return 0;
}
@@ -189,24 +234,31 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
} else if (n_args == 2) {
if (strcmp(op_str, "mov") == 0) {
- uint rlo_dest = get_arg_rlo(op_str, pn_args, 0);
- uint rlo_src = get_arg_rlo(op_str, pn_args, 1);
+ uint rlo_dest = get_arg_reg(emit, op_str, pn_args, 0, 7);
+ uint rlo_src = get_arg_reg(emit, op_str, pn_args, 1, 7);
asm_thumb_mov_reg_reg(emit->as, rlo_dest, rlo_src);
} else if (strcmp(op_str, "movs") == 0) {
- uint rlo_dest = get_arg_rlo(op_str, pn_args, 0);
- int i_src = get_arg_i(op_str, pn_args, 1, 0xff);
+ uint rlo_dest = get_arg_reg(emit, op_str, pn_args, 0, 7);
+ int i_src = get_arg_i(emit, op_str, pn_args, 1, 0xff);
asm_thumb_movs_rlo_i8(emit->as, rlo_dest, i_src);
} else if (strcmp(op_str, "movw") == 0) {
- uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); // TODO can be reg lo or hi
- int i_src = get_arg_i(op_str, pn_args, 1, 0xffff);
- asm_thumb_movw_reg_i16(emit->as, rlo_dest, i_src);
+ uint reg_dest = get_arg_reg(emit, op_str, pn_args, 0, 15);
+ int i_src = get_arg_i(emit, op_str, pn_args, 1, 0xffff);
+ asm_thumb_movw_reg_i16(emit->as, reg_dest, i_src);
} else if (strcmp(op_str, "movt") == 0) {
- uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); // TODO can be reg lo or hi
- int i_src = get_arg_i(op_str, pn_args, 1, 0xffff);
- asm_thumb_movt_reg_i16(emit->as, rlo_dest, i_src);
+ uint reg_dest = get_arg_reg(emit, op_str, pn_args, 0, 15);
+ int i_src = get_arg_i(emit, op_str, pn_args, 1, 0xffff);
+ asm_thumb_movt_reg_i16(emit->as, reg_dest, i_src);
+ } else if (strcmp(op_str, "movwt") == 0) {
+ // this is a convenience instruction
+ // we clear the MSB since it might be set from extracting the small int value
+ uint reg_dest = get_arg_reg(emit, op_str, pn_args, 0, 15);
+ int i_src = get_arg_i(emit, op_str, pn_args, 1, 0xffffffff);
+ asm_thumb_movw_reg_i16(emit->as, reg_dest, i_src & 0xffff);
+ asm_thumb_movt_reg_i16(emit->as, reg_dest, (i_src >> 16) & 0x7fff);
} else if (strcmp(op_str, "cmp") == 0) {
- uint rlo = get_arg_rlo(op_str, pn_args, 0);
- int i8 = get_arg_i(op_str, pn_args, 1, 0xff);
+ uint rlo = get_arg_reg(emit, op_str, pn_args, 0, 7);
+ int i8 = get_arg_i(emit, op_str, pn_args, 1, 0xff);
asm_thumb_cmp_rlo_i8(emit->as, rlo, i8);
} else {
goto unknown_op;
@@ -214,15 +266,26 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
} else if (n_args == 3) {
if (strcmp(op_str, "add") == 0) {
- uint rlo_dest = get_arg_rlo(op_str, pn_args, 0);
- uint rlo_src_a = get_arg_rlo(op_str, pn_args, 1);
- uint rlo_src_b = get_arg_rlo(op_str, pn_args, 2);
- asm_thumb_add_reg_reg_reg(emit->as, rlo_dest, rlo_src_a, rlo_src_b);
+ uint rlo_dest = get_arg_reg(emit, op_str, pn_args, 0, 7);
+ uint rlo_src_a = get_arg_reg(emit, op_str, pn_args, 1, 7);
+ uint rlo_src_b = get_arg_reg(emit, op_str, pn_args, 2, 7);
+ asm_thumb_add_rlo_rlo_rlo(emit->as, rlo_dest, rlo_src_a, rlo_src_b);
} else if (strcmp(op_str, "subs") == 0) {
- uint rlo_dest = get_arg_rlo(op_str, pn_args, 0);
- uint rlo_src = get_arg_rlo(op_str, pn_args, 1);
- int i3_src = get_arg_i(op_str, pn_args, 2, 0x7);
+ uint rlo_dest = get_arg_reg(emit, op_str, pn_args, 0, 7);
+ uint rlo_src = get_arg_reg(emit, op_str, pn_args, 1, 7);
+ int i3_src = get_arg_i(emit, op_str, pn_args, 2, 0x7);
asm_thumb_subs_rlo_rlo_i3(emit->as, rlo_dest, rlo_src, i3_src);
+ } else if (strcmp(op_str, "ldr") == 0) {
+ // TODO maybe use ldr(rd, [rb, 4]) syntax?
+ uint rlo_dest = get_arg_reg(emit, op_str, pn_args, 0, 7);
+ uint rlo_base = get_arg_reg(emit, op_str, pn_args, 1, 7);
+ int i5 = get_arg_i(emit, op_str, pn_args, 2, 0x7c);
+ asm_thumb_ldr_rlo_rlo_i5(emit->as, rlo_dest, rlo_base, i5 >> 2);
+ } else if (strcmp(op_str, "str") == 0) {
+ uint rlo_src = get_arg_reg(emit, op_str, pn_args, 0, 7);
+ uint rlo_base = get_arg_reg(emit, op_str, pn_args, 1, 7);
+ int i5 = get_arg_i(emit, op_str, pn_args, 2, 0x7c);
+ asm_thumb_str_rlo_rlo_i5(emit->as, rlo_src, rlo_base, i5 >> 2);
} else {
goto unknown_op;
}
@@ -234,7 +297,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
return;
unknown_op:
- printf("SyntaxError: unsupported ARM Thumb instruction '%s' with %d arguments\n", op_str, n_args);
+ emit_inline_thumb_error(emit, "unsupported Thumb instruction '%s' with %d arguments\n", op_str, n_args);
}
const emit_inline_asm_method_table_t emit_inline_thumb_method_table = {
diff --git a/py/emitnative.c b/py/emitnative.c
index d2a3df25dd..29da5b8c99 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -1058,7 +1058,7 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
#if N_X64
asm_x64_add_r64_to_r64(emit->as, REG_ARG_3, REG_ARG_2);
#elif N_THUMB
- asm_thumb_add_reg_reg_reg(emit->as, REG_ARG_2, REG_ARG_2, REG_ARG_3);
+ asm_thumb_add_rlo_rlo_rlo(emit->as, REG_ARG_2, REG_ARG_2, REG_ARG_3);
#endif
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
} else if (op == MP_BINARY_OP_LESS) {