Mercurial > repos > blastem
comparison m68k_core_x86.c @ 847:7decd421cdc8
Update timing and order of steps in interrupt processing to match latest measurements
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 01 Nov 2015 00:12:52 -0700 |
parents | 98d7b6073163 |
children | 7022ba865cfd |
comparison
equal
deleted
inserted
replaced
846:98d7b6073163 | 847:7decd421cdc8 |
---|---|
2516 do_int = code->cur + 1; | 2516 do_int = code->cur + 1; |
2517 jcc(code, CC_NZ, do_int); | 2517 jcc(code, CC_NZ, do_int); |
2518 mov_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); | 2518 mov_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); |
2519 retn(code); | 2519 retn(code); |
2520 *do_int = code->cur - (do_int + 1); | 2520 *do_int = code->cur - (do_int + 1); |
2521 //save PC as stored in scratch1 for later | |
2522 push_r(code, opts->gen.scratch1); | |
2521 //set target cycle to sync cycle | 2523 //set target cycle to sync cycle |
2522 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.limit, SZ_D); | 2524 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.limit, SZ_D); |
2523 //swap USP and SSP if not already in supervisor mode | 2525 //swap USP and SSP if not already in supervisor mode |
2524 check_user_mode_swap_ssp_usp(opts); | 2526 check_user_mode_swap_ssp_usp(opts); |
2525 //save PC | |
2526 subi_areg(opts, 4, 7); | |
2527 areg_to_native(opts, 7, opts->gen.scratch2); | |
2528 call(code, opts->write_32_lowfirst); | |
2529 //save status register | 2527 //save status register |
2530 subi_areg(opts, 2, 7); | 2528 subi_areg(opts, 6, 7); |
2531 call(code, opts->get_sr); | 2529 call(code, opts->get_sr); |
2530 //6 cycles before SR gets saved | |
2531 cycles(&opts->gen, 6); | |
2532 //save SR to stack | |
2532 areg_to_native(opts, 7, opts->gen.scratch2); | 2533 areg_to_native(opts, 7, opts->gen.scratch2); |
2533 call(code, opts->write_16); | 2534 call(code, opts->write_16); |
2535 //interrupt ack cycle | |
2536 //the Genesis responds to these exclusively with !VPA which means its a slow | |
2537 //6800 operation. documentation says these can take between 10 and 19 cycles. | |
2538 //actual results measurements seem to suggest it's actually between 9 and 18 | |
2539 //WARNING: this code might break with register assignment changes | |
2540 //save RDX | |
2541 push_r(code, RDX); | |
2542 //save cycle count | |
2543 mov_rr(code, RAX, opts->gen.scratch1, SZ_D); | |
2544 //clear top doubleword of dividend | |
2545 xor_rr(code, RDX, RDX, SZ_D); | |
2546 //set divisor to clock divider | |
2547 mov_ir(code, opts->gen.clock_divider, opts->gen.scratch2, SZ_D); | |
2548 div_r(code, opts->gen.scratch2, SZ_D); | |
2549 //discard remainder | |
2550 xor_rr(code, RDX, RDX, SZ_D); | |
2551 //set divisor to 10, the period of E | |
2552 mov_ir(code, 10, opts->gen.scratch2, SZ_D); | |
2553 div_r(code, opts->gen.scratch2, SZ_D); | |
2554 //delay will be (9 + 4 + the remainder) * clock_divider | |
2555 //the extra 4 is to cover the idle bus period after the ack | |
2556 add_ir(code, 9 + 4, RDX, SZ_D); | |
2557 mov_ir(code, opts->gen.clock_divider, RAX, SZ_D); | |
2558 mul_r(code, RDX, SZ_D); | |
2559 pop_r(code, RDX); | |
2560 //add saved cycle count to result | |
2561 add_rr(code, opts->gen.scratch1, RAX, SZ_D); | |
2562 | |
2534 //update status register | 2563 //update status register |
2535 and_irdisp(code, 0xF8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | 2564 and_irdisp(code, 0xF8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); |
2536 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B); | 2565 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B); |
2537 or_ir(code, 0x20, opts->gen.scratch1, SZ_B); | 2566 or_ir(code, 0x20, opts->gen.scratch1, SZ_B); |
2538 or_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); | 2567 or_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); |
2568 | |
2569 pop_r(code, opts->gen.scratch1); | |
2570 | |
2571 //save PC | |
2572 areg_to_native(opts, 7, opts->gen.scratch2); | |
2573 add_ir(code, 2, opts->gen.scratch2, SZ_D); | |
2574 call(code, opts->write_32_lowfirst); | |
2575 | |
2539 //calculate interrupt vector address | 2576 //calculate interrupt vector address |
2540 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_D); | 2577 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_D); |
2541 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_ack), SZ_W); | 2578 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_ack), SZ_W); |
2542 shl_ir(code, 2, opts->gen.scratch1, SZ_D); | 2579 shl_ir(code, 2, opts->gen.scratch1, SZ_D); |
2543 add_ir(code, 0x60, opts->gen.scratch1, SZ_D); | 2580 add_ir(code, 0x60, opts->gen.scratch1, SZ_D); |
2544 call(code, opts->read_32); | 2581 call(code, opts->read_32); |
2545 call(code, opts->native_addr_and_sync); | 2582 call(code, opts->native_addr_and_sync); |
2546 cycles(&opts->gen, 24); | 2583 //2 prefetch bus operations + 2 idle bus cycles |
2584 cycles(&opts->gen, 10); | |
2547 //discard function return address | 2585 //discard function return address |
2548 pop_r(code, opts->gen.scratch2); | 2586 pop_r(code, opts->gen.scratch2); |
2549 jmp_r(code, opts->gen.scratch1); | 2587 jmp_r(code, opts->gen.scratch1); |
2550 | 2588 |
2551 opts->trap = code->cur; | 2589 opts->trap = code->cur; |