📄 vartick.c
字号:
// calculate the tick difference.
nDiffTick = nDiffMSec * ARMCount1MS;
// shift tick if we need to (too close to count register)
nTicksFromCountReg = nDiffTick - (countReg - CurTicks.LowPart);
if ((nShiftTick = OEMMinTickDistance - nTicksFromCountReg) > 0) {
nDiffTick += nShiftTick;
}
// update NextINTMSec
NextINTMSec = nDiffMSec + dwPrev;
// update compare register
pOSTreg->osmr0 = CurTicks.LowPart + nDiffTick;
// Tick shift is not enough if the following debugchk failed. Increase OEMMinTickDistance if this happens.
DEBUGCHK (dwPrev == LastINTMSec);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
int ARMTimerISR (DWORD ra)
{
int nDiffMSec;
int nRetVal;
int nTicks = pOSTreg->oscr - pOSTreg->osmr0;
// fix the case if we're interrupted way too late (should only occur when we're in debugger).
// We just need to line up CurTick with count register here. Yes, we'll 'lose' some time, but
// we've already lost way more during interrupts off.
if (nTicks >= ARMCount1MS) {
CurTicks.QuadPart += nTicks;
}
nDiffMSec = dwReschedTime - NextINTMSec;
nRetVal = SYSINTR_RESCHED;
if (nDiffMSec <= 0) {
// time to reschedule, update next reschedule time to the max we can set
nDiffMSec = nMaxSchedMSec;
} else {
// don't need to reschedule yet (most likely due to timer's limit of setting
// interrupt tick too far away)
if (nDiffMSec > nMaxSchedMSec) {
nDiffMSec = nMaxSchedMSec;
}
nRetVal = SYSINTR_NOP;
}
// update ticks, compare register, and LastINTMSec/NextINTMSec
CurTicks.QuadPart += (NextINTMSec - CurMSec) * ARMCount1MS;
LastINTMSec = NextINTMSec;
NextINTMSec += nDiffMSec;
pOSTreg->osmr0 = CurTicks.LowPart + nDiffMSec * ARMCount1MS;
// clear timer0 interrupts
pOSTreg->ossr = OSSR_M0;
// update LED if any
if (pOEMUpdateTimerLED)
pOEMUpdateTimerLED (LastINTMSec);
return nRetVal;
}
//------------------------------------------------------------------------------
// Initialize system timer. We use match register for timer tick
//------------------------------------------------------------------------------
BOOL ARMInitClock(void)
{
// initialize the timer address
pOSTreg = (PVOST_REGS) OEMOSTBaseAddr;
// derive constants from OEMTimerFreq;
ARMCount1MS = OEMTimerFreq / 1000; // 1 MS
ARMMaxSchedMSec = nMaxSchedMSec = 0x7FFFFFFF / ARMCount1MS; // Max MS representable by 32 integer
NextINTMSec = LastINTMSec + nMaxSchedMSec;
CurTicks.LowPart = pOSTreg->oscr;
pOSTreg->osmr0 = CurTicks.LowPart + nMaxSchedMSec * ARMCount1MS;
idleconv = ARMCount1MS;
pOSTreg->ossr = OSSR_M0; // clear any current interrupt
pOSTreg->oier = OIER_E0; // turn on timer 0 the interrupt
pQueryPerformanceCounter = OEMQueryPerformanceCounter;
pQueryPerformanceFrequency = OEMQueryPerformanceFrequency;
pOEMUpdateRescheduleTime = ARMUpdateReschedTime;
return(TRUE);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
FakedCPUEnterIdle(
DWORD dwIdleParam
)
{
fInterruptFlag = FALSE;
INTERRUPTS_ON();
while (!fInterruptFlag) {
// Just sit here. Any interrupt will bump us out.
}
}
//------------------------------------------------------------------------------
//
// This routine is called by the kernel when there are no threads ready to
// run. The CPU should be put into a reduced power mode and halted. It is
// important to be able to resume execution quickly upon receiving an interrupt.
// Note: It is assumed that interrupts are off when OEMIdle is called. Interrrupts
// are turned off when OEMIdle returns.
//
//------------------------------------------------------------------------------
void
OEMIdle(
DWORD dwIdleParam
)
{
ULARGE_INTEGER prevTicks = CurTicks;
ULARGE_INTEGER currIdle = {
curridlelow,
curridlehigh
};
pCPUEnterIdle (dwIdleParam);
// wake up from Idle, calculate idle time
INTERRUPTS_OFF ();
currIdle.QuadPart += CurTicks.QuadPart - prevTicks.QuadPart + PerfCountSinceTick ();
curridlelow = currIdle.LowPart;
curridlehigh = currIdle.HighPart;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
DWORD SC_GetTickCount(void)
{
DWORD dwPrev = LastINTMSec;
DWORD dwMSec = dwPrev + PerfCountSinceTick () / ARMCount1MS;
// return LastINTMSec if timer interrup occur in the middle of this function
return (dwPrev == LastINTMSec)? dwMSec : LastINTMSec;
}
//------------------------------------------------------------------------------
// profiler/iltiming related funciton
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Start timer 2 (parameter - interrupt interval in micro-seconds)
//------------------------------------------------------------------------------
void ARMStartTimer2 (DWORD dwUSec)
{
if (!dwUSec) {
//
// Use default rate (1 MS)
//
dwUSec = 1000;
} else if (dwUSec < 20) {
//
// Rate specified: at least 20us
//
dwUSec = 20;
}
dwTimer2Ticks = (dwUSec * ARMCount1MS) / 1000;
//
// Init timer2 and enable timer2 interrupt
//
// clear and disable timer2 interrupts
// initialize timer compare register
pOSTreg->osmr2 = pOSTreg->oscr + dwTimer2Ticks;
// enable timer2 interrupts
pOSTreg->ossr = OSSR_M2;
pOSTreg->oier |= OIER_E2;
}
//------------------------------------------------------------------------------
// Stop Timer 2
//------------------------------------------------------------------------------
void ARMStopTimer2 (void)
{
//
// Diable timer2 interrupt
//
pOSTreg->oier &= ~OIER_E2;
}
static volatile DWORD dwCompareReg;
//------------------------------------------------------------------------------
// Timer 2 perf count since tick. Since we don't have to worry about interrupt here
// it's a lot simplier.
//------------------------------------------------------------------------------
DWORD ARMTimer2CountSinceTick (void)
{
return pOSTreg->oscr - dwCompareReg;
}
int ARMTimer2ISR (DWORD ra)
{
extern void ProfilerHit (DWORD ra);
dwCompareReg = pOSTreg->osmr2;
// take care of ilTiming
if (fIntrTime) {
dwIsrTime1 = pOSTreg->oscr - dwCompareReg;
dwSPC = ra;
}
// clear timer2 interrupts
pOSTreg->ossr = OSSR_M2;
// update compare register
pOSTreg->osmr2 += dwTimer2Ticks;
// take care of ilTiming
if (fIntrTime) {
dwIsrTime2 = pOSTreg->oscr - dwCompareReg;
wNumInterrupts = 0;
return SYSINTR_TIMING;
}
// take care of profiler
if (fProfilerRunning) {
ProfilerHit (ra);
}
return SYSINTR_NOP;
}
//------------------------------------------------------------------------------
// disable profiler interrupts
//------------------------------------------------------------------------------
void OEMProfileTimerDisable(void)
{
//
// Stop Timer 2
//
if (fProfilerRunning) {
ARMStopTimer2 ();
fProfilerRunning = FALSE;
RETAILMSG(1, (TEXT("Profiler interrupt stopped\r\n")));
}
}
//------------------------------------------------------------------------------
// start profiler interrupts
//------------------------------------------------------------------------------
void OEMProfileTimerEnable(DWORD dwUSec)
{
if (fIntrTime) {
RETAILMSG(1, (TEXT("Cannot starting Monte Carlo Profiler while iltiming is running\r\n")));
} else if (!fProfilerRunning) {
RETAILMSG(1, (TEXT("Starting profile timer at %d uS rate\r\n"), dwUSec));
fProfilerRunning = TRUE;
ARMStartTimer2 (dwUSec);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -