py: Factor out common code from assemblers into asmbase.[ch].

All assemblers should "derive" from mp_asm_base_t.
This commit is contained in:
Damien George
2016-11-28 09:24:50 +11:00
parent 21e1703d37
commit 612599587b
13 changed files with 262 additions and 565 deletions

View File

@@ -38,50 +38,6 @@
#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000)
struct _asm_arm_t {
uint 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;
uint push_reglist;
uint stack_adjust;
};
asm_arm_t *asm_arm_new(uint max_num_labels) {
asm_arm_t *as;
as = m_new0(asm_arm_t, 1);
as->max_num_labels = max_num_labels;
as->label_offsets = m_new(mp_uint_t, max_num_labels);
return as;
}
void asm_arm_free(asm_arm_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_arm_t, as);
}
void asm_arm_start_pass(asm_arm_t *as, uint pass) {
if (pass == ASM_ARM_PASS_COMPUTE) {
memset(as->label_offsets, -1, as->max_num_labels * sizeof(mp_uint_t));
} else if (pass == ASM_ARM_PASS_EMIT) {
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size);
if (as->code_base == NULL) {
assert(0);
}
}
as->pass = pass;
as->code_offset = 0;
}
void asm_arm_end_pass(asm_arm_t *as) {
if (as->pass == ASM_ARM_PASS_EMIT) {
#ifdef __arm__
@@ -97,32 +53,6 @@ void asm_arm_end_pass(asm_arm_t *as) {
}
}
// all functions must go through this one to emit bytes
// if as->pass < ASM_ARM_PASS_EMIT, then this function only returns a buffer of 4 bytes length
STATIC byte *asm_arm_get_cur_to_write_bytes(asm_arm_t *as, int num_bytes_to_write) {
if (as->pass < ASM_ARM_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_arm_get_code_pos(asm_arm_t *as) {
return as->code_offset;
}
uint asm_arm_get_code_size(asm_arm_t *as) {
return as->code_size;
}
void *asm_arm_get_code(asm_arm_t *as) {
return as->code_base;
}
// Insert word into instruction flow
STATIC void emit(asm_arm_t *as, uint op) {
*(uint*)asm_arm_get_cur_to_write_bytes(as, 4) = op;
@@ -263,35 +193,6 @@ void asm_arm_pop(asm_arm_t *as, uint reglist) {
emit_al(as, asm_arm_op_pop(reglist));
}
void asm_arm_label_assign(asm_arm_t *as, uint label) {
assert(label < as->max_num_labels);
if (as->pass < ASM_ARM_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
assert(as->label_offsets[label] == as->code_offset);
}
}
void asm_arm_align(asm_arm_t* as, uint align) {
// TODO fill unused data with NOPs?
as->code_offset = (as->code_offset + align - 1) & (~(align - 1));
}
void asm_arm_data(asm_arm_t* as, uint bytesize, uint val) {
byte *c = asm_arm_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_ARM_PASS_EMIT) {
// little endian
for (uint i = 0; i < bytesize; i++) {
*c++ = val;
val >>= 8;
}
}
}
void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src) {
emit_al(as, asm_arm_op_mov_reg(reg_dest, reg_src));
}