This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
us_delay() improvement
- From: Nick Garnett <nickg at ecoscentric dot com>
- To: ecos-patches at sources dot redhat dot com
- Date: 19 Jun 2003 19:29:11 +0100
- Subject: us_delay() improvement
This is something I've had floating about for a while...
Index: ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/common/current/ChangeLog,v
retrieving revision 1.92
diff -u -5 -r1.92 ChangeLog
--- ChangeLog 6 May 2003 21:00:20 -0000 1.92
+++ ChangeLog 19 Jun 2003 18:25:39 -0000
@@ -1,5 +1,10 @@
+2003-06-19 Nick Garnett <nickg@balti.calivar.com>
+
+ * src/hal_if.c (delay_us): Reorganized to cope with high frequency
+ timers by eliminating a source of arithmetic overflow.
+
2003-05-06 Mark Salter <msalter@redhat.com>
* src/hal_stub.c (handle_exception_exit): Call sys_profile_reset from
here. Setup to return through return_from_stub() when appropriate.
(return_from_stub): New function to call CYGACC_CALL_IF_MONITOR_RETURN
Index: src/hal_if.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/common/current/src/hal_if.c,v
retrieving revision 1.22
diff -u -5 -r1.22 hal_if.c
--- src/hal_if.c 3 Mar 2003 17:09:56 -0000 1.22
+++ src/hal_if.c 19 Jun 2003 18:25:52 -0000
@@ -8,10 +8,11 @@
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002 Gary Thomas
+// Copyright (C) 2003 Nick Garnett <nickg@calivar.com>
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
@@ -32,12 +33,12 @@
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
-// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
-// at http://sources.redhat.com/ecos/ecos-license/
+// Alternative licenses for eCos may be arranged by contacting the copyright
+// holders.
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
@@ -158,37 +159,70 @@
delay_us(cyg_int32 usecs)
{
CYGARC_HAL_SAVE_GP();
#ifdef CYGPKG_KERNEL
{
- cyg_int32 start, elapsed;
- cyg_int32 usec_ticks, slice;
-
- // How many ticks total we should wait for.
- usec_ticks = usecs*CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
- usec_ticks /= CYGNUM_HAL_RTC_NUMERATOR/CYGNUM_HAL_RTC_DENOMINATOR/1000;
-
+ cyg_int32 start, elapsed, elapsed_usec;
+ cyg_int32 slice;
+ cyg_int32 usec_per_period = CYGNUM_HAL_RTC_NUMERATOR/CYGNUM_HAL_RTC_DENOMINATOR/1000;
+ cyg_int32 ticks_per_usec = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD/usec_per_period;
+
do {
// Spin in slices of 1/2 the RTC period. Allows interrupts
- // time to run without messing up the algorithm. If we spun
- // for 1 period (or more) of the RTC, there'd be also problems
- // figuring out when the timer wrapped. We may lose a tick or
- // two for each cycle but it shouldn't matter much.
- slice = usec_ticks % (CYGNUM_KERNEL_COUNTERS_RTC_PERIOD / 2);
+ // time to run without messing up the algorithm. If we
+ // spun for 1 period (or more) of the RTC, there would also
+ // be problems figuring out when the timer wrapped. We
+ // may lose a tick or two for each cycle but it shouldn't
+ // matter much.
+
+ // The tests against CYGNUM_KERNEL_COUNTERS_RTC_PERIOD
+ // check for a value that would cause a 32 bit signed
+ // multiply to overflow. But this also implies that just
+ // multiplying by ticks_per_usec will yield a good
+ // approximation. Otherwise we need to do the full
+ // multiply+divide to get sufficient accuracy. Note that
+ // this test is actually constant, so the compiler will
+ // eliminate it and only compile the branch that is
+ // selected.
+
+ if( usecs > usec_per_period/2 )
+ slice = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD/2;
+ else if( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD >= 0x7FFFFFFF/usec_per_period )
+ slice = usecs * ticks_per_usec;
+ else
+ {
+ slice = usecs*CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
+ slice /= usec_per_period;
+ }
HAL_CLOCK_READ(&start);
do {
HAL_CLOCK_READ(&elapsed);
elapsed = (elapsed - start); // counts up!
if (elapsed < 0)
elapsed += CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
} while (elapsed < slice);
- // Adjust by elapsed, not slice, since an interrupt may have
- // been stalling us for some time.
- usec_ticks -= elapsed;
- } while (usec_ticks > 0);
+ // Adjust by elapsed, not slice, since an interrupt may
+ // have been stalling us for some time.
+
+ if( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD >= 0x7FFFFFFF/usec_per_period )
+ elapsed_usec = elapsed / ticks_per_usec;
+ else
+ {
+ elapsed_usec = elapsed * usec_per_period;
+ elapsed_usec = elapsed_usec / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
+ }
+
+ // It is possible for elapsed_usec to end up zero in some
+ // circumstances and we could end up looping indefinitely.
+ // Avoid that by ensuring that we always decrement usec by
+ // at least 1 each time.
+
+ usecs -= elapsed_usec ? elapsed_usec : 1;
+
+ } while (usecs > 0);
}
#else // CYGPKG_KERNEL
#ifdef HAL_DELAY_US
// Use a HAL feature if defined
HAL_DELAY_US(usecs);
--
Nick Garnett eCos Kernel Architect
http://www.ecoscentric.com/ The eCos and RedBoot experts