# HG changeset patch # User Mike Pavone # Date 1355977439 28800 # Node ID 918468c623e93e82eb7945a6caa8b9bcefcdf5d1 # Parent 6ffea860773004de5960284050690e82f6b25e62 Add support for BTST instruction (untested), absolute addressing mode for instructions other than move (untested) and fix decoding of MOVEM. diff -r 6ffea8607730 -r 918468c623e9 68kinst.c --- a/68kinst.c Tue Dec 18 23:55:10 2012 -0800 +++ b/68kinst.c Wed Dec 19 20:23:59 2012 -0800 @@ -124,8 +124,11 @@ } decoded->src.addr_mode = MODE_REG; decoded->src.params.regs.pri = m68k_reg_quick_field(*istream); - decoded->extra.size = OPSIZE_LONG; - istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->dst)); + decoded->extra.size = OPSIZE_BYTE; + istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst)); + if (decoded->dst.addr_mode == MODE_REG) { + decoded->extra.size = OPSIZE_LONG; + } } else if ((*istream & 0xF00) == 0x800) { //BTST, BCHG, BCLR, BSET switch ((*istream >> 6) & 0x3) @@ -145,10 +148,13 @@ } opmode = (*istream >> 3) & 0x7; reg = *istream & 0x7; - decoded->src.addr_mode = MODE_IMMEDIATE; + decoded->src.addr_mode = MODE_IMMEDIATE_WORD; decoded->src.params.immed = *(++istream) & 0xFF; decoded->extra.size = OPSIZE_BYTE; - istream = m68k_decode_op_ex(istream, opmode, reg, OPSIZE_BYTE, &(decoded->dst)); + istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); + if (decoded->dst.addr_mode == MODE_REG) { + decoded->extra.size = OPSIZE_LONG; + } } else if ((*istream & 0xC0) == 0xC0) { #ifdef M68020 //CMP2, CHK2, CAS, CAS2, RTM, CALLM @@ -407,7 +413,8 @@ 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) { + if ((*istream & 0xB80) == 0x880 && opmode != MODE_REG && opmode != MODE_AREG) { + //TODO: Check for invalid modes that are dependent on direction decoded->op = M68K_MOVEM; decoded->extra.size = *istream & 0x40 ? OPSIZE_LONG : OPSIZE_WORD; reg = *istream & 0x7; @@ -1143,6 +1150,7 @@ case MODE_AREG_DISPLACE: return sprintf(dst, "%s (a%d, %d)", c, decoded->params.regs.pri, decoded->params.regs.displacement); case MODE_IMMEDIATE: + case MODE_IMMEDIATE_WORD: return sprintf(dst, "%s #%d", c, decoded->params.immed); case MODE_ABSOLUTE_SHORT: return sprintf(dst, "%s $%X.w", c, decoded->params.immed); diff -r 6ffea8607730 -r 918468c623e9 68kinst.h --- a/68kinst.h Tue Dec 18 23:55:10 2012 -0800 +++ b/68kinst.h Wed Dec 19 20:23:59 2012 -0800 @@ -128,6 +128,7 @@ MODE_PC_DISPLACE, MODE_PC_INDEX, MODE_IMMEDIATE, + MODE_IMMEDIATE_WORD,//used to indicate an immediate operand that only uses a single extension word even for a long operation MODE_UNUSED } m68k_addr_modes; diff -r 6ffea8607730 -r 918468c623e9 gen_x86.c --- a/gen_x86.c Tue Dec 18 23:55:10 2012 -0800 +++ b/gen_x86.c Wed Dec 19 20:23:59 2012 -0800 @@ -40,6 +40,8 @@ #define OP2_JCC 0x80 #define OP2_SETCC 0x90 +#define OP2_BT 0xA3 +#define OP2_BTX_I 0xBA #define OP_EX_ADDI 0x0 #define OP_EX_ORI 0x1 @@ -59,6 +61,11 @@ #define OP_EX_SAL 0x6 //identical to SHL #define OP_EX_SAR 0x7 +#define OP_EX_BT 0x4 +#define OP_EX_BTS 0x5 +#define OP_EX_BTR 0x6 +#define OP_EX_BTC 0x7 + #define BIT_IMMED_RAX 0x4 #define BIT_DIR 0x2 #define BIT_SIZE 0x1 @@ -880,6 +887,106 @@ return out; } +uint8_t * bt_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +{ + if (size == SZ_W) { + *(out++) = PRE_SIZE; + } + if (size == SZ_Q || src >= R8 || dst >= R8) { + *out = PRE_REX; + if (size == SZ_Q) { + *out |= REX_QUAD; + } + if (src >= R8) { + *out |= REX_REG_FIELD; + src -= (R8 - X86_R8); + } + if (dst >= R8) { + *out |= REX_RM_FIELD; + dst -= (R8 - X86_R8); + } + out++; + } + *(out++) = PRE_2BYTE; + *(out++) = OP2_BT; + *(out++) = MODE_REG_DIRECT | dst | (src << 3); + return out; +} + +uint8_t * bt_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size) +{ + if (size == SZ_W) { + *(out++) = PRE_SIZE; + } + if (size == SZ_Q || src >= R8 || dst_base >= R8) { + *out = PRE_REX; + if (size == SZ_Q) { + *out |= REX_QUAD; + } + if (src >= R8) { + *out |= REX_REG_FIELD; + src -= (R8 - X86_R8); + } + if (dst_base >= R8) { + *out |= REX_RM_FIELD; + dst_base -= (R8 - X86_R8); + } + out++; + } + *(out++) = PRE_2BYTE; + *(out++) = OP2_BT; + *(out++) = MODE_REG_DISPLACE8 | dst_base | (src << 3); + *(out++) = dst_disp; + return out; +} + +uint8_t * bt_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size) +{ + 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++; + } + *(out++) = PRE_2BYTE; + *(out++) = OP2_BTX_I; + *(out++) = MODE_REG_DIRECT | dst | (OP_EX_BT << 3); + *(out++) = val; + return out; +} + +uint8_t * bt_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size) +{ + if (size == SZ_W) { + *(out++) = PRE_SIZE; + } + if (size == SZ_Q || dst_base >= R8) { + *out = PRE_REX; + if (size == SZ_Q) { + *out |= REX_QUAD; + } + if (dst_base >= R8) { + *out |= REX_RM_FIELD; + dst_base -= (R8 - X86_R8); + } + out++; + } + *(out++) = PRE_2BYTE; + *(out++) = OP2_BTX_I; + *(out++) = MODE_REG_DISPLACE8 | dst_base | (OP_EX_BT << 3); + *(out++) = dst_disp; + *(out++) = val; + return out; +} + uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t * dest) { ptrdiff_t disp = dest-(out+2); diff -r 6ffea8607730 -r 918468c623e9 gen_x86.h --- a/gen_x86.h Tue Dec 18 23:55:10 2012 -0800 +++ b/gen_x86.h Wed Dec 19 20:23:59 2012 -0800 @@ -136,6 +136,10 @@ 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 * bt_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); +uint8_t * bt_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size); +uint8_t * bt_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size); +uint8_t * bt_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size); 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); diff -r 6ffea8607730 -r 918468c623e9 m68k_to_x86.c --- a/m68k_to_x86.c Tue Dec 18 23:55:10 2012 -0800 +++ b/m68k_to_x86.c Wed Dec 19 20:23:59 2012 -0800 @@ -175,8 +175,9 @@ ea->base = SCRATCH1; break; case MODE_IMMEDIATE: + case MODE_IMMEDIATE_WORD: if (inst->variant != VAR_QUICK) { - if (inst->extra.size == OPSIZE_LONG) { + if (inst->extra.size == OPSIZE_LONG && inst->src.addr_mode == MODE_IMMEDIATE) { out = cycles(out, BUS); out = check_cycles(out); } @@ -254,6 +255,32 @@ ea->mode = MODE_REG_DIRECT; ea->base = SCRATCH1; break; + case MODE_ABSOLUTE: + case MODE_ABSOLUTE_SHORT: + //Add cycles for reading address from instruction stream + if (inst->dst.addr_mode == MODE_ABSOLUTE) { + out = cycles(out, BUS*2); + } else { + out = cycles(out, BUS); + } + out = mov_ir(out, inst->dst.params.immed, SCRATCH1, SZ_D); + out = push_r(out, SCRATCH1); + 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; + } + out = pop_r(out, SCRATCH2); + ea->mode = MODE_REG_DIRECT; + ea->base = SCRATCH1; + break; default: printf("address mode %d not implemented (dst)\n", inst->dst.addr_mode); exit(1); @@ -1010,7 +1037,46 @@ case M68K_BCHG: case M68K_BCLR: case M68K_BSET: + break; case M68K_BTST: + dst = cycles(dst, inst->extra.size == OPSIZE_BYTE ? 4 : 6); + if (src_op.mode == MODE_IMMEDIATE) { + if (inst->extra.size == OPSIZE_BYTE) { + src_op.disp &= 0x7; + } + if (dst_op.mode == MODE_REG_DIRECT) { + dst = bt_ir(dst, src_op.disp, dst_op.base, SZ_D); + } else { + dst = bt_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, SZ_D); + } + } else { + if (src_op.mode == MODE_REG_DISPLACE8) { + if (dst_op.base == SCRATCH1) { + dst = push_r(dst, SCRATCH2); + dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_B); + src_op.base = SCRATCH1; + } else { + dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_B); + src_op.base = SCRATCH1; + } + } + if (inst->extra.size == OPSIZE_BYTE) { + dst = and_ir(dst, 0x7, src_op.base, SZ_B); + } + if (dst_op.mode == MODE_REG_DIRECT) { + dst = bt_rr(dst, src_op.base, dst_op.base, SZ_D); + } else { + dst = bt_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, SZ_D); + } + } + //x86 sets the carry flag to the value of the bit tested + //68K sets the zero flag to the complement of the bit tested + dst = setcc_r(dst, CC_NC, FLAG_Z); + if (src_op.base == SCRATCH2) { + dst = pop_r(dst, SCRATCH2); + } + dst = m68k_save_result(inst, dst, opts); + break; case M68K_CHK: break; case M68K_CMP: @@ -1096,7 +1162,6 @@ 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: