📄 timer.c
字号:
/* timer.c - Peripheral extension model of RPS timer counter.
* Copyright (C) ARM Limited, 1998-2001 . All rights reserved.
*
* RCS $Revision: 1.11.4.12 $
* Checkin $Date: 2001/10/02 17:26:23 $
* Revising $Author: dsinclai $
*/
#define MODEL_NAME Timer
#include "minperip.h"
#if !defined(NDEBUG)
# if 1
# else
# define VERBOSE_KICKOFF
# define VERBOSE_NOINTC
# define VERBOSE_TIMEOUT
# define VERBOSE_GETNOW
# define VERBOSE_RUNAGAIN
# define VERBOSE_ACCESS
# endif
#endif
#include "armul_agent.h" /* for ARMul_ShowModuleDesc */
#ifndef ARMulCnf_CLK
# define ARMulCnf_CLK (tag_t)"CLK"
#endif
#ifndef ARMulCnf_IntOne
# define ARMulCnf_IntOne (tag_t)"INT1"
#endif
#ifndef ARMulCnf_IntTwo
# define ARMulCnf_IntTwo (tag_t)"INT2"
#endif
#ifndef ARMulCnf_Warn
# define ARMulCnf_Warn (tag_t)"WARN"
#endif
#ifndef ARMulCnf_Waits
# define ARMulCnf_Waits (tag_t)"WAITS"
#endif
typedef struct {
unsigned long TimerLoad; /* Timer load register */
unsigned long TimerValue; /* Current Timer value register */
unsigned long TimerControl; /* Timer Control register */
unsigned long TimerControlChangeMask; /* internal use change mask register */
int enabled; /* mirror of TimerControl register bit 7 */
int mode; /* mirror of TimerControl register bit 6 */
int prescale; /* mirror of TimerControl register bits 2..3 */
int oldPrescale; /* Previous prescale - not used currently */
unsigned long clockRate; /* The clock speed, read from armul.cnf in MemInit */
int interruptNumber; /* The interrupt signal number for this timer */
ARMTime nextEventTime; /* In case we need to remove it!! */
struct ARMulif_TimedCallback *timedCallback;
ARMul_TimedCallBackProc *fn; /* ptr to timeout function */
unsigned TimerNumber; /* 1 or 2, for debugging */
unsigned dbgIndex; /* Number of timeouts, for debugging. */
} timer_state;
static ARMul_BusPeripAccessFunc Timer_Access;
static ARMul_TimedCallBackProc Timer1Timeout;
static ARMul_TimedCallBackProc Timer2Timeout;
BEGIN_STATE_DECL(Timer)
GenericAccessCallback **intcInterface;
ARMul_BusPeripAccessRegistration my_bpar;
timer_state timer1; /* timer 1 structure */
timer_state timer2;
int useCoreEventSystem; /* Use memory or core cycle event system */
int warn; /* Warn users about invalid register accesses*/
int waits; /* Number of idle cycles before access */
int waitStates; /* stored number of wait states */
int accessState; /* Current access state */
END_STATE_DECL(Timer) /*} tic_state; */
static RDI_InfoProc TimerRDIInfo2;
NamedMethodFunc TimerInterfaceFuncs[] = {
{"RDI_InfoProc",(GenericMethodFunc*)TimerRDIInfo2},
{NULL,NULL}
};
static int TimerRDIInfo2(void *handle, unsigned subcode,
ARMword *arg1, ARMword *arg2)
{
TimerState *state = (TimerState*)handle;
#ifdef VERBOSE_TimerRDIInfo2
Hostif_PrettyPrint(state->hostif,state->config,
"\n*** Timer RDIInfo2:0x%04x ***\n", subcode);
#endif
switch (subcode)
{
case RDIInfo_QueryMethod:
#ifdef VERBOSE_TimerRDIInfo2
Hostif_PrettyPrint(state->hostif,state->config,"\n*** Timer FindMethodInterface ***\n");
#endif
return FindMethodInterface((GenericMethod *)arg2,(char const *)arg1,
state,&TimerInterfaceFuncs[0]);
case RDIInfo_RouteLinks:
/* Q: Do we want fake-time, or any other static scheduling scheme,
* during makelinks? */
/* !Todo: Form a (faster) link to the interrupt-controller here. */
/* (1) Request an InterfaceSource for Intc. */
/* (2) Ask that for an interrupt-input. */
/* (3) Throw away the old callback, if we got one. */
#ifdef VERBOSE_TimerRDIInfo2
Hostif_PrettyPrint(state->hostif,state->config,"\n*** Timer RouteLinks ***\n");
#endif
return RDIError_UnimplementedMessage; /* Carry on! */
default:
return RDIError_UnimplementedMessage;
}
}
BEGIN_INIT(Timer)
Hostif_PrettyPrint(state->hostif, config, ", Timer");
{
unsigned int TIC_Clk = ToolConf_DLookupUInt(config, ARMulCnf_CLK,
20000000);
unsigned int tic1IntNum = ToolConf_DLookupUInt(config, ARMulCnf_IntOne, 4);
unsigned int tic2IntNum = ToolConf_DLookupUInt(config, ARMulCnf_IntTwo, 5);
int warn = ToolConf_DLookupBool(config, ARMulCnf_Warn, FALSE);
int waits = ToolConf_DLookupUInt(config, ARMulCnf_Waits, 0 /*1*/);
if ( waits < 0 || waits > 30)
{
/*ARMul_PrettyPrint*/
Hostif_ConsolePrint(state->hostif, "(Timer Error: Invalid "
"wait state value - defaulting to zero waits)");
waits = 0;
}
{
TimerState *ts = state;
ts->timer1.clockRate=TIC_Clk; /* as read from armul.cnf */
ts->timer1.interruptNumber = tic1IntNum; /* as read from armul.cnf */
ts->timer1.nextEventTime=0l; /* In case we need to remove it!! */
ts->timer1.fn = Timer1Timeout; /* The timeout function to call */
ts->timer1.TimerNumber = 1;
ts->timer2.clockRate =TIC_Clk; /* as read from armul.cnf */
ts->timer2.interruptNumber = tic2IntNum; /* as read from armul.cnf */
ts->timer2.nextEventTime=0l; /* In case we need to remove it!! */
ts->timer2.fn = Timer2Timeout; /* The timeout function to call */
ts->timer2.TimerNumber = 2;
ts->warn = warn;
ts->waitStates = waits;
/* Get the Interrupt controller interface structure pointer.
*/
ts->intcInterface = ARMulif_GetInterruptController(&state->coredesc);
}
}
{ unsigned err = RDIError_NoError;
/* Provide access-callback */
state->my_bpar.access_func = Timer_Access;
state->my_bpar.access_handle = state;
state->my_bpar.capabilities = PeripAccessCapability_Minimum;
err = ARMulif_ReadBusRange(&state->coredesc, state->hostif,
ToolConf_FlatChild(config, (tag_t)"RANGE"),
&state->my_bpar,
0x0a800000,0x40,"");
if (err)
{
Hostif_PrettyPrint(hostif,config,
"\nTimer got err=%i from ReadBusRange\n", err);
return err;
}
if (!err)
{
err = state->my_bpar.bus->bus_registerPeripFunc(BusRegAct_Insert,
&state->my_bpar);
}
if (err)
{
Hostif_PrettyPrint(hostif,config,
"\nTimer got err=%i from bus_registerPeripFunc\n",
err);
return err;
}
}
ADD_INTERFACE_SOURCE(TimerInterfaceFuncs)
END_INIT(Timer)
BEGIN_EXIT(Timer)
END_EXIT(Timer)
/* ******************* */
/* Static declarations */
/* ******************* */
static void KickOffTimer(TimerState *ts, timer_state *myTimer,
unsigned long alternateLoadValue,
bool bRepeating);
static int iCheckIntcIf(TimerState *ts);
static void PrescaleValueChanged(TimerState *ts, timer_state *myTimer);
/*
Function Name: RunTimerAgain
Parameters:
TimerState *ts - pointer to TimerState
timer_state *myTimer - pointer to timer_state
Return: void
Description: Called when Timeout occurs. The purpose of the function
is to determine if the timer needs to be restarted and if so
whether it should be as periodic or free running.
Free running reloads the timer with 0xFFFF on timeout
Periodic reloads the timer with the Load value on timeout.
*/
static void RunTimerAgain(TimerState *ts, timer_state *myTimer)
{
/*
Depending on the mode we reload and start again - or we
just let the timer free run.
*/
#ifdef VERBOSE_RUNAGAIN
printf("RunTimerAgain.\n");
#endif
if ( myTimer->enabled == 1 )
{
/* Timer is enabled - this check is really belt and braces - the
chances of a timeout occuring AND the timer being disabled
at the same time are relatively slim and the consequent
possible timer restart could be attributed to race conditions.
However it is relatively inexpensive to do the check - so why not.
*/
if ( myTimer->mode ==0)
{
/* If timer is in free running mode then the timer will continue to
decrement from its maximum value. Mode bit=0
*/
KickOffTimer(ts,myTimer, 0xffff, TRUE); /* Use maximum run time */
}
else
{
/* If timer is in periodic mode then the timer will reload from the load
register and continue to decrement. Mode bit =1
*/
KickOffTimer(ts,myTimer,0, TRUE); /* Use Load value */
}
} /* if timer->enable ==1 */
}
/*
* Return: 1 for failure, 0 for success
*/
static int iCheckIntcIf(TimerState *ts)
{
int endcondition;
if (ts->intcInterface == NULL)
{
/* No we don't have it installed yet.
By the time we have started running code the intc WILL have been
installed if it exists - so we can try again to install it
*/
ts->intcInterface = ARMulif_GetInterruptController(&ts->coredesc);
if (ts->intcInterface == NULL || *ts->intcInterface == NULL)
{
endcondition = RDIError_Reset;
return 1;
}
}
return 0;
}
/*
Function Name: Timer1Timeout.
Parameters: void *handle - This is void * because we are re-using the
armul_Event typedef for pointers to event functions
and this specified that a void* is used instead
of a specific type.
Return: unsigned - always return 0;
Description: This function is registered as the function to call when timer 1
times out.
Notes: Note that we check that the intcInterface has been installed correctly
by MemInit - if it hasn't then we do a late installation.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -