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

📄 vartick.c

📁 WinCE5.0BSP for Renesas SH7770
💻 C
📖 第 1 页 / 共 2 页
字号:
//
//  Copyright(C) Renesas Technology Corp. 2004-2005. All rights reserved.
//
//  NK Kernel for ITS-DS7 Ver.0.8.0
//
//  FILE      : vartick.c
//  CREATED   : 2004.09.01
//  MODIFIED  : 2004.10.12
//  AUTHOR    : Renesas Technology Corp.
//  HARDWARE  : RENESAS ITS-DS7
//  HISTORY   : 
//              2004.09.01
//              - Created release code.
//                (based on ASPEN for WCE5.0)
//              2004.10.12
//              - Modified ISR of Timer2 (SHxTimer2ISRWrapped)
//

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

Module Name:

   vartick.c

Abstract:

   This module implements the code necessary to handle SHx tiemr interrupt and
   Kernel interface routines.

Notes:


--*/

#include <windows.h>
#include <nkintr.h>
#include <pkfuncs.h>
#include <shxtimer.h>

#include "sh7770.h"
#include "platform.h"
#include "drv_glob.h"

PTMU_COMREG pTmuComReg;
PTMU_CLOCK_REG pTmuTimer0, pTmuTimer1, pTmuTimer2;

//
// Implementation of variable tick scheduling for CPUs with count down timer. 
// NOTE: we must be able to update the counter of the count down timer on the fly for this to work
//       (i.e. will not work on x86 PIT since update can only be applied to the reload register, not
//             the counter register)
// The algorithm we use here:
//  (1) the constant register, which will be auto-reload on interrupt into counter register, is always set 
//      to the maximun possible value.
//  (2) counter register will be on be updated in two places
//      a. SetReschedTime
//      b. TimerISR when SYSINTR_NOP is returned (scheduler wants to set the interrupt further away than
//         the hardware limit), or tick is shifted.
//      
//

// OEM constants
extern const DWORD OEMTimerFreq;		// timer frequency
extern const int OEMMinTickDistance;	// minimum distance between compare and count register while updating compare register
extern const DWORD OEMTimerBaseAddr;    // base of the TMU register

void (* pOEMUpdateTimerLED) (DWORD dwMSec);
void (* pOEMUpdateProfLED) (DWORD dwSPC);

// NK variables
extern  DWORD volatile CurMSec, dwReschedTime;

// constants derived from OEMTimerFreq
DWORD SHxMaxTicks;                      // max value set to counter register
int SHxCount1MS;						// # of tick per MS

// variables
int nMaxSchedMSec;						// this can be dynamically change when profiler/iltiming is running

//
// Kernel global variables used by GetIdleTime( ) to determine CPU utilization
//
extern DWORD curridlehigh, curridlelow, idleconv;

//
// set pointers to OEM functions
extern BOOL (*pQueryPerformanceCounter)(LARGE_INTEGER *lpliPerformanceCount);
extern BOOL (*pQueryPerformanceFrequency)(LARGE_INTEGER *lpliPerformanceFreq);


volatile ULARGE_INTEGER CurTicks;
volatile ULARGE_INTEGER * pCurTicks = &CurTicks;

#define	LastINTMSec			CurMSec

extern void (*pOEMUpdateRescheduleTime) (DWORD dwTime);

volatile DWORD NextINTMSec;
volatile DWORD dwCounterBase;
volatile DWORD shifted_tick;

DWORD PerfCountSinceTick (void);

// BSP specific function
extern void SHxEnterIdle (DWORD dwIdleParam);
void (* pCPUEnterIdle) (DWORD dwIdleParam) = SHxEnterIdle;

// iltiming and profiler related variable
volatile BOOL fIntrTime, fProfilerRunning;
extern DWORD dwIsrTime1;
extern DWORD dwIsrTime2;
extern DWORD dwSPC;
extern WORD  wNumInterrupts;

#pragma optimize("", off)
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
DWORD PerfCountFreq (void)
{
	return OEMTimerFreq;
}

