960 lines
25 KiB
C
960 lines
25 KiB
C
/* wvTmrLib.c - timer library (System Viewer) */
|
|
|
|
/*
|
|
* Copyright (c) 1993-1995, 1998, 2004-2010, 2013, 2023
|
|
* Wind River Systems, Inc.
|
|
*
|
|
* The right to copy, distribute, modify or otherwise make use
|
|
* of this software may be licensed only pursuant to the terms
|
|
* of an applicable Wind River license agreement.
|
|
*/
|
|
|
|
/*
|
|
modification history
|
|
--------------------
|
|
01y,16oct23,kch Fixed warnings when time_t is 64-bit.
|
|
01x,30oct13,elp checked wdStart() return value.
|
|
01w,28jan13,wzc WIND00399576 - initialize value when enabling timestamp.
|
|
01v,06sep10,tcr Share timestamp with Cafe
|
|
01v,15nov10,tcr Allow Cafe to use timestamp
|
|
01u,14jun10,vhe Fixed VSB/CDF compatibility (CQ:WIND00216392); cleanup
|
|
01t,21jan10,wzc Adapt SV to vxWorks 64bit.
|
|
01s,27jul09,jpb Fixed compiler warning.
|
|
01r,27aug08,jpb Renamed VSB header file
|
|
01q,18jun08,jpb Renamed _WRS_VX_SMP to _WRS_CONFIG_SMP. Added include path
|
|
for kernel configurations options set in vsb.
|
|
01p,25sep07,tcr fix incorrect timestamp calculation (WIND00105916)
|
|
01o,17sep07,tcr WIND00103129: NULL-ptr deref in traceTimestampGet() on SMP
|
|
01n,08apr07,mmi make traceTimestampGet () SMP safe
|
|
01m,29apr07,cjj included private/tickLibP.h for vxAbsTicks
|
|
made pRolloverCount a volatile like vxAbsTicks
|
|
01l,28jun06,tcr add support for POSIX trace timer: Remove i960 support
|
|
01k,22sep05,tcr Fix SPR 112648: System Viewer wvTmrRegister() reference entry
|
|
incorrect
|
|
01j,20apr04,tcr change references to WindView to 'System Viewer'
|
|
01i,05oct98,jmp doc: fixed SEE ALSO section.
|
|
01h,28may98,dgp clean up man pages for WV 2.0 beta release
|
|
01g,15apr98,cjtc WV2.0 i960 port
|
|
01f,03feb95,rhp docn improvements from last printed man pages
|
|
01e,01feb95,rhp library man page: add ref to User's Guide
|
|
01d,05apr94,smb and more documentation changes
|
|
01c,07mar94,smb more documentation changes
|
|
01b,17jan94,smb documentation changes
|
|
01a,10dec93,smb created
|
|
*/
|
|
|
|
/*
|
|
DESCRIPTION
|
|
This library allows a Wind River System Viewer timestamp timer to be
|
|
registered. When this timer is enabled, events are tagged with a
|
|
timestamp as they are logged.
|
|
|
|
Seven routines are required for System Viewer: a timestamp routine, a timestamp
|
|
routine that guarantees interrupt lockout, a routine that enables the timer
|
|
driver, a routine that disables the timer driver, a routine that specifies the
|
|
routine to run when the timer hits a rollover, a routine that returns the
|
|
period of the timer, and a routine that returns the frequency of the
|
|
timer.
|
|
|
|
|
|
INTERNAL
|
|
|
|
This library now allows System Viewer, the POSIX trace system, and Cafe to
|
|
share the timestamp driver. System Viewer requires that when the timestamp is
|
|
connected, the rollover interrupt will be connected to the routine nominated by
|
|
System Viewer. When POSIX trace is involved, this cannot be done directly,
|
|
because trace needs to count rollovers.
|
|
|
|
When System Viever calls the connect routine, we actually connect a function in
|
|
this library, but note the function that System Viewer requested. When the
|
|
interrupt is handled, the function here counts the interrupt, and then passes
|
|
control on to the function specified by System Viewer.
|
|
|
|
INCLUDE FILES:
|
|
|
|
SEE ALSO: wvLib,
|
|
.I Wind River System Viewer User's Guide
|
|
*/
|
|
|
|
/* includes */
|
|
|
|
#include <vxWorks.h>
|
|
#include <vsbConfig.h>
|
|
#include <wdLib.h>
|
|
#include <intLib.h>
|
|
#include <time.h>
|
|
#include <wvTmrLib.h>
|
|
#include <private/svFuncBindP.h>
|
|
#include <vxAtomicLib.h>
|
|
|
|
/* defines */
|
|
|
|
#define TEN_EXP9 (1000000000L)
|
|
|
|
#define MAX_CLIENTS 3
|
|
|
|
#define WV_TMR_INDEX 0
|
|
#define TRACE_TMR_INDEX 1
|
|
#define CAFE_TMR_INDEX 2
|
|
|
|
/* typedefs */
|
|
|
|
/* locals */
|
|
|
|
LOCAL struct ts_desc ts_descs[MAX_CLIENTS];
|
|
|
|
LOCAL WDOG_ID rolloverWd = NULL;
|
|
|
|
|
|
/* globals */
|
|
|
|
struct timespec traceTimerStartValue = {0,0};
|
|
|
|
/* forward declarations */
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* localRolloverHandler - handler for all rollover interrupts
|
|
*
|
|
* This function uses the supplied ts_desc structure to determine which
|
|
* timestamp has rolled over. Since a timestamp source may be shared with
|
|
* several clients, it then calls the handlers of any client which uses the same
|
|
* source. If the interrupt source was a watchdog, it is restarted.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
*/
|
|
|
|
LOCAL void localRolloverHandler
|
|
(
|
|
struct ts_desc * ts_desc
|
|
)
|
|
{
|
|
int i;
|
|
unsigned int (*ts)(void);
|
|
/* get identification of which timestamp source */
|
|
ts = ts_desc->ts;
|
|
|
|
|
|
/* call rollover function for all enabled clients using this source */
|
|
for (i = 0; i < MAX_CLIENTS; i++)
|
|
{
|
|
if (ts == ts_descs [i].ts &&
|
|
ts_descs [i].client_handler != NULL &&
|
|
ts_descs [i].enabled)
|
|
{
|
|
/* call handler */
|
|
ts_descs [i].client_handler((_Vx_usr_arg_t)(ts_descs + i));
|
|
}
|
|
}
|
|
if (ts_desc->useWd)
|
|
(void)wdStart (rolloverWd, 1, (FUNCPTR)localRolloverHandler,
|
|
(_Vx_usr_arg_t)ts_desc);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* localEnable - enable a timestamp for a client
|
|
*
|
|
* This function enables a timestamp source for a client. If the source is
|
|
* already enabled, then it just enables the client. Otherwise, it enables both
|
|
* the source and client
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
*/
|
|
LOCAL STATUS localEnable
|
|
(
|
|
struct ts_desc * ts /* timestamp to enable */
|
|
)
|
|
{
|
|
int enabledCount = 0;
|
|
unsigned int i;
|
|
STATUS res = OK;
|
|
|
|
|
|
if (ts->enabled)
|
|
return OK;
|
|
|
|
/* count enabled clients which use the same underlying function */
|
|
|
|
for (i = 0; i < MAX_CLIENTS; i++)
|
|
{
|
|
if (ts_descs [i].ts == ts->ts &&
|
|
ts_descs [i].enabled)
|
|
{
|
|
enabledCount++;
|
|
}
|
|
}
|
|
|
|
/* try not to enable a sourcce if it's already done */
|
|
if (enabledCount == 0)
|
|
res = ts->source_enable();
|
|
|
|
/* clear time stamp data */
|
|
ts->lastRollover0 = 0;
|
|
ts->lastRollover1 = 0;
|
|
ts->lastTimestamp = ts->ts();
|
|
|
|
ts->enabled = TRUE;
|
|
|
|
/* if wd for this time source, start it now */
|
|
if (ts->useWd)
|
|
{
|
|
if (rolloverWd == NULL)
|
|
return ERROR;
|
|
|
|
res = wdStart (rolloverWd, 1, (FUNCPTR)localRolloverHandler,
|
|
(_Vx_usr_arg_t)ts);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* localDisable - disable a timestamp for a client
|
|
*
|
|
* This function disables a timestamp source for a client. If the requesting
|
|
* client is the only one for this timestamp source, then the source is disabled.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
*/
|
|
|
|
LOCAL STATUS localDisable
|
|
(
|
|
struct ts_desc * ts /* timestamp to disable */
|
|
)
|
|
{
|
|
int enabledCount = 0;
|
|
int wdClients = 0;
|
|
unsigned int i;
|
|
STATUS res = OK;
|
|
|
|
if (!ts->enabled)
|
|
return OK;
|
|
|
|
/* count enabled clients using this source */
|
|
for (i = 0; i < MAX_CLIENTS; i++)
|
|
{
|
|
if (ts_descs [i].ts == ts->ts &&
|
|
ts_descs [i].enabled)
|
|
{
|
|
enabledCount++;
|
|
|
|
if (ts_descs [i].useWd)
|
|
wdClients++;
|
|
}
|
|
}
|
|
|
|
if (enabledCount == 1)
|
|
res = ts->source_disable();
|
|
|
|
ts->enabled = FALSE;
|
|
|
|
if (!ts->useWd)
|
|
return res;
|
|
|
|
/* client uses watchdog: If there are no others, using it, cancel it */
|
|
if (wdClients == 1)
|
|
{
|
|
if (rolloverWd == NULL)
|
|
return ERROR;
|
|
|
|
wdCancel (rolloverWd);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* localWvEnable - enable a timestamp for System Viewer
|
|
*
|
|
* This function enables a previously-registered timestamp source for System
|
|
* Viewer.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
*/
|
|
|
|
LOCAL void localWvEnable (void)
|
|
{
|
|
localEnable (ts_descs + WV_TMR_INDEX);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* localWvDisable - diable a timestamp for System Viewer
|
|
*
|
|
* This function disables a previously-registered timestamp source for a System
|
|
* Viewer.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
*/
|
|
|
|
LOCAL void localWvDisable (void)
|
|
{
|
|
localDisable (ts_descs + WV_TMR_INDEX);
|
|
}
|
|
|
|
|
|
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* localCafeEnable - enable a timestamp for Cafe
|
|
*
|
|
* This function enables a previously-registered timestamp source for Cafe
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
*/
|
|
|
|
LOCAL void localCafeEnable (void)
|
|
{
|
|
localEnable (ts_descs + CAFE_TMR_INDEX);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* localCafeDisable - disable a timestamp for Cafe
|
|
*
|
|
* This function disables a previously-registered timestamp source for Cafe
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
*/
|
|
|
|
LOCAL void localCafeDisable (void)
|
|
{
|
|
localDisable (ts_descs + CAFE_TMR_INDEX);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* traceTmrMuxEnable - enable a timestamp for POSIX trace
|
|
*
|
|
* This function enables a previously-registered timestamp source for POSIX
|
|
* tracing
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
*/
|
|
|
|
void traceTmrMuxEnable (void)
|
|
{
|
|
localEnable (ts_descs + TRACE_TMR_INDEX);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* traceTmrMuxDisable - disable a timestamp for POSIX trace
|
|
*
|
|
* This function disables a previously-registered timestamp source for POSIX
|
|
* tracing
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
*/
|
|
|
|
void traceTmrMuxDisable (void)
|
|
{
|
|
localDisable (ts_descs + TRACE_TMR_INDEX);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* localConnect - connect a rollover handler for a client
|
|
*
|
|
* This function is called by a client to attach a handler, which will be called
|
|
* later when a timestamp rolls over. It notes the requested handler in the
|
|
* supplied ts_desc structure, and connects the local handler.
|
|
*
|
|
* It returns the result of calling the rollover connect function for the
|
|
* requested timestamp.
|
|
*
|
|
* RETURNS: OK or ERROR
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
*/
|
|
|
|
LOCAL STATUS localConnect
|
|
(
|
|
void (*client_handler)(_Vx_usr_arg_t),
|
|
struct ts_desc * ts
|
|
)
|
|
{
|
|
STATUS result;
|
|
|
|
ts->client_handler = client_handler;
|
|
ts->useWd = FALSE;
|
|
|
|
/* interrupt will call nominated local function with ts_desc */
|
|
result = ts->source_connect((void (*)(_Vx_usr_arg_t))localRolloverHandler,
|
|
(_Vx_usr_arg_t)ts);
|
|
return result;
|
|
}
|
|
|
|
|
|
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wvRolloverConnect - connect a rollover handler for System Viewer
|
|
*
|
|
* This function attempts to connect a rollover handler to the System Viewer
|
|
* timestamp source
|
|
*
|
|
* RETURNS: OK or ERROR
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
*/
|
|
|
|
LOCAL STATUS wvRolloverConnect
|
|
(
|
|
void (*handler)(_Vx_usr_arg_t),
|
|
struct ts_desc *ts
|
|
)
|
|
{
|
|
STATUS res;
|
|
|
|
res = localConnect(handler, ts_descs + WV_TMR_INDEX);
|
|
if (res == ERROR)
|
|
ts_descs [WV_TMR_INDEX].client_handler = NULL;
|
|
return res;
|
|
|
|
}
|
|
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* rolloverHandler - count rollover for a timestamp source
|
|
*
|
|
* This function records a rollover for a client
|
|
*
|
|
* RETURNS: OK or ERROR
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
*/
|
|
|
|
LOCAL void rolloverHandler
|
|
(
|
|
_Vx_usr_arg_t arg
|
|
)
|
|
{
|
|
struct ts_desc * ts = (struct ts_desc *)arg;
|
|
unsigned int p = ts->period ();
|
|
int key = INT_CPU_LOCK ();
|
|
|
|
ts->lastRollover0 += p;
|
|
ts->lastTimestamp = ts->ts();
|
|
|
|
/* ensure both lastRollover0 and lastTimestamp have been updated */
|
|
VX_MEM_BARRIER_RW();
|
|
|
|
ts->lastRollover1 += p;
|
|
|
|
INT_CPU_UNLOCK (key);
|
|
}
|
|
|
|
|
|
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wvTmrRegister - register a timestamp timer
|
|
*
|
|
* This routine registers a timestamp routine for each of the following:
|
|
* .iP <wvTmrRtn>
|
|
* a timestamp routine, which returns a timestamp when called (must be called
|
|
* with interrupts locked).
|
|
* .iP <wvTmrLockRtn>
|
|
* a timestamp routine, which returns a timestamp when called (locks interrupts).
|
|
* .iP <wvTmrEnable>
|
|
* an enable-timer routine, which enables the timestamp timer.
|
|
* .iP <wvTmrDisable>
|
|
* a disable-timer routine, which disables the timestamp timer.
|
|
* .iP <wvTmrConnect>
|
|
* a connect-to-timer routine, which connects a handler to be run when the timer
|
|
* rolls over; this routine should return ERROR if the system clock tick is to be
|
|
* used.
|
|
* .iP <wvTmrPeriod>
|
|
* a period-of-timer routine, which returns the period of the timer.
|
|
* .iP <wvTmrFreq>
|
|
* a frequency-of-timer routine, which returns the frequency of the timer.
|
|
* .LP
|
|
*
|
|
* If any of these routines is set to NULL, the behavior of instrumented code
|
|
* is undefined.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO:
|
|
*/
|
|
|
|
void wvTmrRegister
|
|
(
|
|
UINTFUNCPTR wvTmrRtn, /* timestamp function */
|
|
UINTFUNCPTR wvTmrLockRtn, /* int-locked timestamp function */
|
|
FUNCPTR wvTmrEnable, /* enable timestamp */
|
|
FUNCPTR wvTmrDisable, /* disable timestamp */
|
|
FUNCPTR wvTmrConnect, /* connect rollover */
|
|
UINTFUNCPTR wvTmrPeriod, /* period of timestamp */
|
|
UINTFUNCPTR wvTmrFreq /* frequency of timestamp */
|
|
)
|
|
{
|
|
ts_descs [WV_TMR_INDEX].ts = wvTmrRtn;
|
|
ts_descs [WV_TMR_INDEX].tsLock = wvTmrLockRtn;
|
|
ts_descs [WV_TMR_INDEX].source_enable = wvTmrEnable;
|
|
ts_descs [WV_TMR_INDEX].source_disable = wvTmrDisable;
|
|
ts_descs [WV_TMR_INDEX].period = wvTmrPeriod;
|
|
ts_descs [WV_TMR_INDEX].frequency = wvTmrFreq;
|
|
ts_descs [WV_TMR_INDEX].source_connect = wvTmrConnect;
|
|
|
|
ts_descs [WV_TMR_INDEX].enable = (FUNCPTR)localWvEnable;
|
|
ts_descs [WV_TMR_INDEX].disable = (FUNCPTR)localWvDisable;
|
|
ts_descs [WV_TMR_INDEX].connect = (FUNCPTR)wvRolloverConnect;
|
|
|
|
ts_descs [WV_TMR_INDEX].enabled = FALSE;
|
|
|
|
if (rolloverWd == NULL)
|
|
rolloverWd = wdCreate ();
|
|
|
|
/*
|
|
use our rollover connect function, having saved the one the client
|
|
requested into source_connect
|
|
*/
|
|
|
|
_func_tmrConnect = (FUNCPTR)wvRolloverConnect;
|
|
|
|
/* because this is WV tmr, connect to global funcptrs */
|
|
|
|
_func_tmrDisable = localWvDisable;
|
|
_func_tmrEnable = localWvEnable;
|
|
_func_tmrFreq = (FUNCPTR)wvTmrFreq;
|
|
_func_tmrPeriod = (FUNCPTR)wvTmrPeriod;
|
|
_func_tmrStamp = (FUNCPTR)wvTmrRtn;
|
|
_func_tmrStampLock = (FUNCPTR)wvTmrLockRtn;
|
|
|
|
}
|
|
|
|
#endif /*_WRS_CONFIG_SV_INSTRUMENTATION */
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* cafeTmrRegister - register a timestamp driver for Cafe analysis system
|
|
*
|
|
* This routine registers a timestamp routine for each of the following:
|
|
*
|
|
* .iP <tmrRtn>
|
|
* a timestamp routine, which returns a timestamp when called
|
|
* .iP <tmrLockRtn>
|
|
* a timestamp routine, which returns a timestamp when called. Interrupts are
|
|
* lockded while the timestamp is read
|
|
* .iP <tmrEnable>
|
|
* an enable-timer routine, which enables the timestamp timer.
|
|
* .iP <tmrDisable>
|
|
* a disable-timer routine, which disables the timestamp timer.
|
|
* .iP <tmrConnect>
|
|
* a connect-to-timer routine, which connects a handler to be run when the timer
|
|
* rolls over; this routine should return ERROR if the system clock tick is to be
|
|
* used.
|
|
* .iP <tmrPeriod>
|
|
* a period-of-timer routine, which returns the period of the timer.
|
|
* .iP <tmrFreq>
|
|
* a frequency-of-timer routine, which returns the frequency of the timer.
|
|
* .LP
|
|
*
|
|
* If any of these routines is set to NULL, the behavior of instrumented code
|
|
* is undefined.
|
|
*
|
|
* RETURNS: Pointer to TS_DESC structure containing cached function pointers and
|
|
* values used by timestamp functions for Cafe
|
|
*
|
|
* ERRNO:
|
|
*
|
|
*/
|
|
|
|
TS_DESC * cafeTmrRegister
|
|
(
|
|
UINTFUNCPTR tmrRtn, /* timestamp function */
|
|
UINTFUNCPTR tmrLockRtn, /* int-locked timestamp function */
|
|
FUNCPTR tmrEnable, /* enable timestamp */
|
|
FUNCPTR tmrDisable, /* disable timestamp */
|
|
FUNCPTR tmrConnect, /* connect rollover */
|
|
UINTFUNCPTR tmrPeriod, /* period of timestamp */
|
|
UINTFUNCPTR tmrFreq /* frequency of timestamp */
|
|
)
|
|
{
|
|
ts_descs [CAFE_TMR_INDEX].ts = tmrRtn;
|
|
ts_descs [CAFE_TMR_INDEX].tsLock = tmrLockRtn;
|
|
ts_descs [CAFE_TMR_INDEX].source_enable = tmrEnable;
|
|
ts_descs [CAFE_TMR_INDEX].source_disable = tmrDisable;
|
|
ts_descs [CAFE_TMR_INDEX].period = tmrPeriod;
|
|
ts_descs [CAFE_TMR_INDEX].frequency = tmrFreq;
|
|
ts_descs [CAFE_TMR_INDEX].source_connect = tmrConnect;
|
|
|
|
ts_descs [CAFE_TMR_INDEX].enable = (FUNCPTR)localCafeEnable;
|
|
ts_descs [CAFE_TMR_INDEX].disable = (FUNCPTR)localCafeDisable;
|
|
ts_descs [CAFE_TMR_INDEX].connect = NULL; /* no external rollover handler */
|
|
|
|
if (rolloverWd == NULL)
|
|
rolloverWd = wdCreate ();
|
|
|
|
if (localConnect (rolloverHandler, ts_descs + CAFE_TMR_INDEX) != OK)
|
|
{
|
|
/* source uses sysClk as rollover */
|
|
ts_descs [CAFE_TMR_INDEX].useWd = TRUE;
|
|
}
|
|
|
|
return ts_descs + CAFE_TMR_INDEX;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* traceTmrRegister - register a timestamp driver for POSIX trace
|
|
*
|
|
* This routine registers a timestamp routine for each of the following:
|
|
*
|
|
* .iP <traceTmrRtn>
|
|
* a timestamp routine, which returns a timestamp when called (must be called
|
|
* with interrupts locked).
|
|
* .iP <traceTmrEnable>
|
|
* an enable-timer routine, which enables the timestamp timer.
|
|
* .iP <traceTmrDisable>
|
|
* a disable-timer routine, which disables the timestamp timer.
|
|
* .iP <traceTmrConnect>
|
|
* a connect-to-timer routine, which connects a handler to be run when the timer
|
|
* rolls over; this routine should return ERROR if the system clock tick is to be
|
|
* used.
|
|
* .iP <traceTmrPeriod>
|
|
* a period-of-timer routine, which returns the period of the timer.
|
|
* .iP <traceTmrFreq>
|
|
* a frequency-of-timer routine, which returns the frequency of the timer.
|
|
* .LP
|
|
*
|
|
* If any of these routines is set to NULL, the behavior of instrumented code
|
|
* is undefined.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO:
|
|
*
|
|
* NOMANUAL
|
|
*/
|
|
|
|
void traceTmrRegister
|
|
(
|
|
UINTFUNCPTR tmrRtn,
|
|
FUNCPTR tmrEnable,
|
|
FUNCPTR tmrDisable,
|
|
FUNCPTR tmrConnect,
|
|
UINTFUNCPTR tmrPeriod,
|
|
UINTFUNCPTR tmrFreq
|
|
)
|
|
{
|
|
ts_descs [TRACE_TMR_INDEX].ts = tmrRtn;
|
|
ts_descs [TRACE_TMR_INDEX].tsLock = tmrRtn;
|
|
ts_descs [TRACE_TMR_INDEX].source_enable = tmrEnable;
|
|
ts_descs [TRACE_TMR_INDEX].source_disable = tmrDisable;
|
|
ts_descs [TRACE_TMR_INDEX].period = tmrPeriod;
|
|
ts_descs [TRACE_TMR_INDEX].frequency = tmrFreq;
|
|
ts_descs [TRACE_TMR_INDEX].source_connect = tmrConnect;
|
|
|
|
ts_descs [TRACE_TMR_INDEX].enabled = FALSE;
|
|
|
|
ts_descs [TRACE_TMR_INDEX].enable = (FUNCPTR)traceTmrMuxEnable;
|
|
ts_descs [TRACE_TMR_INDEX].disable = (FUNCPTR)traceTmrMuxDisable;
|
|
ts_descs [TRACE_TMR_INDEX].connect = NULL; /* no external rollover handler */
|
|
|
|
if (rolloverWd == NULL)
|
|
rolloverWd = wdCreate ();
|
|
|
|
if (localConnect (rolloverHandler, ts_descs + TRACE_TMR_INDEX) != OK)
|
|
{
|
|
/* source uses sysClk as rollover */
|
|
ts_descs [TRACE_TMR_INDEX].useWd = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ticksToTime - convert system-specific time to struct timespec
|
|
*
|
|
* This function takes system clock ticks, and the high-res timer value, and
|
|
* converts to seconds and nanoseconds. It also applies an offset, which could be
|
|
* derived from time-of-day at system startup
|
|
*
|
|
* \INTERNAL
|
|
* The nowTicks variable (64bit) will contain the time since boot, in units of the
|
|
* high-resolution clock, so it's a bit like the Intel TSC. At a clockrate
|
|
* of (say) 4GHz, it will overflow in 146 years.
|
|
*
|
|
* \NOMANUAL
|
|
*/
|
|
|
|
LOCAL STATUS ticksToTime
|
|
(
|
|
UINT64 ticks, /* extended tick count */
|
|
struct ts_desc * ts_desc, /* timestamp selection */
|
|
const struct timespec * offset, /* offset */
|
|
struct timespec * now /* result */
|
|
)
|
|
{
|
|
UINT64 nowTicks; /* timestamp in clock ticks */
|
|
UINT64 nowFracSec; /* fraction of second, high-res ticks */
|
|
|
|
UINT32 tsFreq;
|
|
UINT32 tsPeriod;
|
|
|
|
tsFreq = ts_desc->frequency ();
|
|
tsPeriod = ts_desc->period ();
|
|
|
|
now->tv_sec = (time_t) (ticks / tsFreq);
|
|
|
|
nowFracSec = ticks % tsFreq;
|
|
|
|
/* Convert from ticks to nsec */
|
|
|
|
now->tv_nsec = (long) (nowFracSec * TEN_EXP9 / tsFreq);
|
|
|
|
now->tv_sec += offset->tv_sec;
|
|
now->tv_nsec += offset->tv_nsec;
|
|
|
|
while (now->tv_nsec >= TEN_EXP9)
|
|
{
|
|
now->tv_nsec -= TEN_EXP9;
|
|
now->tv_sec++;
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wvTmrTimestamp64ToTime - convert system-specific time to struct timespec
|
|
*
|
|
* This function converts a 64bit timestamp into struct timespec
|
|
*
|
|
*/
|
|
|
|
STATUS wvTmrTimestamp64ToTime
|
|
(
|
|
UINT64 ticks, /* extended tick count */
|
|
struct ts_desc * ts_desc, /* timestamp selection */
|
|
struct timespec * now /* result */
|
|
)
|
|
{
|
|
struct timespec offset = {0,0};
|
|
|
|
return (ticksToTime (ticks, ts_desc, &offset, now));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wvTmrTimestamp64Get - get an extended timestamp
|
|
*
|
|
* This function reads a 64bit timestamp from the requested timestamp source
|
|
*
|
|
* RETURNS: OK ,or ERROR
|
|
*
|
|
*/
|
|
|
|
STATUS wvTmrTimestamp64Get
|
|
(
|
|
TS_DESC * ts, /* timestamp to get timestamp from */
|
|
unsigned long long * result /* 64bit timestamp result */
|
|
)
|
|
{
|
|
unsigned long long rollover0;
|
|
unsigned long long rollover1;
|
|
unsigned int timestamp;
|
|
unsigned int timestampSave;
|
|
|
|
if (ts == NULL)
|
|
return ERROR;
|
|
|
|
do
|
|
{
|
|
rollover0 = ts->lastRollover0;
|
|
timestampSave = ts->lastTimestamp;
|
|
timestamp = ts->ts();
|
|
|
|
rollover1 = ts->lastRollover1;
|
|
} while (rollover0 != rollover1);
|
|
|
|
if (timestamp < timestampSave)
|
|
rollover0 += ts->period();
|
|
|
|
*result = rollover0 + timestamp;
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wvTmrFrequency64Get - get timestamp frequency
|
|
*
|
|
* This function retrieves 64bit frequency from the requested timestamp source
|
|
*
|
|
* RETURNS: OK ,or ERROR
|
|
*
|
|
*/
|
|
|
|
STATUS wvTmrFrequency64Get
|
|
(
|
|
TS_DESC * ts, /* timestamp to get timestamp from */
|
|
unsigned long long * result /* 64bit frequency result */
|
|
)
|
|
{
|
|
if (ts == NULL)
|
|
return ERROR;
|
|
|
|
*result = ts->frequency();
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wvTmrEnable - enable timestamp source
|
|
*
|
|
* This function enables the source of the timestamp
|
|
*
|
|
* RETURNS: OK ,or ERROR
|
|
*
|
|
*/
|
|
|
|
STATUS wvTmrEnable
|
|
(
|
|
TS_DESC * ts /* timestamp to enable */
|
|
)
|
|
{
|
|
if (ts == NULL)
|
|
return ERROR;
|
|
|
|
return ts->enable();
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wvTmrDisable - disable timestamp source
|
|
*
|
|
* This function disables the source of the timestamp
|
|
*
|
|
* RETURNS: OK ,or ERROR
|
|
*
|
|
*/
|
|
|
|
STATUS wvTmrDisable
|
|
(
|
|
TS_DESC * ts /* timestamp to enable */
|
|
)
|
|
{
|
|
if (ts == NULL)
|
|
return ERROR;
|
|
|
|
return ts->disable();
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* traceTimestampGet - get a timestamp in 'struct timespec' form
|
|
*
|
|
* This function uses the timestamp driver and the tick count to get the time
|
|
*
|
|
* The timestamp driver provides high resolution, but the result has to be
|
|
* normalised. To do this we use the timestamp frequency and period, and the
|
|
* number of times the counter has rolled over since startup.
|
|
* The frequency and period are known from the driver, the number of rollovers is
|
|
* updated during the rollover interrupt.
|
|
*
|
|
* NOMANUAL
|
|
*/
|
|
|
|
STATUS traceTimestampGet
|
|
(
|
|
struct timespec * pTimestamp /* destination for timestamp */
|
|
)
|
|
{
|
|
unsigned long long tmrTimestamp;
|
|
|
|
if (wvTmrTimestamp64Get (ts_descs + TRACE_TMR_INDEX,
|
|
&tmrTimestamp) != OK)
|
|
return ERROR;
|
|
|
|
ticksToTime (tmrTimestamp, ts_descs + TRACE_TMR_INDEX,
|
|
&traceTimerStartValue, pTimestamp);
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* traceTmrResolutionGet - get resolution of timestamp source, in nanoseconds
|
|
*
|
|
* Write the resolution of the timestamp source into the supplied timespec. If
|
|
* the timestamp resolution cannot be obtained (maybe the timestamp driver is not
|
|
* available) then the timespec structure will be filled with zeroes.
|
|
*
|
|
* RETURNS: OK, or ERROR.
|
|
*
|
|
*/
|
|
|
|
STATUS traceTmrResolutionGet
|
|
(
|
|
struct timespec * pTimestamp /* destination for resolution */
|
|
)
|
|
{
|
|
UINT32 freq;
|
|
long resolution;
|
|
int result = OK;
|
|
|
|
if (ts_descs [TRACE_TMR_INDEX].frequency != NULL)
|
|
{
|
|
freq = (ts_descs [TRACE_TMR_INDEX].frequency)();
|
|
|
|
resolution = TEN_EXP9 / freq;
|
|
|
|
pTimestamp->tv_nsec = resolution % TEN_EXP9;
|
|
pTimestamp->tv_sec = resolution / TEN_EXP9;
|
|
}
|
|
else
|
|
{
|
|
pTimestamp->tv_nsec = 0;
|
|
pTimestamp->tv_sec = 0;
|
|
|
|
result = ERROR;
|
|
}
|
|
return (result);
|
|
}
|