diff options
Diffstat (limited to 'py/asmthumb.c')
-rw-r--r-- | py/asmthumb.c | 156 |
1 files changed, 31 insertions, 125 deletions
diff --git a/py/asmthumb.c b/py/asmthumb.c index 1aae3d38eb..749c1e405b 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -42,49 +42,8 @@ #define SIGNED_FIT12(x) (((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800) #define SIGNED_FIT23(x) (((x) & 0xffc00000) == 0) || (((x) & 0xffc00000) == 0xffc00000) -struct _asm_thumb_t { - mp_uint_t pass; - mp_uint_t code_offset; - mp_uint_t code_size; - byte *code_base; - byte dummy_data[4]; - - mp_uint_t max_num_labels; - mp_uint_t *label_offsets; - mp_uint_t push_reglist; - mp_uint_t stack_adjust; -}; - -asm_thumb_t *asm_thumb_new(uint max_num_labels) { - asm_thumb_t *as; - - as = m_new0(asm_thumb_t, 1); - as->max_num_labels = max_num_labels; - as->label_offsets = m_new(mp_uint_t, max_num_labels); - - return as; -} - -void asm_thumb_free(asm_thumb_t *as, bool free_code) { - if (free_code) { - MP_PLAT_FREE_EXEC(as->code_base, as->code_size); - } - m_del(mp_uint_t, as->label_offsets, as->max_num_labels); - m_del_obj(asm_thumb_t, as); -} - -void asm_thumb_start_pass(asm_thumb_t *as, uint pass) { - if (pass == ASM_THUMB_PASS_COMPUTE) { - memset(as->label_offsets, -1, as->max_num_labels * sizeof(mp_uint_t)); - } else if (pass == ASM_THUMB_PASS_EMIT) { - MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size); - if (as->code_base == NULL) { - assert(0); - } - //printf("code_size: %u\n", as->code_size); - } - as->pass = pass; - as->code_offset = 0; +static inline byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int n) { + return mp_asm_base_get_cur_to_write_bytes(&as->base, n); } void asm_thumb_end_pass(asm_thumb_t *as) { @@ -92,42 +51,15 @@ void asm_thumb_end_pass(asm_thumb_t *as) { // could check labels are resolved... #if defined(MCU_SERIES_F7) - if (as->pass == ASM_THUMB_PASS_EMIT) { + if (as->base.pass == MP_ASM_PASS_EMIT) { // flush D-cache, so the code emited is stored in memory - SCB_CleanDCache_by_Addr((uint32_t*)as->code_base, as->code_size); + SCB_CleanDCache_by_Addr((uint32_t*)as->base.code_base, as->base.code_size); // invalidate I-cache SCB_InvalidateICache(); } #endif } -// all functions must go through this one to emit bytes -// if as->pass < ASM_THUMB_PASS_EMIT, then this function only returns a buffer of 4 bytes length -STATIC byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int num_bytes_to_write) { - //printf("emit %d\n", num_bytes_to_write); - if (as->pass < ASM_THUMB_PASS_EMIT) { - as->code_offset += num_bytes_to_write; - return as->dummy_data; - } else { - assert(as->code_offset + num_bytes_to_write <= as->code_size); - byte *c = as->code_base + as->code_offset; - as->code_offset += num_bytes_to_write; - return c; - } -} - -uint asm_thumb_get_code_pos(asm_thumb_t *as) { - return as->code_offset; -} - -uint asm_thumb_get_code_size(asm_thumb_t *as) { - return as->code_size; -} - -void *asm_thumb_get_code(asm_thumb_t *as) { - return as->code_base; -} - /* STATIC void asm_thumb_write_byte_1(asm_thumb_t *as, byte b1) { byte *c = asm_thumb_get_cur_to_write_bytes(as, 1); @@ -223,55 +155,29 @@ void asm_thumb_exit(asm_thumb_t *as) { asm_thumb_op16(as, OP_POP_RLIST_PC(as->push_reglist)); } -void asm_thumb_label_assign(asm_thumb_t *as, uint label) { - assert(label < as->max_num_labels); - if (as->pass < ASM_THUMB_PASS_EMIT) { - // assign label offset - assert(as->label_offsets[label] == -1); - as->label_offsets[label] = as->code_offset; - } else { - // ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT - //printf("l%d: (at %d=%ld)\n", label, as->label_offsets[label], as->code_offset); - assert(as->label_offsets[label] == as->code_offset); - } -} - -void asm_thumb_align(asm_thumb_t* as, uint align) { - // TODO fill unused data with NOPs? - as->code_offset = (as->code_offset + align - 1) & (~(align - 1)); -} - -void asm_thumb_data(asm_thumb_t* as, uint bytesize, uint val) { - byte *c = asm_thumb_get_cur_to_write_bytes(as, bytesize); - // only write to the buffer in the emit pass (otherwise we overflow dummy_data) - if (as->pass == ASM_THUMB_PASS_EMIT) { - // little endian - for (uint i = 0; i < bytesize; i++) { - *c++ = val; - val >>= 8; - } - } -} - STATIC mp_uint_t get_label_dest(asm_thumb_t *as, uint label) { - assert(label < as->max_num_labels); - return as->label_offsets[label]; + assert(label < as->base.max_num_labels); + return as->base.label_offsets[label]; } void asm_thumb_op16(asm_thumb_t *as, uint op) { byte *c = asm_thumb_get_cur_to_write_bytes(as, 2); - // little endian - c[0] = op; - c[1] = op >> 8; + if (c != NULL) { + // little endian + c[0] = op; + c[1] = op >> 8; + } } void asm_thumb_op32(asm_thumb_t *as, uint op1, uint op2) { byte *c = asm_thumb_get_cur_to_write_bytes(as, 4); - // little endian, op1 then op2 - c[0] = op1; - c[1] = op1 >> 8; - c[2] = op2; - c[3] = op2 >> 8; + if (c != NULL) { + // little endian, op1 then op2 + c[0] = op1; + c[1] = op1 >> 8; + c[2] = op2; + c[3] = op2 >> 8; + } } #define OP_FORMAT_4(op, rlo_dest, rlo_src) ((op) | ((rlo_src) << 3) | (rlo_dest)) @@ -309,10 +215,10 @@ void asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_ bool asm_thumb_b_n_label(asm_thumb_t *as, uint label) { mp_uint_t dest = get_label_dest(as, label); - mp_int_t rel = dest - as->code_offset; + mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction asm_thumb_op16(as, OP_B_N(rel)); - return as->pass != ASM_THUMB_PASS_EMIT || SIGNED_FIT12(rel); + return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT12(rel); } #define OP_BCC_N(cond, byte_offset) (0xd000 | ((cond) << 8) | (((byte_offset) >> 1) & 0x00ff)) @@ -323,11 +229,11 @@ bool asm_thumb_b_n_label(asm_thumb_t *as, uint label) { bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide) { mp_uint_t dest = get_label_dest(as, label); - mp_int_t rel = dest - as->code_offset; + mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction if (!wide) { asm_thumb_op16(as, OP_BCC_N(cond, rel)); - return as->pass != ASM_THUMB_PASS_EMIT || SIGNED_FIT9(rel); + return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT9(rel); } else { asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel)); return true; @@ -339,10 +245,10 @@ bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide) { bool asm_thumb_bl_label(asm_thumb_t *as, uint label) { mp_uint_t dest = get_label_dest(as, label); - mp_int_t rel = dest - as->code_offset; + mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction asm_thumb_op32(as, OP_BL_HI(rel), OP_BL_LO(rel)); - return as->pass != ASM_THUMB_PASS_EMIT || SIGNED_FIT23(rel); + return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT23(rel); } void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) { @@ -367,13 +273,13 @@ void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32) { // TODO this is very inefficient, improve it! void asm_thumb_mov_reg_i32_aligned(asm_thumb_t *as, uint reg_dest, int i32) { // align on machine-word + 2 - if ((as->code_offset & 3) == 0) { + if ((as->base.code_offset & 3) == 0) { asm_thumb_op16(as, ASM_THUMB_OP_NOP); } // jump over the i32 value (instruction prefetch adds 2 to PC) asm_thumb_op16(as, OP_B_N(2)); // store i32 on machine-word aligned boundary - asm_thumb_data(as, 4, i32); + mp_asm_base_data(&as->base, 4, i32); // do the actual load of the i32 value asm_thumb_mov_reg_i32_optimised(as, reg_dest, i32); } @@ -384,14 +290,14 @@ void asm_thumb_mov_reg_i32_aligned(asm_thumb_t *as, uint reg_dest, int i32) { void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num, uint rlo_src) { assert(rlo_src < ASM_THUMB_REG_R8); int word_offset = local_num; - assert(as->pass < ASM_THUMB_PASS_EMIT || word_offset >= 0); + assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0); asm_thumb_op16(as, OP_STR_TO_SP_OFFSET(rlo_src, word_offset)); } void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num) { assert(rlo_dest < ASM_THUMB_REG_R8); int word_offset = local_num; - assert(as->pass < ASM_THUMB_PASS_EMIT || word_offset >= 0); + assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0); asm_thumb_op16(as, OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset)); } @@ -400,7 +306,7 @@ void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num) { void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num) { assert(rlo_dest < ASM_THUMB_REG_R8); int word_offset = local_num; - assert(as->pass < ASM_THUMB_PASS_EMIT || word_offset >= 0); + assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0); asm_thumb_op16(as, OP_ADD_REG_SP_OFFSET(rlo_dest, word_offset)); } @@ -410,7 +316,7 @@ void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num) void asm_thumb_b_label(asm_thumb_t *as, uint label) { mp_uint_t dest = get_label_dest(as, label); - mp_int_t rel = dest - as->code_offset; + mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction if (dest != (mp_uint_t)-1 && rel <= -4) { // is a backwards jump, so we know the size of the jump on the first pass @@ -429,7 +335,7 @@ void asm_thumb_b_label(asm_thumb_t *as, uint label) { void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) { mp_uint_t dest = get_label_dest(as, label); - mp_int_t rel = dest - as->code_offset; + mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction if (dest != (mp_uint_t)-1 && rel <= -4) { // is a backwards jump, so we know the size of the jump on the first pass |