diff --git a/BasiliskII/src/Unix/main_unix.cpp b/BasiliskII/src/Unix/main_unix.cpp index 9653ed52..1ac70743 100644 --- a/BasiliskII/src/Unix/main_unix.cpp +++ b/BasiliskII/src/Unix/main_unix.cpp @@ -291,6 +291,68 @@ static void sigsegv_dump_state(sigsegv_address_t fault_address, sigsegv_address_ } +/* + * Update virtual clock and trigger interrupts if necessary + */ + +#ifdef USE_CPU_EMUL_SERVICES +static uint64 n_check_ticks = 0; +static uint64 emulated_ticks_start = 0; +static uint64 emulated_ticks_count = 0; +static int64 emulated_ticks_current = 0; +static int32 emulated_ticks_quantum = 1000; +int32 emulated_ticks = emulated_ticks_quantum; + +void cpu_do_check_ticks(void) +{ +#if DEBUG + n_check_ticks++; +#endif + + uint64 now; + static uint64 next = 0; + if (next == 0) + next = emulated_ticks_start = GetTicks_usec(); + + // Update total instructions count + if (emulated_ticks <= 0) { + emulated_ticks_current += (emulated_ticks_quantum - emulated_ticks); + // XXX: can you really have a machine fast enough to overflow + // a 63-bit m68k instruction counter within 16 ms? + if (emulated_ticks_current < 0) { + printf("WARNING: Overflowed 63-bit m68k instruction counter in less than 16 ms!\n"); + goto recalibrate_quantum; + } + } + + // Check for interrupt opportunity + now = GetTicks_usec(); + if (next < now) { + one_tick(); + do { + next += 16625; + } while (next < now); + emulated_ticks_count++; + + // Recalibrate 1000 Hz quantum every 10 ticks + static uint64 last = 0; + if (last == 0) + last = now; + else if (now - last > 166250) { + recalibrate_quantum: + emulated_ticks_quantum = ((uint64)emulated_ticks_current * 1000) / (now - last); + emulated_ticks_current = 0; + last = now; + } + } + + // Update countdown + if (emulated_ticks <= 0) + emulated_ticks += emulated_ticks_quantum; +} +#endif + + /* * Main program */ @@ -652,6 +714,7 @@ int main(int argc, char **argv) sigaction(SIGINT, &sigint_sa, NULL); #endif +#ifndef USE_CPU_EMUL_SERVICES #if defined(HAVE_PTHREADS) // POSIX threads available, start 60Hz thread @@ -715,8 +778,9 @@ int main(int argc, char **argv) setitimer(ITIMER_REAL, &req, NULL); #endif +#endif -#ifdef HAVE_PTHREADS +#ifdef USE_PTHREADS_SERVICES // Start XPRAM watchdog thread memcpy(last_xpram, XPRAM, XPRAM_SIZE); xpram_thread_active = (pthread_create(&xpram_thread, NULL, xpram_func, NULL) == 0); @@ -745,7 +809,13 @@ void QuitEmulator(void) Exit680x0(); #endif -#if defined(HAVE_PTHREADS) +#if defined(USE_CPU_EMUL_SERVICES) + // Show statistics + uint64 emulated_ticks_end = GetTicks_usec(); + D(bug("%ld ticks in %ld usec = %f ticks/sec [%ld tick checks]\n", + (long)emulated_ticks_count, (long)(emulated_ticks_end - emulated_ticks_start), + emulated_ticks_count * 1000000.0 / (emulated_ticks_end - emulated_ticks_start), (long)n_check_ticks)); +#elif defined(USE_PTHREADS_SERVICES) // Stop 60Hz thread if (tick_thread_active) { tick_thread_cancel = true; @@ -764,7 +834,7 @@ void QuitEmulator(void) setitimer(ITIMER_REAL, &req, NULL); #endif -#ifdef HAVE_PTHREADS +#ifdef USE_PTHREADS_SERVICES // Stop XPRAM watchdog thread if (xpram_thread_active) { xpram_thread_cancel = true; @@ -1021,7 +1091,7 @@ static void xpram_watchdog(void) } } -#ifdef HAVE_PTHREADS +#ifdef USE_PTHREADS_SERVICES static void *xpram_func(void *arg) { while (!xpram_thread_cancel) { @@ -1046,7 +1116,7 @@ static void one_second(void) SetInterruptFlag(INTFLAG_1HZ); TriggerInterrupt(); -#ifndef HAVE_PTHREADS +#ifndef USE_PTHREADS_SERVICES static int second_counter = 0; if (++second_counter > 60) { second_counter = 0; @@ -1063,7 +1133,7 @@ static void one_tick(...) one_second(); } -#if !defined(HAVE_PTHREADS) && !defined(USE_SDL_VIDEO) +#if !defined(USE_PTHREADS_SERVICES) && !defined(USE_SDL_VIDEO) // No threads available, perform video refresh and networking from here VideoRefresh(); SetInterruptFlag(INTFLAG_ETHER); @@ -1076,7 +1146,7 @@ static void one_tick(...) } } -#ifdef HAVE_PTHREADS +#ifdef USE_PTHREADS_SERVICES static void *tick_func(void *arg) { uint64 start = GetTicks_usec(); diff --git a/BasiliskII/src/Unix/sysdeps.h b/BasiliskII/src/Unix/sysdeps.h index 46a39b0a..3b4a0c42 100644 --- a/BasiliskII/src/Unix/sysdeps.h +++ b/BasiliskII/src/Unix/sysdeps.h @@ -110,6 +110,19 @@ /* BSD socket API supported */ #define SUPPORTS_UDP_TUNNEL 1 +/* Use the CPU emulator to check for periodic tasks? */ +#ifdef HAVE_PTHREADS +#define USE_PTHREADS_SERVICES +#endif +#if EMULATED_68K +#if defined(__NetBSD__) +#define USE_CPU_EMUL_SERVICES +#endif +#endif +#ifdef USE_CPU_EMUL_SERVICES +#undef USE_PTHREADS_SERVICES +#endif + /* Data types */ typedef unsigned char uint8; diff --git a/BasiliskII/src/Unix/video_x.cpp b/BasiliskII/src/Unix/video_x.cpp index 238fdc07..dc53df1e 100644 --- a/BasiliskII/src/Unix/video_x.cpp +++ b/BasiliskII/src/Unix/video_x.cpp @@ -1549,7 +1549,7 @@ bool X11_monitor_desc::video_open(void) LOCK_FRAME_BUFFER; // Start redraw/input thread -#ifdef HAVE_PTHREADS +#ifdef USE_PTHREADS_SERVICES redraw_thread_cancel = false; Set_pthread_attr(&redraw_thread_attr, 0); redraw_thread_active = (pthread_create(&redraw_thread, &redraw_thread_attr, redraw_func, NULL) == 0); @@ -1745,7 +1745,7 @@ void X11_monitor_desc::video_close(void) D(bug("video_close()\n")); // Stop redraw thread -#ifdef HAVE_PTHREADS +#ifdef USE_PTHREADS_SERVICES if (redraw_thread_active) { redraw_thread_cancel = true; redraw_thread_cancel_ack = false; @@ -2596,7 +2596,7 @@ void VideoRefresh(void) const int VIDEO_REFRESH_HZ = 60; const int VIDEO_REFRESH_DELAY = 1000000 / VIDEO_REFRESH_HZ; -#ifdef HAVE_PTHREADS +#ifdef USE_PTHREADS_SERVICES static void *redraw_func(void *arg) { int fd = ConnectionNumber(x_display); diff --git a/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp b/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp index ad377a46..25a5ddec 100644 --- a/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp +++ b/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp @@ -6727,6 +6727,15 @@ static void compile_block(cpu_history* pc_hist, int blocklen) init_comp(); was_comp=1; +#ifdef USE_CPU_EMUL_SERVICES + raw_sub_l_mi((uintptr)&emulated_ticks,blocklen); + raw_jcc_b_oponly(NATIVE_CC_GT); + uae_s8 *branchadd=(uae_s8*)get_target(); + emit_byte(0); + raw_call((uintptr)cpu_do_check_ticks); + *branchadd=(uintptr)get_target()-((uintptr)branchadd+1); +#endif + #if JIT_DEBUG if (JITDebug) { raw_mov_l_mi((uintptr)&last_regs_pc_p,(uintptr)pc_hist[0].location); @@ -7037,6 +7046,9 @@ static void compile_block(cpu_history* pc_hist, int blocklen) compile_time += (clock() - start_time); #endif } + + /* Account for compilation time */ + cpu_do_check_ticks(); } void do_nothing(void) @@ -7052,6 +7064,7 @@ void exec_nostats(void) m68k_record_step(m68k_getpc()); #endif (*cpufunctbl[opcode])(opcode); + cpu_check_ticks(); if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL)) { return; /* We will deal with the spcflags in the caller */ } @@ -7077,6 +7090,7 @@ void execute_normal(void) m68k_record_step(m68k_getpc()); #endif (*cpufunctbl[opcode])(opcode); + cpu_check_ticks(); if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL) || blocklen>=MAXRUN) { compile_block(pc_hist, blocklen); return; /* We will deal with the spcflags in the caller */ diff --git a/BasiliskII/src/uae_cpu/newcpu.cpp b/BasiliskII/src/uae_cpu/newcpu.cpp index 9122a99d..a82f2c87 100644 --- a/BasiliskII/src/uae_cpu/newcpu.cpp +++ b/BasiliskII/src/uae_cpu/newcpu.cpp @@ -1349,6 +1349,7 @@ void m68k_do_execute (void) m68k_record_step(m68k_getpc()); #endif (*cpufunctbl[opcode])(opcode); + cpu_check_ticks(); if (SPCFLAGS_TEST(SPCFLAG_ALL_BUT_EXEC_RETURN)) { if (m68k_do_specialties()) return; diff --git a/BasiliskII/src/uae_cpu/newcpu.h b/BasiliskII/src/uae_cpu/newcpu.h index f3c47e6d..24518c16 100644 --- a/BasiliskII/src/uae_cpu/newcpu.h +++ b/BasiliskII/src/uae_cpu/newcpu.h @@ -295,5 +295,18 @@ extern void m68k_do_compile_execute(void); extern void m68k_compile_execute(void); #endif #endif +#ifdef USE_CPU_EMUL_SERVICES +extern int32 emulated_ticks; +extern void cpu_do_check_ticks(void); + +static inline void cpu_check_ticks(void) +{ + if (--emulated_ticks <= 0) + cpu_do_check_ticks(); +} +#else +#define cpu_check_ticks() +#define cpu_do_check_ticks() +#endif #endif /* NEWCPU_H */