summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gen.h2
-rw-r--r--gen_x86.c8
-rw-r--r--m68k_core.c174
-rw-r--r--m68k_core.h12
4 files changed, 145 insertions, 51 deletions
diff --git a/gen.h b/gen.h
index 7d9b373..7eeeb27 100644
--- a/gen.h
+++ b/gen.h
@@ -24,6 +24,8 @@ void init_code_info(code_info *code);
void call(code_info *code, code_ptr fun);
void jmp(code_info *code, code_ptr dest);
void jmp_r(code_info *code, uint8_t dst);
+//standard return from subroutine instruction
+void rts(code_info *code);
//call a function and put the arguments in the appropriate place according to the host ABI
void call_args(code_info *code, code_ptr fun, uint32_t num_args, ...);
//like the above, but call a function pointer stored in a register
diff --git a/gen_x86.c b/gen_x86.c
index a0cbc19..2da8055 100644
--- a/gen_x86.c
+++ b/gen_x86.c
@@ -1999,9 +1999,10 @@ void call_noalign(code_info *code, code_ptr fun)
code->cur = out;
}
-
+volatile int foo;
void call(code_info *code, code_ptr fun)
{
+ foo = *fun;
code->stack_off += sizeof(void *);
int32_t adjust = 0;
if (code->stack_off & 0xF) {
@@ -2064,6 +2065,11 @@ void retn(code_info *code)
code->cur = out;
}
+void rts(code_info *code)
+{
+ retn(code);
+}
+
void cdq(code_info *code)
{
check_alloc_code(code, 1);
diff --git a/m68k_core.c b/m68k_core.c
index 0efaeec..64bee47 100644
--- a/m68k_core.c
+++ b/m68k_core.c
@@ -385,15 +385,127 @@ static void translate_m68k_move_usp(m68k_options *opts, m68kinst *inst)
}
}
+static void translate_movem_regtomem_reglist(m68k_options * opts, m68kinst *inst)
+{
+ code_info *code = &opts->gen.code;
+ int8_t bit,reg,dir;
+ if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
+ reg = 15;
+ dir = -1;
+ } else {
+ reg = 0;
+ dir = 1;
+ }
+ for(bit=0; reg < 16 && reg >= 0; reg += dir, bit++) {
+ if (inst->src.params.immed & (1 << bit)) {
+ if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
+ subi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
+ }
+ push_native(opts, opts->gen.scratch2);
+ if (reg > 7) {
+ areg_to_native(opts, reg-8, opts->gen.scratch1);
+ } else {
+ dreg_to_native(opts, reg, opts->gen.scratch1);
+ }
+ if (inst->extra.size == OPSIZE_LONG) {
+ call(code, opts->write_32_lowfirst);
+ } else {
+ call(code, opts->write_16);
+ }
+ pop_native(opts, opts->gen.scratch2);
+ if (inst->dst.addr_mode != MODE_AREG_PREDEC) {
+ addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
+ }
+ }
+ }
+}
+
+static void translate_movem_memtoreg_reglist(m68k_options * opts, m68kinst *inst)
+{
+ code_info *code = &opts->gen.code;
+ for(uint8_t reg = 0; reg < 16; reg ++) {
+ if (inst->dst.params.immed & (1 << reg)) {
+ push_native(opts, opts->gen.scratch1);
+ if (inst->extra.size == OPSIZE_LONG) {
+ call(code, opts->read_32);
+ } else {
+ call(code, opts->read_16);
+ }
+ if (inst->extra.size == OPSIZE_WORD) {
+ sign_extend16_native(opts, opts->gen.scratch1);
+ }
+ if (reg > 7) {
+ native_to_areg(opts, opts->gen.scratch1, reg-8);
+ } else {
+ native_to_dreg(opts, opts->gen.scratch1, reg);
+ }
+ pop_native(opts, opts->gen.scratch1);
+ addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch1);
+ }
+ }
+}
+
+static code_ptr get_movem_impl(m68k_options *opts, m68kinst *inst)
+{
+ uint8_t reg_to_mem = inst->src.addr_mode == MODE_REG;
+ uint8_t size = inst->extra.size;
+ int8_t dir = reg_to_mem && inst->dst.addr_mode == MODE_AREG_PREDEC ? -1 : 1;
+ uint16_t reglist = reg_to_mem ? inst->src.params.immed : inst->dst.params.immed;
+ for (uint32_t i = 0; i < opts->num_movem; i++)
+ {
+ if (
+ opts->big_movem[i].reglist == reglist && opts->big_movem[i].reg_to_mem == reg_to_mem
+ && opts->big_movem[i].size == size && opts->big_movem[i].dir == dir
+ ) {
+ return opts->big_movem[i].impl;
+ }
+ }
+ if (opts->num_movem == opts->movem_storage) {
+ opts->movem_storage *= 2;
+ opts->big_movem = realloc(opts->big_movem, sizeof(movem_fun) * opts->movem_storage);
+ }
+ if (!opts->extra_code.cur) {
+ init_code_info(&opts->extra_code);
+ }
+ check_alloc_code(&opts->extra_code, 512);
+ code_ptr impl = opts->extra_code.cur;
+ code_info tmp = opts->gen.code;
+ opts->gen.code = opts->extra_code;
+ if (reg_to_mem) {
+ translate_movem_regtomem_reglist(opts, inst);
+ } else {
+ translate_movem_memtoreg_reglist(opts, inst);
+ }
+ opts->extra_code = opts->gen.code;
+ opts->gen.code = tmp;
+
+ rts(&opts->extra_code);
+ return impl;
+}
+
static void translate_m68k_movem(m68k_options * opts, m68kinst * inst)
{
code_info *code = &opts->gen.code;
- int8_t bit,reg,sec_reg;
uint8_t early_cycles;
+ uint16_t num_regs = inst->src.addr_mode == MODE_REG ? inst->src.params.immed : inst->dst.params.immed;
+ {
+ //TODO: Move this popcount alg to a utility function
+ uint16_t a = (num_regs & 0b1010101010101010) >> 1;
+ uint16_t b = num_regs & 0b0101010101010101;
+ num_regs = a + b;
+ a = (num_regs & 0b1100110011001100) >> 2;
+ b = num_regs & 0b0011001100110011;
+ num_regs = a + b;
+ a = (num_regs & 0b1111000011110000) >> 4;
+ b = num_regs & 0b0000111100001111;
+ num_regs = a + b;
+ a = (num_regs & 0b1111111100000000) >> 8;
+ b = num_regs & 0b0000000011111111;
+ num_regs = a + b;
+ }
if(inst->src.addr_mode == MODE_REG) {
//reg to mem
early_cycles = 8;
- int8_t dir;
switch (inst->dst.addr_mode)
{
case MODE_AREG_INDIRECT:
@@ -426,35 +538,12 @@ static void translate_m68k_movem(m68k_options * opts, m68kinst * inst)
m68k_disasm(inst, disasm_buf);
fatal_error("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
}
- if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
- reg = 15;
- dir = -1;
- } else {
- reg = 0;
- dir = 1;
- }
+
cycles(&opts->gen, early_cycles);
- for(bit=0; reg < 16 && reg >= 0; reg += dir, bit++) {
- if (inst->src.params.immed & (1 << bit)) {
- if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
- subi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
- }
- push_native(opts, opts->gen.scratch2);
- if (reg > 7) {
- areg_to_native(opts, reg-8, opts->gen.scratch1);
- } else {
- dreg_to_native(opts, reg, opts->gen.scratch1);
- }
- if (inst->extra.size == OPSIZE_LONG) {
- call(code, opts->write_32_lowfirst);
- } else {
- call(code, opts->write_16);
- }
- pop_native(opts, opts->gen.scratch2);
- if (inst->dst.addr_mode != MODE_AREG_PREDEC) {
- addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
- }
- }
+ if (num_regs <= 9) {
+ translate_movem_regtomem_reglist(opts, inst);
+ } else {
+ call(code, get_movem_impl(opts, inst));
}
if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
native_to_areg(opts, opts->gen.scratch2, inst->dst.params.regs.pri);
@@ -470,7 +559,6 @@ static void translate_m68k_movem(m68k_options * opts, m68kinst * inst)
break;
case MODE_AREG_DISPLACE:
early_cycles += BUS;
- reg = opts->gen.scratch2;
calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
break;
case MODE_AREG_INDEX_DISP8:
@@ -497,25 +585,11 @@ static void translate_m68k_movem(m68k_options * opts, m68kinst * inst)
fatal_error("%X: %s\naddress mode %d not implemented (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode);
}
cycles(&opts->gen, early_cycles);
- for(reg = 0; reg < 16; reg ++) {
- if (inst->dst.params.immed & (1 << reg)) {
- push_native(opts, opts->gen.scratch1);
- if (inst->extra.size == OPSIZE_LONG) {
- call(code, opts->read_32);
- } else {
- call(code, opts->read_16);
- }
- if (inst->extra.size == OPSIZE_WORD) {
- sign_extend16_native(opts, opts->gen.scratch1);
- }
- if (reg > 7) {
- native_to_areg(opts, opts->gen.scratch1, reg-8);
- } else {
- native_to_dreg(opts, opts->gen.scratch1, reg);
- }
- pop_native(opts, opts->gen.scratch1);
- addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch1);
- }
+
+ if (num_regs <= 9) {
+ translate_movem_memtoreg_reglist(opts, inst);
+ } else {
+ call(code, get_movem_impl(opts, inst));
}
if (inst->src.addr_mode == MODE_AREG_POSTINC) {
native_to_areg(opts, opts->gen.scratch1, inst->src.params.regs.pri);
diff --git a/m68k_core.h b/m68k_core.h
index 33daa70..786447f 100644
--- a/m68k_core.h
+++ b/m68k_core.h
@@ -24,6 +24,14 @@ struct m68kinst;
typedef void (*start_fun)(uint8_t * addr, void * context);
typedef struct {
+ code_ptr impl;
+ uint16_t reglist;
+ uint8_t reg_to_mem;
+ uint8_t size;
+ int8_t dir;
+} movem_fun;
+
+typedef struct {
cpu_options gen;
int8_t dregs[8];
@@ -46,6 +54,10 @@ typedef struct {
code_ptr get_sr;
code_ptr set_sr;
code_ptr set_ccr;
+ code_info extra_code;
+ movem_fun *big_movem;
+ uint32_t num_movem;
+ uint32_t movem_storage;
} m68k_options;
typedef struct m68k_context {