From 47e1b85d9c2e87aad8396da8b2c492157deaaf3a Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 8 Apr 2014 18:28:33 +0100 Subject: [PATCH] py: Improve inline assembler; add a few more opcodes. --- py/asmthumb.c | 32 ++++----- py/asmthumb.h | 7 +- py/emitinlinethumb.c | 163 ++++++++++++++++++++++++++----------------- 3 files changed, 118 insertions(+), 84 deletions(-) diff --git a/py/asmthumb.c b/py/asmthumb.c index 3fcd28a91d..f37b1ff8fe 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -275,6 +275,12 @@ 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)) + +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)); +} + #define OP_SUBS_RLO_RLO_I3(rlo_dest, rlo_src, i3_src) (0x1e00 | ((i3_src) << 6) | ((rlo_src) << 3) | (rlo_dest)) void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int i3_src) { @@ -283,6 +289,12 @@ void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int asm_thumb_write_op16(as, OP_SUBS_RLO_RLO_I3(rlo_dest, rlo_src, i3_src)); } +#define OP_CMP_REG_REG(rlo_a, rlo_b) (0x4280 | ((rlo_b) << 3) | (rlo_a)) + +void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b) { + asm_thumb_write_op16(as, OP_CMP_REG_REG(rlo_a, rlo_b)); +} + #define OP_CMP_RLO_I8(rlo, i8) (0x2800 | ((rlo) << 8) | (i8)) void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { @@ -290,6 +302,10 @@ 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)); } +void asm_thumb_ite_ge(asm_thumb_t *as) { + asm_thumb_write_op16(as, 0xbfac); +} + #define OP_B_N(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff)) 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) asm_thumb_write_op16(as, OP_ADD_REG_SP_OFFSET(rlo_dest, word_offset)); } -#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)) - -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)); -} - -#define OP_CMP_REG_REG(rlo_a, rlo_b) (0x4280 | ((rlo_b) << 3) | (rlo_a)) - -void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b) { - asm_thumb_write_op16(as, OP_CMP_REG_REG(rlo_a, rlo_b)); -} - -void asm_thumb_ite_ge(asm_thumb_t *as) { - asm_thumb_write_op16(as, 0xbfac); -} - // this could be wrong, because it should have a range of +/- 16MiB... #define OP_BW_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff)) #define OP_BW_LO(byte_offset) (0xb800 | (((byte_offset) >> 1) & 0x07ff)) diff --git a/py/asmthumb.h b/py/asmthumb.h index dcd9c2e3ad..60a86ea50b 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -62,8 +62,11 @@ 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_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_ite_ge(asm_thumb_t *as); void asm_thumb_b_n(asm_thumb_t *as, int label); void asm_thumb_bcc_n(asm_thumb_t *as, int cond, int label); @@ -73,10 +76,6 @@ void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src); void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience -void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b); // convenience ? -void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b); // convenience ? -void asm_thumb_ite_ge(asm_thumb_t *as); // convenience ? - void asm_thumb_b_label(asm_thumb_t *as, int label); // convenience ? void asm_thumb_bcc_label(asm_thumb_t *as, int cc, int label); // convenience: picks narrow or wide branch void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp); // convenience ? 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); + const char *op_str = qstr_str(op); + uint op_len = strlen(op_str); - // 2 args - } else if (strcmp(qstr_str(op), "movs") == 0) { - if (!check_n_arg(op, n_args, 2)) { - return; + 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; - } - 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; - } - 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 == 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; + } + + } 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; + } + + } 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 = {