📄 timer.c
字号:
The check is prudent for pointers to functions/handles.
The late installation is an alternative to bombing out - this
is really a protection against user who don't read the documentation
and ignore the warnings that intc MUST be the first peripheral
in the peripheral list in armul.cnf. - or for users who have simply
left out the intc from their armul.cnf. These checks could be removed
to slightly improve performace for very timer intensive systems.
*/
static void Timer1Timeout(void *handle)
{
TimerState *ts = (TimerState*)handle;
timer_state *myTimer = &ts->timer1;
#ifdef VERBOSE_TIMEOUT
printf("Timer:1:Timeout.\n");
#endif
myTimer->timedCallback = NULL;
/* Check that we have the intc interface installed */
if (iCheckIntcIf(ts))
{
#ifdef VERBOSE_NOINTC
printf("Timer:1: no interrupt controller available.\n");
#endif
return;
}
{
GenericAccessCallback *cb1 = *ts->intcInterface;
ARMword data = 1;
cb1->func(cb1,myTimer->interruptNumber,&data,ACCESS_WRITE_WORD);
}
/* See if the timer should be restarted - and if so in what mode */
RunTimerAgain( ts, myTimer);
}
/* See TimerTimeout for function comment block */
static void Timer2Timeout(void *handle)
{
TimerState *ts = (TimerState*)handle;
timer_state *myTimer = &ts->timer2;
#ifdef VERBOSE_TIMEOUT
printf("Timer:2:Timeout.\n");
#endif
myTimer->timedCallback = NULL;
/* Check that we have the intc interface installed */
if (iCheckIntcIf(ts))
{
#ifdef VERBOSE_NOINTC
printf("Timer:2: no interrupt controller available.\n");
#endif
return;
}
{
GenericAccessCallback *cb1 = *ts->intcInterface;
ARMword data = 1;
cb1->func(cb1,myTimer->interruptNumber,&data,ACCESS_WRITE_WORD);
}
RunTimerAgain( ts, myTimer);
}
/*
Function Name: DivisorValue
Parameters: ARMul_State *state - the original ARMul_State
int prescale - the prescale bits from intc->control shifted right 2 places
Return: int - the Clock Divisor value represented by the prescale bits passed in.
these will be one of 1, 16, 256 or controversially 65536.
The 65536 value is returned for the undefined result bits 2..3 == 11
Description: See Return description.
*/
static int DivisorValue(TimerState *state, int prescale)
{
int ClockDivisor;
switch(prescale)
{
case 0: ClockDivisor = 1;
break;
case 1: ClockDivisor = 16;
break;
case 2: ClockDivisor = 256;
break;
default: Hostif_ConsolePrint(state->hostif,"TIC Divisor value (%d) "
"has undefined behaviour - (using 65536)\n",prescale);
ClockDivisor = 65536;
break;
}
return ClockDivisor;
}
static ARMTime getNow(TimerState *ts)
{
/* use BCLK */
/* ARMulif_BusTime(&ts->coredesc); */
#ifdef VERBOSE_GETNOW
printf("getNow->0x%08x=%u bus:%p BU:%p\n",
(unsigned)ts->my_bpar.bus->bus_BusyUntil,
(unsigned)ts->my_bpar.bus->bus_BusyUntil,
ts->my_bpar.bus, &ts->my_bpar.bus->bus_BusyUntil);
#endif
return ts->my_bpar.bus->bus_BusyUntil;
}
/*
Function Name: KickOffTimer
Parameters: TimerState *ts - the TimerState pointer
timer_state *myTimer - the timer_state pointer
unsigned long alternateLoadValue - if not 0 then this is the value to use for reload.
Return: void
Description: This function is called to start/restart a timer.
It calculates how long from now the timer would timeout
for the supplied values of load, prescale. An event is
scheduled for the 'timer timerout' time. The function
to be called at timeout time is from the timer_state
structure.
Notes: In normal use the parameter alternateLoadValue should be zero.
When this is zero the timer's own load register is used to
calculate the timer delay. However if you need to restart the
timer with a different load value then you may supply an
alternate load value. An example of the usage of this is for
free running timer restarts where the load value is 0xFFFF
for restart.
*/
static void KickOffTimer(TimerState *ts, timer_state *myTimer,
unsigned long alternateLoadValue,
bool bRepeating)
{
unsigned long delay;
int ClockDivisor;
unsigned long loadValue;
ARMTime Now;
if ( myTimer->enabled ==0 )
{
/* timer disabled - user probably wrote to load value before
* timer was enabled
*/
return;
}
Now = getNow(ts);
/* Select the loadValue to use - either the reload value or a supplied
value ( if it is non zero )
*/
/* Make sure it isn't bigger than the allowable 16 bits */
alternateLoadValue &= 0xFFFF;
loadValue = alternateLoadValue ? alternateLoadValue : myTimer->TimerLoad;
/* Calculate the delay */
ClockDivisor = DivisorValue(ts, myTimer->prescale);
delay = (ClockDivisor * loadValue);
/*
* Correct for the difference between now and when we expected to
* be called.
*/
if (myTimer->nextEventTime != 0)
{
int delta = (int)(Now - myTimer->nextEventTime);
assert(delta >=0);
if (delta > 0 && delay > (unsigned long)delta)
{
delay -= delta;
}
}
if (bRepeating)
delay += ClockDivisor; /* Period = 1 + reload-value. */
delay = delay ? delay : 1; /* forbid 0 delays */
/* Now submit the event and record the time at which it occurs
for removal purposes */
myTimer->nextEventTime = Now + delay;
myTimer->timedCallback = ARMulif_ScheduleTimedCallback(
&ts->coredesc, myTimer->fn, ts, myTimer->nextEventTime,
ARMulCallbackID_ScheduleFunctionEvery /*BCLK */,
0 /* absolute, UPDATE-time-only.. */
);
/* handle, ARMTime when, ARMTime period) */
assert(myTimer->timedCallback != NULL);
#ifdef VERBOSE_KICKOFF
myTimer->dbgIndex++;
printf("KickOffTimer:%u:[%u] when:%lu t=%lu delay=%lu\n",
myTimer->TimerNumber,myTimer->dbgIndex,
(unsigned long)myTimer->nextEventTime,
(unsigned long)Now, delay);
#endif
}
/*
Function Name: ValueRegRead
Parameters: TimerState *ts
timer_state *myTimer
Return: ARMword - the number of timer counts remaining until timeout.
Description: Work out the numer of counts remaining - this is for
value register reads
*/
static ARMword ValueRegRead(TimerState *ts, timer_state *myTimer )
{
int ClockDivisor;
ARMTime now, diff;
now = getNow(ts);
ClockDivisor = DivisorValue(ts, myTimer->prescale);
/* Difference between the time the event is scheduled and current time */
diff = myTimer->nextEventTime - now;
/*
Return the 'counts' remaining
*/
return (ARMword)(diff / ClockDivisor);
}
/*
Function Name: PrescaleValueChanged
Parameters: TimerState *ts
timer_state *myTimer
Return: void
Description: When the timer is active and the prescale value is changed
we have a problem. For the real hardware the prescaled just starts
dividing at a different rate and the timeout will happen at the
correct time. Because we don't actually count the clocks, instead
we calculate the timeout time when the imter is started, we have
to retract the first event and work out what the *NEW* timeout
time will be. Luckily it is only the prescale value that causes
this problem - the load register is only read when the timer restarts,
the mode bit is read at timeout only.
*/
static void PrescaleValueChanged(TimerState *ts, timer_state *myTimer)
{
ARMword remaining;
/* OH - the prescale has changed
we have to do the following;
1. Retract the scheduled timeout event.
2. Work out what the 16 bit down counter value
actually was
3. Recalculate the timeout time and re-schedule
*/
if (myTimer->timedCallback != NULL)
ARMulif_DescheduleTimedCallback(&ts->coredesc, myTimer->timedCallback,
ARMulCallbackID_ScheduleFunctionEvery/*BCLK*/);
myTimer->timedCallback = NULL;
myTimer->nextEventTime = 0;
remaining = ValueRegRead(ts, myTimer);
KickOffTimer(ts,myTimer, remaining, FALSE);
}
/*
Function Name: TimerClearInterrupt
Paremeters: TimerState *ts
timer_state *myTimer
Return: void
Description: Clears the interrupt source
*/
static void TimerClearInterrupt(TimerState *ts, timer_state *myTimer)
{
/* Check that we have the intc interface installed */
if (! iCheckIntcIf(ts))
{
/* Now tell the interrupt controller that our
* interrupt source has cleared */
{
GenericAccessCallback *cb1 = *ts->intcInterface;
ARMword data = 0; /* Signal_Off */
cb1->func(cb1,myTimer->interruptNumber,&data,ACCESS_WRITE_WORD);
}
}
}
/*
Function Name: TICControlRegisterWrite
Parameters: TimerState *ts,
timer_state *myTimer,
ARMword *word pointer to data to use for write.
Return: int - always return 0
Description: Breakout function for TICRegisterAccess - the final address decoder - to
keep the complexity of one function down a little to keep it readable - this
is hand generated not auto-generated code.
This function performs the processing for a write to the timer counter control
registers. It updates the mirror struct members such as enabled/prescale.
It processes changes to enable and prescale.
*/
static int TICControlRegisterWrite(TimerState *ts, timer_state *myTimer, ARMword *word)
{
/* Update the internal representation first */
myTimer->TimerControlChangeMask = (myTimer->TimerControl) ^ (*word) ;
myTimer->TimerControl = *word ;
myTimer->enabled = (*word >> 7) & 0x1;
myTimer->mode = (*word >> 6) & 0x1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -