# HG changeset patch # User Mike Pavone # Date 1359167962 28800 # Node ID c82f65a87a5331136aad3e70661141f38de9cf12 # Parent 807ca611b561eb5cbf5aeebac178c45f43fc413c Fix overflow flag on ASL diff -r 807ca611b561 -r c82f65a87a53 gen_x86.c --- a/gen_x86.c Wed Jan 23 21:54:58 2013 -0800 +++ b/gen_x86.c Fri Jan 25 18:39:22 2013 -0800 @@ -35,6 +35,7 @@ #define OP_MOV_IEA 0xC6 #define OP_SHIFTROT_1 0xD0 #define OP_SHIFTROT_CL 0xD2 +#define OP_LOOP 0xE2 #define OP_CALL 0xE8 #define OP_JMP 0xE9 #define OP_JMP_BYTE 0xEB @@ -1533,4 +1534,10 @@ return out; } - +uint8_t * loop(uint8_t * out, uint8_t * dst) +{ + ptrdiff_t disp = dst-(out+2); + *(out++) = OP_LOOP; + *(out++) = disp; + return out; +} diff -r 807ca611b561 -r c82f65a87a53 gen_x86.h --- a/gen_x86.h Wed Jan 23 21:54:58 2013 -0800 +++ b/gen_x86.h Fri Jan 25 18:39:22 2013 -0800 @@ -190,6 +190,7 @@ uint8_t * call_r(uint8_t * out, uint8_t dst); uint8_t * retn(uint8_t * out); uint8_t * cdq(uint8_t * out); +uint8_t * loop(uint8_t * out, uint8_t * dst); #endif //GEN_X86_H_ diff -r 807ca611b561 -r c82f65a87a53 m68k_to_x86.c --- a/m68k_to_x86.c Wed Jan 23 21:54:58 2013 -0800 +++ b/m68k_to_x86.c Fri Jan 25 18:39:22 2013 -0800 @@ -92,7 +92,7 @@ void print_regs_exit(m68k_context * context) { - printf("XNVZC\n%d%d%d%d%d\n", context->flags[0], context->flags[1], context->flags[2], context->flags[3], context->flags[4]); + printf("XNZVC\n%d%d%d%d%d\n", context->flags[0], context->flags[1], context->flags[2], context->flags[3], context->flags[4]); for (int i = 0; i < 8; i++) { printf("d%d: %X\n", i, context->dregs[i]); } @@ -2619,6 +2619,8 @@ uint8_t * translate_shift(uint8_t * dst, m68kinst * inst, x86_ea *src_op, x86_ea * dst_op, x86_68k_options * opts, shift_ir_t shift_ir, shift_irdisp8_t shift_irdisp8, shift_clr_t shift_clr, shift_clrdisp8_t shift_clrdisp8, shift_ir_t special, shift_irdisp8_t special_disp8) { uint8_t * end_off = NULL; + uint8_t * nz_off = NULL; + uint8_t * z_off = NULL; if (inst->src.addr_mode == MODE_UNUSED) { dst = cycles(dst, BUS); //Memory shift @@ -2626,10 +2628,24 @@ } else { dst = cycles(dst, inst->extra.size == OPSIZE_LONG ? 8 : 6); if (src_op->mode == MODE_IMMED) { - if (dst_op->mode == MODE_REG_DIRECT) { - dst = shift_ir(dst, src_op->disp, dst_op->base, inst->extra.size); + if (src_op->disp != 1 && inst->op == M68K_ASL) { + dst = mov_ir(dst, 0, FLAG_V, SZ_B); + for (int i = 0; i < src_op->disp; i++) { + if (dst_op->mode == MODE_REG_DIRECT) { + dst = shift_ir(dst, 1, dst_op->base, inst->extra.size); + } else { + dst = shift_irdisp8(dst, 1, dst_op->base, dst_op->disp, inst->extra.size); + } + //dst = setcc_r(dst, CC_O, FLAG_V); + dst = jcc(dst, CC_NO, dst+4); + dst = mov_ir(dst, 1, FLAG_V, SZ_B); + } } else { - dst = shift_irdisp8(dst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); + if (dst_op->mode == MODE_REG_DIRECT) { + dst = shift_ir(dst, src_op->disp, dst_op->base, inst->extra.size); + } else { + dst = shift_irdisp8(dst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); + } } } else { if (src_op->base != RCX) { @@ -2638,58 +2654,92 @@ } else { dst = mov_rdisp8r(dst, src_op->base, src_op->disp, RCX, SZ_B); } + } dst = and_ir(dst, 63, RCX, SZ_D); + nz_off = dst+1; + dst = jcc(dst, CC_NZ, dst+2); + //Flag behavior for shift count of 0 is different for x86 than 68K + if (dst_op->mode == MODE_REG_DIRECT) { + dst = cmp_ir(dst, 0, dst_op->base, inst->extra.size); + } else { + dst = cmp_irdisp8(dst, 0, dst_op->base, dst_op->disp, inst->extra.size); + } + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + dst = mov_ir(dst, 0, FLAG_C, SZ_B); + //For other instructions, this flag will be set below + if (inst->op == M68K_ASL) { + dst = mov_ir(dst, 0, FLAG_V, SZ_B); + } + z_off = dst+1; + dst = jmp(dst, dst+2); + *nz_off = dst - (nz_off + 1); //add 2 cycles for every bit shifted dst = add_rr(dst, RCX, CYCLES, SZ_D); dst = add_rr(dst, RCX, CYCLES, SZ_D); - //x86 shifts modulo 32 for operand sizes less than 64-bits - //but M68K shifts modulo 64, so we need to check for large shifts here - dst = cmp_ir(dst, 32, RCX, SZ_B); - uint8_t * norm_shift_off = dst + 1; - dst = jcc(dst, CC_L, dst+2); - if (special) { - if (inst->extra.size == OPSIZE_LONG) { - uint8_t * neq_32_off = dst + 1; - dst = jcc(dst, CC_NZ, dst+2); - - //set the carry bit to the lsb - if (dst_op->mode == MODE_REG_DIRECT) { - dst = special(dst, 1, dst_op->base, SZ_D); - } else { - dst = special_disp8(dst, 1, dst_op->base, dst_op->disp, SZ_D); - } - dst = setcc_r(dst, CC_C, FLAG_C); - dst = jmp(dst, dst+4); - *neq_32_off = dst - (neq_32_off+1); - } - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - dst = mov_ir(dst, 1, FLAG_Z, SZ_B); - dst = mov_ir(dst, 0, FLAG_N, SZ_B); + if (inst->op == M68K_ASL) { + //ASL has Overflow flag behavior that depends on all of the bits shifted through the MSB + //Easiest way to deal with this is to shift one bit at a time + dst = mov_ir(dst, 0, FLAG_V, SZ_B); + uint8_t * loop_start = dst; if (dst_op->mode == MODE_REG_DIRECT) { - dst = xor_rr(dst, dst_op->base, dst_op->base, inst->extra.size); - } else { - dst = mov_irdisp8(dst, 0, dst_op->base, dst_op->disp, inst->extra.size); - } - } else { - if (dst_op->mode == MODE_REG_DIRECT) { - dst = shift_ir(dst, 31, dst_op->base, inst->extra.size); dst = shift_ir(dst, 1, dst_op->base, inst->extra.size); } else { - dst = shift_irdisp8(dst, 31, dst_op->base, dst_op->disp, inst->extra.size); dst = shift_irdisp8(dst, 1, dst_op->base, dst_op->disp, inst->extra.size); } + //dst = setcc_r(dst, CC_O, FLAG_V); + dst = jcc(dst, CC_NO, dst+4); + dst = mov_ir(dst, 1, FLAG_V, SZ_B); + dst = loop(dst, loop_start); + } else { + //x86 shifts modulo 32 for operand sizes less than 64-bits + //but M68K shifts modulo 64, so we need to check for large shifts here + dst = cmp_ir(dst, 32, RCX, SZ_B); + uint8_t * norm_shift_off = dst + 1; + dst = jcc(dst, CC_L, dst+2); + if (special) { + if (inst->extra.size == OPSIZE_LONG) { + uint8_t * neq_32_off = dst + 1; + dst = jcc(dst, CC_NZ, dst+2); + + //set the carry bit to the lsb + if (dst_op->mode == MODE_REG_DIRECT) { + dst = special(dst, 1, dst_op->base, SZ_D); + } else { + dst = special_disp8(dst, 1, dst_op->base, dst_op->disp, SZ_D); + } + dst = setcc_r(dst, CC_C, FLAG_C); + dst = jmp(dst, dst+4); + *neq_32_off = dst - (neq_32_off+1); + } + dst = mov_ir(dst, 0, FLAG_C, SZ_B); + dst = mov_ir(dst, 1, FLAG_Z, SZ_B); + dst = mov_ir(dst, 0, FLAG_N, SZ_B); + if (dst_op->mode == MODE_REG_DIRECT) { + dst = xor_rr(dst, dst_op->base, dst_op->base, inst->extra.size); + } else { + dst = mov_irdisp8(dst, 0, dst_op->base, dst_op->disp, inst->extra.size); + } + } else { + if (dst_op->mode == MODE_REG_DIRECT) { + dst = shift_ir(dst, 31, dst_op->base, inst->extra.size); + dst = shift_ir(dst, 1, dst_op->base, inst->extra.size); + } else { + dst = shift_irdisp8(dst, 31, dst_op->base, dst_op->disp, inst->extra.size); + dst = shift_irdisp8(dst, 1, dst_op->base, dst_op->disp, inst->extra.size); + } + } + end_off = dst+1; + dst = jmp(dst, dst+2); + *norm_shift_off = dst - (norm_shift_off+1); + if (dst_op->mode == MODE_REG_DIRECT) { + dst = shift_clr(dst, dst_op->base, inst->extra.size); + } else { + dst = shift_clrdisp8(dst, dst_op->base, dst_op->disp, inst->extra.size); + } } - end_off = dst+1; - dst = jmp(dst, dst+2); - *norm_shift_off = dst - (norm_shift_off+1); - if (dst_op->mode == MODE_REG_DIRECT) { - dst = shift_clr(dst, dst_op->base, inst->extra.size); - } else { - dst = shift_clrdisp8(dst, dst_op->base, dst_op->disp, inst->extra.size); - } - } } @@ -2702,9 +2752,14 @@ if (special && end_off) { *end_off = dst - (end_off + 1); } - dst = mov_ir(dst, 0, FLAG_V, SZ_B); //set X flag to same as C flag dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); + if (z_off) { + *z_off = dst - (z_off + 1); + } + if (inst->op != M68K_ASL && inst->src.addr_mode != MODE_UNUSED && !(src_op->mode == MODE_IMMED && src_op->disp == 1)) { + dst = mov_ir(dst, 0, FLAG_V, SZ_B); + } if (inst->src.addr_mode == MODE_UNUSED) { dst = m68k_save_result(inst, dst, opts); } diff -r 807ca611b561 -r c82f65a87a53 runtime.S --- a/runtime.S Wed Jan 23 21:54:58 2013 -0800 +++ b/runtime.S Fri Jan 25 18:39:22 2013 -0800 @@ -598,8 +598,8 @@ .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 %dl, 2(%rsi) /* Z flag */ + mov %bh, 3(%rsi) /* V flag */ mov %dh, 4(%rsi) /* C flag */ mov %r10d, 8(%rsi) /* d0 */ mov %r11d, 12(%rsi) /* d1 */ @@ -613,8 +613,8 @@ .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 2(%rsi), %dl /* Z flag */ + mov 3(%rsi), %bh /* V flag */ mov 4(%rsi), %dh /* C flag */ mov 8(%rsi), %r10d /* d0 */ mov 12(%rsi), %r11d /* d1 */