1 ///////////////////////////////////////////////////////////////////////
2 // $Id: pit_wrap.cc,v 1.70 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
32 //Important constant #defines:
33 #define USEC_PER_SECOND (1000000)
35 #define TICKS_PER_SECOND (1193181)
38 // define a macro to convert floating point numbers into 64-bit integers.
39 // In MSVC++ you can convert a 64-bit float into a 64-bit signed integer,
40 // but it will not convert a 64-bit float into a 64-bit unsigned integer.
41 // This macro works around that.
42 #define F2I(x) ((Bit64u)(Bit64s) (x))
43 #define I2F(x) ((double)(Bit64s) (x))
45 //DEBUG configuration:
48 #define LOG_THIS bx_pit.
53 #define this (&bx_pit)
57 //Generic MAX and MIN Functions
58 #define BX_MAX(a,b) ( ((a)>(b))?(a):(b) )
59 #define BX_MIN(a,b) ( ((a)>(b))?(b):(a) )
62 //USEC_ALPHA is multiplier for the past.
63 //USEC_ALPHA_B is 1-USEC_ALPHA, or multiplier for the present.
64 #define USEC_ALPHA ((double)(.8))
65 #define USEC_ALPHA_B ((double)(((double)1)-USEC_ALPHA))
66 #define USEC_ALPHA2 ((double)(.5))
67 #define USEC_ALPHA2_B ((double)(((double)1)-USEC_ALPHA2))
68 #define ALPHA_LOWER(old,new) ((Bit64u)((old<new)?((USEC_ALPHA*(I2F(old)))+(USEC_ALPHA_B*(I2F(new)))):((USEC_ALPHA2*(I2F(old)))+(USEC_ALPHA2_B*(I2F(new))))))
71 //PIT tick to usec conversion functions:
73 #define TICKS_TO_USEC(a) (((a)*USEC_PER_SECOND)/TICKS_PER_SECOND)
74 #define USEC_TO_TICKS(a) (((a)*TICKS_PER_SECOND)/USEC_PER_SECOND)
82 /* 8254 PIT (Programmable Interval Timer) */
84 BX_PIT_THIS s
.timer_handle
[1] = BX_NULL_TIMER_HANDLE
;
85 BX_PIT_THIS s
.timer_handle
[2] = BX_NULL_TIMER_HANDLE
;
86 BX_PIT_THIS s
.timer_handle
[0] = BX_NULL_TIMER_HANDLE
;
89 int bx_pit_c::init(void)
91 DEV_register_irq(0, "8254 PIT");
92 DEV_register_ioread_handler(this, read_handler
, 0x0040, "8254 PIT", 1);
93 DEV_register_ioread_handler(this, read_handler
, 0x0041, "8254 PIT", 1);
94 DEV_register_ioread_handler(this, read_handler
, 0x0042, "8254 PIT", 1);
95 DEV_register_ioread_handler(this, read_handler
, 0x0043, "8254 PIT", 1);
96 DEV_register_ioread_handler(this, read_handler
, 0x0061, "8254 PIT", 1);
98 DEV_register_iowrite_handler(this, write_handler
, 0x0040, "8254 PIT", 1);
99 DEV_register_iowrite_handler(this, write_handler
, 0x0041, "8254 PIT", 1);
100 DEV_register_iowrite_handler(this, write_handler
, 0x0042, "8254 PIT", 1);
101 DEV_register_iowrite_handler(this, write_handler
, 0x0043, "8254 PIT", 1);
102 DEV_register_iowrite_handler(this, write_handler
, 0x0061, "8254 PIT", 1);
104 BX_DEBUG(("pit: starting init"));
106 BX_PIT_THIS s
.speaker_data_on
= 0;
107 BX_PIT_THIS s
.refresh_clock_div2
= 0;
109 BX_PIT_THIS s
.timer
.init();
110 BX_PIT_THIS s
.timer
.set_OUT_handler(0, irq_handler
);
112 Bit64u my_time_usec
= bx_virt_timer
.time_usec();
114 if (BX_PIT_THIS s
.timer_handle
[0] == BX_NULL_TIMER_HANDLE
) {
115 BX_PIT_THIS s
.timer_handle
[0] = bx_virt_timer
.register_timer(this, timer_handler
, (unsigned) 100 , 1, 1, "pit_wrap");
117 BX_DEBUG(("pit: RESETting timer."));
118 bx_virt_timer
.deactivate_timer(BX_PIT_THIS s
.timer_handle
[0]);
119 BX_DEBUG(("deactivated timer."));
120 if (BX_PIT_THIS s
.timer
.get_next_event_time()) {
121 bx_virt_timer
.activate_timer(BX_PIT_THIS s
.timer_handle
[0],
122 (Bit32u
)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s
.timer
.get_next_event_time())),
124 BX_DEBUG(("activated timer."));
126 BX_PIT_THIS s
.last_next_event_time
= BX_PIT_THIS s
.timer
.get_next_event_time();
127 BX_PIT_THIS s
.last_usec
=my_time_usec
;
129 BX_PIT_THIS s
.total_ticks
=0;
130 BX_PIT_THIS s
.total_usec
=0;
132 BX_DEBUG(("pit: finished init"));
134 BX_DEBUG(("s.last_usec="FMT_LL
"d",BX_PIT_THIS s
.last_usec
));
135 BX_DEBUG(("s.timer_id=%d",BX_PIT_THIS s
.timer_handle
[0]));
136 BX_DEBUG(("s.timer.get_next_event_time=%d",BX_PIT_THIS s
.timer
.get_next_event_time()));
137 BX_DEBUG(("s.last_next_event_time=%d",BX_PIT_THIS s
.last_next_event_time
));
142 void bx_pit_c::exit(void)
144 BX_PIT_THIS s
.timer_handle
[0] = BX_NULL_TIMER_HANDLE
;
145 BX_PIT_THIS s
.timer
.init();
148 void bx_pit_c::reset(unsigned type
)
150 BX_PIT_THIS s
.timer
.reset(type
);
153 void bx_pit_c::register_state(void)
155 bx_list_c
*list
= new bx_list_c(SIM
->get_bochs_root(), "pit", "8254 PIT State", 7);
156 new bx_shadow_num_c(list
, "speaker_data_on", &BX_PIT_THIS s
.speaker_data_on
, BASE_HEX
);
157 new bx_shadow_bool_c(list
, "refresh_clock_div2", &BX_PIT_THIS s
.refresh_clock_div2
);
158 new bx_shadow_num_c(list
, "last_usec", &BX_PIT_THIS s
.last_usec
);
159 new bx_shadow_num_c(list
, "last_next_event_time", &BX_PIT_THIS s
.last_next_event_time
);
160 new bx_shadow_num_c(list
, "total_ticks", &BX_PIT_THIS s
.total_ticks
);
161 new bx_shadow_num_c(list
, "total_usec", &BX_PIT_THIS s
.total_usec
);
162 bx_list_c
*counter
= new bx_list_c(list
, "counter", 4);
163 BX_PIT_THIS s
.timer
.register_state(counter
);
166 void bx_pit_c::timer_handler(void *this_ptr
)
168 bx_pit_c
* class_ptr
= (bx_pit_c
*) this_ptr
;
169 class_ptr
->handle_timer();
172 void bx_pit_c::handle_timer()
174 Bit64u my_time_usec
= bx_virt_timer
.time_usec();
175 Bit64u time_passed
= my_time_usec
-BX_PIT_THIS s
.last_usec
;
176 Bit32u time_passed32
= (Bit32u
)time_passed
;
178 BX_DEBUG(("pit: entering timer handler"));
181 periodic(time_passed32
);
183 BX_PIT_THIS s
.last_usec
=BX_PIT_THIS s
.last_usec
+ time_passed
;
184 if(time_passed
|| (BX_PIT_THIS s
.last_next_event_time
!= BX_PIT_THIS s
.timer
.get_next_event_time()))
186 BX_DEBUG(("pit: RESETting timer"));
187 bx_virt_timer
.deactivate_timer(BX_PIT_THIS s
.timer_handle
[0]);
188 BX_DEBUG(("deactivated timer"));
189 if(BX_PIT_THIS s
.timer
.get_next_event_time()) {
190 bx_virt_timer
.activate_timer(BX_PIT_THIS s
.timer_handle
[0],
191 (Bit32u
)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s
.timer
.get_next_event_time())),
193 BX_DEBUG(("activated timer"));
195 BX_PIT_THIS s
.last_next_event_time
= BX_PIT_THIS s
.timer
.get_next_event_time();
197 BX_DEBUG(("s.last_usec="FMT_LL
"d",BX_PIT_THIS s
.last_usec
));
198 BX_DEBUG(("s.timer_id=%d",BX_PIT_THIS s
.timer_handle
[0]));
199 BX_DEBUG(("s.timer.get_next_event_time=%x",BX_PIT_THIS s
.timer
.get_next_event_time()));
200 BX_DEBUG(("s.last_next_event_time=%d",BX_PIT_THIS s
.last_next_event_time
));
203 // static IO port read callback handler
204 // redirects to non-static class handler to avoid virtual functions
206 Bit32u
bx_pit_c::read_handler(void *this_ptr
, Bit32u address
, unsigned io_len
)
209 bx_pit_c
*class_ptr
= (bx_pit_c
*) this_ptr
;
210 return class_ptr
->read(address
, io_len
);
213 Bit32u
bx_pit_c::read(Bit32u address
, unsigned io_len
)
217 #endif // !BX_USE_PIT_SMF
218 BX_DEBUG(("pit: entering read handler"));
222 Bit64u my_time_usec
= bx_virt_timer
.time_usec();
225 BX_INFO(("pit: io read from port %04x", (unsigned) address
));
229 case 0x40: /* timer 0 - system ticks */
230 return(BX_PIT_THIS s
.timer
.read(0));
232 case 0x41: /* timer 1 read */
233 return(BX_PIT_THIS s
.timer
.read(1));
235 case 0x42: /* timer 2 read */
236 return(BX_PIT_THIS s
.timer
.read(2));
238 case 0x43: /* timer 1 read */
239 return(BX_PIT_THIS s
.timer
.read(3));
244 BX_PIT_THIS s
.refresh_clock_div2
= (bx_bool
)((my_time_usec
/ 15) & 1);
245 return (BX_PIT_THIS s
.timer
.read_OUT(2)<<5) |
246 (BX_PIT_THIS s
.refresh_clock_div2
<<4) |
247 (BX_PIT_THIS s
.speaker_data_on
<<1) |
248 (BX_PIT_THIS s
.timer
.read_GATE(2)?1:0);
252 BX_PANIC(("pit: unsupported io read from port %04x", address
));
254 return(0); /* keep compiler happy */
257 // static IO port write callback handler
258 // redirects to non-static class handler to avoid virtual functions
260 void bx_pit_c::write_handler(void *this_ptr
, Bit32u address
, Bit32u dvalue
, unsigned io_len
)
263 bx_pit_c
*class_ptr
= (bx_pit_c
*) this_ptr
;
264 class_ptr
->write(address
, dvalue
, io_len
);
267 void bx_pit_c::write(Bit32u address
, Bit32u dvalue
, unsigned io_len
)
271 #endif // !BX_USE_PIT_SMF
273 Bit64u my_time_usec
= bx_virt_timer
.time_usec();
274 Bit64u time_passed
= my_time_usec
-BX_PIT_THIS s
.last_usec
;
275 Bit32u time_passed32
= (Bit32u
)time_passed
;
277 BX_DEBUG(("pit: entering write handler"));
280 periodic(time_passed32
);
282 BX_PIT_THIS s
.last_usec
=BX_PIT_THIS s
.last_usec
+ time_passed
;
284 value
= (Bit8u
) dvalue
;
287 BX_INFO(("pit: write to port %04x = %02x",
288 (unsigned) address
, (unsigned) value
));
291 case 0x40: /* timer 0: write count register */
292 BX_PIT_THIS s
.timer
.write(0, value
);
295 case 0x41: /* timer 1: write count register */
296 BX_PIT_THIS s
.timer
.write(1, value
);
299 case 0x42: /* timer 2: write count register */
300 BX_PIT_THIS s
.timer
.write(2, value
);
303 case 0x43: /* timer 0-2 mode control */
304 BX_PIT_THIS s
.timer
.write(3, value
);
308 BX_PIT_THIS s
.speaker_data_on
= (value
>> 1) & 0x01;
309 if (BX_PIT_THIS s
.speaker_data_on
) {
310 DEV_speaker_beep_on((float)(1193180.0 / this->get_timer(2)));
312 DEV_speaker_beep_off();
314 /* ??? only on AT+ */
315 BX_PIT_THIS s
.timer
.set_GATE(2, value
& 0x01);
319 BX_PANIC(("pit: unsupported io write to port %04x = %02x",
320 (unsigned) address
, (unsigned) value
));
323 if(time_passed
|| (BX_PIT_THIS s
.last_next_event_time
!= BX_PIT_THIS s
.timer
.get_next_event_time()))
325 BX_DEBUG(("pit: RESETting timer"));
326 bx_virt_timer
.deactivate_timer(BX_PIT_THIS s
.timer_handle
[0]);
327 BX_DEBUG(("deactivated timer"));
328 if(BX_PIT_THIS s
.timer
.get_next_event_time()) {
329 bx_virt_timer
.activate_timer(BX_PIT_THIS s
.timer_handle
[0],
330 (Bit32u
)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s
.timer
.get_next_event_time())),
332 BX_DEBUG(("activated timer"));
334 BX_PIT_THIS s
.last_next_event_time
= BX_PIT_THIS s
.timer
.get_next_event_time();
336 BX_DEBUG(("s.last_usec="FMT_LL
"d",BX_PIT_THIS s
.last_usec
));
337 BX_DEBUG(("s.timer_id=%d",BX_PIT_THIS s
.timer_handle
[0]));
338 BX_DEBUG(("s.timer.get_next_event_time=%x",BX_PIT_THIS s
.timer
.get_next_event_time()));
339 BX_DEBUG(("s.last_next_event_time=%d",BX_PIT_THIS s
.last_next_event_time
));
343 bx_bool
bx_pit_c::periodic(Bit32u usec_delta
)
345 Bit32u ticks_delta
= 0;
347 BX_PIT_THIS s
.total_usec
+= usec_delta
;
348 ticks_delta
=(Bit32u
)((USEC_TO_TICKS((Bit64u
)(BX_PIT_THIS s
.total_usec
)))-BX_PIT_THIS s
.total_ticks
);
349 BX_PIT_THIS s
.total_ticks
+= ticks_delta
;
351 while ((BX_PIT_THIS s
.total_ticks
>= TICKS_PER_SECOND
) && (BX_PIT_THIS s
.total_usec
>= USEC_PER_SECOND
)) {
352 BX_PIT_THIS s
.total_ticks
-= TICKS_PER_SECOND
;
353 BX_PIT_THIS s
.total_usec
-= USEC_PER_SECOND
;
356 while(ticks_delta
>0) {
357 Bit32u maxchange
=BX_PIT_THIS s
.timer
.get_next_event_time();
358 Bit32u timedelta
=maxchange
;
359 if((maxchange
==0) || (maxchange
>ticks_delta
)) {
360 timedelta
=ticks_delta
;
362 BX_PIT_THIS s
.timer
.clock_all(timedelta
);
363 ticks_delta
-=timedelta
;
369 void bx_pit_c::irq_handler(bx_bool value
)
372 DEV_pic_raise_irq(0);
374 DEV_pic_lower_irq(0);