⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 timer.c

📁 Windows CE 6.0 BSP for VOIPAC Board (PXA270) Version 2b.
💻 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.
//
//------------------------------------------------------------------------------
//
//  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.
//  
//------------------------------------------------------------------------------
#include <windows.h>
#include <pc.h>
#include <nkintr.h>
#include <timer.h>


extern volatile DWORD CurMSec;
extern DWORD dwReschedTime;

DWORD  g_dwOALTimerCount;

static DWORD  dwOALTicksPerMs;

volatile ULARGE_INTEGER CurTicks = { 0, 0 };
//
// 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

//
// Profiling
//
DWORD dwReschedCount;
extern DWORD GetEPC(void);
extern int (*PProfileInterrupt)(void);  // pointer to profiler ISR, 
extern void ProfilerHit(DWORD);
DWORD dwProfilingMultiple;



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
SetTimer0(
    WORD wVal
    )
{
    __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, wVal
        out     040h, al
        jmp     short $+2
        mov     al,ah
        out     040h, al
    }
}



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
int 
ProfileInterrupt(void) 
{
    ProfilerHit(GetEPC());
    dwReschedCount++;
    
    if (dwReschedCount < dwProfilingMultiple)
        return SYSINTR_NOP;

    dwReschedCount=0;
    return SYSINTR_RESCHED;
}



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void 
OEMProfileTimerEnable(
    DWORD dwUSec
    )
{
    DWORD dwUSecAdjusted;

    if (dwUSec) {
        //
        // Rate specified (limit boundary)
        //
        if (dwUSec < 50) {
            dwUSec = 50;
        }
        if (dwUSec > 1000) {
            dwUSec = 1000;
        }
    } else {
        //
        // Use default rate (100 uS)
        //
        dwUSec = 100;
    }
    //
    // We can only program the timer such that 1ms is a direct multiple
    //
    dwProfilingMultiple = 1000 * g_dwBSPMsPerIntr / dwUSec;
    dwUSecAdjusted = 1000 * g_dwBSPMsPerIntr / dwProfilingMultiple;

    RETAILMSG(1, (TEXT("Starting profile timer at %d uS rate\r\n"), dwUSecAdjusted));

    dwReschedCount = 0;
    PProfileInterrupt = ProfileInterrupt;
    
    SetTimer0((WORD) (g_dwOALTimerCount / dwProfilingMultiple));
    
    PICEnableInterrupt(INTR_TIMER0, TRUE);
}



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void 
OEMProfileTimerDisable(void) 
{
    PProfileInterrupt = NULL;
    SetTimer0 ((WORD) g_dwOALTimerCount);
    PICEnableInterrupt(INTR_TIMER0, TRUE);
}

extern BOOL x86InitPerfCounter (void);

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
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;

    x86InitPerfCounter ();
    
    //
    // Setup Timer0 to fire every TICK_RATE mS and generate interrupt
    //
    g_dwOALTimerCount = (g_dwBSPMsPerIntr * TIMER_FREQ) / 1000;
    dwOALTicksPerMs   = TIMER_FREQ / 1000;
    
    SetTimer0 ((WORD) g_dwOALTimerCount);
    PICEnableInterrupt(INTR_TIMER0, TRUE);

    //
    // 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);
}



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
CPUEnterIdle(
    DWORD dwIdleParam
    )
{
    _asm {
        sti
        hlt
    }
}


//------------------------------------------------------------------------------
//
//  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.
//
// In general the PIT (8254) does not support immediate reprogramming of the counter
// (the 8254 waits until the current countdown cycle is finished before reloading the
// counter with the new value) so OEMIdle never re-program the counter.  If this
// OAL is being adapted to a system with a reprogrammable countdown timer or a
// free running counter with compare registers, see other platforms for example
//------------------------------------------------------------------------------
void
OEMIdle(
    DWORD dwIdleParam
    )
{
    DWORD dwIdleMs = dwReschedTime - CurMSec;

    if ((int) dwIdleMs > 0) {

        // Use for 64-bit math
        ULARGE_INTEGER currIdle = {
            curridlelow,
            curridlehigh
        };
        DWORD dwPrevMSec = CurMSec;

        // max idle time is the system tick
        if (dwIdleMs > g_dwBSPMsPerIntr)
            dwIdleMs = g_dwBSPMsPerIntr;

        // enter idle
        CPUEnterIdle (dwIdleParam);

        INTERRUPTS_OFF ();

        if (dwPrevMSec != CurMSec) 
        {
            // waked up by timer interrupt, update global idle time
            currIdle.QuadPart += dwIdleMs;
            curridlelow = currIdle.LowPart;
            curridlehigh = currIdle.HighPart;
        }
        
    }
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
DWORD SC_GetTickCount(void) 
{
    return CurMSec;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -