diff options
Diffstat (limited to 'py/emitinlinethumb.c')
-rw-r--r-- | py/emitinlinethumb.c | 163 |
1 files changed, 99 insertions, 64 deletions
diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index 9ea2cc24bc..c5136ab371 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -81,45 +81,36 @@ STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, int label_num, qstr asm_thumb_label_assign(emit->as, label_num); } -STATIC bool check_n_arg(qstr op, int n_args, int wanted_n_args) { - if (wanted_n_args == n_args) { - return true; - } else { - printf("SyntaxError: '%s' expects %d arguments'\n", qstr_str(op), wanted_n_args); - return false; - } -} - -STATIC uint get_arg_rlo(qstr op, mp_parse_node_t *pn_args, int wanted_arg_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", qstr_str(op), 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", qstr_str(op), wanted_arg_num); + printf("SyntaxError: '%s' expects a register in position %d\n", op, wanted_arg_num); return 0; } return reg_str[1] - '0'; } -STATIC int get_arg_i(qstr op, mp_parse_node_t *pn_args, int wanted_arg_num, int fit_mask) { +STATIC int get_arg_i(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", qstr_str(op), wanted_arg_num); + printf("SyntaxError: '%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", qstr_str(op), i, fit_mask); + printf("SyntaxError: '%s' integer 0x%x does not fit in mask 0x%x\n", op, i, fit_mask); return 0; } return i; } -STATIC int get_arg_label(emit_inline_asm_t *emit, qstr op, mp_parse_node_t *pn_args, int wanted_arg_num) { +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", qstr_str(op), wanted_arg_num); + printf("SyntaxError: '%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]); @@ -135,6 +126,24 @@ STATIC int get_arg_label(emit_inline_asm_t *emit, qstr op, mp_parse_node_t *pn_a return 0; } +typedef struct _cc_name_t { byte cc; byte name[2]; } cc_name_t; +STATIC const cc_name_t cc_name_table[] = { + {THUMB_CC_EQ, "eq"}, + {THUMB_CC_NE, "ne"}, + {THUMB_CC_CS, "cs"}, + {THUMB_CC_CC, "cc"}, + {THUMB_CC_MI, "mi"}, + {THUMB_CC_PL, "pl"}, + {THUMB_CC_VS, "vs"}, + {THUMB_CC_VC, "vc"}, + {THUMB_CC_HI, "hi"}, + {THUMB_CC_LS, "ls"}, + {THUMB_CC_GE, "ge"}, + {THUMB_CC_LT, "lt"}, + {THUMB_CC_GT, "gt"}, + {THUMB_CC_LE, "le"}, +}; + STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, mp_parse_node_t *pn_args) { // TODO perhaps make two tables: // one_args = @@ -146,60 +155,86 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m // three_args = // "subs", RLO, RLO, I3, asm_thumb_subs_reg_reg_i3 - // 1 arg - if (strcmp(qstr_str(op), "b") == 0) { - if (!check_n_arg(op, n_args, 1)) { - return; - } - int label_num = get_arg_label(emit, op, pn_args, 0); - // TODO check that this succeeded, ie branch was within range - asm_thumb_b_n(emit->as, label_num); - } else if (strcmp(qstr_str(op), "bgt") == 0) { - if (!check_n_arg(op, n_args, 1)) { - return; - } - int label_num = get_arg_label(emit, op, pn_args, 0); - // TODO check that this succeeded, ie branch was within range - asm_thumb_bcc_n(emit->as, THUMB_CC_GT, label_num); - - // 2 args - } else if (strcmp(qstr_str(op), "movs") == 0) { - if (!check_n_arg(op, n_args, 2)) { - return; + const char *op_str = qstr_str(op); + uint op_len = strlen(op_str); + + if (n_args == 0) { + if (strcmp(op_str, "ite.ge") == 0) { // TODO correct name for this op? + asm_thumb_ite_ge(emit->as); + } else { + goto unknown_op; } - uint rlo_dest = get_arg_rlo(op, pn_args, 0); - int i_src = get_arg_i(op, pn_args, 1, 0xff); - asm_thumb_movs_rlo_i8(emit->as, rlo_dest, i_src); - } else if (strcmp(qstr_str(op), "movw") == 0) { - if (!check_n_arg(op, n_args, 2)) { - return; + + } else if (n_args == 1) { + if (strcmp(op_str, "b") == 0) { + int label_num = get_arg_label(emit, op_str, pn_args, 0); + // TODO check that this succeeded, ie branch was within range + asm_thumb_b_n(emit->as, label_num); + } else if (op_str[0] == 'b' && op_len == 3) { + uint cc = -1; + for (uint i = 0; i < (sizeof cc_name_table) / (sizeof cc_name_table[0]); i++) { + if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) { + cc = cc_name_table[i].cc; + } + } + if (cc == -1) { + goto unknown_op; + } + int label_num = get_arg_label(emit, op_str, pn_args, 0); + // TODO check that this succeeded, ie branch was within range + asm_thumb_bcc_n(emit->as, cc, label_num); + } else { + goto unknown_op; } - uint rlo_dest = get_arg_rlo(op, pn_args, 0); // TODO can be reg lo or hi - int i_src = get_arg_i(op, pn_args, 1, 0xffff); - asm_thumb_movw_reg_i16(emit->as, rlo_dest, i_src); - } else if (strcmp(qstr_str(op), "cmp") == 0) { - if (!check_n_arg(op, n_args, 2)) { - return; + + } 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); + 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); + 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); + } 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); + } 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); + asm_thumb_cmp_rlo_i8(emit->as, rlo, i8); + } else { + goto unknown_op; } - uint rlo = get_arg_rlo(op, pn_args, 0); - int i8 = get_arg_i(op, pn_args, 1, 0xff); - asm_thumb_cmp_rlo_i8(emit->as, rlo, i8); - - // 3 args - } else if (strcmp(qstr_str(op), "subs") == 0) { - if (!check_n_arg(op, n_args, 3)) { - return; + + } 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); + } 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); + asm_thumb_subs_rlo_rlo_i3(emit->as, rlo_dest, rlo_src, i3_src); + } else { + goto unknown_op; } - uint rlo_dest = get_arg_rlo(op, pn_args, 0); - uint rlo_src = get_arg_rlo(op, pn_args, 1); - int i3_src = get_arg_i(op, pn_args, 2, 0x7); - asm_thumb_subs_rlo_rlo_i3(emit->as, rlo_dest, rlo_src, i3_src); - // unknown op } else { - printf("SyntaxError: unsupported ARM Thumb instruction '%s'\n", qstr_str(op)); - return; + goto unknown_op; } + + return; + +unknown_op: + printf("SyntaxError: unsupported ARM Thumb instruction '%s' with %d arguments\n", op_str, n_args); } const emit_inline_asm_method_table_t emit_inline_thumb_method_table = { |