//------------------------------------------------------------------------------
//
//  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 
//      performance counter, the return value is FALSE.
//  
//  If this function is implemented by the OEM, the pointer pQueryPerformanceFrequency
//  should be initialized as follows:
//  
//  BOOL (*pQueryPerformanceFrequency)(LARGE_INTEGER *lpPerformanceFrequency)=OEMQueryPerformanceFrequency;
//
//------------------------------------------------------------------------------
BOOL 
OEMQueryPerformanceFrequency(
    LARGE_INTEGER *lpliPerformanceFreq
    ) 
{
    extern DWORD PerfCountFreq();
    
    lpliPerformanceFreq->HighPart = 0;
    lpliPerformanceFreq->LowPart  = OEMTimerFreq;
    return TRUE;
}


//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
void SHxIncrCounterRegister (int nTicks)
{
#if (SH7770_REVISION == SH7770_1STCUT)
	UCHAR	*tstr;
#endif

    // stop timer-0 count down
#if (SH7770_REVISION == SH7770_1STCUT)
	tstr = (UCHAR *)DRV_GLOBAL_BASE + TSTR0_GLOBAL_OFFSET;
	*tstr &= ~TMU0_ENABLE;
    pTmuComReg->tstr0 = *tstr;
#else
    pTmuComReg->tstr0 &= ~TMU0_ENABLE;
#endif

    // increment counter
    pTmuTimer0->tcnt += nTicks;

    // restart timer-0
#if (SH7770_REVISION == SH7770_1STCUT)
	tstr = (UCHAR *)DRV_GLOBAL_BASE + TSTR0_GLOBAL_OFFSET;
	*tstr |= TMU0_ENABLE;
    pTmuComReg->tstr0 = *tstr;
#else
    pTmuComReg->tstr0 |= TMU0_ENABLE;
#endif
}

void SHxSetCounterRegister (int nTicks)
{
#if (SH7770_REVISION == SH7770_1STCUT)
	UCHAR	*tstr;
#endif

    // stop timer-0 count down
#if (SH7770_REVISION == SH7770_1STCUT)
	tstr = (UCHAR *)DRV_GLOBAL_BASE + TSTR0_GLOBAL_OFFSET;
	*tstr &= ~TMU0_ENABLE;
    pTmuComReg->tstr0 = *tstr;
#else
    pTmuComReg->tstr0 &= ~TMU0_ENABLE;
#endif

    // update counter
    pTmuTimer0->tcnt = nTicks;

    // restart timer-0
#if (SH7770_REVISION == SH7770_1STCUT)
	tstr = (UCHAR *)DRV_GLOBAL_BASE + TSTR0_GLOBAL_OFFSET;
	*tstr |= TMU0_ENABLE;
    pTmuComReg->tstr0 = *tstr;
#else
    pTmuComReg->tstr0 |= TMU0_ENABLE;
#endif
}

//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
void SHxInitTimer (int nTicks)
{
#if (SH7770_REVISION == SH7770_1STCUT)
	UCHAR	*tstr;
#endif
    DEBUGMSG(1, (TEXT("+SHxInitTimer\r\n")));

    // stop all timers count down
#if (SH7770_REVISION == SH7770_1STCUT)
	tstr = (UCHAR *)DRV_GLOBAL_BASE + TSTR0_GLOBAL_OFFSET;
	*tstr = 0;
    pTmuComReg->tstr0 = *tstr;
#else
    pTmuComReg->tstr0 = 0;
#endif

    DEBUGMSG(1, (TEXT("TMU_TSTR0 0x%02X \r\n"), pTmuComReg->tstr0 ));
    DEBUGMSG(1, (TEXT("TMU_TCR0  0x%08X \r\n"), pTmuTimer0->tcr  ));
    DEBUGMSG(1, (TEXT("TMU_TCOR0 0x%08X \r\n"), pTmuTimer0->tcor ));
    DEBUGMSG(1, (TEXT("TMU_TCNT0 0x%08X \r\n"), pTmuTimer0->tcnt ));

    // TMU0: underflow interrupt enable, divide by 16
    pTmuTimer0->tcr = TMU_TCR_UNIE | TMU_TCR_TPSC_D16;

    // initialize counter and constant
    pTmuTimer0->tcor = nTicks;
    pTmuTimer0->tcnt = nTicks;

    // start timer 0
#if (SH7770_REVISION == SH7770_1STCUT)
	tstr = (UCHAR *)DRV_GLOBAL_BASE + TSTR0_GLOBAL_OFFSET;
	*tstr |= TMU0_ENABLE;
    pTmuComReg->tstr0 = *tstr;
#else
    pTmuComReg->tstr0 |= TMU0_ENABLE;
#endif

    DEBUGMSG(1, (TEXT("->TMU_TSTR0 0x%02X \r\n"), pTmuComReg->tstr0 ));
    DEBUGMSG(1, (TEXT("->TMU_TCR0  0x%08X \r\n"), pTmuTimer0->tcr  ));
    DEBUGMSG(1, (TEXT("->TMU_TCOR0 0x%08X \r\n"), pTmuTimer0->tcor ));
    DEBUGMSG(1, (TEXT("->TMU_TCNT0 0x%08X \r\n"), pTmuTimer0->tcnt ));

    DEBUGMSG(1, (TEXT("TMU_TCR1  0x%08X \r\n"), pTmuTimer1->tcr  ));
    DEBUGMSG(1, (TEXT("TMU_TCOR1 0x%08X \r\n"), pTmuTimer1->tcor ));
    DEBUGMSG(1, (TEXT("TMU_TCNT1 0x%08X \r\n"), pTmuTimer1->tcnt ));

    // TMU1: underflow interrupt enable, divide by 4
    pTmuTimer1->tcr = TMU_TCR_TPSC_D4;

    // initialize counter and constant
    pTmuTimer1->tcor = 0xffffffff;
    pTmuTimer1->tcnt = 0xffffffff;

    // start timer 1
#if (SH7770_REVISION == SH7770_1STCUT)
	tstr = (UCHAR *)DRV_GLOBAL_BASE + TSTR0_GLOBAL_OFFSET;
	*tstr |= TMU1_ENABLE;
    pTmuComReg->tstr0 = *tstr;
#else
    pTmuComReg->tstr0 |= TMU1_ENABLE;
#endif
    DEBUGMSG(1, (TEXT("->TMU_TSTR0 0x%02X \r\n"), pTmuComReg->tstr0 ));
    DEBUGMSG(1, (TEXT("->TMU_TCR1  0x%08X \r\n"), pTmuTimer1->tcr  ));
    DEBUGMSG(1, (TEXT("->TMU_TCOR1 0x%08X \r\n"), pTmuTimer1->tcor ));
    DEBUGMSG(1, (TEXT("->TMU_TCNT1 0x%08X \r\n"), pTmuTimer1->tcnt ));

    DEBUGMSG(1, (TEXT("-SHxInitTimer\r\n")));
}

//-------------------------------------------------------------------------------
// Update reschedule time.
//-------------------------------------------------------------------------------
void SHxUpdateReschedTime (DWORD dwTime)
{
    volatile DWORD dwNext = NextINTMSec;
    int   nNewCounter, nDiffTick, nDiffMSec = dwTime - LastINTMSec;
#ifdef DEBUG
    DWORD dwPrev = LastINTMSec;
#endif

    // if timer interrupts occurs, or within 1MS of the scheduled interrupt, just return
    // TimerISR will take care of it.
    if (((int) pTmuTimer0->tcnt < SHxCount1MS) || (pTmuTimer0->tcr & TMU_TCR_UNF) || (dwNext != NextINTMSec)) {
        return;
    }

    // we know we're not going to be interrupted by timer within 1MS if we reach here.
    DEBUGCHK (0 == shifted_tick);

    // trying to set reschedule time prior or equal to LastINTMSec - this could happen if a thread is on its way to 
    // sleep while preempted before getting into the Sleep Queue
    if (nDiffMSec < 0) {
        nDiffMSec = 0;
    } else if (nDiffMSec > nMaxSchedMSec) {
        nDiffMSec = nMaxSchedMSec;
    }
    dwTime = LastINTMSec + nDiffMSec;

    nDiffTick = (dwTime - NextINTMSec) * SHxCount1MS;
    NextINTMSec = dwTime;
    dwCounterBase += nDiffTick;

    // calculation here:
    // current_tick = NextINTMSec * SHxCount1MS - CounterRegister;
    // tick_to_interrupt = dwTime * SHxCount1MS
    // new_counter = ticks_to_interrupt - current_tick = (dwTime - NextINTMSec) * SHxCount1MS + CounterRegister;
    nNewCounter = nDiffTick + pTmuTimer0->tcnt;

    // update 'Next'

    // shift tick if new counter will be too small
    if (OEMMinTickDistance > nNewCounter) {
        shifted_tick = OEMMinTickDistance - nNewCounter;
        nDiffTick += shifted_tick;

⌨️ 快捷键说明

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