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.
This commit is contained in:
gbeauche 2005-06-11 06:43:24 +00:00
parent e423a07632
commit 0f0b06b099
6 changed files with 121 additions and 10 deletions

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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 */

View File

@ -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;

View File

@ -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 */