timer.c
来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 704 行 · 第 1/2 页
C
704 行
//------------------------------------------------------------------------------
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved.
//
//------------------------------------------------------------------------------
#include <windows.h>
#include <nkintr.h>
#include <bldver.h>
#include <pc.h>
#include "timer.h"
int __cdecl _inp(unsigned short);
int __cdecl _outp(unsigned short, int);
UCHAR __inline READ_PORT_UCHAR(PUCHAR port)
{
return _inp((USHORT)port);
}
VOID __inline WRITE_PORT_UCHAR(PUCHAR port, UCHAR value)
{
_outp((USHORT)port, (value));
}
UCHAR PICGetCurrentInterrupt();
extern volatile DWORD CurMSec;
#if (CE_MAJOR_VER == 0x0003)
// cedar
extern volatile DWORD DiffMSec;
static volatile DWORD * pCurMSec = &CurMSec;
static volatile DWORD * pDiffMSec = &DiffMSec;
extern DWORD dwSleepMin;
extern DWORD dwPartialDiffMSec;
extern DWORD ticksleft;
#else
// dougfir or later
extern DWORD dwReschedTime;
static DWORD dwPartialCurMSec = 0; // Keep CPU-specific sub-millisecond leftover.
#endif
volatile ULARGE_INTEGER CurTicks = { 0, 0 };
volatile ULARGE_INTEGER *pCurTicks = &CurTicks;
static volatile DWORD dwReschedPeriod;
extern BOOL fIntrTime;
extern BOOL bProfileTimerRunning;
//
// Kernel global variables used by GetIdleTime() to determine CPU utilization.
//
extern DWORD idleconv; // translation constant in 1 ms units.
extern DWORD curridlehigh, curridlelow; // 64-bit idle time in ms
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
InitClock(void)
{
BYTE cData;
//
// Set up translation constant for GetIdleTime() (1 ms units).
// Note: Since curridlehigh, curridlelow is counting in ms, and GetIdleTime( )
// reports in ms, the conversion ratio is one. If curridlehigh, curridlelow
// were using other units (like ticks), then the conversion would be calculated
// from the clock frequency.
//
idleconv = 1;
//
// Setup Timer0 to fire every TICK_RATE mS and generate interrupt
//
__asm {
// configure counter for correct mode
mov al, 00110100b ; counter 0, 16-bit, mode 2, binary
out 043h, al
jmp short $+2
// load the timer with correct count value
mov ax, TIMER_COUNT ; Divisor for SYSTEM TICK
out 040h, al
jmp short $+2
mov al,ah
out 040h, al
}
PICEnableInterrupt(INTR_TIMER0, TRUE);
dwReschedPeriod = TIMER_COUNT;
//
// Set up Timer2 to use its full range for kcall profiling
//
__asm {
// configure counter for correct mode
mov al, 10110100b ; counter 2, 16-bit, mode 2, binary
out 043h, al
jmp short $+2
// Start counter at highest value, it's a countdown.
// It's confusing, but 0 is largest initial value. Read the manual.
xor eax, eax ; 0x00
out 042h, al
jmp short $+2
out 042h, al
// Enable bit 0 of Port B to start counter2 counting
in al, 61h ;Read Current value of Port B
or al, 00000001b ;Set bit 0 to enable gate
out 61h, al ;Store new value to Port B
}
do {
cData = CMOS_Read( RTC_STATUS_A);
} while ( cData & RTC_SRA_UIP );
cData = CMOS_Read( RTC_STATUS_B );
CMOS_Write( RTC_STATUS_B, (BYTE)(cData|RTC_SRB_24HR) );
cData = CMOS_Read( (BYTE)(RTC_STATUS_B) );
RETAILMSG(1, (TEXT("RTC - Status Reg B - 0x%2.2X\r\n"), cData));
PICEnableInterrupt(INTR_RTC, TRUE);
}
//------------------------------------------------------------------------------
//
// For the KCALL Profiling timers, I chose timer2 of the PIT. Timer0 could
// have been used, but it is wrapping once every system tick. By using
// timer2, the frequency of the wrap is reduced to every 54918 uS
// The clock frequency is 1.19318 Mhz, or .838 uS granularity.
//
//------------------------------------------------------------------------------
DWORD
KCP_ScaleDown(
DWORD N
)
{
extern DWORD OEMClockFreq;
return (N*1000 + (TIMER_FREQ/2000)) / (TIMER_FREQ/1000);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
DWORD
KCP_GetStartTime()
{
WORD wTimer;
__asm {
cli
// read timer2
mov al, 10000000b; Latch Counter 2
out 043h, al
jmp short $+2
in al, 042h ; Get LSB
mov ah, al
jmp short $+2
in al, 042h ; Get MSB
xchg ah, al ; Get them in the right order
mov wTimer, ax
sti
}
return wTimer;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
DWORD
KCP_GetElapsedTime(
DWORD dwPrev
)
{
WORD wTimer;
__asm {
cli
; read timer2
mov al, 10000000b; Latch Counter 2
out 043h, al
jmp short $+2
in al, 042h ; Get LSB
mov ah, al
jmp short $+2
in al, 042h ; Get MSB
xchg ah, al ; Get them in the right order
mov wTimer, ax
sti
}
if( wTimer > dwPrev )
{
// If the numbers are reversed, assume we just rolled over
return ( 0xFFFF - (wTimer-dwPrev) );
}
else
{
return ( dwPrev - wTimer );
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
DWORD
PerfCountFreq()
{
return TIMER_FREQ;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
DWORD
PerfCountSinceTick(void)
{
WORD wCurCount;
UCHAR ucInterrupt;
__asm {
TRY_LATCHING_AGAIN:
pushfd ; Save interrupt state
cli
in al,20h ; get current interrupt state bits
mov ucInterrupt, al
in al,40h ; clear latches, in case they are loaded
in al,40h ;
mov al,11000010b ;latch status and count of counter 0
out 43h,al
in al,40h ; read status
shl eax, 16 ; move into high side of eax
in al,40h ; read counter 0 lsb
mov ah,al
in al,40h ; read msb
xchg ah, al ; Get them in the right order
mov wCurCount, ax
shr eax, 16 ; get the status back into al
popfd ; Restore interrupt state
test al, 40h ; did the latch operation fail?
jne TRY_LATCHING_AGAIN ; if so, just do it again
}
//
// Note : this is a countdown timer, not count up.
//
if (ucInterrupt & (1 << INTR_TIMER0)) {
return dwReschedPeriod + (dwReschedPeriod - wCurCount);
} else {
return dwReschedPeriod - wCurCount;
}
}
//------------------------------------------------------------------------------
//
// OEMQueryPerformanceCounter
//
// The OEMQueryPerformanceCounter function retrieves the current value of
// the high-resolution performance counter, if one exists.
//
// BOOL QueryPerformanceCounter(
//
// LARGE_INTEGER *lpliPerformanceCount // address of current counter value
// );
//
// Parameters
//
// lpliPerformanceCount
//
// Points to a variable that the function sets, in counts, to the current
// performance-counter value. If the installed hardware does not support
// a high-resolution performance counter, this parameter can be to zero.
//
// Return Value
//
// If the installed hardware supports a high-resolution performance
// counter, the return value is TRUE.
// If the installed hardware does not support a high-resolution
// performance counter, the return value is FALSE.
//
// If this function is implemented by the OEM, the pointer pQueryPerformanceCounter
// should be initialized as follows:
//
// BOOL (*pQueryPerformanceCounter)(LARGE_INTEGER *lpliPerformanceCount)=OEMQueryPerformanceCounter;
//
//------------------------------------------------------------------------------
BOOL
OEMQueryPerformanceCounter(
LARGE_INTEGER *lpliPerformanceCount
)
{
ULARGE_INTEGER liBase;
DWORD dwCurCount;
// Make sure CurTicks is the same before and after read of counter to account for
// possible rollover
do {
liBase = CurTicks;
dwCurCount = PerfCountSinceTick( );
} while (liBase.LowPart != CurTicks.LowPart);
lpliPerformanceCount->QuadPart = liBase.QuadPart + dwCurCount;
return TRUE;
}
//------------------------------------------------------------------------------
//
// OEMQueryPerformanceFrequency
//
// The OEMQueryPerformanceFrequency function retrieves the frequency of
// the high-resolution performance counter, if one exists.
//
// BOOL OEMQueryPerformanceFrequency(
//
// LARGE_INTEGER *lpliPerformanceFreq // address of current frequency
// );
//
// Parameters
//
// lpliPerformanceFreq
//
// Points to a variable that the function sets, in counts per second, to
// the current performance-counter frequency. If the installed hardware
// does not support a high-resolution performance counter, this parameter
// can be to zero.
//
// Return Value
//
// If the installed hardware supports a high-resolution performance
// counter, the return value is TRUE.
// If the installed hardware does not support a high-resolution
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?