- added instructions how to update the online documentation
[bochs-mirror.git] / iodev / pit_wrap.cc
blobdabe499013e95a84dad4dc2e5058e8761a77a877
1 ///////////////////////////////////////////////////////////////////////
2 // $Id: pit_wrap.cc,v 1.70 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
28 #include "iodev.h"
30 #include "speaker.h"
32 //Important constant #defines:
33 #define USEC_PER_SECOND (1000000)
34 //1.193181MHz Clock
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:
47 //Set up Logging.
48 #define LOG_THIS bx_pit.
50 //A single instance.
51 bx_pit_c bx_pit;
52 #if BX_USE_PIT_SMF
53 #define this (&bx_pit)
54 #endif
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:
72 //Direct conversions:
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)
76 bx_pit_c::bx_pit_c()
78 put("PIT");
79 settype(PITLOG);
80 s.speaker_data_on=0;
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));
139 return(1);
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"));
180 if(time_passed32) {
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)
208 #if !BX_USE_PIT_SMF
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)
215 #else
216 UNUSED(this_ptr);
217 #endif // !BX_USE_PIT_SMF
218 BX_DEBUG(("pit: entering read handler"));
220 handle_timer();
222 Bit64u my_time_usec = bx_virt_timer.time_usec();
224 if (bx_dbg.pit)
225 BX_INFO(("pit: io read from port %04x", (unsigned) address));
227 switch (address) {
229 case 0x40: /* timer 0 - system ticks */
230 return(BX_PIT_THIS s.timer.read(0));
231 break;
232 case 0x41: /* timer 1 read */
233 return(BX_PIT_THIS s.timer.read(1));
234 break;
235 case 0x42: /* timer 2 read */
236 return(BX_PIT_THIS s.timer.read(2));
237 break;
238 case 0x43: /* timer 1 read */
239 return(BX_PIT_THIS s.timer.read(3));
240 break;
242 case 0x61:
243 /* AT, port 61h */
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);
249 break;
251 default:
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)
262 #if !BX_USE_PIT_SMF
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)
269 #else
270 UNUSED(this_ptr);
271 #endif // !BX_USE_PIT_SMF
272 Bit8u value;
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"));
279 if(time_passed32) {
280 periodic(time_passed32);
282 BX_PIT_THIS s.last_usec=BX_PIT_THIS s.last_usec + time_passed;
284 value = (Bit8u) dvalue;
286 if (bx_dbg.pit)
287 BX_INFO(("pit: write to port %04x = %02x",
288 (unsigned) address, (unsigned) value));
290 switch (address) {
291 case 0x40: /* timer 0: write count register */
292 BX_PIT_THIS s.timer.write(0, value);
293 break;
295 case 0x41: /* timer 1: write count register */
296 BX_PIT_THIS s.timer.write(1, value);
297 break;
299 case 0x42: /* timer 2: write count register */
300 BX_PIT_THIS s.timer.write(2, value);
301 break;
303 case 0x43: /* timer 0-2 mode control */
304 BX_PIT_THIS s.timer.write(3, value);
305 break;
307 case 0x61:
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)));
311 } else {
312 DEV_speaker_beep_off();
314 /* ??? only on AT+ */
315 BX_PIT_THIS s.timer.set_GATE(2, value & 0x01);
316 break;
318 default:
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;
366 return 0;
369 void bx_pit_c::irq_handler(bx_bool value)
371 if (value == 1) {
372 DEV_pic_raise_irq(0);
373 } else {
374 DEV_pic_lower_irq(0);