From 49d638be979ea7fad86d6d68e98d692ad9e62e1e Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 27 Oct 2017 15:17:38 -0500 Subject: [PATCH] VxWorks osdMonotonic implementation PowerPC time-base frequencies are 32-bit. Adjust when warnings are printed. Use long double to calculate time from time-base. --- src/libCom/osi/os/vxWorks/osdMonotonic.c | 47 +++++++++++++++++------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/src/libCom/osi/os/vxWorks/osdMonotonic.c b/src/libCom/osi/os/vxWorks/osdMonotonic.c index 6a7abadbf..e0c6b2278 100644 --- a/src/libCom/osi/os/vxWorks/osdMonotonic.c +++ b/src/libCom/osi/os/vxWorks/osdMonotonic.c @@ -8,11 +8,11 @@ #define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h> #include +#include #define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE #include "epicsTypes.h" #include "epicsTime.h" -#include "epicsFindSymbol.h" #define NS_PER_SEC 1000000000 @@ -23,30 +23,35 @@ union timebase { UINT64 u64; /* epicsMonotonicGet() */ }; -static epicsUInt64 ticksPerSec; - #if CPU_FAMILY == PPC #include +#include "epicsFindSymbol.h" + +/* On PowerPC the timebase counter runs at a rate related to the + * bus clock and its frequency should always fit into a UINT32. + */ + +static epicsUInt32 ticksPerSec; #define TIMEBASEGET(TB) \ vxTimeBaseGet(&TB.u32[0], &TB.u32[1]) -typedef epicsUInt64 (*sysTimeBaseFreq_t)(void); - void osdMonotonicInit(void) { + typedef epicsUInt32 (*sysTimeBaseFreq_t)(void); sysTimeBaseFreq_t sysTimeBaseFreq = (sysTimeBaseFreq_t) epicsFindSymbol("_sysTimeBaseFreq"); if (sysTimeBaseFreq) { ticksPerSec = sysTimeBaseFreq(); - return; - } - printf("Warning: BSP routine sysTimeBaseFreq() not found,\n" - "can't set up monotonic time source.\n"); - ticksPerSec = 0; + if (!ticksPerSec) + printf("Warning: Failed to set up monotonic time source.\n"); + /* Warn here only if the BSP routine exists but returned 0 */ + } + else + ticksPerSec = 0; /* Warn on first use */ } @@ -55,6 +60,12 @@ void osdMonotonicInit(void) #include #include +/* On Intel the timebase counter frequency is returned by the OS as a + * UINT64. Some CPUs may count at multi-GHz rates so we need 64 bits. + */ + +static epicsUInt64 ticksPerSec; + #define TIMEBASEGET(TB) \ pentiumTscGet64(&TB.i64) @@ -68,7 +79,7 @@ void osdMonotonicInit(void) #else - #error CPU Family not supported yet! + #error This CPU family not supported yet! #endif @@ -84,9 +95,19 @@ epicsUInt64 epicsMonotonicGet(void) { union timebase tbNow; - if (!ticksPerSec) + if (!ticksPerSec) { + static int warned = 0; + + if (!warned) { + printf("Warning: Monotonic time source is not available.\n"); + warned = 1; + } return 0; + } TIMEBASEGET(tbNow); - return tbNow.u64 / (ticksPerSec / NS_PER_SEC); + /* Using a long double for the calculation below to preserve + * as many bits in the mantissa as possible. + */ + return ((long double) tbNow.u64) * NS_PER_SEC / ticksPerSec; }