diff options
Diffstat (limited to 'tools/ioemu/iodev/slowdown_timer.cc')
-rw-r--r-- | tools/ioemu/iodev/slowdown_timer.cc | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/tools/ioemu/iodev/slowdown_timer.cc b/tools/ioemu/iodev/slowdown_timer.cc new file mode 100644 index 0000000000..76d8613ec8 --- /dev/null +++ b/tools/ioemu/iodev/slowdown_timer.cc @@ -0,0 +1,182 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: slowdown_timer.cc,v 1.17.2.1 2004/02/06 22:14:36 danielg4 Exp $ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002 MandrakeSoft S.A. +// +// MandrakeSoft S.A. +// 43, rue d'Aboukir +// 75002 Paris - France +// http://www.linux-mandrake.com/ +// http://www.mandrakesoft.com/ +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include "bochs.h" +#include <errno.h> + +//These need to stay printfs because they are useless in the log file. +#define BX_SLOWDOWN_PRINTF_FEEDBACK 0 + +#define SECINUSEC 1000000 +#define usectosec(a) ((a)/SECINUSEC) +#define sectousec(a) ((a)*SECINUSEC) +#define nsectousec(a) ((a)/1000) + +#define MSECINUSEC 1000 +#define usectomsec(a) ((a)/MSECINUSEC) + +#if BX_HAVE_USLEEP +# define Qval 1000 +#else +# define Qval SECINUSEC +#endif + +#define MAXMULT 1.5 +#define REALTIME_Q SECINUSEC + +#define LOG_THIS bx_slowdown_timer. + +bx_slowdown_timer_c bx_slowdown_timer; + +bx_slowdown_timer_c::bx_slowdown_timer_c() { + put("STIMER"); + settype(STIMERLOG); + + + s.start_time=0; + s.start_emulated_time=0; + s.timer_handle=BX_NULL_TIMER_HANDLE; +} + +void +bx_slowdown_timer_c::init(void) { + + // Return early if slowdown timer not selected + if ( (bx_options.clock.Osync->get () != BX_CLOCK_SYNC_SLOWDOWN) + && (bx_options.clock.Osync->get () != BX_CLOCK_SYNC_BOTH) ) + return; + + BX_INFO(("using 'slowdown' timer synchronization method")); + s.MAXmultiplier=MAXMULT; + s.Q=Qval; + + if(s.MAXmultiplier<1) + s.MAXmultiplier=1; + + s.start_time=sectousec(time(NULL)); + s.start_emulated_time = bx_pc_system.time_usec(); + s.lasttime=0; + if (s.timer_handle == BX_NULL_TIMER_HANDLE) { + s.timer_handle=bx_pc_system.register_timer(this, timer_handler, 100 , 1, 1, + "slowdown_timer"); + } + bx_pc_system.deactivate_timer(s.timer_handle); + bx_pc_system.activate_timer(s.timer_handle,(Bit32u)s.Q,0); +} + +void +bx_slowdown_timer_c::reset(unsigned type) +{ +} + +void +bx_slowdown_timer_c::timer_handler(void * this_ptr) { + bx_slowdown_timer_c * class_ptr = (bx_slowdown_timer_c *) this_ptr; + + class_ptr->handle_timer(); +} + +void +bx_slowdown_timer_c::handle_timer() { + Bit64u total_emu_time = (bx_pc_system.time_usec()) - s.start_emulated_time; + Bit64u wanttime = s.lasttime+s.Q; + Bit64u totaltime = sectousec(time(NULL)) - s.start_time; + Bit64u thistime=(wanttime>totaltime)?wanttime:totaltime; + +#if BX_SLOWDOWN_PRINTF_FEEDBACK + printf("Entering slowdown timer handler.\n"); +#endif + + /* Decide if we're behind. + * Set interrupt interval accordingly. */ + if(totaltime > total_emu_time) { + bx_pc_system.deactivate_timer(s.timer_handle); + bx_pc_system.activate_timer(s.timer_handle, + (Bit32u)(s.MAXmultiplier * (float)((Bit64s)s.Q)), + 0); +#if BX_SLOWDOWN_PRINTF_FEEDBACK + printf("running at MAX speed\n"); +#endif + } else { + bx_pc_system.deactivate_timer(s.timer_handle); + bx_pc_system.activate_timer(s.timer_handle,s.Q,0); +#if BX_SLOWDOWN_PRINTF_FEEDBACK + printf("running at NORMAL speed\n"); +#endif + } + + /* Make sure we took at least one time quantum. */ + /* This is a little strange. I'll try to explain. + * We're running bochs one second ahead of real time. + * this gives us a very precise division on whether + * we're ahead or behind the second line. + * Basically, here's how it works: + * *****|******************|***********... + * Time Time+1sec + * <^Bochs doesn't delay. + * ^>Bochs delays. + * <^Bochs runs at MAX speed. + * ^>Bochs runs at normal + */ + if(wanttime > (totaltime+REALTIME_Q)) { +#if BX_HAVE_USLEEP + usleep(s.Q); +#elif BX_HAVE_MSLEEP + msleep(usectomsec(s.Q)); +#elif BX_HAVE_SLEEP + sleep(usectosec(s.Q)); +#else +#error do not know have to sleep +#endif //delay(wanttime-totaltime); + /*alternatively: delay(Q); + * This works okay because we share the delay between + * two time quantums. + */ +#if BX_SLOWDOWN_PRINTF_FEEDBACK + printf("DELAYING for a quantum\n"); +#endif + } + s.lasttime=thistime; + + //Diagnostic info: +#if 0 + if(wanttime > (totaltime+REALTIME_Q)) { + if(totaltime > total_emu_time) { + printf("Solving OpenBSD problem.\n"); + } else { + printf("too fast.\n"); + } + } else { + if(totaltime > total_emu_time) { + printf("too slow.\n"); + } else { + printf("sometimes invalid state, normally okay.\n"); + } + } +#endif // Diagnostic info +} + |