summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gen_x86.c84
-rw-r--r--gen_x86.h4
-rw-r--r--m68k_to_x86.c114
-rw-r--r--m68k_to_x86.h7
-rw-r--r--runtime.S136
5 files changed, 292 insertions, 53 deletions
diff --git a/gen_x86.c b/gen_x86.c
index 70b77f8..2708c13 100644
--- a/gen_x86.c
+++ b/gen_x86.c
@@ -37,6 +37,7 @@
#define OP_CALL 0xE8
#define OP_JMP 0xE9
#define OP_JMP_BYTE 0xEB
+#define OP_NOT_NEG 0xF6
#define OP_SINGLE_EA 0xFF
#define OP2_JCC 0x80
@@ -68,6 +69,10 @@
#define OP_EX_BTR 0x6
#define OP_EX_BTC 0x7
+#define OP_EX_TEST_I 0x0
+#define OP_EX_NOT 0x2
+#define OP_EX_NEG 0x3
+
#define OP_EX_INC 0x0
#define OP_EX_DEC 0x1
#define OP_EX_CALL_EA 0x2
@@ -222,6 +227,61 @@ uint8_t * x86_rrind_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t
return out;
}
+uint8_t * x86_r_size(uint8_t * out, uint8_t opcode, uint8_t opex, uint8_t dst, uint8_t size)
+{
+ uint8_t tmp;
+ if (size == SZ_W) {
+ *(out++) = PRE_SIZE;
+ }
+ if (size == SZ_Q || dst >= R8) {
+ *out = PRE_REX;
+ if (size == SZ_Q) {
+ *out |= REX_QUAD;
+ }
+ if (dst >= R8) {
+ *out |= REX_RM_FIELD;
+ dst -= (R8 - X86_R8);
+ }
+ out++;
+ }
+ if (size == SZ_B) {
+ if (dst >= AH && dst <= BH) {
+ dst -= (AH-X86_AH);
+ }
+ } else {
+ opcode |= BIT_SIZE;
+ }
+ *(out++) = opcode;
+ *(out++) = MODE_REG_DIRECT | dst | (opex << 3);
+ return out;
+}
+
+uint8_t * x86_rdisp8_size(uint8_t * out, uint8_t opcode, uint8_t opex, uint8_t dst, int8_t disp, uint8_t size)
+{
+ uint8_t tmp;
+ if (size == SZ_W) {
+ *(out++) = PRE_SIZE;
+ }
+ if (size == SZ_Q || dst >= R8) {
+ *out = PRE_REX;
+ if (size == SZ_Q) {
+ *out |= REX_QUAD;
+ }
+ if (dst >= R8) {
+ *out |= REX_RM_FIELD;
+ dst -= (R8 - X86_R8);
+ }
+ out++;
+ }
+ if (size != SZ_B) {
+ opcode |= BIT_SIZE;
+ }
+ *(out++) = opcode;
+ *(out++) = MODE_REG_DISPLACE8 | dst | (opex << 3);
+ *(out++) = disp;
+ return out;
+}
+
uint8_t * x86_ir(uint8_t * out, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, int32_t val, uint8_t dst, uint8_t size)
{
uint8_t sign_extend = 0;
@@ -297,9 +357,6 @@ uint8_t * x86_irdisp8(uint8_t * out, uint8_t opcode, uint8_t op_ex, int32_t val,
}
out++;
}
- if (dst >= AH && dst <= BH) {
- dst -= (AH-X86_AH);
- }
if (size != SZ_B) {
opcode |= BIT_SIZE;
}
@@ -718,6 +775,26 @@ uint8_t * cmp_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst,
return x86_rrdisp8_sizedir(out, OP_CMP, dst, src_base, disp, size, BIT_DIR);
}
+uint8_t * not_r(uint8_t * out, uint8_t dst, uint8_t size)
+{
+ return x86_r_size(out, OP_NOT_NEG, OP_EX_NOT, dst, size);
+}
+
+uint8_t * neg_r(uint8_t * out, uint8_t dst, uint8_t size)
+{
+ return x86_r_size(out, OP_NOT_NEG, OP_EX_NEG, dst, size);
+}
+
+uint8_t * not_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_NOT, dst_base, disp, size);
+}
+
+uint8_t * neg_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_NEG, dst_base, disp, size);
+}
+
uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
return x86_rr_sizedir(out, OP_MOV, src, dst, size);
@@ -1147,6 +1224,7 @@ uint8_t * jmp_r(uint8_t * out, uint8_t dst)
{
*(out++) = OP_SINGLE_EA;
*(out++) = MODE_REG_DIRECT | dst | (OP_EX_JMP_EA << 3);
+ return out;
}
uint8_t * call(uint8_t * out, uint8_t * fun)
diff --git a/gen_x86.h b/gen_x86.h
index adce757..ebc1f97 100644
--- a/gen_x86.h
+++ b/gen_x86.h
@@ -123,6 +123,10 @@ uint8_t * sub_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp,
uint8_t * sub_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size);
uint8_t * cmp_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size);
uint8_t * cmp_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size);
+uint8_t * not_r(uint8_t * out, uint8_t dst, uint8_t size);
+uint8_t * neg_r(uint8_t * out, uint8_t dst, uint8_t size);
+uint8_t * not_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
+uint8_t * neg_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
uint8_t * mov_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size);
uint8_t * mov_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size);
diff --git a/m68k_to_x86.c b/m68k_to_x86.c
index 1235411..d53f98b 100644
--- a/m68k_to_x86.c
+++ b/m68k_to_x86.c
@@ -26,7 +26,7 @@ typedef struct {
uint8_t cycles;
} x86_ea;
-void handle_cycle_limit();
+void handle_cycle_limit_int();
void m68k_read_word_scratch1();
void m68k_read_long_scratch1();
void m68k_read_byte_scratch1();
@@ -37,6 +37,10 @@ void m68k_write_byte();
void m68k_save_context();
void m68k_modified_ret_addr();
void m68k_native_addr();
+void m68k_native_addr_and_sync();
+void set_sr();
+void set_ccr();
+void get_sr();
void m68k_start_context(uint8_t * addr, m68k_context * context);
uint8_t * cycles(uint8_t * dst, uint32_t num)
@@ -44,6 +48,17 @@ uint8_t * cycles(uint8_t * dst, uint32_t num)
dst = add_ir(dst, num, CYCLES, SZ_D);
}
+uint8_t * check_cycles_int(uint8_t * dst, uint32_t address)
+{
+ dst = cmp_rr(dst, LIMIT, CYCLES, SZ_D);
+ uint8_t * jmp_off = dst+1;
+ dst = jcc(dst, CC_NC, dst + 7);
+ dst = mov_ir(dst, address, SCRATCH1, SZ_D);
+ dst = call(dst, (uint8_t *)handle_cycle_limit_int);
+ *jmp_off = dst - (jmp_off+1);
+ return dst;
+}
+
int8_t native_reg(m68k_op_info * op, x86_68k_options * opts)
{
if (op->addr_mode == MODE_REG) {
@@ -513,14 +528,12 @@ void process_deferred(x86_68k_options * opts)
void map_native_address(native_map_slot * native_code_map, uint32_t address, uint8_t * native_addr)
{
- //FIXME: This probably isn't going to work with real code in a lot of cases, no guarantee that
- //all the code in 1KB block is going to be translated at the same time
address &= 0xFFFFFF;
uint32_t chunk = address / NATIVE_CHUNK_SIZE;
if (!native_code_map[chunk].base) {
native_code_map[chunk].base = native_addr;
- native_code_map[chunk].offsets = malloc(sizeof(uint16_t) * NATIVE_CHUNK_SIZE);
- memset(native_code_map[chunk].offsets, 0xFF, sizeof(uint16_t) * NATIVE_CHUNK_SIZE);
+ native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
+ memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
}
uint32_t offset = address % NATIVE_CHUNK_SIZE;
native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base;
@@ -1407,6 +1420,7 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
{
uint8_t * end_off;
map_native_address(opts->native_code_map, inst->address, dst);
+ dst = check_cycles_int(dst, inst->address);
if (inst->op == M68K_MOVE) {
return translate_m68k_move(dst, inst, opts);
} else if(inst->op == M68K_LEA) {
@@ -1653,9 +1667,7 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
dst = call(dst, (uint8_t *)print_regs_exit);
break;
- /*case M68K_JSR:
- case M68K_LEA:
- case M68K_MOVE_FROM_SR:
+ /*case M68K_MOVE_FROM_SR:
break;*/
case M68K_MOVE_CCR:
case M68K_MOVE_SR:
@@ -1677,34 +1689,16 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
}
dst = cycles(dst, 12);
} else {
- if (src_op.mode == MODE_REG_DIRECT) {
- dst = mov_rr(dst, src_op.base, FLAG_C, SZ_B);
- } else {
- dst = mov_rdisp8r(dst, src_op.base, src_op.disp, FLAG_C, SZ_B);
- }
- dst = mov_rr(dst, FLAG_C, FLAG_V, SZ_B);
- dst = and_ir(dst, 1, FLAG_C, SZ_B);
- dst = shr_ir(dst, 1, FLAG_V, SZ_B);
- dst = mov_rr(dst, FLAG_V, FLAG_Z, SZ_B);
- dst = and_ir(dst, 1, FLAG_V, SZ_B);
- dst = shr_ir(dst, 1, FLAG_Z, SZ_B);
- dst = mov_rr(dst, FLAG_Z, FLAG_N, SZ_B);
- dst = and_ir(dst, 1, FLAG_Z, SZ_B);
- dst = shr_ir(dst, 1, FLAG_N, SZ_B);
- dst = mov_rr(dst, 1, SCRATCH2, SZ_B);
- dst = shr_ir(dst, 1, SCRATCH2, SZ_B);
- dst = and_ir(dst, 1, SCRATCH2, SZ_B);
- dst = mov_rrind(dst, SCRATCH2, CONTEXT, SZ_B);
- dst = cycles(dst, 12);
- if (inst->op == M68K_MOVE_SR) {
+ if (src_op.base != SCRATCH1) {
if (src_op.mode == MODE_REG_DIRECT) {
- dst = mov_rr(dst, src_op.base, SCRATCH2, SZ_W);
+ dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_W);
} else {
- dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_W);
+ dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_W);
}
}
- dst = shr_ir(dst, 8, SCRATCH2, SZ_B);
- dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, offsetof(m68k_context, status), SZ_B);
+ dst = call(dst, (uint8_t *)(inst->op == M68K_MOVE_SR ? set_sr : set_ccr));
+ dst = cycles(dst, 12);
+
}
break;
case M68K_MOVE_USP:
@@ -1730,15 +1724,36 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
/*case M68K_MOVEP:
case M68K_MULS:
case M68K_MULU:
- case M68K_NBCD:
+ case M68K_NBCD:*/
case M68K_NEG:
- case M68K_NEGX:
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = neg_r(dst, dst_op.base, inst->extra.size);
+ } else {
+ dst = not_rdisp8(dst, dst_op.base, dst_op.disp, inst->extra.size);
+ }
+ dst = mov_ir(dst, 0, FLAG_C, SZ_B);
+ dst = setcc_r(dst, CC_Z, FLAG_Z);
+ dst = setcc_r(dst, CC_S, FLAG_N);
+ dst = mov_ir(dst, 0, FLAG_V, SZ_B);
+ dst = m68k_save_result(inst, dst, opts);
+ break;
+ /*case M68K_NEGX:
break;*/
case M68K_NOP:
dst = cycles(dst, BUS);
break;
- //case M68K_NOT:
- // break;
+ case M68K_NOT:
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = not_r(dst, dst_op.base, inst->extra.size);
+ } else {
+ dst = not_rdisp8(dst, dst_op.base, dst_op.disp, inst->extra.size);
+ }
+ dst = mov_ir(dst, 0, FLAG_C, SZ_B);
+ dst = setcc_r(dst, CC_Z, FLAG_Z);
+ dst = setcc_r(dst, CC_S, FLAG_N);
+ dst = mov_ir(dst, 0, FLAG_V, SZ_B);
+ dst = m68k_save_result(inst, dst, opts);
+ break;
case M68K_OR:
dst = cycles(dst, BUS);
if (src_op.mode == MODE_REG_DIRECT) {
@@ -1769,9 +1784,28 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
case M68K_ROL:
case M68K_ROR:
case M68K_ROXL:
- case M68K_ROXR:
+ case M68K_ROXR:*/
case M68K_RTE:
- case M68K_RTR:
+ dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D);
+ dst = call(dst, (uint8_t *)m68k_read_long_scratch1);
+ dst = push_r(dst, SCRATCH1);
+ dst = add_ir(dst, 4, opts->aregs[7], SZ_D);
+ dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D);
+ dst = call(dst, (uint8_t *)m68k_read_word_scratch1);
+ dst = add_ir(dst, 2, opts->aregs[7], SZ_D);
+ dst = call(dst, (uint8_t *)set_sr);
+ dst = pop_r(dst, SCRATCH1);
+ dst = bt_irdisp8(dst, 5, CONTEXT, offsetof(m68k_context, status), SZ_B);
+ end_off = dst+1;
+ dst = jcc(dst, CC_NC, dst+2);
+ dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D);
+ dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_D);
+ dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
+ *end_off = dst - (end_off+1);
+ dst = call(dst, (uint8_t *)m68k_native_addr_and_sync);
+ dst = jmp_r(dst, SCRATCH1);
+ break;
+ /*case M68K_RTR:
case M68K_SBCD:
case M68K_SCC:
case M68K_STOP:
@@ -1857,6 +1891,9 @@ uint8_t * translate_m68k_stream(uint8_t * dst, uint8_t * dst_end, uint32_t addre
{
m68kinst instbuf;
x86_68k_options * opts = context->options;
+ if(get_native_address(opts->native_code_map, address)) {
+ return dst;
+ }
char disbuf[1024];
uint16_t *encoded = context->mem_pointers[0] + address/2, *next;
do {
@@ -1918,5 +1955,6 @@ void init_68k_context(m68k_context * context, native_map_slot * native_code_map,
memset(context, 0, sizeof(m68k_context));
context->native_code_map = native_code_map;
context->options = opts;
+ context->int_cycle = 0xFFFFFFFF;
}
diff --git a/m68k_to_x86.h b/m68k_to_x86.h
index 35a593d..12d4f8b 100644
--- a/m68k_to_x86.h
+++ b/m68k_to_x86.h
@@ -4,11 +4,11 @@
#define NUM_MEM_AREAS 4
#define NATIVE_MAP_CHUNKS (32*1024)
#define NATIVE_CHUNK_SIZE ((16 * 1024 * 1024 / NATIVE_MAP_CHUNKS)/2)
-#define INVALID_OFFSET 0xFFFF
+#define INVALID_OFFSET 0xFFFFFFFF
typedef struct {
uint8_t *base;
- uint16_t *offsets;
+ int32_t *offsets;
} native_map_slot;
typedef struct deferred_addr {
@@ -35,9 +35,12 @@ typedef struct {
uint32_t target_cycle; //cycle at which the next synchronization or interrupt occurs
uint32_t current_cycle;
uint32_t sync_cycle;
+ uint32_t int_cycle;
+ uint32_t int_num;
uint16_t *mem_pointers[NUM_MEM_AREAS];
void *next_context;
uint16_t value;
+
native_map_slot *native_code_map;
void *options;
} m68k_context;
diff --git a/runtime.S b/runtime.S
index 355d31c..e55b0bc 100644
--- a/runtime.S
+++ b/runtime.S
@@ -1,11 +1,107 @@
.global handle_cycle_limit
handle_cycle_limit:
+ cmp 84(%rsi), %eax
+ jb skip_sync
call m68k_save_context
mov %rsi, %rdi
call sync_components
mov %rax, %rsi
call m68k_load_context
+skip_sync:
+ ret
+
+ .global handle_cycle_limit_int
+handle_cycle_limit_int:
+ cmp 88(%rsi), %eax
+ jb skip_int
+ push %rcx
+ /* swap USP and SSP if not already in supervisor mode */
+ bt $5, 5(%rsi)
+ jc already_supervisor
+ mov 72(%rsi), %edi
+ mov %r15d, 72(%rsi)
+ mov %edi, %r15d
+already_supervisor:
+ /* save status register on stack */
+ sub $2, %r15d
+ mov %r15d, %edi
+ call get_sr
+ call m68k_write_word
+ /* update status register */
+ andb $0xF8, 5(%rsi)
+ mov 92(%rsi), %cl
+ or $0x20, %cl
+ or %cl, 5(%rsi)
+ /* save PC */
+ sub $4, %r15d
+ mov %r15d, %edi
+ pop %rcx
+ call m68k_write_long_lowfirst
+ /* calculate interrupt vector address */
+ mov 92(%rsi), %ecx
+ shl $2, %ecx
+ add $0x60, %ecx
+ call m68k_read_long_scratch1
+ call m68k_native_addr_and_sync
+ add $24, %eax
+ /* discard function return address */
+ pop %rdi
+ jmp *%rcx
+skip_int:
+ ret
+
+ .global get_sr
+get_sr:
+ mov 5(%rsi), %cl
+ shl $8, %cx
+ mov (%rsi), %cl
+ shl $1, %cl
+ or %bl, %cl
+ shl $1, %cl
+ or %dl, %cl
+ shl $1, %cl
+ or %bh, %cl
+ shl $1, %cl
+ or %dh, %cl
+ ret
+
+ .global set_sr
+set_sr:
+ mov %cl, %dh
+ and $1, %dh
+ shr $1, %cl
+ mov %cl, %bh
+ and $1, %bh
+ shr $1, %cl
+ mov %cl, %dl
+ and $1, %dl
+ shr $1, %cl
+ mov %cl, %bl
+ and $1, %bl
+ shr $1, %cl
+ and $1, %cl
+ mov %cl, (%rsi)
+ shr $8, %cx
+ mov %cl, 5(%rsi)
+ ret
+
+ .global set_ccr
+set_ccr:
+ mov %cl, %dh
+ and $1, %dh
+ shr $1, %cl
+ mov %cl, %bh
+ and $1, %bh
+ shr $1, %cl
+ mov %cl, %dl
+ and $1, %dl
+ shr $1, %cl
+ mov %cl, %bl
+ and $1, %bl
+ shr $1, %cl
+ and $1, %cl
+ mov %cl, (%rsi)
ret
do_vdp_port_write:
@@ -22,7 +118,7 @@ do_vdp_port_read:
call vdp_port_read
mov %rax, %rsi
call m68k_load_context
- mov 128(%rsi), %cx
+ mov 136(%rsi), %cx
ret
do_io_write:
@@ -40,7 +136,7 @@ do_io_read:
call io_read
mov %rax, %rsi
call m68k_load_context
- mov 128(%rsi), %cl
+ mov 136(%rsi), %cl
ret
bad_access_msg:
@@ -76,7 +172,7 @@ try_fifo_write:
push %rdx
push %rbx
/* fetch VDP context pointer from 68K context */
- mov 120(%rsi), %rdx
+ mov 128(%rsi), %rdx
/* get fifo_cur and compare it to fifo_end */
mov (%rdx), %rbx
cmp %rbx, 8(%rdx)
@@ -165,7 +261,7 @@ m68k_write_long_highfirst:
inccycles:
cmp %rbp, %rax
- jge do_limit
+ jnb do_limit
add $4, %rax
ret
do_limit:
@@ -271,10 +367,30 @@ dyn_addr_msg:
.global m68k_native_addr
m68k_native_addr:
- lea dyn_addr_msg(%rip), %rdi
- call puts
- mov $1, %rdi
- call exit
+ call m68k_save_context
+ push %rcx
+ mov %rsi, %rdi
+ call sync_components
+ pop %rsi
+ push %rax
+ mov 144(%rax), %rdi
+ call get_native_address
+ mov %rax, %rcx
+ pop %rsi
+ call m68k_load_context
+ ret
+
+ .global m68k_native_addr_and_sync
+m68k_native_addr_and_sync:
+ call m68k_save_context
+ push %rsi
+ mov 144(%rsi), %rdi
+ mov %ecx, %esi
+ call get_native_address
+ mov %rax, %rcx
+ pop %rsi
+ call m68k_load_context
+ ret
.global m68k_save_context
m68k_save_context:
@@ -305,8 +421,8 @@ m68k_load_context:
mov 68(%rsi), %r15d /* a7 */
mov 76(%rsi), %ebp /* target cycle count */
mov 80(%rsi), %eax /* current cycle count */
- mov 88(%rsi), %r8d /* cartridge address */
- mov 96(%rsi), %r9d /* work ram address */
+ mov 96(%rsi), %r8d /* cartridge address */
+ mov 104(%rsi), %r9d /* work ram address */
ret
.global m68k_start_context