From 0f0b06b0999bf1b9097caa38f3c77ce9221f4141 Mon Sep 17 00:00:00 2001 From: gbeauche <> Date: Sat, 11 Jun 2005 06:43:24 +0000 Subject: [PATCH] Much improved responsiveness on NetBSD systems. On those systems, it's really hard to get high resolution timings and the system oftens fails to honour a timeout in less than 20 ms. The idea here is to have an average m68k instruction count (countdown quantum) that triggers real interrupt checks. The quantum is calibrated every 10 ticks and has a 1000 Hz resolution on average. --- BasiliskII/src/Unix/main_unix.cpp | 84 +++++++++++++++++-- BasiliskII/src/Unix/sysdeps.h | 13 +++ BasiliskII/src/Unix/video_x.cpp | 6 +- .../src/uae_cpu/compiler/compemu_support.cpp | 14 ++++ BasiliskII/src/uae_cpu/newcpu.cpp | 1 + BasiliskII/src/uae_cpu/newcpu.h | 13 +++ 6 files changed, 121 insertions(+), 10 deletions(-) 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 */