diff --git a/src/arm/cpu.S b/src/arm/cpu.S index accb3804..f0ffb8eb 100644 --- a/src/arm/cpu.S +++ b/src/arm/cpu.S @@ -74,13 +74,12 @@ #define CPUStatsReset \ - SYM(r1, cpu65_opcode); \ - strb r0, [r1]; /* r0 should be next opcode */ \ eor r9, r9, r9; \ SYM(r1, cpu65_opcycles); \ strb r9, [r1]; \ SYM(r1, cpu65_rw); \ strb r9, [r1]; + #define CPUStatsSetRead \ SYM(r1, cpu65_rw); \ ldrb r9, [r1]; \ @@ -153,7 +152,8 @@ #define JumpNextInstruction \ TRACE_PROLOGUE \ GetFromPC_B \ - CPUStatsReset \ + SYM(r1, cpu65_opcode); \ + strb r0, [r1]; /* r0 should be next opcode */ \ SYM(r1, cpu65__opcodes); \ ldr r1, [r1, r0, LSL PTR_SHIFT]; \ bx r1; @@ -2431,19 +2431,33 @@ continue: add r9, r9, cycles_exe str r9, [r1] - SYM(r1, cpu65_cycles_to_execute) + SYM(r1, irqCheckTimeout) // AppleWin : CheckInterruptSources() + ldr r9, [r1] + subs r9, r9, cycles_exe + str r9, [r1] + bmi irq_checkpoint + +continue1: SYM(r1, cpu65_cycles_to_execute) ldr r9, [r1] subs r9, r9, cycles_exe str r9, [r1] bmi exit_cpu65_run beq exit_cpu65_run -continue1: SYM(r1, cpu65__signal) +continue2: SYM(r1, cpu65__signal) ldrb r0, [r1] orrs r0, r0, r0 bne exception + CPUStatsReset JumpNextInstruction +irq_checkpoint: + bl CALL(cpu_irqCheck); + SYM(r1, irqCheckTimeout) + eor r9, r9, r9 + str r9, [r1] + b continue1 + /* ------------------------------------------------------------------------- Exception handlers ------------------------------------------------------------------------- */ @@ -2466,10 +2480,12 @@ ex_reset: eor r0, r0, r0 ldrh EffectiveAddr, [EffectiveAddr] GetFromEA_W mov PC_Reg, r0 + CPUStatsReset JumpNextInstruction ex_irq: tst F_Reg, #I_Flag // Already interrupted? beq 1f + CPUStatsReset JumpNextInstruction // Yes (ignored) ... 1: TRACE_IRQ // No (handle IRQ) ... mov r0, PC_Reg @@ -2486,6 +2502,11 @@ ex_irq: tst F_Reg, #I_Flag // Already interrupt ldrh EffectiveAddr, [EffectiveAddr] GetFromEA_W mov PC_Reg, r0 + CPUStatsReset + SYM(r1, cpu65_opcycles) + ldrb r0, [r1] + add r0, r0, #7 // IRQ handling will take additional 7 cycles + strb r0, [r1] JumpNextInstruction /* ------------------------------------------------------------------------- @@ -2517,7 +2538,7 @@ ENTRY(cpu65_run) eorne r0, r0, r0 STRBNE r0, [r1] bne ex_reset - b continue1 + b continue2 /* ------------------------------------------------------------------------- 65c02 CPU processing loop exit point diff --git a/src/cpu.h b/src/cpu.h index b6ad0528..3bee4a68 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -73,6 +73,8 @@ void cpu65_trace_checkpoint(void); #endif /* !__ASSEMBLER__ */ +#define IRQ_CHECK_CYCLES 128 + #define ResetSig 0x02 #define IRQ6522 0x08 #define IRQSpeech 0x10 diff --git a/src/timing.c b/src/timing.c index 8937c5b7..f8fa4e8b 100644 --- a/src/timing.c +++ b/src/timing.c @@ -54,6 +54,7 @@ unsigned long cycles_count_total = 0; // Running at spec ~1MHz, this w int cycles_speaker_feedback = 0; int32_t cpu65_cycles_to_execute = 0; // cycles-to-execute by cpu65_run() int32_t cpu65_cycle_count = 0; // cycles currently excuted by cpu65_run() +int32_t irqCheckTimeout = IRQ_CHECK_CYCLES; static int32_t cycles_checkpoint_count = 0; static unsigned int g_dwCyclesThisFrame = 0; @@ -147,6 +148,8 @@ void reinitialize(void) { #endif cycles_count_total = 0; + g_dwCyclesThisFrame = 0; + irqCheckTimeout = IRQ_CHECK_CYCLES; #if TESTING extern unsigned long (*testing_getCyclesCount)(void); if (testing_getCyclesCount) { @@ -343,7 +346,7 @@ cpu_runloop: MB_StartOfCpuExecute(); if (is_debugging) { - debugging_cycles = cpu65_cycles_to_execute; + debugging_cycles = cpu65_cycles_to_execute; } do { @@ -354,10 +357,15 @@ cpu_runloop: cpu65_cycle_count = 0; cycles_checkpoint_count = 0; cpu65_run(); // run emulation for cpu65_cycles_to_execute cycles ... +#if DEBUG_TIMING + dbg_cycles_executed += cpu65_cycle_count; +#endif + g_dwCyclesThisFrame += cpu65_cycle_count; if (is_debugging) { debugging_cycles -= cpu65_cycle_count; timing_checkpoint_cycles(); + if (c_debugger_should_break() || (debugging_cycles <= 0)) { int err = 0; if ((err = pthread_cond_signal(&dbg_thread_cond))) { @@ -370,18 +378,15 @@ cpu_runloop: break; } } + if (emul_reinitialize) { pthread_mutex_unlock(&interface_mutex); goto cpu_runloop; } } } while (is_debugging); -#if DEBUG_TIMING - dbg_cycles_executed += cpu65_cycle_count; -#endif - g_dwCyclesThisFrame += cpu65_cycle_count; - MB_UpdateCycles(); // update 6522s (NOTE: do this before updating cycles_count_total) + MB_UpdateCycles(); timing_checkpoint_cycles(); @@ -536,6 +541,8 @@ void timing_stopCPU(void) { } unsigned int CpuGetCyclesThisVideoFrame(void) { + assert(pthread_self() == cpu_thread_id); + timing_checkpoint_cycles(); return g_dwCyclesThisFrame + cycles_checkpoint_count; } @@ -546,11 +553,11 @@ void timing_checkpoint_cycles(void) { const int32_t d = cpu65_cycle_count - cycles_checkpoint_count; assert(d >= 0); -#if TESTING - unsigned long previous_cycles_count_total = cycles_count_total; -#endif +#if !TESTING + cycles_count_total += d; +#else + unsigned long previous_cycles_count_total = cycles_count_total; cycles_count_total += d; -#if TESTING if (UNLIKELY(cycles_count_total < previous_cycles_count_total)) { extern void (*testing_cyclesOverflow)(void); if (testing_cyclesOverflow) { diff --git a/src/vm.c b/src/vm.c index 9df74ca0..210bbfa1 100644 --- a/src/vm.c +++ b/src/vm.c @@ -918,6 +918,12 @@ GLUE_C_READ(debug_illegal_bcd) return 0; } +GLUE_C_WRITE(cpu_irqCheck) +{ + MB_UpdateCycles(); + // TODO : other peripheral card interrupt handling +} + // ---------------------------------------------------------------------------- static void _initialize_iie_switches(void) { diff --git a/src/x86/cpu.S b/src/x86/cpu.S index 9daee18e..1c1a22cb 100644 --- a/src/x86/cpu.S +++ b/src/x86/cpu.S @@ -90,12 +90,14 @@ CALL_IND(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR); \ TRACE_ARG1; +#define CPUStatsReset \ + REG2MEM(movb, $0, cpu65_opcycles); \ + REG2MEM(movb, $0, cpu65_rw); + #define JumpNextInstruction \ TRACE_PROLOGUE; \ GetFromPC_B \ REG2MEM(movb, %al, cpu65_opcode); \ - REG2MEM(movb, $0, cpu65_opcycles); \ - REG2MEM(movb, $0, cpu65_rw); \ JUMP_IND(cpu65__opcodes,_XAX,SZ_PTR); #define GetFromEA_B \ @@ -2160,14 +2162,21 @@ continue: REG2MEM(addl, %eax, cpu65_cycle_count) REG2MEM(subl, %eax, gc_cycles_timer_0) REG2MEM(subl, %eax, gc_cycles_timer_1) - REG2MEM(subl, %eax, cpu65_cycles_to_execute) + REG2MEM(subl, %eax, irqCheckTimeout) + jl irq_checkpoint // AppleWin : CheckInterruptSources() +continue1: REG2MEM(subl, %eax, cpu65_cycles_to_execute) jle exit_cpu65_run - -continue1: xorLQ _XAX, _XAX +continue2: xorLQ _XAX, _XAX MEM2REG(orb, cpu65__signal, %al) jnz exception + CPUStatsReset JumpNextInstruction +irq_checkpoint: + CALL_FN(callLQ, cpu_irqCheck, 0x4) + REG2MEM(movl, $IRQ_CHECK_CYCLES, irqCheckTimeout) + jmp continue1 + /* ------------------------------------------------------------------------- Exception handlers ------------------------------------------------------------------------- */ @@ -2184,10 +2193,12 @@ ex_reset: REG2MEM(movb, $0, cpu65__signal) GetFromEA_W movw %ax, PC_Reg xorb %ah, %ah + CPUStatsReset JumpNextInstruction ex_irq: testb $I_Flag, F_Reg // Already interrupted? jz 1f + CPUStatsReset JumpNextInstruction // Yes (ignored) ... 1: TRACE_IRQ // No (handle IRQ) ... movw PC_Reg, %ax @@ -2210,6 +2221,8 @@ ex_irq: testb $I_Flag, F_Reg // Already interrupt GetFromEA_W movw %ax, PC_Reg xorb %ah, %ah + CPUStatsReset + REG2MEM(addb, $7, cpu65_opcycles); // IRQ handling will take additional 7 cycles JumpNextInstruction /* ------------------------------------------------------------------------- @@ -2256,7 +2269,7 @@ ENTRY(cpu65_run) #endif REG2MEM(cmpb, $0, emul_reinitialize) jnz enter_reinit - jmp continue1 + jmp continue2 enter_reinit: REG2MEM(movb, $0, emul_reinitialize) jmp ex_reset