- added instructions how to update the online documentation
[bochs-mirror.git] / iodev / slowdown_timer.cc
blob3df042097d2c6c4e2201702027a5b38aae820d4c
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: slowdown_timer.cc,v 1.30 2008/11/09 22:04:14 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 /////////////////////////////////////////////////////////////////////////
29 #include "bochs.h"
30 #include "slowdown_timer.h"
32 #include <errno.h>
33 #if !defined(_MSC_VER)
34 #include <unistd.h>
35 #endif
37 //These need to stay printfs because they are useless in the log file.
38 #define BX_SLOWDOWN_PRINTF_FEEDBACK 0
40 #define SECINUSEC 1000000
41 #define usectosec(a) ((a)/SECINUSEC)
42 #define sectousec(a) ((a)*SECINUSEC)
43 #define nsectousec(a) ((a)/1000)
45 #define MSECINUSEC 1000
46 #define usectomsec(a) ((a)/MSECINUSEC)
48 #define Qval 1000
49 #define MAXMULT 1.5
50 #define REALTIME_Q SECINUSEC
52 #define LOG_THIS bx_slowdown_timer.
54 bx_slowdown_timer_c bx_slowdown_timer;
56 bx_slowdown_timer_c::bx_slowdown_timer_c()
58 put("STIMER");
59 settype(STIMERLOG);
61 s.start_time=0;
62 s.start_emulated_time=0;
63 s.timer_handle=BX_NULL_TIMER_HANDLE;
66 void bx_slowdown_timer_c::init(void)
68 // Return early if slowdown timer not selected
69 if ((SIM->get_param_enum(BXPN_CLOCK_SYNC)->get() != BX_CLOCK_SYNC_SLOWDOWN) &&
70 (SIM->get_param_enum(BXPN_CLOCK_SYNC)->get() != BX_CLOCK_SYNC_BOTH))
71 return;
73 BX_INFO(("using 'slowdown' timer synchronization method"));
74 s.MAXmultiplier=MAXMULT;
75 s.Q=Qval;
77 if(s.MAXmultiplier<1)
78 s.MAXmultiplier=1;
80 s.start_time=sectousec(time(NULL));
81 s.start_emulated_time = bx_pc_system.time_usec();
82 s.lasttime=0;
83 if (s.timer_handle == BX_NULL_TIMER_HANDLE) {
84 s.timer_handle=bx_pc_system.register_timer(this, timer_handler, 100 , 1, 1,
85 "slowdown_timer");
87 bx_pc_system.deactivate_timer(s.timer_handle);
88 bx_pc_system.activate_timer(s.timer_handle,(Bit32u)s.Q,0);
91 void bx_slowdown_timer_c::exit(void)
93 s.timer_handle = BX_NULL_TIMER_HANDLE;
96 void bx_slowdown_timer_c::after_restore_state(void)
98 s.start_emulated_time = bx_pc_system.time_usec();
101 void bx_slowdown_timer_c::timer_handler(void * this_ptr)
103 bx_slowdown_timer_c * class_ptr = (bx_slowdown_timer_c *) this_ptr;
104 class_ptr->handle_timer();
107 void bx_slowdown_timer_c::handle_timer()
109 Bit64u total_emu_time = (bx_pc_system.time_usec()) - s.start_emulated_time;
110 Bit64u wanttime = s.lasttime+s.Q;
111 Bit64u totaltime = sectousec(time(NULL)) - s.start_time;
112 Bit64u thistime=(wanttime>totaltime)?wanttime:totaltime;
114 #if BX_SLOWDOWN_PRINTF_FEEDBACK
115 printf("Entering slowdown timer handler.\n");
116 #endif
118 /* Decide if we're behind.
119 * Set interrupt interval accordingly. */
120 if(totaltime > total_emu_time) {
121 bx_pc_system.deactivate_timer(s.timer_handle);
122 bx_pc_system.activate_timer(s.timer_handle,
123 (Bit32u)(s.MAXmultiplier * (float)((Bit64s)s.Q)), 0);
124 #if BX_SLOWDOWN_PRINTF_FEEDBACK
125 printf("running at MAX speed\n");
126 #endif
127 } else {
128 bx_pc_system.deactivate_timer(s.timer_handle);
129 bx_pc_system.activate_timer(s.timer_handle,(Bit32u)s.Q,0);
130 #if BX_SLOWDOWN_PRINTF_FEEDBACK
131 printf("running at NORMAL speed\n");
132 #endif
135 /* Make sure we took at least one time quantum. */
136 /* This is a little strange. I'll try to explain.
137 * We're running bochs one second ahead of real time.
138 * this gives us a very precise division on whether
139 * we're ahead or behind the second line.
140 * Basically, here's how it works:
141 * *****|******************|***********...
142 * Time Time+1sec
143 * <^Bochs doesn't delay.
144 * ^>Bochs delays.
145 * <^Bochs runs at MAX speed.
146 * ^>Bochs runs at normal
148 if(wanttime > (totaltime+REALTIME_Q)) {
149 #if BX_HAVE_USLEEP
150 usleep(s.Q);
151 #elif BX_HAVE_MSLEEP
152 msleep(usectomsec((Bit32u)s.Q));
153 #elif BX_HAVE_SLEEP
154 sleep(usectosec(s.Q));
155 #else
156 #error do not know have to sleep
157 #endif //delay(wanttime-totaltime);
158 /* alternatively: delay(Q);
159 * This works okay because we share the delay between
160 * two time quantums.
162 #if BX_SLOWDOWN_PRINTF_FEEDBACK
163 printf("DELAYING for a quantum\n");
164 #endif
166 s.lasttime=thistime;
168 //Diagnostic info:
169 #if 0
170 if(wanttime > (totaltime+REALTIME_Q)) {
171 if(totaltime > total_emu_time) {
172 printf("Solving OpenBSD problem.\n");
173 } else {
174 printf("too fast.\n");
176 } else {
177 if(totaltime > total_emu_time) {
178 printf("too slow.\n");
179 } else {
180 printf("sometimes invalid state, normally okay.\n");
183 #endif // Diagnostic info