From 03d4124320fa2a6c987b86bbcd9afbd1563fdf40 Mon Sep 17 00:00:00 2001 From: Damien Date: Sun, 6 Oct 2013 00:36:05 +0100 Subject: [PATCH] Add b_n opcode to inline thumb asm. --- py/asmthumb.c | 16 ++++++++++++++-- py/asmthumb.h | 1 + py/emitinlinethumb.c | 16 +++++++++++++--- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/py/asmthumb.c b/py/asmthumb.c index 91fff3955..ba61c31f6 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -288,6 +288,19 @@ 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_B_N(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff)) + +void asm_thumb_b_n(asm_thumb_t *as, int label) { + int dest = get_label_dest(as, label); + int rel = dest - as->code_offset; + rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction + if (SIGNED_FIT12(rel)) { + asm_thumb_write_op16(as, OP_B_N(rel)); + } else { + printf("asm_thumb_b_n: branch does not fit in 12 bits\n"); + } +} + #define OP_BEQ_N(byte_offset) (0xd000 | (((byte_offset) >> 1) & 0x00ff)) #define OP_BNE_N(byte_offset) (0xd100 | (((byte_offset) >> 1) & 0x00ff)) #define OP_BCS_N(byte_offset) (0xd200 | (((byte_offset) >> 1) & 0x00ff)) @@ -371,7 +384,6 @@ void asm_thumb_ite_ge(asm_thumb_t *as) { asm_thumb_write_op16(as, 0xbfac); } -#define OP_B(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff)) // 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)) @@ -384,7 +396,7 @@ void asm_thumb_b_label(asm_thumb_t *as, int label) { // is a backwards jump, so we know the size of the jump on the first pass // calculate rel assuming 12 bit relative jump if (SIGNED_FIT12(rel)) { - asm_thumb_write_op16(as, OP_B(rel)); + asm_thumb_write_op16(as, OP_B_N(rel)); } else { goto large_jump; } diff --git a/py/asmthumb.h b/py/asmthumb.h index d71206387..55c36d712 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -49,6 +49,7 @@ 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_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int i3_src); void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8); +void asm_thumb_b_n(asm_thumb_t *as, int label); void asm_thumb_bgt_n(asm_thumb_t *as, int label); void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, machine_uint_t i32_src); // convenience diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index 1e739a34d..a17d39cc8 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -52,7 +52,7 @@ static void emit_inline_thumb_end_pass(emit_inline_asm_t *emit) { static int emit_inline_thumb_count_params(emit_inline_asm_t *emit, int n_params, py_parse_node_t *pn_params) { if (n_params > 4) { - printf("SyntaxError: can only have up to 3 parameters to inline assembler\n"); + printf("SyntaxError: can only have up to 4 parameters to inline thumb assembly\n"); return 0; } for (int i = 0; i < n_params; i++) { @@ -62,7 +62,7 @@ static int emit_inline_thumb_count_params(emit_inline_asm_t *emit, int n_params, } const char *p = qstr_str(PY_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, i); + printf("SyntaxError: parameter %d to inline assembler must be r%d\n", i + 1, i); return 0; } } @@ -128,6 +128,9 @@ static int get_arg_label(emit_inline_asm_t *emit, qstr op, py_parse_node_t *pn_a static void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, py_parse_node_t *pn_args) { // TODO perhaps make two tables: + // one_args = + // "b", LAB, asm_thumb_b_n, + // "bgt", LAB, asm_thumb_bgt_n, // two_args = // "movs", RLO, I8, asm_thumb_movs_reg_i8 // "movw", REG, REG, asm_thumb_movw_reg_i16 @@ -135,7 +138,14 @@ static void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, p // "subs", RLO, RLO, I3, asm_thumb_subs_reg_reg_i3 // 1 arg - if (strcmp(qstr_str(op), "bgt") == 0) { + 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; }