1 /////////////////////////////////////////////////////////////////////////
2 // $Id: slowdown_timer.cc,v 1.30 2008/11/09 22:04:14 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2002 MandrakeSoft S.A.
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 /////////////////////////////////////////////////////////////////////////
30 #include "slowdown_timer.h"
33 #if !defined(_MSC_VER)
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)
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()
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
))
73 BX_INFO(("using 'slowdown' timer synchronization method"));
74 s
.MAXmultiplier
=MAXMULT
;
80 s
.start_time
=sectousec(time(NULL
));
81 s
.start_emulated_time
= bx_pc_system
.time_usec();
83 if (s
.timer_handle
== BX_NULL_TIMER_HANDLE
) {
84 s
.timer_handle
=bx_pc_system
.register_timer(this, timer_handler
, 100 , 1, 1,
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");
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");
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");
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 * *****|******************|***********...
143 * <^Bochs doesn't delay.
145 * <^Bochs runs at MAX speed.
146 * ^>Bochs runs at normal
148 if(wanttime
> (totaltime
+REALTIME_Q
)) {
152 msleep(usectomsec((Bit32u
)s
.Q
));
154 sleep(usectosec(s
.Q
));
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
162 #if BX_SLOWDOWN_PRINTF_FEEDBACK
163 printf("DELAYING for a quantum\n");
170 if(wanttime
> (totaltime
+REALTIME_Q
)) {
171 if(totaltime
> total_emu_time
) {
172 printf("Solving OpenBSD problem.\n");
174 printf("too fast.\n");
177 if(totaltime
> total_emu_time
) {
178 printf("too slow.\n");
180 printf("sometimes invalid state, normally okay.\n");
183 #endif // Diagnostic info