comparison m68k_core_x86.c @ 1989:0d87116630c7

Fix cycle timing of a number of 68K instructions
author Michael Pavone <pavone@retrodev.com>
date Wed, 10 Jun 2020 19:08:41 -0700
parents 35722beaf895
children 8ee7ecbf3f21
comparison
equal deleted inserted replaced
1986:a042e046f7f2 1989:0d87116630c7
419 case MODE_AREG_PREDEC: 419 case MODE_AREG_PREDEC:
420 if (dst && inst->src.addr_mode == MODE_AREG_PREDEC) { 420 if (dst && inst->src.addr_mode == MODE_AREG_PREDEC) {
421 push_r(code, opts->gen.scratch1); 421 push_r(code, opts->gen.scratch1);
422 } 422 }
423 dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 :1)); 423 dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 :1));
424 if (!dst) { 424 if (!dst || (
425 inst->op != M68K_MOVE && inst->op != M68K_MOVEM
426 && inst->op != M68K_SUBX && inst->op != M68K_ADDX
427 && inst->op != M68K_ABCD && inst->op != M68K_SBCD
428 )) {
425 cycles(&opts->gen, PREDEC_PENALTY); 429 cycles(&opts->gen, PREDEC_PENALTY);
426 } 430 }
427 subi_areg(opts, dec_amount, op->params.regs.pri); 431 subi_areg(opts, dec_amount, op->params.regs.pri);
428 case MODE_AREG_INDIRECT: 432 case MODE_AREG_INDIRECT:
429 case MODE_AREG_POSTINC: 433 case MODE_AREG_POSTINC:
872 mov_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B); 876 mov_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
873 } 877 }
874 code_ptr end_off = code->cur+1; 878 code_ptr end_off = code->cur+1;
875 jmp(code, code->cur+2); 879 jmp(code, code->cur+2);
876 *true_off = code->cur - (true_off+1); 880 *true_off = code->cur - (true_off+1);
877 cycles(&opts->gen, 6); 881 cycles(&opts->gen, inst->dst.addr_mode == MODE_REG ? 6 : 4);
878 if (dst_op.mode == MODE_REG_DIRECT) { 882 if (dst_op.mode == MODE_REG_DIRECT) {
879 mov_ir(code, 0xFF, dst_op.base, SZ_B); 883 mov_ir(code, 0xFF, dst_op.base, SZ_B);
880 } else { 884 } else {
881 mov_irdisp(code, 0xFF, dst_op.base, dst_op.disp, SZ_B); 885 mov_irdisp(code, 0xFF, dst_op.base, dst_op.disp, SZ_B);
882 } 886 }
1188 } 1192 }
1189 1193
1190 void translate_m68k_reset(m68k_options *opts, m68kinst *inst) 1194 void translate_m68k_reset(m68k_options *opts, m68kinst *inst)
1191 { 1195 {
1192 code_info *code = &opts->gen.code; 1196 code_info *code = &opts->gen.code;
1193 //RESET instructions take a long time to give peripherals time to reset themselves
1194 cycles(&opts->gen, 132);
1195 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, reset_handler), opts->gen.scratch1, SZ_PTR); 1197 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, reset_handler), opts->gen.scratch1, SZ_PTR);
1196 cmp_ir(code, 0, opts->gen.scratch1, SZ_PTR); 1198 cmp_ir(code, 0, opts->gen.scratch1, SZ_PTR);
1197 code_ptr no_reset_handler = code->cur + 1; 1199 code_ptr no_reset_handler = code->cur + 1;
1198 jcc(code, CC_Z, code->cur+2); 1200 jcc(code, CC_Z, code->cur+2);
1199 call(code, opts->gen.save_context); 1201 call(code, opts->gen.save_context);
1200 call_args_r(code, opts->gen.scratch1, 1, opts->gen.context_reg); 1202 call_args_r(code, opts->gen.scratch1, 1, opts->gen.context_reg);
1201 mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); 1203 mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
1202 call(code, opts->gen.load_context); 1204 call(code, opts->gen.load_context);
1203 *no_reset_handler = code->cur - (no_reset_handler + 1); 1205 *no_reset_handler = code->cur - (no_reset_handler + 1);
1206 //RESET instructions take a long time to give peripherals time to reset themselves
1207 cycles(&opts->gen, 132);
1204 } 1208 }
1205 1209
1206 void op_ir(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, uint8_t size) 1210 void op_ir(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, uint8_t size)
1207 { 1211 {
1208 switch (inst->op) 1212 switch (inst->op)
1307 code_info *code = &opts->gen.code; 1311 code_info *code = &opts->gen.code;
1308 uint8_t size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size; 1312 uint8_t size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size;
1309 1313
1310 uint32_t numcycles; 1314 uint32_t numcycles;
1311 if ((inst->op == M68K_ADDX || inst->op == M68K_SUBX) && inst->src.addr_mode != MODE_REG) { 1315 if ((inst->op == M68K_ADDX || inst->op == M68K_SUBX) && inst->src.addr_mode != MODE_REG) {
1312 numcycles = 6; 1316 numcycles = 4;
1313 } else if (size == OPSIZE_LONG) { 1317 } else if (size == OPSIZE_LONG) {
1314 if (inst->op == M68K_CMP) { 1318 if (inst->op == M68K_CMP) {
1319 numcycles = inst->src.addr_mode > MODE_AREG && inst->dst.addr_mode > MODE_AREG ? 4 : 6;
1320 } else if (inst->op == M68K_AND && inst->variant == VAR_IMMEDIATE && inst->dst.addr_mode == MODE_REG) {
1315 numcycles = 6; 1321 numcycles = 6;
1316 } else if (inst->op == M68K_AND && inst->variant == VAR_IMMEDIATE) { 1322 } else if (inst->dst.addr_mode == MODE_REG) {
1317 numcycles = 6;
1318 } else if (inst->dst.addr_mode <= MODE_AREG) {
1319 numcycles = inst->src.addr_mode <= MODE_AREG || inst->src.addr_mode == MODE_IMMEDIATE ? 8 : 6; 1323 numcycles = inst->src.addr_mode <= MODE_AREG || inst->src.addr_mode == MODE_IMMEDIATE ? 8 : 6;
1324 } else if (inst->dst.addr_mode == MODE_AREG) {
1325 numcycles = numcycles = inst->src.addr_mode <= MODE_AREG || inst->src.addr_mode == MODE_IMMEDIATE
1326 || inst->extra.size == OPSIZE_WORD ? 8 : 6;
1320 } else { 1327 } else {
1321 numcycles = 4; 1328 numcycles = 4;
1322 } 1329 }
1323 } else { 1330 } else {
1324 numcycles = 4; 1331 numcycles = 4;
1491 } 1498 }
1492 if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_AREG_PREDEC) { 1499 if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_AREG_PREDEC) {
1493 //destination is in memory so we need to preserve scratch2 for the write at the end 1500 //destination is in memory so we need to preserve scratch2 for the write at the end
1494 push_r(code, opts->gen.scratch2); 1501 push_r(code, opts->gen.scratch2);
1495 } 1502 }
1496 //MC68000 User's Manual suggests NBCD hides the 2 cycle penalty during the write cycle somehow 1503
1497 cycles(&opts->gen, inst->op == M68K_NBCD && inst->dst.addr_mode != MODE_REG_DIRECT ? BUS : BUS + 2); 1504 //reg to reg takes 6 cycles, mem to mem is 4 cycles + all the operand fetch/writing (including 2 cycle predec penalty for first operand)
1505 cycles(&opts->gen, inst->dst.addr_mode != MODE_REG ? BUS : BUS + 2);
1498 uint8_t other_reg; 1506 uint8_t other_reg;
1499 //WARNING: This may need adjustment if register assignments change 1507 //WARNING: This may need adjustment if register assignments change
1500 if (opts->gen.scratch2 > RBX) { 1508 if (opts->gen.scratch2 > RBX) {
1501 other_reg = RAX; 1509 other_reg = RAX;
1502 xchg_rr(code, opts->gen.scratch2, RAX, SZ_D); 1510 xchg_rr(code, opts->gen.scratch2, RAX, SZ_D);
2066 } 2074 }
2067 2075
2068 void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) 2076 void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
2069 { 2077 {
2070 code_info *code = &opts->gen.code; 2078 code_info *code = &opts->gen.code;
2071 cycles(&opts->gen, BUS); 2079 cycles(&opts->gen, inst->extra.size == OPSIZE_LONG && inst->dst.addr_mode == MODE_REG ? BUS+2 : BUS);
2072 if (dst_op->mode == MODE_REG_DIRECT) { 2080 if (dst_op->mode == MODE_REG_DIRECT) {
2073 if (dst_op->base == opts->gen.scratch1) { 2081 if (dst_op->base == opts->gen.scratch1) {
2074 push_r(code, opts->gen.scratch2); 2082 push_r(code, opts->gen.scratch2);
2075 xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, inst->extra.size); 2083 xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, inst->extra.size);
2076 flag_to_carry(opts, FLAG_X); 2084 flag_to_carry(opts, FLAG_X);
2132 } else { 2140 } else {
2133 op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); 2141 op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
2134 } 2142 }
2135 update_flags(opts, init_flags); 2143 update_flags(opts, init_flags);
2136 } else { 2144 } else {
2145 cycles(&opts->gen, inst->extra.size == OPSIZE_LONG ? 8 : 6);
2137 if (src_op->mode == MODE_REG_DIRECT) { 2146 if (src_op->mode == MODE_REG_DIRECT) {
2138 if (src_op->base != opts->gen.scratch1) { 2147 if (src_op->base != opts->gen.scratch1) {
2139 mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B); 2148 mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B);
2140 } 2149 }
2141 } else { 2150 } else {
2439 } 2448 }
2440 2449
2441 void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) 2450 void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
2442 { 2451 {
2443 code_info *code = &opts->gen.code; 2452 code_info *code = &opts->gen.code;
2444 cycles(&opts->gen, inst->dst.addr_mode == MODE_REG_DIRECT ? BUS+2 : BUS); 2453 cycles(&opts->gen, inst->dst.addr_mode == MODE_REG ? BUS+2 : BUS);
2445 call(code, opts->get_sr); 2454 call(code, opts->get_sr);
2446 if (dst_op->mode == MODE_REG_DIRECT) { 2455 if (dst_op->mode == MODE_REG_DIRECT) {
2447 mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_W); 2456 mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_W);
2448 } else { 2457 } else {
2449 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_W); 2458 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_W);