ktimer.c

来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 298 行

C
298
字号
//------------------------------------------------------------------------------
//
//  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.
//  
//------------------------------------------------------------------------------
//
//  Module Name:  
//  
//      ktimer.c
//  
//  Abstract:  
//
//      SH3 kernel timer functions.
//      
//------------------------------------------------------------------------------
#include <windows.h>
#include <nkintr.h>
#include <bldver.h>
#include "sh4.h"
#include "timer.h"
//#include <aspen.h>
#include <platform.h>


extern DWORD InterruptTable[];

DWORD dwReschedIncrement;
DWORD OEMCount1ms;

extern DWORD dwSleepMin;
extern BOOL fIntrTime;

volatile DWORD dwPerfCountHigh;

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void InitClock(void) 
{
    extern void Timer0ISR(void);
    extern void Timer2ISR(void);
    extern BYTE IntrPrio[];

    // Number of timer counts for reschedule interval
    dwReschedIncrement = RESCHED_INCREMENT;

    // Set OEM timer count for 1 ms
    OEMCount1ms = OEM_COUNT_1MS;

    // Set OEM clock frequency
    OEMClockFreq = OEM_CLOCK_FREQ;

//    TMUADDR->tstr &= ~TMU_START0;               // make sure timer0 is stopped
//    TMUADDR->tcr0 = TMUCR_UNIE | TMUCR_D16;     // interrupt enable, divide by 16
//    TMUADDR->tcor0 = dwReschedIncrement;        // set timer constant register
//    TMUADDR->tcnt0 = dwReschedIncrement;        // initialize the counter
//    INTC_PRA = (INTC_PRA&0x0FFF) | 0x1000;      // priority 1 interrupt
	WRITE_REGISTER_UCHAR(TMU_TSTR, READ_REGISTER_UCHAR(TMU_TSTR)&(~TMU_TSTR_STR0));
	WRITE_REGISTER_USHORT(TMU_TCR0, TMU_TCR_UNIE | TMU_TCR_D16);	// interrupt enable, divide by 16
	WRITE_REGISTER_ULONG(TMU_TCOR0, dwReschedIncrement);				// set timer constant register
	WRITE_REGISTER_ULONG(TMU_TCNT0, dwReschedIncrement);				// initialize the counter
	WRITE_REGISTER_USHORT(INTC_IPRA, 
		READ_REGISTER_USHORT(INTC_IPRA)&(INTC_IPRA_TMU0_MASK) | INTC_IPRA_TMU0_INT);	// priority 1 interrupt

    IntrPrio[16] = 1;
    InterruptTable[16] = (DWORD)Timer0ISR;
//    TMUADDR->tstr |= TMU_START0;    // startup timer0
//    TMUADDR->tstr &= ~TMU_START1;   // make sure timer1 is stopped
//    TMUADDR->tcr1 = TMUCR_D4;       // interrupt disable, divide by 4
//    TMUADDR->tcor1 = 0xffffffff;    // set timer constant register
//    TMUADDR->tcnt1 = 0xffffffff;    // initialize the counter
//    TMUADDR->tstr |= TMU_START1;    // startup timer1
	WRITE_REGISTER_UCHAR(TMU_TSTR, READ_REGISTER_UCHAR(TMU_TSTR) | TMU_TSTR_STR0);	// startup timer0
	WRITE_REGISTER_UCHAR(TMU_TSTR, READ_REGISTER_UCHAR(TMU_TSTR) & ~TMU_TSTR_STR1);	// make sure timer1 is stopped
	WRITE_REGISTER_USHORT(TMU_TCR1, TMU_TCR_D4);					// interrupt disable, divide by 4
	WRITE_REGISTER_ULONG(TMU_TCOR1, 0xffffffff);					// set timer constant register
	WRITE_REGISTER_ULONG(TMU_TCNT1, 0xffffffff);					// initialize the counter
	WRITE_REGISTER_UCHAR(TMU_TSTR, READ_REGISTER_UCHAR(TMU_TSTR) | TMU_TSTR_STR1);	// startup timer1
    
    //
    // Use timer 2 for QueryPerformanceCounter (not used)
    //
//    TMUADDR->tstr &= ~TMU_START2;   // make sure timer2 is stopped
//    TMUADDR->tcr2 = TMUCR_D16; // interrupt disable, divide by 16
//    TMUADDR->tcor2 = 0xffffffff;    // set timer constant register
//    TMUADDR->tcnt2 = 0xffffffff;    // initialize the counter
//    INTC_PRA = (INTC_PRA&0xFF0F) | 0x0010;  // priority 1 interrupt
	WRITE_REGISTER_UCHAR(TMU_TSTR, READ_REGISTER_UCHAR(TMU_TSTR) & ~TMU_TSTR_STR2);	// make sure timer2 is stopped
	WRITE_REGISTER_USHORT(TMU_TCR2, TMU_TCR_D16);					// interrupt disable, divide by 4
	WRITE_REGISTER_ULONG(TMU_TCOR2, 0xffffffff);					// set timer constant register
	WRITE_REGISTER_ULONG(TMU_TCNT2, 0xffffffff);					// initialize the counter
	WRITE_REGISTER_USHORT(INTC_IPRA, 
		READ_REGISTER_USHORT(INTC_IPRA)&(INTC_IPRA_TMU2_MASK) | INTC_IPRA_TMU2_INT);	// priority 1 interrupt
    IntrPrio[18] = 1;
    InterruptTable[18] = (DWORD)Timer2ISR;
    //TMUADDR->tstr |= TMU_START2;  // startup timer2
}


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
#pragma optimize("", off)

DWORD
PerfCountSinceTick()
{
    DWORD dwTCR0 = READ_REGISTER_USHORT(TMU_TCR0);//TMUADDR->tcr0;
    DWORD dwReschedTime =READ_REGISTER_ULONG(TMU_TCOR0); //TMUADDR->tcor0;
    DWORD dwCount = READ_REGISTER_ULONG(TMU_TCNT0);//TMUADDR->tcnt0;

    if (dwCount > dwReschedTime) {
        // This is an error case. Recover gracefully.
        DEBUGMSG(1, (L"PerfCountSinceTick( ): Correcting periodic timer read error\r\n"));
        return 0;
    }

    // Note : this is a countdown timer, not count up.
    if (dwTCR0 & TMU_TCR_UNF) {
        // Rollover case with interrupt pending
        return dwReschedTime + (dwReschedTime - dwCount);
    } else {
        return dwReschedTime - dwCount;
    }
}

#pragma optimize("", on)


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
DWORD
PerfCountFreq()
{
    return OEMClockFreq;
}

extern DWORD CurMSec;


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
CPUSetSysTimerCount(
    DWORD dwCountdownMSec
    )
{
    DWORD dwCount = OEMCount1ms * dwCountdownMSec;
//    TMUADDR->tstr &= ~TMU_START0;   // need to halt timer 
//    TMUADDR->tcor0 = dwCount;       // set timer constant register
//    TMUADDR->tcnt0 = dwCount;       // initialize the counter
//    TMUADDR->tstr |= TMU_START0;    // restart timer
	WRITE_REGISTER_UCHAR(TMU_TSTR, READ_REGISTER_UCHAR(TMU_TSTR)&(~TMU_TSTR_STR0));
	WRITE_REGISTER_ULONG(TMU_TCOR0, dwCount);
	WRITE_REGISTER_ULONG(TMU_TCNT0, dwCount);
	WRITE_REGISTER_UCHAR(TMU_TSTR, READ_REGISTER_UCHAR(TMU_TSTR) | TMU_TSTR_STR0);

}


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL
CPUClearSysTimerIRQ(
    void
    )
{
	if (!(READ_REGISTER_USHORT(TMU_TCR0) & TMU_TCR_UNF)) { //    if (!(TMUADDR->tcr0 & TMUCR_UNF)) {
        return FALSE;
    }
            
    // clear out pending interrupts
    do {
		WRITE_REGISTER_USHORT(TMU_TCR0, READ_REGISTER_USHORT(TMU_TCR0) & (~TMU_TCR_UNF));	// TMUADDR->tcr0 &= ~TMUCR_UNF;
    } while (READ_REGISTER_USHORT(TMU_TCR0) & TMU_TCR_UNF);//(TMUADDR->tcr0 & TMUCR_UNF);

    return TRUE;
}


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
#if (CE_MAJOR_VER == 0x0003)
//
// cedar
//
DWORD
CPUGetSysTimerCountElapsed(
    DWORD dwTimerCountdownMSec,
    volatile DWORD *pCurMSec,
    volatile DWORD *pDiffMSec,
    DWORD *pPartialCurMSec,
    DWORD *pPartialDiffMSec,
    volatile ULARGE_INTEGER *pCurTicks
    )
{
    DWORD dwTick = dwTimerCountdownMSec * OEMCount1ms;
    DWORD dwCount, dwTemp;

    // If timer IRQ pending, a full resched period elapsed
    if (CPUClearSysTimerIRQ( )) {
        *pCurMSec += dwTimerCountdownMSec;
        *pDiffMSec += dwTimerCountdownMSec;
        pCurTicks->QuadPart += dwTick;
        return dwTimerCountdownMSec;
    }

    // No timer IRQ pending, calculate how much time has elapsed
    dwCount = READ_REGISTER_ULONG(TMU_TCNT0);//TMUADDR->tcnt0;

    if (dwCount > dwTick) {
        // This is an error case.  Recover gracefully.
        DEBUGMSG(1, (L"CPUGetSysTimerCountElapsed( ): Correcting periodic timer read error\r\n"));
        dwCount = dwTick;
    } else {
        dwCount = dwTick - dwCount;
    }
    
    pCurTicks->QuadPart += dwCount;

    dwTemp = dwCount;
    dwTemp += *pPartialDiffMSec;
    *pPartialDiffMSec = dwTemp % OEMCount1ms;
    *pDiffMSec += dwTemp / OEMCount1ms;

    dwTemp = dwCount;
    dwTemp += *pPartialCurMSec;
    *pPartialCurMSec = dwTemp % OEMCount1ms;
    dwTemp = dwTemp / OEMCount1ms;
    *pCurMSec += dwTemp;

    return dwTemp;
}

#else
//
// dougfir or later
//
DWORD
CPUGetSysTimerCountElapsed(
    DWORD dwTimerCountdownMSec,
    volatile DWORD *pCurMSec,
    DWORD *pPartialCurMSec,
    volatile ULARGE_INTEGER *pCurTicks
    )
{
    DWORD dwTick = dwTimerCountdownMSec * OEMCount1ms;
    DWORD dwCount;

    // If timer IRQ pending, a full resched period elapsed
    if (CPUClearSysTimerIRQ( )) {
        *pCurMSec += dwTimerCountdownMSec;
        pCurTicks->QuadPart += dwTick;
        return dwTimerCountdownMSec;
    }

    // No timer IRQ pending, calculate how much time has elapsed
    dwCount = READ_REGISTER_ULONG(TMU_TCNT0);//TMUADDR->tcnt0;
        
    if (dwCount > dwTick) {
        // This is an error case.  Recover gracefully.
        DEBUGMSG(1, (L"CPUGetSysTimerCountElapsed( ): Correcting periodic timer read error\r\n"));
        dwCount = dwTick;
    } else {
        dwCount = dwTick - dwCount;
    }
        
    pCurTicks->QuadPart += dwCount;

    dwCount += *pPartialCurMSec;
    *pPartialCurMSec = dwCount % OEMCount1ms;
    *pCurMSec += (dwCount /= OEMCount1ms);

    return dwCount;
}
#endif

#define IDLE_MAX_MS 30000
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
DWORD
CPUGetSysTimerCountMax(
    DWORD dwIdleMSecRequested
    )
{
    if (dwIdleMSecRequested > IDLE_MAX_MS) {
        //
        // Our timer isn't capable of idling more than IDLE_MAX_MS milliseconds. 
        // We'll have to break the sleep time into reasonable chunks.
        //
        return IDLE_MAX_MS;
    }

    return dwIdleMSecRequested;
}

⌨️ 快捷键说明

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