mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-12-25 17:29:19 +00:00
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:
parent
e423a07632
commit
0f0b06b099
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user