# HG changeset patch # User Mike Pavone # Date 1356548944 28800 # Node ID 6331ddec228f96465029b1da217375c51fb012a9 # Parent 6d231dbe75abcbe184e4ce4ef88593ef03839cfc Initial stab at interrupt support. Make native code offsets bigger so I don't have to worry about overflowing the offset. Implement neg and not (untested). diff -r 6d231dbe75ab -r 6331ddec228f gen_x86.c --- a/gen_x86.c Sat Dec 22 21:37:25 2012 -0800 +++ b/gen_x86.c Wed Dec 26 11:09:04 2012 -0800 @@ -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 @@ 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 @@ } out++; } - if (dst >= AH && dst <= BH) { - dst -= (AH-X86_AH); - } if (size != SZ_B) { opcode |= BIT_SIZE; } @@ -718,6 +775,26 @@ 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 @@ { *(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 -r 6d231dbe75ab -r 6331ddec228f gen_x86.h --- a/gen_x86.h Sat Dec 22 21:37:25 2012 -0800 +++ b/gen_x86.h Wed Dec 26 11:09:04 2012 -0800 @@ -123,6 +123,10 @@ 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 -r 6d231dbe75ab -r 6331ddec228f m68k_to_x86.c --- a/m68k_to_x86.c Sat Dec 22 21:37:25 2012 -0800 +++ b/m68k_to_x86.c Wed Dec 26 11:09:04 2012 -0800 @@ -26,7 +26,7 @@ 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_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 @@ 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 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 * 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 @@ 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 @@ } 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 @@ /*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 @@ 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 @@ { 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 @@ memset(context, 0, sizeof(m68k_context)); context->native_code_map = native_code_map; context->options = opts; + context->int_cycle = 0xFFFFFFFF; } diff -r 6d231dbe75ab -r 6331ddec228f m68k_to_x86.h --- a/m68k_to_x86.h Sat Dec 22 21:37:25 2012 -0800 +++ b/m68k_to_x86.h Wed Dec 26 11:09:04 2012 -0800 @@ -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 @@ 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 -r 6d231dbe75ab -r 6331ddec228f runtime.S --- a/runtime.S Sat Dec 22 21:37:25 2012 -0800 +++ b/runtime.S Wed Dec 26 11:09:04 2012 -0800 @@ -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 @@ 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 @@ 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 @@ 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 @@ inccycles: cmp %rbp, %rax - jge do_limit + jnb do_limit add $4, %rax ret do_limit: @@ -271,10 +367,30 @@ .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 @@ 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