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 + -
显示快捷键?