comparison z80_to_x86.c @ 1376:70d88d9bfe13

Implemented Z80 NMI
author Michael Pavone <pavone@retrodev.com>
date Sun, 28 May 2017 21:02:47 -0700
parents cad1642baf66
children 4e5797b3935a
comparison
equal deleted inserted replaced
1375:b68732dcbf00 1376:70d88d9bfe13
3414 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.scratch2, SZ_D); 3414 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.scratch2, SZ_D);
3415 mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, target_cycle), SZ_D); 3415 mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, target_cycle), SZ_D);
3416 neg_r(code, options->gen.cycles, SZ_D); 3416 neg_r(code, options->gen.cycles, SZ_D);
3417 add_rr(code, options->gen.scratch2, options->gen.cycles, SZ_D); 3417 add_rr(code, options->gen.scratch2, options->gen.cycles, SZ_D);
3418 //disable interrupts 3418 //disable interrupts
3419 cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B);
3420 code_ptr is_nmi = code->cur + 1;
3421 jcc(code, CC_NZ, is_nmi);
3419 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B); 3422 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
3420 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B); 3423 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
3424 code_ptr after_int_disable = code->cur + 1;
3425 jmp(code, after_int_disable);
3426 *is_nmi = code->cur - (is_nmi + 1);
3427 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, iff1), options->gen.scratch2, SZ_B);
3428 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
3429 mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
3430 *after_int_disable = code->cur - (after_int_disable + 1);
3421 cycles(&options->gen, 7); 3431 cycles(&options->gen, 7);
3422 //save return address (in scratch1) to Z80 stack 3432 //save return address (in scratch1) to Z80 stack
3423 sub_ir(code, 2, options->regs[Z80_SP], SZ_W); 3433 sub_ir(code, 2, options->regs[Z80_SP], SZ_W);
3424 mov_rr(code, options->regs[Z80_SP], options->gen.scratch2, SZ_W); 3434 mov_rr(code, options->regs[Z80_SP], options->gen.scratch2, SZ_W);
3425 //we need to do check_cycles and cycles outside of the write_8 call 3435 //we need to do check_cycles and cycles outside of the write_8 call
3439 check_cycles(&options->gen); 3449 check_cycles(&options->gen);
3440 cycles(&options->gen, 3); 3450 cycles(&options->gen, 3);
3441 call(code, options->write_8_noinc); 3451 call(code, options->write_8_noinc);
3442 //dispose of return address as we'll be jumping somewhere else 3452 //dispose of return address as we'll be jumping somewhere else
3443 add_ir(code, 16, RSP, SZ_PTR); 3453 add_ir(code, 16, RSP, SZ_PTR);
3454 cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B);
3455 is_nmi = code->cur + 1;
3456 jcc(code, CC_NZ, is_nmi);
3444 //TODO: Support interrupt mode 0 and 2 3457 //TODO: Support interrupt mode 0 and 2
3445 mov_ir(code, 0x38, options->gen.scratch1, SZ_W); 3458 mov_ir(code, 0x38, options->gen.scratch1, SZ_W);
3459 code_ptr after_int_dest = code->cur + 1;
3460 jmp(code, after_int_dest);
3461 *is_nmi = code->cur - (is_nmi + 1);
3462 mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B);
3463 mov_irdisp(code, CYCLE_NEVER, options->gen.context_reg, offsetof(z80_context, nmi_start), SZ_D);
3464 mov_ir(code, 0x66, options->gen.scratch1, SZ_W);
3465 *after_int_dest = code->cur - (after_int_dest + 1);
3446 call(code, options->native_addr); 3466 call(code, options->native_addr);
3447 mov_rrind(code, options->gen.scratch1, options->gen.context_reg, SZ_PTR); 3467 mov_rrind(code, options->gen.scratch1, options->gen.context_reg, SZ_PTR);
3448 tmp_stack_off = code->stack_off; 3468 tmp_stack_off = code->stack_off;
3449 restore_callee_save_regs(code); 3469 restore_callee_save_regs(code);
3450 //return to caller of z80_run to sync 3470 //return to caller of z80_run to sync
3569 z80_context *context = calloc(1, ctx_size); 3589 z80_context *context = calloc(1, ctx_size);
3570 context->options = options; 3590 context->options = options;
3571 context->int_cycle = CYCLE_NEVER; 3591 context->int_cycle = CYCLE_NEVER;
3572 context->int_pulse_start = CYCLE_NEVER; 3592 context->int_pulse_start = CYCLE_NEVER;
3573 context->int_pulse_end = CYCLE_NEVER; 3593 context->int_pulse_end = CYCLE_NEVER;
3594 context->nmi_start = CYCLE_NEVER;
3574 3595
3575 return context; 3596 return context;
3597 }
3598
3599 static void check_nmi(z80_context *context)
3600 {
3601 if (context->nmi_start < context->int_cycle) {
3602 context->int_cycle = context->nmi_start;
3603 context->int_is_nmi = 1;
3604 }
3576 } 3605 }
3577 3606
3578 void z80_run(z80_context * context, uint32_t target_cycle) 3607 void z80_run(z80_context * context, uint32_t target_cycle)
3579 { 3608 {
3580 if (context->reset || context->busack) { 3609 if (context->reset || context->busack) {
3592 if (context->next_int_pulse && (context->int_pulse_end < context->current_cycle || context->int_pulse_end == CYCLE_NEVER)) { 3621 if (context->next_int_pulse && (context->int_pulse_end < context->current_cycle || context->int_pulse_end == CYCLE_NEVER)) {
3593 context->next_int_pulse(context); 3622 context->next_int_pulse(context);
3594 } 3623 }
3595 if (context->iff1) { 3624 if (context->iff1) {
3596 context->int_cycle = context->int_pulse_start < context->int_enable_cycle ? context->int_enable_cycle : context->int_pulse_start; 3625 context->int_cycle = context->int_pulse_start < context->int_enable_cycle ? context->int_enable_cycle : context->int_pulse_start;
3626 context->int_is_nmi = 0;
3597 } else { 3627 } else {
3598 context->int_cycle = CYCLE_NEVER; 3628 context->int_cycle = CYCLE_NEVER;
3599 } 3629 }
3630 check_nmi(context);
3631
3600 context->target_cycle = context->sync_cycle < context->int_cycle ? context->sync_cycle : context->int_cycle; 3632 context->target_cycle = context->sync_cycle < context->int_cycle ? context->sync_cycle : context->int_cycle;
3601 dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d (%d - %d)\n", context->current_cycle, context->sync_cycle, context->int_cycle, context->int_pulse_start, context->int_pulse_end); 3633 dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d (%d - %d)\n", context->current_cycle, context->sync_cycle, context->int_cycle, context->int_pulse_start, context->int_pulse_end);
3602 context->options->run(context); 3634 context->options->run(context);
3603 dprintf("Z80 ran to cycle %d\n", context->current_cycle); 3635 dprintf("Z80 ran to cycle %d\n", context->current_cycle);
3604 } 3636 }
3664 3696
3665 uint8_t z80_get_busack(z80_context * context, uint32_t cycle) 3697 uint8_t z80_get_busack(z80_context * context, uint32_t cycle)
3666 { 3698 {
3667 z80_run(context, cycle); 3699 z80_run(context, cycle);
3668 return context->busack; 3700 return context->busack;
3701 }
3702
3703 void z80_assert_nmi(z80_context *context, uint32_t cycle)
3704 {
3705 context->nmi_start = cycle;
3706 check_nmi(context);
3669 } 3707 }
3670 3708
3671 void z80_adjust_cycles(z80_context * context, uint32_t deduction) 3709 void z80_adjust_cycles(z80_context * context, uint32_t deduction)
3672 { 3710 {
3673 if (context->current_cycle < deduction) { 3711 if (context->current_cycle < deduction) {