📄 timer.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//------------------------------------------------------------------------------
//
// File: timer.c
//
// This file contains timer module functions implementation. The code is
// using coprocessor 0 count/compare counter. It can be used for most
// MIPS based CPU/SoC. Note that some hardware implementation doesn't update
// CP0 counter when it is moved to idle mode. If this is a case this
// implementation can't be used for such hardware.
//
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <oal.h>
#include <oal_intr_mips.h>
//------------------------------------------------------------------------------
//
// External: g_oalLastSysIntr
//
// This global variable should be set by interrupt handler to last SYSINTR
// when interrupt occurs. It is used by fake (busy loop) idle/power off OAL
// implementations.
//
#ifdef OAL_FAKE_IDLE
extern volatile UINT32 g_oalLastSysIntr;
#endif
//------------------------------------------------------------------------------
//
// External: g_oalRTCTicks/g_oalRTCAlarm
//
// This global variables are used when RTC is implemented by timer interrupt.
// The g_oalRTCTicks is incremented in each timer interrupt (RTC implementation
// doesn't uses CurMSec to avoid rollover in approx 47 days). If g_aolRTCAlarm
// is nonzero it is decremented on each timer interrupt. When it reaches zero
// SYSINTR_RTC_ALARM is returned (instead SYSINTR_RESCHED, but reschedule
// is done in all cases when timer interrupt returns value different from
// SYSINTR_NOP).
//
#ifdef OAL_TIMER_RTC
extern UINT64 *g_pOALRTCTicks;
extern UINT64 g_oalRTCTicks;
extern UINT64 g_oalRTCAlarm;
#endif
//------------------------------------------------------------------------------
//
// Function: OALTimerInit
//
// Initialize timer oriented constants and start system timer. Usually system
// timer triggers each 1 ms but it can be changed if required to optimize
// platform and set beat period to multiple of ms.
//
BOOL OALTimerInit(
UINT32 sysTickMSec, UINT32 countsPerMSec, UINT32 countsMargin
) {
BOOL rc = FALSE;
OALMSG(OAL_TIMER&&OAL_FUNC, (
L"+OALTimerInit(%d, %d, %d)\r\n", sysTickMSec, countsPerMSec,
countsMargin
));
// MIPS counter has 32 bits, but we need to avoid too long periods
g_oalTimer.maxPeriodMSec = 0x3FFFFFFF/countsPerMSec;
// System tick period must be smaller than counter maximal period.
// This reduction will be usual when variable tick is used.
if (sysTickMSec > g_oalTimer.maxPeriodMSec) {
sysTickMSec = g_oalTimer.maxPeriodMSec;
}
// Initialize timer state structure
g_oalTimer.countsPerMSec = countsPerMSec;
g_oalTimer.countsMargin = countsMargin;
g_oalTimer.msecPerSysTick = sysTickMSec;
g_oalTimer.countsPerSysTick = g_oalTimer.countsPerMSec * sysTickMSec;
g_oalTimer.actualMSecPerSysTick = g_oalTimer.msecPerSysTick;
g_oalTimer.actualCountsPerSysTick = g_oalTimer.countsPerSysTick;
// Set idle conversion constant and counters
idleconv = countsPerMSec;
curridlehigh = curridlelow = 0;
g_oalTimer.curCounts = 0;
// Initialize high resolution timer function pointers
pQueryPerformanceFrequency = OALTimerQueryPerformanceFrequency;
pQueryPerformanceCounter = OALTimerQueryPerformanceCounter;
#ifdef OAL_TIMER_RTC
// Get counter from arguments (depends on platform)
g_pOALRTCTicks = OALArgsQuery(OAL_ARGS_QUERY_RTC);
// If platform hasn't such location use internal one
if (g_pOALRTCTicks == NULL) g_pOALRTCTicks = &g_oalRTCTicks;
// Clear alarm
g_oalRTCAlarm = 0;
#endif
// Hook timer ISR
if (!HookInterrupt(5, OALTimerIntrHandler)) {
OALMSG(OAL_ERROR, (
L"ERROR: OALTimerInit: HookInterrupt for MIPS interrupt 5 failed\r\n"
));
goto cleanUp;
}
// Initialize counter/compare registers
OALTimerInitCount(g_oalTimer.countsPerSysTick);
// We are ok
rc = TRUE;
cleanUp:
OALMSG(OAL_TIMER&&OAL_FUNC, (L"-OALTimerInit(rc = %d)\r\n", rc));
return rc;
}
//------------------------------------------------------------------------------
//
// Function: OALTimerIntrHandler
//
// This function implements timer interrupt handler. The implementation
// can be compiled to support interrupt latency timing, real time clock
// based on system interrupt and fake idle wakeup.
//
UINT32 OALTimerIntrHandler()
{
UINT32 sysIntr;
UINT32 delta, msecPeriod, countsPeriod;
#ifdef OAL_ILTIMING
if (g_oalILT.active) {
g_oalILT.counter--;
if (g_oalILT.counter == 0) {
g_oalILT.interrupts = 0;
g_oalILT.isrTime1 = OALTimerCountsSinceSysTick();
g_oalILT.isrTime1 -= g_oalTimer.actualCountsPerSysTick;
}
}
#endif
// Update the millisecond and high resolution counters
CurMSec += g_oalTimer.actualMSecPerSysTick;
g_oalTimer.curCounts += g_oalTimer.actualCountsPerSysTick;
// Reschedule?
delta = dwReschedTime - CurMSec;
if ((INT32)delta <= 0) {
// We have to reschedule
sysIntr = SYSINTR_RESCHED;
msecPeriod = g_oalTimer.msecPerSysTick;
countsPeriod = g_oalTimer.countsPerSysTick;
} else {
// No reschedule
sysIntr = SYSINTR_NOP;
// Is next tick longer than maximal tick period?
if (delta >= g_oalTimer.msecPerSysTick) {
// Yes, do maximal tick
msecPeriod = g_oalTimer.msecPerSysTick;
countsPeriod = g_oalTimer.countsPerSysTick;
} else {
// No, next tick must be shorter to catch planned reschedule
msecPeriod = delta;
countsPeriod = delta * g_oalTimer.countsPerMSec;
}
}
#ifdef OAL_TIMER_RTC
// Update RTC global variable
*g_pOALRTCTicks += g_oalTimer.actualMSecPerSysTick;
// When RTC alarm is active check if it has to be fired
if (g_oalRTCAlarm > 0) {
if (g_oalRTCAlarm > g_oalTimer.actualMSecPerSysTick) {
g_oalRTCAlarm -= g_oalTimer.actualMSecPerSysTick;
} else {
g_oalRTCAlarm = 0;
sysIntr = SYSINTR_RTC_ALARM;
}
}
#endif
// Reload actual period values and recharge timer to start new period
g_oalTimer.actualMSecPerSysTick = msecPeriod;
g_oalTimer.actualCountsPerSysTick = countsPeriod;
OALTimerRecharge(countsPeriod, g_oalTimer.countsMargin);
#ifdef OAL_FAKE_IDLE
// Set flag for fake wake/idle
if (sysIntr != SYSINTR_NOP) g_oalLastSysIntr = sysIntr;
#endif
#ifdef OAL_ILTIMING
#ifdef OAL_FAKE_IDLE
// When ILT is active we must set g_oalLastSysIntr to non - SYSINTR_NOP
if (g_oalILT.active && sysIntr == SYSINTR_NOP) {
g_oalLastSysIntr = SYSINTR_TIMING;
}
#endif
if (g_oalILT.active && g_oalILT.counter == 0) {
sysIntr = SYSINTR_TIMING;
g_oalILT.counter = g_oalILT.counterSet;
g_oalILT.isrTime2 = OALTimerCountsSinceSysTick();
}
#endif
// Return
return sysIntr;
}
//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -