summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/i386
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2000-12-05 16:49:23 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2000-12-05 16:49:23 +0000
commitd57c04e1f3a2c704d3479f85de706ad7de65b8b0 (patch)
treec950d8370cad1952893da1a3331be486a4c9d308 /c/src/lib/libbsp/i386
parent2000-12-05 Joel Sherrill <joel@OARcorp.com> (diff)
downloadrtems-d57c04e1f3a2c704d3479f85de706ad7de65b8b0.tar.bz2
2000-12-05 Eric Valette <valette@crf.canon.fr>
* console/inch.c, console/keyboard.c, console/pc_keyb.c, console/vt.c, include/bsp.h: Correct incorrect interrupt level handling in new keyboard management code. Correct BSP_poll_char initialization routine. * start/start.S, startup/bspstart.c: Correct when the video is initialized. * timer/timer.c (Calibrate_1ms_loop): Address problem where this did not work correctly on all PC speeds. The new calibrate routine has been tested on Pentium 166, pentium II 200, pentium III 300 Mhz and does work as expected.
Diffstat (limited to 'c/src/lib/libbsp/i386')
-rw-r--r--c/src/lib/libbsp/i386/pc386/ChangeLog13
-rw-r--r--c/src/lib/libbsp/i386/pc386/console/inch.c229
-rw-r--r--c/src/lib/libbsp/i386/pc386/console/keyboard.c12
-rw-r--r--c/src/lib/libbsp/i386/pc386/console/pc_keyb.c10
-rw-r--r--c/src/lib/libbsp/i386/pc386/console/vt.c7
-rw-r--r--c/src/lib/libbsp/i386/pc386/include/bsp.h8
-rw-r--r--c/src/lib/libbsp/i386/pc386/start/start.S13
-rw-r--r--c/src/lib/libbsp/i386/pc386/startup/bspstart.c8
-rw-r--r--c/src/lib/libbsp/i386/pc386/timer/timer.c298
9 files changed, 470 insertions, 128 deletions
diff --git a/c/src/lib/libbsp/i386/pc386/ChangeLog b/c/src/lib/libbsp/i386/pc386/ChangeLog
index 0b75b293a2..956cb7e3a4 100644
--- a/c/src/lib/libbsp/i386/pc386/ChangeLog
+++ b/c/src/lib/libbsp/i386/pc386/ChangeLog
@@ -1,3 +1,16 @@
+2000-12-05 Eric Valette <valette@crf.canon.fr>
+
+ * console/inch.c, console/keyboard.c, console/pc_keyb.c,
+ console/vt.c, include/bsp.h: Correct incorrect interrupt level
+ handling in new keyboard management code. Correct
+ BSP_poll_char initialization routine.
+ * start/start.S, startup/bspstart.c: Correct when the video is
+ initialized.
+ * timer/timer.c (Calibrate_1ms_loop): Address problem where this
+ did not work correctly on all PC speeds. The new calibrate routine
+ has been tested on Pentium 166, pentium II 200, pentium III
+ 300 Mhz and does work as expected.
+
2000-12-05 Joel Sherrill <joel@OARcorp.com>
* pc386/console/console.c, pc386/console/serial_mouse.c,
diff --git a/c/src/lib/libbsp/i386/pc386/console/inch.c b/c/src/lib/libbsp/i386/pc386/console/inch.c
index 3aa3ad706d..ac6cec61dd 100644
--- a/c/src/lib/libbsp/i386/pc386/console/inch.c
+++ b/c/src/lib/libbsp/i386/pc386/console/inch.c
@@ -36,7 +36,37 @@
/*-------------------------------------------------------------------------+
| Constants
+--------------------------------------------------------------------------*/
-#define KBD_BUF_SIZE 256
+#define KBD_CTL 0x61 /* -------------------------------- */
+#define KBD_DATA 0x60 /* Ports for PC keyboard controller */
+#define KBD_STATUS 0x64 /* -------------------------------- */
+
+#define KBD_BUF_SIZE 256
+
+/*-------------------------------------------------------------------------+
+| Global Variables
++--------------------------------------------------------------------------*/
+static char key_map[] =
+{
+ 0,033,'1','2','3','4','5','6','7','8','9','0','-','=','\b','\t',
+ 'q','w','e','r','t','y','u','i','o','p','[',']',015,0x80,
+ 'a','s','d','f','g','h','j','k','l',';',047,0140,0x80,
+ 0134,'z','x','c','v','b','n','m',',','.','/',0x80,
+ '*',0x80,' ',0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,'0',0177
+}; /* Keyboard scancode -> character map with no modifiers. */
+
+static char shift_map[] =
+{
+ 0,033,'!','@','#','$','%','^','&','*','(',')','_','+','\b','\t',
+ 'Q','W','E','R','T','Y','U','I','O','P','{','}',015,0x80,
+ 'A','S','D','F','G','H','J','K','L',':',042,'~',0x80,
+ '|','Z','X','C','V','B','N','M','<','>','?',0x80,
+ '*',0x80,' ',0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,'7','8','9',0x80,'4','5','6',0x80,
+ '1','2','3','0',177
+}; /* Keyboard scancode -> character map with SHIFT key modifier. */
+
static unsigned short kbd_buffer[KBD_BUF_SIZE];
static rtems_unsigned16 kbd_first = 0;
@@ -57,25 +87,212 @@ void rtemsReboot(void)
} /* rtemsReboot */
+/*-------------------------------------------------------------------------+
+| Function: _IBMPC_scankey
+| Description: This function can be called during a poll for input, or by
+| an ISR. Basically any time you want to process a keypress.
+| Global Variables: key_map, shift_map.
+| Arguments: outChar - character read in case of a valid reading,
+| otherwise unchanged.
+| Returns: TRUE in case a valid character has been read,
+| FALSE otherwise.
++--------------------------------------------------------------------------*/
+static rtems_boolean
+_IBMPC_scankey(char *outChar)
+{
+ unsigned char inChar;
+ static int alt_pressed = 0;
+ static int ctrl_pressed = 0;
+ static int shift_pressed = 0;
+ static int caps_pressed = 0;
+ static int extended = 0;
+
+ *outChar = '\0'; /* default value if we return FALSE */
+
+ /* Read keyboard controller, toggle enable */
+ inport_byte(KBD_CTL, inChar);
+ outport_byte(KBD_CTL, inChar & ~0x80);
+ outport_byte(KBD_CTL, inChar | 0x80);
+ outport_byte(KBD_CTL, inChar & ~0x80);
+
+ /* See if it has data */
+ inport_byte(KBD_STATUS, inChar);
+ if ((inChar & 0x01) == 0)
+ return FALSE;
+
+ /* Read the data. Handle nonsense with shift, control, etc. */
+ inport_byte(KBD_DATA, inChar);
+
+ if (extended)
+ extended--;
+
+ switch (inChar)
+ {
+ case 0xe0:
+ extended = 2;
+ return FALSE;
+ break;
+
+ case 0x38:
+ alt_pressed = 1;
+ return FALSE;
+ break;
+ case 0xb8:
+ alt_pressed = 0;
+ return FALSE;
+ break;
+
+ case 0x1d:
+ ctrl_pressed = 1;
+ return FALSE;
+ break;
+ case 0x9d:
+ ctrl_pressed = 0;
+ return FALSE;
+ break;
+
+ case 0x2a:
+ if (extended)
+ return FALSE;
+ case 0x36:
+ shift_pressed = 1;
+ return FALSE;
+ break;
+ case 0xaa:
+ if (extended)
+ return FALSE;
+ case 0xb6:
+ shift_pressed = 0;
+ return FALSE;
+ break;
+
+ case 0x3a:
+ caps_pressed = 1;
+ return FALSE;
+ break;
+ case 0xba:
+ caps_pressed = 0;
+ return FALSE;
+ break;
+
+ case 0x53:
+ if (ctrl_pressed && alt_pressed)
+ rtemsReboot(); /* ctrl+alt+del -> reboot */
+ break;
+
+ /*
+ * Ignore unrecognized keys--usually arrow and such
+ */
+ default:
+ if ((inChar & 0x80) || (inChar > 0x39))
+ /* High-bit on means key is being released, not pressed */
+ return FALSE;
+ break;
+ } /* switch */
+
+ /* Strip high bit, look up in our map */
+ inChar &= 0x7f;
+ if (ctrl_pressed)
+ {
+ *outChar = key_map[inChar];
+ *outChar &= 037;
+ }
+ else
+ {
+ *outChar = shift_pressed ? shift_map[inChar] : key_map[inChar];
+ if (caps_pressed)
+ {
+ if (*outChar >= 'A' && *outChar <= 'Z')
+ *outChar += 'a' - 'A';
+ else if (*outChar >= 'a' && *outChar <= 'z')
+ *outChar -= 'a' - 'A';
+ }
+ }
+
+ return TRUE;
+} /* _IBMPC_scankey */
+
+/*-------------------------------------------------------------------------+
+| Function: _IBMPC_chrdy
+| Description: Check keyboard ISR buffer and return character if not empty.
+| Global Variables: kbd_buffer, kbd_first, kbd_last.
+| Arguments: c - character read if keyboard buffer not empty, otherwise
+| unchanged.
+| Returns: TRUE if keyboard buffer not empty, FALSE otherwise.
++--------------------------------------------------------------------------*/
+static rtems_boolean
+_IBMPC_chrdy(char *c)
+{
+ /* FIX ME!!! It doesn't work without something like the following line.
+ Find out why! */
+ printk("");
+
+ /* Check buffer our ISR builds */
+ if (kbd_first != kbd_last)
+ {
+ *c = kbd_buffer[kbd_first];
+
+ kbd_first = (kbd_first + 1) % KBD_BUF_SIZE;
+ return TRUE;
+ }
+ else
+ return FALSE;
+} /* _IBMPC_chrdy */
+
+
+/*-------------------------------------------------------------------------+
+| Function: _IBMPC_inch
+| Description: Poll keyboard until a character is ready and return it.
+| Global Variables: None.
+| Arguments: None.
+| Returns: character read from keyboard.
++--------------------------------------------------------------------------*/
+char
+_IBMPC_inch(void)
+{
+ char c;
+ while (!_IBMPC_chrdy(&c))
+ continue;
+
+ return c;
+} /* _IBMPC_inch */
+
+
+ /*
+ * Routine that can be used before interrupt management is initialized.
+ */
+
+char
+BSP_wait_polled_input(void)
+{
+ char c;
+ while (!_IBMPC_scankey(&c))
+ continue;
+
+ return c;
+}
-#define disable __asm__ __volatile__("cli")
-#define enable __asm__ __volatile__("sti");
/*
* Check if a key has been pressed. This is a non-destructive
* call, meaning, it keeps the key in the buffer.
*/
int rtems_kbpoll( void )
{
- int rc;
- disable;
+ int rc,level;
+
+ _CPU_ISR_Disable(level);
+
rc = ( kbd_first != kbd_last ) ? TRUE : FALSE;
- enable;
+
+ _CPU_ISR_Enable (level);
+
return rc;
}
int getch( void )
{
int c;
+
while( kbd_first == kbd_last )
{
rtems_task_wake_after( 10 );
diff --git a/c/src/lib/libbsp/i386/pc386/console/keyboard.c b/c/src/lib/libbsp/i386/pc386/console/keyboard.c
index 5520ae7354..db9e0b6f1a 100644
--- a/c/src/lib/libbsp/i386/pc386/console/keyboard.c
+++ b/c/src/lib/libbsp/i386/pc386/console/keyboard.c
@@ -60,27 +60,27 @@ extern void rtemsReboot( void );
int set_bit(int nr, unsigned long * addr)
{
- int mask, retval;
+ int mask, retval,level;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
- cli();
+ _CPU_ISR_Disable(level)
retval = (mask & *addr) != 0;
*addr |= mask;
- sti();
+ _CPU_ISR_Enable (level);
return retval;
}
int clear_bit(int nr, unsigned long * addr)
{
- int mask, retval;
+ int mask, retval,level;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
- cli();
+ _CPU_ISR_Disable(level)
retval = (mask & *addr) != 0;
*addr &= ~mask;
- sti();
+ _CPU_ISR_Enable (level);
return retval;
}
diff --git a/c/src/lib/libbsp/i386/pc386/console/pc_keyb.c b/c/src/lib/libbsp/i386/pc386/console/pc_keyb.c
index 0b94666504..d9feaca1b4 100644
--- a/c/src/lib/libbsp/i386/pc386/console/pc_keyb.c
+++ b/c/src/lib/libbsp/i386/pc386/console/pc_keyb.c
@@ -636,13 +636,15 @@ void pckbd_init_hw(void)
}
-
+/*
char BSP_wait_polled_input( void )
{
- int c;
- cli();
+ int c,level;
+
+ _CPU_ISR_Disable(level);
while ( ( c= kbd_wait_for_input() ) < 0 )
continue;
- sti();
+ _CPU_ISR_Enable (level);
return c;
}
+*/
diff --git a/c/src/lib/libbsp/i386/pc386/console/vt.c b/c/src/lib/libbsp/i386/pc386/console/vt.c
index eb8ec64c76..218a907c92 100644
--- a/c/src/lib/libbsp/i386/pc386/console/vt.c
+++ b/c/src/lib/libbsp/i386/pc386/console/vt.c
@@ -66,12 +66,13 @@ kd_nosound(unsigned long ignored)
void
_kd_mksound(unsigned int hz, unsigned int ticks)
{
- unsigned int count = 0;
+ unsigned int count = 0;
+ int level;
if (hz > 20 && hz < 32767)
count = 1193180 / hz;
- cli();
+ _CPU_ISR_Disable(level);
/* del_timer(&sound_timer); */
if (count) {
/* enable counter 2 */
@@ -91,7 +92,7 @@ _kd_mksound(unsigned int hz, unsigned int ticks)
} else
kd_nosound(0);
- sti();
+ _CPU_ISR_Enable (level);
return;
}
diff --git a/c/src/lib/libbsp/i386/pc386/include/bsp.h b/c/src/lib/libbsp/i386/pc386/include/bsp.h
index c152152fb7..7431059314 100644
--- a/c/src/lib/libbsp/i386/pc386/include/bsp.h
+++ b/c/src/lib/libbsp/i386/pc386/include/bsp.h
@@ -122,6 +122,14 @@ extern int rtems_dec21140_driver_attach(struct rtems_bsdnet_ifconfig *, int);
#define TIMER_MSB 0x20 /* r/w counter MSB */
#define TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */
#define TIMER_BCD 0x01 /* count in BCD */
+#define TIMER_RD_BACK 0xc0 /* Read Back Command */
+ /* READ BACK command layout in the Command Register */
+#define RB_NOT_COUNT 0x40 /* Don't select counter latch */
+#define RB_NOT_STATUS 0x20 /* Don't select status latch */
+#define RB_COUNT_0 0x02 /* Counter 0 latch */
+#define RB_COUNT_1 0x04 /* Counter 1 latch */
+#define RB_COUNT_2 0x08 /* Counter 2 latch */
+#define RB_OUTPUT 0x80 /* Output of the counter is 1 */
#define TIMER_TICK 1193182 /* The internal tick rate in ticks per second */
diff --git a/c/src/lib/libbsp/i386/pc386/start/start.S b/c/src/lib/libbsp/i386/pc386/start/start.S
index 33af08e17c..09aa589807 100644
--- a/c/src/lib/libbsp/i386/pc386/start/start.S
+++ b/c/src/lib/libbsp/i386/pc386/start/start.S
@@ -145,12 +145,21 @@ SYM (zero_bss):
shrl ecx
xorl eax, eax # value to clear out memory
repne # while ecx != 0
- stosl # clear a long in the bss
-
+ stosl
+ # clear a long in the bss
+
+/*-------------------------------------------------------------------+
+| Initialize the video because zero_bss has cleared initVideo parameters
+| if it was called earlier
+| So from now we can use printk
++-------------------------------------------------------------------*/
+ call _IBMPC_initVideo
+
/*---------------------------------------------------------------------+
| Check CPU type. Enable Cache and init coprocessor if needed.
+---------------------------------------------------------------------*/
call checkCPUtypeSetCr0
+
/*---------------------------------------------------------------------+
| Transfer control to User's Board Support Package
+---------------------------------------------------------------------*/
diff --git a/c/src/lib/libbsp/i386/pc386/startup/bspstart.c b/c/src/lib/libbsp/i386/pc386/startup/bspstart.c
index 96091455a9..e4f051dc07 100644
--- a/c/src/lib/libbsp/i386/pc386/startup/bspstart.c
+++ b/c/src/lib/libbsp/i386/pc386/startup/bspstart.c
@@ -138,18 +138,12 @@ void bsp_pretasking_hook(void)
void bsp_start_default( void )
{
void Calibrate_loop_1ms(void);
-
+
/*
* Calibrate variable for 1ms-loop (see timer.c)
*/
Calibrate_loop_1ms();
- /*
- * Initialize printk channel
- */
-
- _IBMPC_initVideo();
-
rtemsFreeMemStart = (rtems_unsigned32)&_end + _stack_size;
/* set the value of start of free memory. */
diff --git a/c/src/lib/libbsp/i386/pc386/timer/timer.c b/c/src/lib/libbsp/i386/pc386/timer/timer.c
index 1095061bea..8d5a36055e 100644
--- a/c/src/lib/libbsp/i386/pc386/timer/timer.c
+++ b/c/src/lib/libbsp/i386/pc386/timer/timer.c
@@ -60,8 +60,8 @@
| Global Variables
+--------------------------------------------------------------------------*/
volatile rtems_unsigned32 Ttimer_val;
- rtems_boolean Timer_driver_Find_average_overhead = TRUE;
- unsigned int loop1ms;
+rtems_boolean Timer_driver_Find_average_overhead = TRUE;
+volatile unsigned int fastLoop1ms, slowLoop1ms;
/*-------------------------------------------------------------------------+
| External Prototypes
@@ -305,137 +305,233 @@ Set_find_average_overhead(rtems_boolean find_flag)
Timer_driver_Find_average_overhead = find_flag;
} /* Set_find_average_overhead */
-
+static unsigned short lastLoadedValue;
/*-------------------------------------------------------------------------+
| Description: Loads timer 0 with value passed as arguemnt.
-| Returns: Nothing.
+| Returns: Nothing. Loaded value must be a number of clock bits...
+--------------------------------------------------------------------------*/
-inline void loadTimerValue( unsigned short loadedValue )
+void loadTimerValue( unsigned short loadedValue )
{
- outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
- outport_byte(TIMER_CNTR0, loadedValue >> 0 & 0xff);
- outport_byte(TIMER_CNTR0, loadedValue >> 8 & 0xff);
-}
-
-
-/*-------------------------------------------------------------------------+
-| Description: Waits until the counter on timer 0 reaches 0.
-| Returns: Nothing.
-+--------------------------------------------------------------------------*/
-inline void waitTimerStatus( void )
-{
- unsigned char status;
- outport_byte(TIMER_MODE, CMD_READ_BACK_STATUS); /* read Status counter 0 */
- inport_byte(TIMER_CNTR0, status);
- while (status & MSK_NULL_COUNT){ /* wait for counter ready */
- outport_byte(TIMER_MODE, CMD_READ_BACK_STATUS);
- inport_byte(TIMER_CNTR0, status);
- }
+ lastLoadedValue = loadedValue;
+ outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_SQWAVE);
+ outport_byte(TIMER_CNTR0, loadedValue & 0xff);
+ outport_byte(TIMER_CNTR0, (loadedValue >> 8) & 0xff);
}
/*-------------------------------------------------------------------------+
| Description: Reads the current value of the timer, and converts the
| number of ticks to micro-seconds.
-| Returns: current number of microseconds since last value loaded..
+| Returns: number of clock bits elapsed since last load.
+--------------------------------------------------------------------------*/
-inline unsigned short readCurrentTimer()
+unsigned int readTimer0()
{
unsigned short lsb, msb;
- outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH);
+ unsigned char status;
+ unsigned int count;
+
+ outport_byte(TIMER_MODE, (TIMER_RD_BACK | (RB_COUNT_0 & ~(RB_NOT_STATUS | RB_NOT_COUNT))));
+ inport_byte(TIMER_CNTR0, status);
inport_byte(TIMER_CNTR0, lsb);
inport_byte(TIMER_CNTR0, msb);
- return TICK_TO_US( ( msb << 8 ) | lsb );
+ count = ( msb << 8 ) | lsb ;
+ if (status & RB_OUTPUT )
+ count += lastLoadedValue;
+
+ return (2*lastLoadedValue - count);
}
+void Timer0Reset()
+{
+ loadTimerValue(0xffff);
+ readTimer0();
+}
-/*-------------------------------------------------------------------------+
- * clockbits - Read low order bits of timer 0 (the TOD clock)
- * This works only for the 8254 chips used in ATs and 386s.
- *
- * The timer runs in mode 3 (square wave mode), counting down
- * by twos, twice for each cycle. So it is necessary to read back the
- * OUTPUT pin to see which half of the cycle we're in. I.e., the OUTPUT
- * pin forms the most significant bit of the count. Unfortunately,
- * the 8253 in the PC/XT lacks a command to read the OUTPUT pin...
- *
- * The PC's clock design is soooo brain damaged...
- *
- * Rosimildo - I've got this routine from the KA9Q32 distribution and
- * have updated it for the RTEMS environment.
- +--------------------------------------------------------------------------*/
-unsigned int clockbits(void)
+void fastLoop (unsigned int loopCount)
{
- unsigned int stat,count1, count;
-
- do
- {
- outport_byte( 0x43, 0xc2 ); /* latch timer 0 count and status for reading */
- inport_byte( 0x40, stat ); /* get status of timer 0 */
- inport_byte( 0x40, count1 ); /* lsb of count */
- inport_byte( 0x40, count ); /* msb of count */
- count = count1 | ( count << 8 );
- } while(stat & 0x40); /* reread if NULL COUNT bit set */
- stat = (stat & 0x80) << 8; /* Shift OUTPUT to msb of 16-bit word */
- if(count == 0)
- return stat ^ 0x8000; /* return complement of OUTPUT bit */
- else
- return count | stat; /* Combine OUTPUT with counter */
+ unsigned int i;
+ for( i=0; i < loopCount; i++ )outport_byte( SLOW_DOWN_IO, 0 );
}
+void slowLoop (unsigned int loopCount)
+{
+ unsigned int j;
+ for (j=0; j <100 ; j++) {
+ fastLoop (loopCount);
+ }
+}
-/*-------------------------------------------------------------------------+
-| Function: Calibrate_loop_1ms
-| Description: Set loop variable to calibrate a 1ms loop
-| Global Variables: loop1ms
-| Arguments: none
-| Returns: Nothing.
-+--------------------------------------------------------------------------*/
+/*
+ * #define DEBUG_CALIBRATE
+ */
void
Calibrate_loop_1ms(void)
{
- unsigned int i;
- unsigned short loadedValue, offset;
- unsigned int timerValue, t1_ref, t2_ref=0;
+ unsigned int offset, offsetTmp, emptyCall, emptyCallTmp, res, i, j;
+ unsigned int targetClockBits, currentClockBits;
+ unsigned int slowLoopGranularity, fastLoopGranularity;
rtems_interrupt_level level;
+#ifdef DEBUG_CALIBRATE
+ printk( "Calibrate_loop_1ms is starting, please wait ( but not too loooong. )\n" );
+#endif
+ targetClockBits = US_TO_TICK(1000);
+
+ rtems_interrupt_disable(level);
+ /*
+ * Fill up the cache to get a correct offset
+ */
+ Timer0Reset();
+ readTimer0();
+ /*
+ * Compute the minimal offset to apply due to read counter register.
+ */
+ offset = 0xffffffff;
+ for (i=0; i <1000; i++) {
+ Timer0Reset();
+ offsetTmp = readTimer0();
+ offset += offsetTmp;
+ }
+ offset = offset / 1000; /* compute average */
+ /*
+ * calibrate empty call
+ */
+ fastLoop (0);
+ emptyCall = 0;
+ j = 0;
+ for (i=0; i <10; i++) {
+ Timer0Reset();
+ fastLoop (0);
+ res = readTimer0();
+ /* res may be inferior to offset on fast
+ * machine because we took an average for offset
+ */
+ if (res > offset) {
+ ++j;
+ emptyCallTmp = res - offset;
+ emptyCall += emptyCallTmp;
+ }
+ }
+ if (j == 0) emptyCall = 0;
+ else emptyCall = emptyCall / j; /* compute average */
+ /*
+ * calibrate fast loop
+ */
+ Timer0Reset();
+ fastLoop (10000);
+ res = readTimer0() - offset;
+ if (res < emptyCall) {
+ printk("Problem #1 in offset computation in Calibrate_loop_1ms in file libbsp/i386/pc386/timer/timer.c\n");
+ while (1);
+ }
+ fastLoopGranularity = (res - emptyCall) / 10000;
+ /*
+ * calibrate slow loop
+ */
+ Timer0Reset();
+ slowLoop(10);
+ res = readTimer0();
+ if (res < offset + emptyCall) {
+ printk("Problem #2 in offset computation in Calibrate_loop_1ms in file libbsp/i386/pc386/timer/timer.c\n");
+ while (1);
+ }
+ slowLoopGranularity = (res - offset - emptyCall)/ 10;
+
+ if (slowLoopGranularity == 0) {
+ printk("Problem #3 in Calibrate_loop_1ms in file libbsp/i386/pc386/timer/timer.c\n");
+ while (1);
+ }
- printk( "Calibrate_loop_1ms is starting, please wait ( but not too loooong. )\n" );
-
- loop1ms = 200;
- timerValue = 0;
+ targetClockBits += offset;
+#ifdef DEBUG_CALIBRATE
+ printk("offset = %u, emptyCall = %u, targetClockBits = %u\n",
+ offset, emptyCall, targetClockBits);
+ printk("slowLoopGranularity = %u fastLoopGranularity = %u\n",
+ slowLoopGranularity, fastLoopGranularity);
+#endif
+ slowLoop1ms = (targetClockBits - emptyCall) / slowLoopGranularity;
+ if (slowLoop1ms != 0) {
+ fastLoop1ms = targetClockBits % slowLoopGranularity;
+ if (fastLoop1ms > emptyCall) fastLoop1ms -= emptyCall;
+ }
+ else
+ fastLoop1ms = targetClockBits - emptyCall / fastLoopGranularity;
- /* Let's load the timer with 2ms, initially */
- loadedValue = US_TO_TICK( 2000 );
+ if (slowLoop1ms != 0) {
+ /*
+ * calibrate slow loop
+ */
- rtems_interrupt_disable(level);
+ while(1)
+ {
+ int previousSign = 0; /* 0 = unset, 1 = incrementing, 2 = decrementing */
+ Timer0Reset();
+ slowLoop(slowLoop1ms);
+ currentClockBits = readTimer0();
+ if (currentClockBits > targetClockBits) {
+ if ((currentClockBits - targetClockBits) < slowLoopGranularity) {
+ /* decrement loop counter anyway to be sure slowLoop(slowLoop1ms) < targetClockBits */
+ --slowLoop1ms;
+ break;
+ }
+ else {
+ --slowLoop1ms;
+ if (slowLoop1ms == 0) break;
+ if (previousSign == 0) previousSign = 2;
+ if (previousSign == 1) break;
+ }
+ }
+ else {
+ if ((targetClockBits - currentClockBits) < slowLoopGranularity) {
+ break;
+ }
+ else {
+ ++slowLoop1ms;
+ if (previousSign == 0) previousSign = 1;
+ if (previousSign == 2) break;
+ }
+ }
+ }
+ }
/*
- * Compute the offset to apply due to read counter register
+ * calibrate fast loop
*/
- offset = 0;
- loadTimerValue( loadedValue + offset );
- waitTimerStatus();
- t1_ref = clockbits();
- offset = loadedValue - readCurrentTimer();
- while( timerValue < 1000 )
- {
- loop1ms++;
- loadTimerValue( loadedValue + offset );
- waitTimerStatus();
- t1_ref = clockbits();
- for( i=0; i < loop1ms; i++ )
- outport_byte( SLOW_DOWN_IO, 0 ); /* write is # 1us */
- t2_ref = clockbits();
- timerValue = TICK_TO_US( t1_ref - t2_ref ); /* timer0 is decrementing number of ticks */
+
+ if (fastLoopGranularity != 0 ) {
+ while(1) {
+ int previousSign = 0; /* 0 = unset, 1 = incrementing, 2 = decrementing */
+ Timer0Reset();
+ if (slowLoop1ms != 0) slowLoop(slowLoop1ms);
+ fastLoop(fastLoop1ms);
+ currentClockBits = readTimer0();
+ if (currentClockBits > targetClockBits) {
+ if ((currentClockBits - targetClockBits) < fastLoopGranularity)
+ break;
+ else {
+ --fastLoop1ms;
+ if (previousSign == 0) previousSign = 2;
+ if (previousSign == 1) break;
+ }
+ }
+ else {
+ if ((targetClockBits - currentClockBits) < fastLoopGranularity)
+ break;
+ else {
+ ++fastLoop1ms;
+ if (previousSign == 0) previousSign = 1;
+ if (previousSign == 2) break;
+ }
+ }
+ }
}
- printk( "Calibrate_loop_1ms timerValue=%d, loop1ms=%d, t1_ref=%x, clockbits=%x, delta=%d\n",
- timerValue, loop1ms, t1_ref, t2_ref, t1_ref - t2_ref );
+#ifdef DEBUG_CALIBRATE
+ printk("slowLoop1ms = %u, fastLoop1ms = %u\n", slowLoop1ms, fastLoop1ms);
+#endif
rtems_interrupt_enable(level);
+
}
-
-
/*-------------------------------------------------------------------------+
| Function: Wait_X_1ms
| Description: loop which waits at least timeToWait ms
@@ -446,11 +542,13 @@ Calibrate_loop_1ms(void)
void
Wait_X_ms( unsigned int timeToWait){
- unsigned int i, j;
+ unsigned int j;
+
+ for (j=0; j<timeToWait ; j++) {
+ if (slowLoop1ms != 0) slowLoop(slowLoop1ms);
+ fastLoop(fastLoop1ms);
+ }
- for (j=0; j<timeToWait ; j++)
- for (i=0; i<loop1ms; i++)
- outport_byte(SLOW_DOWN_IO, 0); /* write is # 1us */
}