# HG changeset patch # User Mike Pavone # Date 1354677192 28800 # Node ID 3e7bfde7606e72191108ae0f596b9e7d48cb87fc # Parent de0085d4ea40b6630c97ed0ab9837c3bb468ecb0 M68K to x86 translation works for a limited subset of instructions and addressing modes diff -r de0085d4ea40 -r 3e7bfde7606e 68kinst.c --- a/68kinst.c Tue Nov 27 22:54:38 2012 -0800 +++ b/68kinst.c Tue Dec 04 19:13:12 2012 -0800 @@ -86,12 +86,12 @@ decoded->extra.cond = (op >> 0x8) & 0xF; } -uint8_t m68K_reg_quick_field(uint16_t op) +uint8_t m68k_reg_quick_field(uint16_t op) { return (op >> 9) & 0x7; } -uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded) +uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) { uint8_t optype = *istream >> 12; uint8_t size; @@ -101,6 +101,7 @@ decoded->op = M68K_INVALID; decoded->src.addr_mode = decoded->dst.addr_mode = MODE_UNUSED; decoded->variant = VAR_NORMAL; + decoded->address = address; switch(optype) { case BIT_MOVEP_IMMED: @@ -122,7 +123,7 @@ break; } decoded->src.addr_mode = MODE_REG; - decoded->src.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->src.params.regs.pri = m68k_reg_quick_field(*istream); decoded->extra.size = OPSIZE_LONG; istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->dst)); } else if ((*istream & 0xF00) == 0x800) { @@ -353,13 +354,13 @@ if (*istream & 0x80) { //memory dest decoded->src.addr_mode = MODE_REG; - decoded->src.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->src.params.regs.pri = m68k_reg_quick_field(*istream); decoded->dst.addr_mode = MODE_AREG_DISPLACE; decoded->dst.params.regs.pri = *istream & 0x7; } else { //memory source decoded->dst.addr_mode = MODE_REG; - decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); decoded->src.addr_mode = MODE_AREG_DISPLACE; decoded->src.params.regs.pri = *istream & 0x7; } @@ -374,8 +375,10 @@ case MOVE_WORD: decoded->op = M68K_MOVE; decoded->extra.size = optype == MOVE_BYTE ? OPSIZE_BYTE : (optype == MOVE_WORD ? OPSIZE_WORD : OPSIZE_LONG); + opmode = (*istream >> 6) & 0x7; + reg = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); - istream = m68k_decode_op_ex(istream, (*istream >> 6) & 0x7, m68K_reg_quick_field(*istream), decoded->extra.size, &(decoded->dst)); + istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); break; case MISC: @@ -383,7 +386,7 @@ decoded->op = M68K_LEA; decoded->extra.size = OPSIZE_LONG; decoded->dst.addr_mode = MODE_AREG; - decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); } else { if (*istream & 0x100) { @@ -401,7 +404,7 @@ } istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); decoded->dst.addr_mode = MODE_REG; - decoded->dst.addr_mode = m68K_reg_quick_field(*istream); + decoded->dst.addr_mode = m68k_reg_quick_field(*istream); } else { opmode = (*istream >> 3) & 0x7; if ((*istream & 0xB80) == 0x880 && opmode != MODE_REG && opmode != MODE_AREG && opmode != MODE_AREG_POSTINC) { @@ -684,7 +687,7 @@ decoded->extra.size = size; decoded->src.addr_mode = MODE_IMMEDIATE; istream = m68k_decode_op(istream, size, &(decoded->dst)); - immed = m68K_reg_quick_field(*istream); + immed = m68k_reg_quick_field(*istream); if (!immed) { immed = 8; } @@ -722,7 +725,7 @@ decoded->src.addr_mode = MODE_IMMEDIATE; decoded->src.params.immed = sign_extend8(*istream & 0xFF); decoded->dst.addr_mode = MODE_REG; - decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); immed = *istream & 0xFF; break; case OR_DIV_SBCD: @@ -785,10 +788,12 @@ //SUBA.l decoded->extra.size = OPSIZE_LONG; decoded->dst.addr_mode = MODE_AREG; + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src)); } else { decoded->extra.size = size; decoded->src.addr_mode = MODE_REG; + decoded->src.params.regs.pri = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, size, &(decoded->dst)); } } else { @@ -797,7 +802,7 @@ decoded->extra.size = size; istream = m68k_decode_op(istream, size, &(decoded->src)); decoded->dst.addr_mode = decoded->src.addr_mode; - decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); } } else { if (size == OPSIZE_INVALID) { @@ -808,7 +813,7 @@ decoded->extra.size = size; decoded->dst.addr_mode = MODE_REG; } - decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); } break; @@ -824,19 +829,19 @@ //CMPM decoded->src.addr_mode = decoded->dst.addr_mode = MODE_AREG_POSTINC; decoded->src.params.regs.pri = decoded->dst.params.regs.pri; - decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); } else { //EOR decoded->op = M68K_EOR; decoded->extra.size = size; decoded->src.addr_mode = MODE_REG; - decoded->src.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->src.params.regs.pri = m68k_reg_quick_field(*istream); } } else { //CMP decoded->extra.size = size; decoded->dst.addr_mode = MODE_REG; - decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, size, &(decoded->src)); } break; @@ -855,18 +860,18 @@ decoded->op = M68K_MULS; decoded->extra.size = OPSIZE_WORD; decoded->dst.addr_mode = MODE_REG; - decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src)); } else if(!(*istream & 0xF0)) { decoded->op = M68K_ABCD; decoded->extra.size = OPSIZE_BYTE; decoded->src.params.regs.pri = *istream & 0x7; - decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); decoded->dst.addr_mode = decoded->src.addr_mode = (*istream & 8) ? MODE_AREG_PREDEC : MODE_REG; } else if(!(*istream & 0x30)) { decoded->op = M68K_EXG; decoded->extra.size = OPSIZE_LONG; - decoded->src.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->src.params.regs.pri = m68k_reg_quick_field(*istream); decoded->dst.params.regs.pri = *istream & 0x7; if (*istream & 0x8) { if (*istream & 0x80) { @@ -882,7 +887,7 @@ decoded->op = M68K_AND; decoded->extra.size = (*istream >> 6); decoded->dst.addr_mode = MODE_REG; - decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); } } else { @@ -890,13 +895,13 @@ decoded->op = M68K_MULU; decoded->extra.size = OPSIZE_WORD; decoded->dst.addr_mode = MODE_REG; - decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src)); } else { decoded->op = M68K_AND; decoded->extra.size = (*istream >> 6); decoded->src.addr_mode = MODE_REG; - decoded->src.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->src.params.regs.pri = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst)); } } @@ -911,10 +916,12 @@ //ADDA.l decoded->extra.size = OPSIZE_LONG; decoded->dst.addr_mode = MODE_AREG; + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src)); } else { decoded->extra.size = size; decoded->src.addr_mode = MODE_REG; + decoded->src.params.regs.pri = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, size, &(decoded->dst)); } } else { @@ -924,7 +931,7 @@ decoded->extra.size = size; istream = m68k_decode_op(istream, size, &(decoded->src)); decoded->dst.addr_mode = decoded->src.addr_mode; - decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); } } else { if (size == OPSIZE_INVALID) { @@ -935,7 +942,7 @@ decoded->extra.size = size; decoded->dst.addr_mode = MODE_REG; } - decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream); + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); } break; diff -r de0085d4ea40 -r 3e7bfde7606e 68kinst.h --- a/68kinst.h Tue Nov 27 22:54:38 2012 -0800 +++ b/68kinst.h Tue Dec 04 19:13:12 2012 -0800 @@ -169,13 +169,14 @@ uint8_t size; uint8_t cond; } extra; + uint32_t address; m68k_op_info src; m68k_op_info dst; } m68kinst; -uint16_t * m68K_decode(uint16_t * istream, m68kinst * dst); +uint16_t * m68k_decode(uint16_t * istream, m68kinst * dst, uint32_t address); uint32_t m68k_cycles(m68kinst * inst); -int m68K_disasm(m68kinst * decoded, char * dst); +int m68k_disasm(m68kinst * decoded, char * dst); #endif diff -r de0085d4ea40 -r 3e7bfde7606e Makefile --- a/Makefile Tue Nov 27 22:54:38 2012 -0800 +++ b/Makefile Tue Dec 04 19:13:12 2012 -0800 @@ -1,7 +1,12 @@ + +all : dis trans dis : dis.o 68kinst.o $(CC) -o dis dis.o 68kinst.o +trans : trans.o 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o + $(CC) -o trans trans.o 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o + test_x86 : test_x86.o gen_x86.o $(CC) -o test_x86 test_x86.o gen_x86.o @@ -12,7 +17,10 @@ $(CC) -c -o $@ $< %.o : %.c - $(CC) -ggdb -c -o $@ $< + $(CC) -ggdb -std=gnu99 -c -o $@ $< + +%.bin : %.s68 + vasmm68k_mot -Fbin -m68000 -spaces -o $@ $< clean : - rm -rf dis test_x86 gen_fib *.o + rm -rf dis trans test_x86 gen_fib *.o diff -r de0085d4ea40 -r 3e7bfde7606e dis.c --- a/dis.c Tue Nov 27 22:54:38 2012 -0800 +++ b/dis.c Tue Dec 04 19:13:12 2012 -0800 @@ -24,9 +24,9 @@ { //printf("cur: %p: %x\n", cur, *cur); unsigned short * start = cur; - cur = m68K_decode(cur, &instbuf); + cur = m68k_decode(cur, &instbuf, (start - filebuf)*2); m68k_disasm(&instbuf, disbuf); - printf("%lX: %s\n", (start - filebuf)*2, disbuf); + printf("%X: %s\n", instbuf.address, disbuf); } return 0; } diff -r de0085d4ea40 -r 3e7bfde7606e gen_x86.c --- a/gen_x86.c Tue Nov 27 22:54:38 2012 -0800 +++ b/gen_x86.c Tue Dec 04 19:13:12 2012 -0800 @@ -31,6 +31,8 @@ #define OP_RETN 0xC3 #define OP_MOV_IEA 0xC6 #define OP_CALL 0xE8 +#define OP_JMP 0xE9 +#define OP_JMP_BYTE 0xEB #define OP_CALL_EA 0xFF #define OP2_JCC 0x80 @@ -49,12 +51,6 @@ #define BIT_DIR 0x2 #define BIT_SIZE 0x1 -#define M68K_N_REG RBX -#define M68K_V_REG BH -#define M68K_Z_REG RDX -#define M68K_C_REG DH - -#define M68K_SCRATCH RCX enum { X86_RAX = 0, @@ -79,13 +75,6 @@ X86_R15 } x86_regs_enc; -enum { - MODE_REG_INDIRECT = 0, - MODE_REG_DISPLACE8 = 0x40, - MODE_REG_DIPSLACE32 = 0x80, - MODE_REG_DIRECT = 0xC0 -} x86_modes; - uint8_t * x86_rr_sizedir(uint8_t * out, uint8_t opcode, uint8_t src, uint8_t dst, uint8_t size) { //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix @@ -160,6 +149,10 @@ } *(out++) = opcode | dir; *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3); + if (base == RSP) { + //add SIB byte, with no index and RSP as base + *(out++) = (RSP << 3) | RSP; + } *(out++) = disp; return out; } @@ -195,6 +188,10 @@ } *(out++) = opcode | dir; *(out++) = MODE_REG_INDIRECT | base | (reg << 3); + if (base == RSP) { + //add SIB byte, with no index and RSP as base + *(out++) = (RSP << 3) | RSP; + } return out; } @@ -251,6 +248,51 @@ return out; } +uint8_t * x86_irdisp8(uint8_t * out, uint8_t opcode, uint8_t op_ex, int32_t val, uint8_t dst, int8_t disp, uint8_t size) +{ + uint8_t sign_extend = 0; + if ((size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) { + sign_extend = 1; + opcode |= BIT_DIR; + } + if (size == SZ_W) { + *(out++) = PRE_SIZE; + } + + if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) { + *out = PRE_REX; + if (size == SZ_Q) { + *out |= REX_QUAD; + } + if (dst >= R8) { + *out |= REX_RM_FIELD; + dst -= (R8 - X86_R8); + } + out++; + } + if (dst >= AH && dst <= BH) { + dst -= (AH-X86_AH); + } + if (size != SZ_B) { + opcode |= BIT_SIZE; + } + *(out++) = opcode; + *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3); + *(out++) = disp; + *(out++) = val; + if (size != SZ_B && !sign_extend) { + val >>= 8; + *(out++) = val; + if (size != SZ_W) { + val >>= 8; + *(out++) = val; + val >>= 8; + *(out++) = val; + } + } + return out; +} + uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) { @@ -262,6 +304,21 @@ return x86_ir(out, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst, size); } +uint8_t * add_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ADDI, val, dst_base, disp, size); +} + +uint8_t * add_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_ADD, src, dst_base, disp, size, 0); +} + +uint8_t * add_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_ADD, dst, src_base, disp, size, BIT_DIR); +} + uint8_t * or_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) { return x86_rr_sizedir(out, OP_OR, src, dst, size); @@ -271,6 +328,21 @@ return x86_ir(out, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst, size); } +uint8_t * or_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ORI, val, dst_base, disp, size); +} + +uint8_t * or_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_OR, src, dst_base, disp, size, 0); +} + +uint8_t * or_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_OR, dst, src_base, disp, size, BIT_DIR); +} + uint8_t * and_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) { return x86_rr_sizedir(out, OP_AND, src, dst, size); @@ -281,6 +353,21 @@ return x86_ir(out, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size); } +uint8_t * and_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ANDI, val, dst_base, disp, size); +} + +uint8_t * and_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_AND, src, dst_base, disp, size, 0); +} + +uint8_t * and_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_AND, dst, src_base, disp, size, BIT_DIR); +} + uint8_t * xor_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) { return x86_rr_sizedir(out, OP_XOR, src, dst, size); @@ -291,6 +378,21 @@ return x86_ir(out, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size); } +uint8_t * xor_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_XORI, val, dst_base, disp, size); +} + +uint8_t * xor_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_XOR, src, dst_base, disp, size, 0); +} + +uint8_t * xor_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_XOR, dst, src_base, disp, size, BIT_DIR); +} + uint8_t * sub_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) { return x86_rr_sizedir(out, OP_SUB, src, dst, size); @@ -301,6 +403,21 @@ return x86_ir(out, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size); } +uint8_t * sub_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_SUBI, val, dst_base, disp, size); +} + +uint8_t * sub_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_SUB, src, dst_base, disp, size, 0); +} + +uint8_t * sub_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_SUB, dst, src_base, disp, size, BIT_DIR); +} + uint8_t * cmp_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) { return x86_rr_sizedir(out, OP_CMP, src, dst, size); @@ -311,6 +428,21 @@ return x86_ir(out, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size); } +uint8_t * cmp_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_CMPI, val, dst_base, disp, size); +} + +uint8_t * cmp_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_CMP, src, dst_base, disp, size, 0); +} + +uint8_t * cmp_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_CMP, dst, src_base, disp, size, BIT_DIR); +} + 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); @@ -360,12 +492,12 @@ dst -= (AH-X86_AH); } if (size == SZ_B) { - *(out++) = OP_MOV_I8R; + *(out++) = OP_MOV_I8R | dst; } else if (size == SZ_Q && sign_extend) { *(out++) = OP_MOV_IEA | BIT_SIZE; *(out++) = MODE_REG_DIRECT | dst; } else { - *(out++) = OP_MOV_IR; + *(out++) = OP_MOV_IR | dst; } *(out++) = val; if (size != SZ_B) { @@ -391,6 +523,43 @@ return out; } +uint8_t * mov_irdisp8(uint8_t * out, int32_t val, uint8_t dst, int8_t disp, uint8_t size) +{ + if (size == SZ_W) { + *(out++) = PRE_SIZE; + } + if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) { + *out = PRE_REX; + if (size == SZ_Q) { + *out |= REX_QUAD; + } + if (dst >= R8) { + *out |= REX_RM_FIELD; + dst -= (R8 - X86_R8); + } + out++; + } + if (dst >= AH && dst <= BH) { + dst -= (AH-X86_AH); + } + *(out++) = OP_MOV_IEA | (size == SZ_B ? 0 : BIT_SIZE); + *(out++) = MODE_REG_DISPLACE8 | dst; + *(out++) = disp; + + *(out++) = val; + if (size != SZ_B) { + val >>= 8; + *(out++) = val; + if (size != SZ_W) { + val >>= 8; + *(out++) = val; + val >>= 8; + *(out++) = val; + } + } + return out; +} + uint8_t * pushf(uint8_t * out) { *(out++) = OP_PUSHF; @@ -451,21 +620,53 @@ return out; } -uint8_t * jcc(uint8_t * out, uint8_t cc, int32_t disp) +uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t * dest) { + ptrdiff_t disp = dest-(out+2); if (disp <= 0x7F && disp >= -0x80) { *(out++) = OP_JCC | cc; *(out++) = disp; } else { - *(out++) = PRE_2BYTE; - *(out++) = OP2_JCC | cc; - *(out++) = disp; - disp >>= 8; + disp = dest-(out+6); + if (disp <= 0x7FFFFFFF && disp >= -2147483648) { + *(out++) = PRE_2BYTE; + *(out++) = OP2_JCC | cc; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + } else { + printf("%p - %p = %lX\n", dest, out + 6, disp); + return NULL; + } + } + return out; +} + +uint8_t * jmp(uint8_t * out, uint8_t * dest) +{ + ptrdiff_t disp = dest-(out+2); + if (disp <= 0x7F && disp >= -0x80) { + *(out++) = OP_JMP_BYTE; *(out++) = disp; - disp >>= 8; - *(out++) = disp; - disp >>= 8; - *(out++) = disp; + } else { + disp = dest-(out+5); + if (disp <= 0x7FFFFFFF && disp >= -2147483648) { + *(out++) = OP_JMP; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + } else { + printf("%p - %p = %lX\n", dest, out + 6, disp); + return NULL; + } } return out; } @@ -483,8 +684,8 @@ disp >>= 8; *(out++) = disp; } else { - //TODO: Implement far call - printf("%p - %p = %ld, %d, %d, %d\n", fun, out + 5, disp, disp <= 0x7FFFFFFF, disp >= (-2147483648), -2147483648); + //TODO: Implement far call??? + printf("%p - %p = %lX\n", fun, out + 5, disp); return NULL; } return out; diff -r de0085d4ea40 -r 3e7bfde7606e gen_x86.h --- a/gen_x86.h Tue Nov 27 22:54:38 2012 -0800 +++ b/gen_x86.h Tue Dec 04 19:13:12 2012 -0800 @@ -52,6 +52,19 @@ SZ_Q } x86_size; +enum { + MODE_REG_INDIRECT = 0, + MODE_REG_INDEXED = 4, + MODE_REG_DISPLACE8 = 0x40, + MODE_REG_INDEXED_DISPLACE8 = 0x44, + MODE_REG_DIPSLACE32 = 0x80, + MODE_REG_INDEXED_DIPSLACE32 = 0x84, + MODE_REG_DIRECT = 0xC0, +//"phony" mode + MODE_IMMED = 0xFF +} x86_modes; + + uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); uint8_t * or_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); uint8_t * xor_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); @@ -64,19 +77,39 @@ uint8_t * and_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size); uint8_t * sub_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size); uint8_t * cmp_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size); +uint8_t * add_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); +uint8_t * or_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); +uint8_t * xor_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); +uint8_t * and_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); +uint8_t * sub_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); +uint8_t * cmp_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); +uint8_t * add_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); +uint8_t * add_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); +uint8_t * or_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); +uint8_t * or_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); +uint8_t * xor_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); +uint8_t * xor_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); +uint8_t * and_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); +uint8_t * and_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); +uint8_t * sub_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); +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 * 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); uint8_t * mov_rrind(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); uint8_t * mov_rindr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); uint8_t * mov_ir(uint8_t * out, int64_t val, uint8_t dst, uint8_t size); +uint8_t * mov_irdisp8(uint8_t * out, int32_t val, uint8_t dst, int8_t disp, uint8_t size); uint8_t * pushf(uint8_t * out); uint8_t * popf(uint8_t * out); uint8_t * push_r(uint8_t * out, uint8_t reg); uint8_t * pop_r(uint8_t * out, uint8_t reg); uint8_t * setcc_r(uint8_t * out, uint8_t cc, uint8_t dst); uint8_t * setcc_rind(uint8_t * out, uint8_t cc, uint8_t dst); -uint8_t * jcc(uint8_t * out, uint8_t cc, int32_t disp); +uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t *dest); +uint8_t * jmp(uint8_t * out, uint8_t *dest); uint8_t * call(uint8_t * out, uint8_t * fun); uint8_t * retn(uint8_t * out); diff -r de0085d4ea40 -r 3e7bfde7606e m68k_to_x86.c --- a/m68k_to_x86.c Tue Nov 27 22:54:38 2012 -0800 +++ b/m68k_to_x86.c Tue Dec 04 19:13:12 2012 -0800 @@ -1,11 +1,16 @@ #include "gen_x86.h" #include "m68k_to_x86.h" - +#include +#include +#include +#include #define BUS 4 +#define PREDEC_PENALTY 2 #define CYCLES RAX #define LIMIT RBP -#define SCRATCH RCX +#define SCRATCH1 RCX +#define SCRATCH2 RDI #define CONTEXT RSI #define FLAG_N RBX @@ -22,16 +27,26 @@ } x86_ea; void handle_cycle_limit(); +void m68k_read_word_scratch1(); +void m68k_read_long_scratch1(); +void m68k_read_byte_scratch1(); +void m68k_write_word(); +void m68k_write_long_lowfirst(); +void m68k_write_long_highfirst(); +void m68k_write_byte(); +void m68k_save_context(); +void m68k_modified_ret_addr(); +void m68k_start_context(uint8_t * addr, m68k_context * context); uint8_t * cycles(uint8_t * dst, uint32_t num) { - dst = add_i32r(dst, num, CYCLES); + dst = add_ir(dst, num, CYCLES, SZ_D); } -uint8_t * check_cycles(uint8_t * dst) Ivds +uint8_t * check_cycles(uint8_t * dst) { dst = cmp_rr(dst, CYCLES, LIMIT, SZ_D); - dst = jcc(dst, CC_G, 5); + dst = jcc(dst, CC_G, dst+7); dst = call(dst, (char *)handle_cycle_limit); } @@ -46,37 +61,551 @@ return -1; } -uint8_t * translate_m68k_ea(m68k_op_info * op, x86_ea * dst, uint8_t * out, x86_68k_options * opts) +void print_regs_exit(m68k_context * context) { - int8_t reg = native_reg(op, opts); + for (int i = 0; i < 8; i++) { + printf("d%d: %X\n", i, context->dregs[i]); + } + for (int i = 0; i < 8; i++) { + printf("a%d: %X\n", i, context->aregs[i]); + } + exit(0); +} + +uint8_t * translate_m68k_src(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68k_options * opts) +{ + int8_t reg = native_reg(&(inst->src), opts); + int32_t dec_amount,inc_amount; if (reg >= 0) { - dst->mode = MODE_REG_DIRECT; - dst->base = reg; - return; + ea->mode = MODE_REG_DIRECT; + ea->base = reg; + return out; } - switch (op->addr_mode) + switch (inst->src.addr_mode) + { + case MODE_REG: + case MODE_AREG: + //We only get one memory parameter, so if the dst operand is a register in memory, + //we need to copy this to a temp register first + reg = native_reg(&(inst->dst), opts); + if (reg >= 0 || inst->dst.addr_mode == MODE_UNUSED || (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode == MODE_AREG) + || inst->op == M68K_EXG) { + + ea->mode = MODE_REG_DISPLACE8; + ea->base = CONTEXT; + ea->disp = (inst->src.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->src.params.regs.pri; + } else { + out = mov_rdisp8r(out, CONTEXT, (inst->src.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->src.params.regs.pri, SCRATCH1, inst->extra.size); + ea->mode = MODE_REG_DIRECT; + ea->base = SCRATCH1; + } + break; + case MODE_AREG_PREDEC: + dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); + out = cycles(out, PREDEC_PENALTY); + if (opts->aregs[inst->src.params.regs.pri] >= 0) { + out = sub_ir(out, inc_amount, opts->aregs[inst->src.params.regs.pri], SZ_D); + } else { + out = sub_irdisp8(out, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SZ_D); + } + out = check_cycles(out); + case MODE_AREG_INDIRECT: + case MODE_AREG_POSTINC: + if (opts->aregs[inst->src.params.regs.pri] >= 0) { + out = mov_rr(out, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); + } else { + out = mov_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D); + } + switch (inst->extra.size) + { + case OPSIZE_BYTE: + out = call(out, (char *)m68k_read_byte_scratch1); + break; + case OPSIZE_WORD: + out = call(out, (char *)m68k_read_word_scratch1); + break; + case OPSIZE_LONG: + out = call(out, (char *)m68k_read_long_scratch1); + break; + } + + if (inst->src.addr_mode == MODE_AREG_POSTINC) { + inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); + if (opts->aregs[inst->src.params.regs.pri] >= 0) { + out = add_ir(out, inc_amount, opts->aregs[inst->src.params.regs.pri], SZ_D); + } else { + out = add_irdisp8(out, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SZ_D); + } + } + ea->mode = MODE_REG_DIRECT; + ea->base = SCRATCH1; + break; + case MODE_IMMEDIATE: + if (inst->variant != VAR_QUICK) { + if (inst->extra.size == OPSIZE_LONG) { + out = cycles(out, BUS); + out = check_cycles(out); + } + out = cycles(out, BUS); + out = check_cycles(out); + } + ea->mode = MODE_IMMED; + ea->disp = inst->src.params.immed; + break; + default: + printf("address mode %d not implemented (src)\n", inst->src.addr_mode); + exit(1); + } + return out; +} + +uint8_t * translate_m68k_dst(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68k_options * opts) +{ + int8_t reg = native_reg(&(inst->dst), opts); + int32_t dec_amount, inc_amount; + if (reg >= 0) { + ea->mode = MODE_REG_DIRECT; + ea->base = reg; + return out; + } + switch (inst->dst.addr_mode) { case MODE_REG: case MODE_AREG: - dst->mode = MODE_DISPLACE8; - dst->base = CONTEXT; - dst->disp = (op->addr_mode = MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * op->params.regs.pri; + ea->mode = MODE_REG_DISPLACE8; + ea->base = CONTEXT; + ea->disp = (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri; + break; + case MODE_AREG_PREDEC: + dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + out = sub_ir(out, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); + } else { + out = sub_irdisp8(out, dec_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); + } + case MODE_AREG_INDIRECT: + case MODE_AREG_POSTINC: + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH1, SZ_D); + } else { + out = mov_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SCRATCH1, SZ_D); + } + switch (inst->extra.size) + { + case OPSIZE_BYTE: + out = call(out, (char *)m68k_read_byte_scratch1); + break; + case OPSIZE_WORD: + out = call(out, (char *)m68k_read_word_scratch1); + break; + case OPSIZE_LONG: + out = call(out, (char *)m68k_read_long_scratch1); + break; + } + //save reg value in SCRATCH2 so we can use it to save the result in memory later + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); + } else { + out = mov_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SCRATCH2, SZ_D); + } + + if (inst->src.addr_mode == MODE_AREG_POSTINC) { + inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + out = add_ir(out, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); + } else { + out = add_irdisp8(out, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); + } + } + ea->mode = MODE_REG_DIRECT; + ea->base = SCRATCH1; + break; + default: + printf("address mode %d not implemented (dst)\n", inst->dst.addr_mode); + exit(1); + } + return out; +} + +uint8_t * m68k_save_result(m68kinst * inst, uint8_t * out, x86_68k_options * opts) +{ + if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) { + switch (inst->extra.size) + { + case OPSIZE_BYTE: + out = call(out, (char *)m68k_write_byte); + break; + case OPSIZE_WORD: + out = call(out, (char *)m68k_write_word); + break; + case OPSIZE_LONG: + out = call(out, (char *)m68k_write_long_lowfirst); + break; + } + } + return out; +} + +uint8_t * get_native_address(native_map_slot * native_code_map, uint32_t address) +{ + address &= 0xFFFFFF; + uint32_t chunk = address / NATIVE_CHUNK_SIZE; + if (!native_code_map[chunk].base) { + return NULL; + } + uint32_t offset = address % NATIVE_CHUNK_SIZE; + if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) { + return NULL; + } + return native_code_map[chunk].base + native_code_map[chunk].offsets[offset]; +} + +deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest) +{ + deferred_addr * new_head = malloc(sizeof(deferred_addr)); + new_head->next = old_head; + new_head->address = address & 0xFFFFFF; + new_head->dest = dest; + return new_head; +} + +void process_deferred(x86_68k_options * opts) +{ + deferred_addr * cur = opts->deferred; + deferred_addr **last_next = &(opts->deferred); + while(cur) + { + uint8_t * native = get_native_address(opts->native_code_map, cur->address); + if (native) { + int32_t disp = native - (cur->dest + 4); + printf("Native dest: %p, Offset address: %p, displacement: %X\n", native, cur->dest, disp); + uint8_t * out = cur->dest; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *out = disp; + *last_next = cur->next; + free(cur); + cur = *last_next; + } else { + last_next = &(cur->next); + cur = cur->next; + } + } +} + +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); + } + uint32_t offset = address % NATIVE_CHUNK_SIZE; + native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base; +} + +uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) +{ + int8_t reg, flags_reg; + uint8_t dir = 0; + int32_t offset; + int32_t inc_amount, dec_amount; + x86_ea src; + dst = translate_m68k_src(inst, &src, dst, opts); + reg = native_reg(&(inst->dst), opts); + if (src.mode == MODE_REG_DIRECT) { + flags_reg = src.base; + } else { + if (reg >= 0) { + flags_reg = reg; + } else { + printf("moving %d to temp register %d\n", src.disp, SCRATCH1); + dst = mov_ir(dst, src.disp, SCRATCH1, SZ_D); + src.mode = MODE_REG_DIRECT; + flags_reg = src.base = SCRATCH1; + } + } + switch(inst->dst.addr_mode) + { + case MODE_REG: + case MODE_AREG: + if (reg >= 0) { + if (src.mode == MODE_REG_DIRECT) { + dst = mov_rr(dst, src.base, reg, inst->extra.size); + } else if (src.mode == MODE_REG_DISPLACE8) { + dst = mov_rdisp8r(dst, src.base, src.disp, reg, inst->extra.size); + } else { + dst = mov_ir(dst, src.disp, reg, inst->extra.size); + } + } else if(src.mode == MODE_REG_DIRECT) { + printf("mov_rrdisp8 from reg %d to offset %d from reg %d (%d)\n", src.base, (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri, CONTEXT, inst->dst.params.regs.pri); + dst = mov_rrdisp8(dst, src.base, CONTEXT, (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri, inst->extra.size); + } else { + dst = mov_irdisp8(dst, src.disp, CONTEXT, (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri, inst->extra.size); + } break; + case MODE_AREG_PREDEC: + dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + dst = sub_ir(dst, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); + } else { + dst = sub_irdisp8(dst, dec_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); + } case MODE_AREG_INDIRECT: - + case MODE_AREG_POSTINC: + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + dst = mov_rr(dst, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); + } else { + dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SCRATCH2, SZ_D); + } + if (src.mode == MODE_REG_DIRECT) { + if (src.base != SCRATCH1) { + dst = mov_rr(dst, src.base, SCRATCH1, inst->extra.size); + } + } else if (src.mode == MODE_REG_DISPLACE8) { + dst = mov_rdisp8r(dst, src.base, src.disp, SCRATCH1, inst->extra.size); + } else { + dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); + } + switch (inst->extra.size) + { + case OPSIZE_BYTE: + dst = call(dst, (char *)m68k_write_byte); + break; + case OPSIZE_WORD: + dst = call(dst, (char *)m68k_write_word); + break; + case OPSIZE_LONG: + dst = call(dst, (char *)m68k_write_long_highfirst); + break; + } + if (inst->dst.addr_mode == MODE_AREG_POSTINC) { + inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + dst = add_ir(dst, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); + } else { + dst = add_irdisp8(dst, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); + } + } break; + default: + printf("address mode %d not implemented (move dst)\n", inst->dst.addr_mode); + exit(1); } + + //add cycles for prefetch + dst = cycles(dst, BUS); + //update flags + dst = mov_ir(dst, 0, FLAG_V, SZ_B); + dst = mov_ir(dst, 0, FLAG_C, SZ_B); + dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + dst = check_cycles(dst); + return dst; +} + +uint8_t * translate_m68k_lea(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) +{ + int8_t dst_reg = native_reg(&(inst->dst), opts); + switch(inst->src.addr_mode) + { + case MODE_AREG_INDIRECT: + dst = cycles(dst, BUS); + if (opts->aregs[inst->src.params.regs.pri] >= 0) { + if (dst_reg >= 0) { + dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], dst_reg, SZ_D); + } else { + dst = mov_rrdisp8(dst, opts->aregs[inst->src.params.regs.pri], CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); + } + } else { + if (dst_reg >= 0) { + dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, dst_reg, SZ_D); + } else { + dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D); + dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); + } + } + dst = check_cycles(dst); + break; + case MODE_ABSOLUTE: + dst = cycles(dst, BUS); + dst = check_cycles(dst); + case MODE_ABSOLUTE_SHORT: + dst = cycles(dst, BUS); + dst = check_cycles(dst); + dst = cycles(dst, BUS); + if (dst_reg >= 0) { + dst = mov_ir(dst, inst->src.params.immed, dst_reg, SZ_D); + } else { + dst = mov_irdisp8(dst, inst->src.params.immed, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); + } + dst = check_cycles(dst); + break; + } + return dst; +} + +uint8_t * translate_m68k_bsr(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) +{ + //TODO: Add cycles + int32_t disp = inst->src.params.immed; + uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : (inst->variant == VAR_WORD ? 4 : 6)); + dst = mov_ir(dst, after, SCRATCH1, SZ_D); + dst = push_r(dst, SCRATCH1); + dst = sub_ir(dst, 4, opts->aregs[7], SZ_D); + dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); + dst = call(dst, (char *)m68k_write_long_highfirst); + printf("bsr@%X: after=%X, disp=%X, dest=%X\n", inst->address, after, disp, after+disp); + uint8_t * dest_addr = get_native_address(opts->native_code_map, after + disp); + if (!dest_addr) { + opts->deferred = defer_address(opts->deferred, after + disp, dst + 1); + //dummy address to be replaced later + dest_addr = dst + 5; + } + dst = call(dst, (char *)dest_addr); + //would add_ir(dst, 8, RSP, SZ_Q) be faster here? + dst = pop_r(dst, SCRATCH1); + return dst; +} + +uint8_t * translate_m68k_bcc(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) +{ + //TODO: Add cycles + int32_t disp = inst->src.params.immed; + uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : (inst->variant == VAR_WORD ? 4 : 6)); + printf("bcc@%X: after=%X, disp=%X, dest=%X\n", inst->address, after, disp, after+disp); + uint8_t * dest_addr = get_native_address(opts->native_code_map, after + disp); + if (inst->extra.cond == COND_TRUE) { + if (!dest_addr) { + opts->deferred = defer_address(opts->deferred, after + disp, dst + 1); + //dummy address to be replaced later, make sure it generates a 4-byte displacement + dest_addr = dst + 256; + } + dst = jmp(dst, dest_addr); + } else { + uint8_t cond = CC_NZ; + switch (inst->extra.cond) + { + case COND_HIGH: + cond = CC_Z; + case COND_LOW_SAME: + dst = mov_rr(dst, FLAG_Z, SCRATCH1, SZ_B); + dst = or_rr(dst, FLAG_C, SCRATCH1, SZ_B); + break; + case COND_CARRY_CLR: + cond = CC_Z; + case COND_CARRY_SET: + dst = cmp_ir(dst, 0, FLAG_C, SZ_B); + break; + case COND_NOT_EQ: + cond = CC_Z; + case COND_EQ: + dst = cmp_ir(dst, 0, FLAG_Z, SZ_B); + break; + case COND_OVERF_CLR: + cond = CC_Z; + case COND_OVERF_SET: + dst = cmp_ir(dst, 0, FLAG_V, SZ_B); + break; + case COND_PLUS: + cond = CC_Z; + case COND_MINUS: + dst = cmp_ir(dst, 0, FLAG_N, SZ_B); + break; + case COND_GREATER_EQ: + cond = CC_Z; + case COND_LESS: + dst = cmp_rr(dst, FLAG_N, FLAG_V, SZ_B); + break; + case COND_GREATER: + cond = CC_Z; + case COND_LESS_EQ: + dst = mov_rr(dst, FLAG_V, SCRATCH1, SZ_B); + dst = xor_rr(dst, FLAG_N, SCRATCH1, SZ_B); + dst = or_rr(dst, FLAG_Z, SCRATCH1, SZ_B); + break; + } + if (!dest_addr) { + opts->deferred = defer_address(opts->deferred, after + disp, dst + 2); + //dummy address to be replaced later, make sure it generates a 4-byte displacement + dest_addr = dst + 256; + } + dst = jcc(dst, cond, dest_addr); + } + return dst; +} + +uint8_t * translate_m68k_rts(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) +{ + //TODO: Add cycles + dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D); + dst = add_ir(dst, 4, opts->aregs[7], SZ_D); + dst = call(dst, (char *)m68k_read_long_scratch1); + dst = cmp_rdisp8r(dst, RSP, 8, SCRATCH1, SZ_D); + dst = jcc(dst, CC_NZ, dst+3); + dst = retn(dst); + dst = jmp(dst, (char *)m68k_modified_ret_addr); + return dst; } uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) { - int8_t reg_a, reg_b, flags_reg; - uint8_t dir = 0; - int32_t offset; + map_native_address(opts->native_code_map, inst->address, dst); + if (inst->op == M68K_MOVE) { + return translate_m68k_move(dst, inst, opts); + } else if(inst->op == M68K_LEA) { + return translate_m68k_lea(dst, inst, opts); + } else if(inst->op == M68K_BSR) { + return translate_m68k_bsr(dst, inst, opts); + } else if(inst->op == M68K_BCC) { + return translate_m68k_bcc(dst, inst, opts); + } else if(inst->op == M68K_RTS) { + return translate_m68k_rts(dst, inst, opts); + } + x86_ea src_op, dst_op; + if (inst->src.addr_mode != MODE_UNUSED) { + dst = translate_m68k_src(inst, &src_op, dst, opts); + } + if (inst->dst.addr_mode != MODE_UNUSED) { + dst = translate_m68k_dst(inst, &dst_op, dst, opts); + } switch(inst->op) { case M68K_ABCD: + break; case M68K_ADD: + dst = cycles(dst, BUS); + if (src_op.mode == MODE_REG_DIRECT) { + if (dst_op.mode == MODE_REG_DIRECT) { + dst = add_rr(dst, src_op.base, dst_op.base, inst->extra.size); + } else { + dst = add_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); + } + } else if (src_op.mode == MODE_REG_DISPLACE8) { + dst = add_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size); + } else { + if (dst_op.mode == MODE_REG_DIRECT) { + dst = add_ir(dst, src_op.disp, dst_op.base, inst->extra.size); + } else { + dst = add_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); + } + } + dst = setcc_r(dst, CC_C, FLAG_C); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + dst = setcc_r(dst, CC_O, FLAG_V); + dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); + dst = check_cycles(dst); + break; case M68K_ADDX: case M68K_AND: case M68K_ANDI_CCR: @@ -92,6 +621,28 @@ case M68K_CHK: case M68K_CLR: case M68K_CMP: + dst = cycles(dst, BUS); + if (src_op.mode == MODE_REG_DIRECT) { + if (dst_op.mode == MODE_REG_DIRECT) { + dst = cmp_rr(dst, src_op.base, dst_op.base, inst->extra.size); + } else { + dst = cmp_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); + } + } else if (src_op.mode == MODE_REG_DISPLACE8) { + dst = cmp_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size); + } else { + if (dst_op.mode == MODE_REG_DIRECT) { + dst = cmp_ir(dst, src_op.disp, dst_op.base, inst->extra.size); + } else { + dst = cmp_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); + } + } + dst = setcc_r(dst, CC_C, FLAG_C); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + dst = setcc_r(dst, CC_O, FLAG_V); + dst = check_cycles(dst); + break; case M68K_DBCC: case M68K_DIVS: case M68K_DIVU: @@ -99,95 +650,41 @@ case M68K_EORI_CCR: case M68K_EORI_SR: case M68K_EXG: + dst = cycles(dst, 6); + if (dst_op.mode == MODE_REG_DIRECT) { + dst = mov_rr(dst, dst_op.base, SCRATCH2, SZ_D); + if (src_op.mode == MODE_REG_DIRECT) { + dst = mov_rr(dst, src_op.base, dst_op.base, SZ_D); + dst = mov_rr(dst, SCRATCH2, src_op.base, SZ_D); + } else { + dst = mov_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, SZ_D); + dst = mov_rrdisp8(dst, SCRATCH2, src_op.base, src_op.disp, SZ_D); + } + } else { + dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH2, SZ_D); + if (src_op.mode == MODE_REG_DIRECT) { + dst = mov_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, SZ_D); + dst = mov_rr(dst, SCRATCH2, src_op.base, SZ_D); + } else { + dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_D); + dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_D); + dst = mov_rrdisp8(dst, SCRATCH2, src_op.base, src_op.disp, SZ_D); + } + } + dst = check_cycles(dst); + break; case M68K_EXT: case M68K_ILLEGAL: + dst = call(dst, (uint8_t *)m68k_save_context); + dst = mov_rr(dst, CONTEXT, RDI, SZ_Q); + dst = call(dst, (uint8_t *)print_regs_exit); + break; case M68K_JMP: case M68K_JSR: case M68K_LEA: case M68K_LINK: case M68K_LSL: case M68K_LSR: - case M68K_MOVE: - - if ((inst->src.addr_mode == MODE_REG || inst->src.addr_mode == MODE_AREG || (inst->src.addr_mode == MODE_IMMEDIATE && inst->src.variant == VAR_QUICK)) && (inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG)) { - dst = cycles(dst, BUS); - reg_a = native_reg(&(inst->src), opts); - reg_b = native_reg(&(inst->dst), opts); - dst = cycles(dst, BUS); - if (reg_a >= 0 && reg_b >= 0) { - dst = mov_rr(dst, reg_a, reg_b, inst->extra.size); - flags_reg = reg_b; - } else if(reg_a >= 0) { - offset = inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs); - dst = mov_rrdisp8(dst, reg_a, CONTEXT, offset + 4 * inst->dst.params.regs.pri, inst->extra.size); - flags_reg = reg_a; - } else if(reg_b >= 0) { - if (inst->src.addr_mode == MODE_REG) { - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + 4 * inst->src.params.regs.pri, reg_b, inst->extra.size); - } else if(inst->src.addr_mode == MODE_AREG) { - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, reg_b, inst->extra.size); - } else { - dst = mov_i32r(dst, inst->src.params.u32, reg_b); - } - flags_reg = reg_b; - } else { - - } - dst = mov_i8r(dst, 0, FLAG_V); - dst = mov_i8r(dst, 0, FLAG_C); - switch (inst->extra.size) - { - case OPSIZE_BYTE: - dst = cmp_i8r(dst, 0, reg_b, SZ_B); - break; - case OPSIZE_WORD: - dst = cmp_i8r(dst, 0, reg_b, SZ_W); - break; - case OPSIZE_LONG: - dst = cmp_i8r(dst, 0, reg_b, SZ_D); - break; - } - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = check_cycles(dst); - } - - if (reg_a >= 0 && reg_b >= 0) { - dst = cycles(dst, BUS); - dst = mov_rr(dst, reg_a, reg_b, inst->extra.size); - dst = mov_i8r(dst, 0, FLAG_V); - dst = mov_i8r(dst, 0, FLAG_C); - switch (inst->extra.size) - { - case OPSIZE_BYTE: - dst = cmp_i8r(dst, 0, reg_b, SZ_B); - break; - case OPSIZE_WORD: - dst = cmp_i8r(dst, 0, reg_b, SZ_W); - break; - case OPSIZE_LONG: - dst = cmp_i8r(dst, 0, reg_b, SZ_D); - break; - } - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = check_cycles(dst); - } else if(reg_a >= 0 || reg_b >= 0) { - if (reg_a >= 0) { - switch (inst->dst.addr_mode) - { - case MODE_REG: - dst = cycles(dst, BUS); - dst = mov_rr(dst, reg_a, reg_b, inst->extra.size); - dst = check_cycles(dst); - break; - case MODE_AREG: - break; - } - } else { - } - } - break; case M68K_MOVE_CCR: case M68K_MOVE_FROM_SR: case M68K_MOVE_SR: @@ -217,6 +714,29 @@ case M68K_SCC: case M68K_STOP: case M68K_SUB: + dst = cycles(dst, BUS); + if (src_op.mode == MODE_REG_DIRECT) { + if (dst_op.mode == MODE_REG_DIRECT) { + dst = sub_rr(dst, src_op.base, dst_op.base, inst->extra.size); + } else { + dst = sub_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); + } + } else if (src_op.mode == MODE_REG_DISPLACE8) { + dst = sub_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size); + } else { + if (dst_op.mode == MODE_REG_DIRECT) { + dst = sub_ir(dst, src_op.disp, dst_op.base, inst->extra.size); + } else { + dst = sub_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); + } + } + dst = setcc_r(dst, CC_C, FLAG_C); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + dst = setcc_r(dst, CC_O, FLAG_V); + dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); + dst = check_cycles(dst); + break; case M68K_SUBX: case M68K_SWAP: case M68K_TAS: @@ -227,5 +747,65 @@ case M68K_INVALID: break; } + return dst; } +uint8_t * translate_m68k_stream(uint8_t * dst, uint8_t * dst_end, uint32_t address, m68k_context * context) +{ + m68kinst instbuf; + x86_68k_options * opts = context->options; + char disbuf[1024]; + uint16_t *encoded = context->mem_pointers[0] + address/2, *next; + do { + do { + if (dst_end-dst < 128) { + puts("out of code memory"); + exit(1); + } + next = m68k_decode(encoded, &instbuf, address); + address += (next-encoded)*2; + encoded = next; + m68k_disasm(&instbuf, disbuf); + printf("%X: %s\n", instbuf.address, disbuf); + dst = translate_m68k(dst, &instbuf, opts); + } while(instbuf.op != M68K_ILLEGAL && instbuf.op != M68K_RTS && instbuf.op != M68K_RTE && !(instbuf.op == M68K_BCC && instbuf.extra.cond == COND_TRUE) && instbuf.op != M68K_JMP); + process_deferred(opts); + if (opts->deferred) { + address = opts->deferred->address; + encoded = context->mem_pointers[0] + address/2; + } else { + encoded = NULL; + } + } while(encoded != NULL); + return dst; +} + +void start_68k_context(m68k_context * context, uint32_t address) +{ + uint8_t * addr = get_native_address(context->native_code_map, address); + m68k_start_context(addr, context); +} + +void init_x86_68k_opts(x86_68k_options * opts) +{ + opts->flags = 0; + for (int i = 0; i < 8; i++) + opts->dregs[i] = opts->aregs[i] = -1; + opts->dregs[0] = R10; + opts->dregs[1] = R11; + opts->dregs[2] = R12; + opts->aregs[0] = R13; + opts->aregs[1] = R14; + opts->aregs[7] = R15; + opts->native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS); + memset(opts->native_code_map, 0, sizeof(native_map_slot) * NATIVE_MAP_CHUNKS); + opts->deferred = NULL; +} + +void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts) +{ + memset(context, 0, sizeof(m68k_context)); + context->native_code_map = native_code_map; + context->options = opts; +} + diff -r de0085d4ea40 -r 3e7bfde7606e m68k_to_x86.h --- a/m68k_to_x86.h Tue Nov 27 22:54:38 2012 -0800 +++ b/m68k_to_x86.h Tue Dec 04 19:13:12 2012 -0800 @@ -1,16 +1,46 @@ #include +#include "68kinst.h" + +#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 typedef struct { - uint32_t flags; - int8_t dregs[8]; - int8_t aregs[8]; + uint8_t *base; + uint16_t *offsets; +} native_map_slot; + +typedef struct deferred_addr { + struct deferred_addr *next; + uint8_t *dest; + uint32_t address; +} deferred_addr; + +typedef struct { + uint32_t flags; + int8_t dregs[8]; + int8_t aregs[8]; + native_map_slot *native_code_map; + deferred_addr *deferred; + } x86_68k_options; typedef struct { - uint8_t flags[5]; - uint8_t status; - uint16_t reserved; - uint32_t dregs[8]; - uint32_t aregs[8]; + uint8_t flags[5]; + uint8_t status; + uint16_t reserved; + uint32_t dregs[8]; + uint32_t aregs[8]; + uint32_t target_cycle; + uint32_t current_cycle; + uint16_t *mem_pointers[NUM_MEM_AREAS]; + native_map_slot *native_code_map; + void *options; } m68k_context; +uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts); +uint8_t * translate_m68k_stream(uint8_t * dst, uint8_t * dst_end, uint32_t address, m68k_context * context); +void start_68k_context(m68k_context * context, uint32_t address); +void init_x86_68k_opts(x86_68k_options * opts); +void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts); diff -r de0085d4ea40 -r 3e7bfde7606e mem.c --- a/mem.c Tue Nov 27 22:54:38 2012 -0800 +++ b/mem.c Tue Dec 04 19:13:12 2012 -0800 @@ -1,10 +1,35 @@ #include #include +#include +#include +#include #include "mem.h" +/* void * alloc_code(size_t *size) { *size += PAGE_SIZE - (*size & (PAGE_SIZE - 1)); return mmap(NULL, *size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } +*/ +/* +void * alloc_code(size_t *size) +{ + char * ret = malloc(*size); + char * base = (char *)(((intptr_t)ret) & (~(PAGE_SIZE-1))); + mprotect(base, (ret + *size) - base, PROT_EXEC | PROT_READ | PROT_WRITE); + return ret; +} +*/ + +void * alloc_code(size_t *size) +{ + *size += PAGE_SIZE - (*size & (PAGE_SIZE - 1)); + void * ret = sbrk(*size); + if (ret == ((void *)-1)) { + return NULL; + } + mprotect(ret, *size, PROT_EXEC | PROT_READ | PROT_WRITE); + return ret; +} diff -r de0085d4ea40 -r 3e7bfde7606e notes.txt --- a/notes.txt Tue Nov 27 22:54:38 2012 -0800 +++ b/notes.txt Tue Dec 04 19:13:12 2012 -0800 @@ -36,16 +36,15 @@ dh = C flag rbp = target cycle count rsi = context pointer -rdi = d0 -r8 = d1 -r9 = d2 -r10 = d3 -r11 = a0 -r12 = a1 -r13 = a6 -r14 = a7 -r15 = work ram address -r16 = cartridge address +rdi = scratch register +r8 = cartridge address +r9 = work ram address +r10 = d0 +r11 = d1 +r12 = d2 +r13 = a0 +r14 = a1 +r15 = a7 rsp = native stack pointer 68K context: diff -r de0085d4ea40 -r 3e7bfde7606e runtime.S --- a/runtime.S Tue Nov 27 22:54:38 2012 -0800 +++ b/runtime.S Tue Dec 04 19:13:12 2012 -0800 @@ -1,5 +1,162 @@ - .global _handle_cycle_limit -_handle_cycle_limit: - retn + .global handle_cycle_limit +handle_cycle_limit: + ret + + .global m68k_write_word +m68k_write_word: + and $0xFFFFFF, %rdi + cmp $0x400000, %edi + jle cart_w + cmp $0xE00000, %edi + jge workram_w + jmp inccycles +workram_w: + and $0xFFFF, %rdi + mov %cx, (%r9, %rdi) + jmp inccycles +cart_w: + mov %cx, (%r8, %rdi) + jmp inccycles + + .global m68k_write_byte +m68k_write_byte: + and $0xFFFFFF, %rdi + /* deal with byte swapping */ + xor $1, %edi + cmp $0x400000, %edi + jle cart_wb + cmp $0xE00000, %edi + jge workram_wb + jmp inccycles +workram_wb: + and $0xFFFF, %rdi + mov %cl, (%r9, %rdi) + jmp inccycles +cart_wb: + mov %cl, (%r8, %rdi) + jmp inccycles + + .global m68k_write_long_lowfirst +m68k_write_long_lowfirst: + push %rdi + add $2, %edi + call m68k_write_word + shr $16, %ecx + pop %rdi + jmp m68k_write_word + + .global m68k_write_long_highfirst +m68k_write_long_highfirst: + push %rdi + push %rcx + shr $16, %ecx + call m68k_write_word + pop %rcx + pop %rdi + add $2, %rdi + jmp m68k_write_word + .global m68k_read_word_scratch1 +m68k_read_word_scratch1: + and $0xFFFFFF, %rcx + cmp $0x400000, %ecx + jle cart + cmp $0xE00000, %ecx + jge workram + xor %cx, %cx + jmp inccycles +workram: + and $0xFFFF, %rcx + mov (%r9, %rcx), %cx + jmp inccycles +cart: + mov (%r8, %rcx), %cx +inccycles: + add $4, %rax + cmp %rbp, %rax + jge sync + ret +sync: + ret + + .global m68k_read_long_scratch1 +m68k_read_long_scratch1: + push %rcx + call m68k_read_word_scratch1 + mov %cx, %di + pop %rcx + add $2, %ecx + call m68k_read_word_scratch1 + and $0xFFFF, %ecx + shl $16, %edi + or %edi, %ecx + ret + + .global m68k_read_byte_scratch1 +m68k_read_byte_scratch1: + and $0xFFFFFF, %rcx + /* deal with byte swapping */ + xor $1, %ecx + cmp $0x400000, %ecx + jle cart_b + cmp $0xE00000, %ecx + jge workram_b + xor %cl, %cl + jmp inccycles +workram_b: + and $0xFFFF, %rcx + mov (%r9, %rcx), %cl + jmp inccycles +cart_b: + mov (%r8, %rcx), %cl + jmp inccycles + +ret_addr_msg: + .asciz "Program modified return address on stack: found %X, expected %X\n" + + .global m68k_modified_ret_addr +m68k_modified_ret_addr: + lea ret_addr_msg(%rip), %rdi + mov %rcx, %rsi + mov 8(%rsp), %rdx + call printf + mov $1, %rdi + call exit + + .global m68k_save_context +m68k_save_context: + mov %bl, 1(%rsi) /* N Flag */ + mov %bh, 2(%rsi) /* V flag */ + mov %dl, 3(%rsi) /* Z flag */ + mov %dh, 4(%rsi) /* C flag */ + mov %r10d, 8(%rsi) /* d0 */ + mov %r11d, 12(%rsi) /* d1 */ + mov %r12d, 16(%rsi) /* d2 */ + mov %r13d, 40(%rsi) /* a0 */ + mov %r14d, 44(%rsi) /* a1 */ + mov %r15d, 68(%rsi) /* a7 */ + ret + + .global m68k_load_context +m68k_load_context: + mov 1(%rsi), %bl /* N Flag */ + mov 2(%rsi), %bh /* V flag */ + mov 3(%rsi), %dl /* Z flag */ + mov 4(%rsi), %dh /* C flag */ + mov 8(%rsi), %r10d /* d0 */ + mov 12(%rsi), %r11d /* d1 */ + mov 16(%rsi), %r12d /* d2 */ + mov 40(%rsi), %r13d /* a0 */ + mov 44(%rsi), %r14d /* a1 */ + mov 68(%rsi), %r15d /* a7 */ + mov 72(%rsi), %ebp /* target cycle count */ + mov 76(%rsi), %eax /* current cycle count */ + mov 80(%rsi), %r8d /* cartridge address */ + mov 88(%rsi), %r9d /* work ram address */ + ret + + .global m68k_start_context +m68k_start_context: + call m68k_load_context + jmp *%rdi diff -r de0085d4ea40 -r 3e7bfde7606e trans.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trans.c Tue Dec 04 19:13:12 2012 -0800 @@ -0,0 +1,39 @@ +#include "68kinst.h" +#include "m68k_to_x86.h" +#include "mem.h" +#include +#include + +int main(int argc, char ** argv) +{ + long filesize; + unsigned short *filebuf; + char disbuf[1024]; + size_t size = 1024 * 1024; + uint8_t * transbuf = alloc_code(&size); + uint8_t *trans_cur, *end; + unsigned short * cur; + x86_68k_options opts; + m68k_context context; + FILE * f = fopen(argv[1], "rb"); + fseek(f, 0, SEEK_END); + filesize = ftell(f); + fseek(f, 0, SEEK_SET); + filebuf = malloc(filesize); + fread(filebuf, 2, filesize/2, f); + fclose(f); + for(cur = filebuf; cur - filebuf < (filesize/2); ++cur) + { + *cur = (*cur >> 8) | (*cur << 8); + } + init_x86_68k_opts(&opts); + init_68k_context(&context, opts.native_code_map, &opts); + //cartridge ROM + context.mem_pointers[0] = filebuf; + context.target_cycle = 0x7FFFFFFF; + //work RAM + context.mem_pointers[1] = malloc(64 * 1024); + translate_m68k_stream(transbuf, transbuf + size, 0, &context); + start_68k_context(&context, 0); + return 0; +}