742 lines
18 KiB
C
742 lines
18 KiB
C
/*++
|
||
|
||
Copyright (c) 1994 Digital Equipment Corporation
|
||
|
||
Module Name:
|
||
|
||
ev5prof.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the Profile Counter using the performance
|
||
counters within the EV5 core. This module is appropriate for all
|
||
machines based on microprocessors using the EV5 core.
|
||
|
||
N.B. - This module assumes that all processors in a multiprocessor
|
||
system are running the microprocessor at the same clock speed.
|
||
|
||
Author:
|
||
|
||
Steve Brooks 14-Feb-1995 (adapted from ev4prof.c)
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "halp.h"
|
||
#include "axp21164.h"
|
||
|
||
|
||
//
|
||
// Define space in the HAL-reserved part of the PCR structure for each
|
||
// performance counter's interval count
|
||
//
|
||
// Note that ev5ints.s depends on these positions in the PCR.
|
||
//
|
||
#define PCRProfileCount ((PULONG)(HAL_PCR->ProfileCount.ProfileCount))
|
||
#define PCRProfileCountReload ((PULONG)(&HAL_PCR->ProfileCount.ProfileCountReload))
|
||
|
||
|
||
//
|
||
// Define the currently selected profile source for each counter
|
||
//
|
||
KPROFILE_SOURCE HalpProfileSource0;
|
||
KPROFILE_SOURCE HalpProfileSource1;
|
||
KPROFILE_SOURCE HalpProfileSource2;
|
||
|
||
#define INTERVAL_DELTA (10)
|
||
|
||
//
|
||
// Define the mapping between possible profile sources and the
|
||
// CPU-specific settings.
|
||
//
|
||
typedef struct _HALP_PROFILE_MAPPING {
|
||
BOOLEAN Supported;
|
||
ULONG MuxControl;
|
||
ULONG Counter;
|
||
ULONG EventCount;
|
||
ULONG NumberOfTicks;
|
||
} HALP_PROFILE_MAPPING, *PHALP_PROFILE_MAPPING;
|
||
|
||
HALP_PROFILE_MAPPING HalpProfileMapping[ProfileMaximum] =
|
||
{
|
||
{TRUE, Ev5Cycles, Ev5PerformanceCounter0, Ev5CountEvents2xx16, 10},
|
||
{FALSE, 0,0,0,0},
|
||
{TRUE, Ev5Instructions, Ev5PerformanceCounter0, Ev5CountEvents2xx16, 10},
|
||
{TRUE, Ev5PipeDry, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
|
||
{TRUE, Ev5LoadsIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
|
||
{FALSE, 0,0,0,0},
|
||
{TRUE, Ev5AllFlowIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
|
||
{TRUE, Ev5NonIssue, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
|
||
{TRUE, Ev5DcacheLDMisses, Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10},
|
||
{TRUE, Ev5IcacheRFBMisses, Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10},
|
||
{FALSE, 0,0,0,0},
|
||
{TRUE, Ev5BRMispredicts, Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10},
|
||
{TRUE, Ev5StoresIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
|
||
{TRUE, Ev5FPOpsIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
|
||
{TRUE, Ev5IntOpsIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
|
||
{TRUE, Ev5DualIssue, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
|
||
{TRUE, Ev5TripleIssue, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
|
||
{TRUE, Ev5QuadIssue, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
|
||
{FALSE, 0,0,0,0},
|
||
{TRUE, Ev5Cycles, Ev5PerformanceCounter0, Ev5CountEvents2xx16, 10},
|
||
{TRUE, Ev5IcacheIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
|
||
{TRUE, Ev5DcacheAccesses,Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
|
||
{TRUE, Ev5MBStallCycles, Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10},
|
||
{TRUE, Ev5LDxLInstIssued,Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10}
|
||
};
|
||
|
||
BOOLEAN
|
||
HalQueryProfileInterval(
|
||
IN KPROFILE_SOURCE Source
|
||
);
|
||
|
||
NTSTATUS
|
||
HalSetProfileSourceInterval(
|
||
IN KPROFILE_SOURCE ProfileSource,
|
||
IN OUT ULONG *Interval
|
||
);
|
||
|
||
VOID
|
||
HalpUpdatePerformanceCounter(
|
||
IN ULONG PerformanceCounter,
|
||
IN ULONG MuxControl,
|
||
IN ULONG EventCount
|
||
);
|
||
|
||
|
||
NTSTATUS
|
||
HalpProfileSourceInformation (
|
||
OUT PVOID Buffer,
|
||
IN ULONG BufferLength,
|
||
OUT PULONG ReturnedLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the HAL_PROFILE_SOURCE_INFORMATION for this processor.
|
||
|
||
Arguments:
|
||
|
||
Buffer - output buffer
|
||
BufferLength - length of buffer on input
|
||
ReturnedLength - The length of data returned
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS
|
||
STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
|
||
currently needed.
|
||
|
||
--*/
|
||
{
|
||
PHAL_PROFILE_SOURCE_INFORMATION SourceInfo;
|
||
NTSTATUS Status;
|
||
|
||
|
||
if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INFORMATION)) {
|
||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||
return Status;
|
||
}
|
||
|
||
SourceInfo = (PHAL_PROFILE_SOURCE_INFORMATION)Buffer;
|
||
SourceInfo->Supported = HalQueryProfileInterval(SourceInfo->Source);
|
||
|
||
if (SourceInfo->Supported) {
|
||
SourceInfo->Interval =
|
||
HalpProfileMapping[SourceInfo->Source].EventCount *
|
||
HalpProfileMapping[SourceInfo->Source].NumberOfTicks;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
HalpProfileSourceInterval (
|
||
OUT PVOID Buffer,
|
||
IN ULONG BufferLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the HAL_PROFILE_SOURCE_INTERVAL for this processor.
|
||
|
||
Arguments:
|
||
|
||
Buffer - output buffer
|
||
BufferLength - length of buffer on input
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS
|
||
STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
|
||
currently needed.
|
||
|
||
--*/
|
||
{
|
||
PHAL_PROFILE_SOURCE_INTERVAL Interval;
|
||
NTSTATUS Status;
|
||
|
||
|
||
if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INTERVAL)) {
|
||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||
return Status;
|
||
}
|
||
|
||
Interval = (PHAL_PROFILE_SOURCE_INTERVAL)Buffer;
|
||
Status = HalSetProfileSourceInterval(Interval->Source,
|
||
&Interval->Interval);
|
||
return Status;
|
||
}
|
||
|
||
VOID
|
||
HalpInitializeProfiler(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called during initialization to initialize profiling
|
||
for each processor in the system.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// Establish the profile interrupt as the interrupt handler for
|
||
// all performance counter interrupts.
|
||
//
|
||
|
||
PCR->InterruptRoutine[PC0_VECTOR] = HalpPerformanceCounter0Interrupt;
|
||
PCR->InterruptRoutine[PC1_VECTOR] = HalpPerformanceCounter1Interrupt;
|
||
PCR->InterruptRoutine[PC2_VECTOR] = HalpPerformanceCounter2Interrupt;
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
HalQueryProfileInterval(
|
||
IN KPROFILE_SOURCE Source
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Given a profile source, returns whether or not that source is
|
||
supported.
|
||
|
||
Arguments:
|
||
|
||
Source - Supplies the profile source
|
||
|
||
Return Value:
|
||
|
||
TRUE - Profile source is supported
|
||
|
||
FALSE - Profile source is not supported
|
||
|
||
--*/
|
||
|
||
{
|
||
if (Source > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) {
|
||
return(FALSE);
|
||
}
|
||
|
||
return(HalpProfileMapping[Source].Supported);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
HalSetProfileSourceInterval(
|
||
IN KPROFILE_SOURCE ProfileSource,
|
||
IN OUT ULONG *Interval
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sets the profile interval for a specified profile source
|
||
|
||
Arguments:
|
||
|
||
ProfileSource - Supplies the profile source
|
||
|
||
Interval - Supplies the specified profile interval
|
||
Returns the actual profile interval
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG FastTickPeriod;
|
||
ULONG SlowTickPeriod;
|
||
ULONG TickPeriod;
|
||
ULONG FastCountEvents;
|
||
ULONG SlowCountEvents;
|
||
ULONGLONG CountEvents;
|
||
ULONGLONG TempInterval;
|
||
|
||
if (!HalQueryProfileInterval(ProfileSource)) {
|
||
return(STATUS_NOT_IMPLEMENTED);
|
||
}
|
||
|
||
if (ProfileSource == ProfileTime) {
|
||
|
||
//
|
||
// Convert the clock tick period (in 100ns units ) into
|
||
// a cycle count period
|
||
//
|
||
|
||
CountEvents = ((ULONGLONG)(*Interval) * 100000) / PCR->CycleClockPeriod;
|
||
} else {
|
||
CountEvents = (ULONGLONG)*Interval;
|
||
}
|
||
|
||
FastCountEvents = Ev5CountEvents2xx8;
|
||
SlowCountEvents = Ev5CountEvents2xx16;
|
||
|
||
if (HalpProfileMapping[ProfileSource].Counter == Ev5PerformanceCounter0) {
|
||
FastCountEvents = Ev5CountEvents2xx16;
|
||
}
|
||
else if (HalpProfileMapping[ProfileSource].Counter == Ev5PerformanceCounter2) {
|
||
SlowCountEvents = Ev5CountEvents2xx14;
|
||
}
|
||
|
||
//
|
||
// Limit the interval to the smallest interval we can time.
|
||
//
|
||
if (CountEvents < FastCountEvents) {
|
||
CountEvents = (ULONGLONG)FastCountEvents;
|
||
}
|
||
|
||
//
|
||
// Assume we will use the fast event count
|
||
//
|
||
HalpProfileMapping[ProfileSource].EventCount = FastCountEvents;
|
||
HalpProfileMapping[ProfileSource].NumberOfTicks =
|
||
(ULONG)((CountEvents + FastCountEvents - 1) / FastCountEvents);
|
||
|
||
//
|
||
// See if we can successfully use the slower period. If the requested
|
||
// interval is greater than the slower tick period and the difference
|
||
// between the requested interval and the interval that we can deliver
|
||
// with the slower clock is acceptable, then use the slower clock.
|
||
// We define an acceptable difference as a difference of less than
|
||
// INTERVAL_DELTA of the requested interval.
|
||
//
|
||
if (CountEvents > SlowCountEvents) {
|
||
ULONG NewInterval;
|
||
|
||
NewInterval = (ULONG)(((CountEvents + SlowCountEvents-1) /
|
||
SlowCountEvents) * SlowCountEvents);
|
||
if (((NewInterval - CountEvents) * 100 / CountEvents) < INTERVAL_DELTA) {
|
||
HalpProfileMapping[ProfileSource].EventCount = SlowCountEvents;
|
||
HalpProfileMapping[ProfileSource].NumberOfTicks = NewInterval / SlowCountEvents;
|
||
}
|
||
}
|
||
|
||
*Interval = HalpProfileMapping[ProfileSource].EventCount *
|
||
HalpProfileMapping[ProfileSource].NumberOfTicks;
|
||
|
||
if (ProfileSource == ProfileTime) {
|
||
//
|
||
// Convert cycle count back into 100ns clock ticks
|
||
//
|
||
// Use 64-bit integer to prevent overflow.
|
||
//
|
||
TempInterval = (ULONGLONG)(*Interval) * (ULONGLONG)(PCR->CycleClockPeriod);
|
||
*Interval = (ULONG)(TempInterval / 100000);
|
||
}
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
ULONG
|
||
HalSetProfileInterval (
|
||
IN ULONG Interval
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the profile interrupt interval.
|
||
|
||
Arguments:
|
||
|
||
Interval - Supplies the desired profile interval in 100ns units.
|
||
|
||
Return Value:
|
||
|
||
The actual profile interval.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG NewInterval;
|
||
|
||
NewInterval = Interval;
|
||
HalSetProfileSourceInterval(ProfileTime, &NewInterval);
|
||
return(NewInterval);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
HalStartProfileInterrupt (
|
||
KPROFILE_SOURCE ProfileSource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine turns on the profile interrupt.
|
||
|
||
N.B. This routine must be called at PROCLK_LEVEL while holding the
|
||
profile lock.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG PerformanceCounter;
|
||
ULONG MuxControl;
|
||
ULONG EventCount;
|
||
|
||
//
|
||
// Check input to see if we are turning on a source that is
|
||
// supported. If it is unsupported, just return.
|
||
//
|
||
|
||
if ((ProfileSource > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) ||
|
||
(!HalpProfileMapping[ProfileSource].Supported)) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Set the performance counter within the processor to begin
|
||
// counting total cycles.
|
||
//
|
||
PerformanceCounter = HalpProfileMapping[ProfileSource].Counter;
|
||
MuxControl = HalpProfileMapping[ProfileSource].MuxControl;
|
||
|
||
if (PerformanceCounter == Ev5PerformanceCounter0) {
|
||
|
||
EventCount = (HalpProfileMapping[ProfileSource].EventCount ==
|
||
Ev5CountEvents2xx16) ? Ev5EventCountLow
|
||
: Ev5EventCountHigh;
|
||
|
||
HalpProfileSource0 = ProfileSource;
|
||
HalpUpdatePerformanceCounter( PerformanceCounter,
|
||
MuxControl,
|
||
EventCount );
|
||
|
||
PCRProfileCountReload[0] = HalpProfileMapping[ProfileSource].NumberOfTicks;
|
||
PCRProfileCount[0] = HalpProfileMapping[ProfileSource].NumberOfTicks;
|
||
|
||
//
|
||
// Enable the performance counter interrupt.
|
||
//
|
||
|
||
HalEnableSystemInterrupt ( PC0_VECTOR,
|
||
PROFILE_LEVEL,
|
||
LevelSensitive );
|
||
|
||
|
||
} else if (PerformanceCounter == Ev5PerformanceCounter1) {
|
||
|
||
EventCount = (HalpProfileMapping[ProfileSource].EventCount ==
|
||
Ev5CountEvents2xx16) ? Ev5EventCountLow
|
||
: Ev5EventCountHigh;
|
||
|
||
HalpProfileSource1 = ProfileSource;
|
||
HalpUpdatePerformanceCounter( PerformanceCounter,
|
||
MuxControl,
|
||
EventCount );
|
||
|
||
PCRProfileCountReload[1] = HalpProfileMapping[ProfileSource].NumberOfTicks;
|
||
PCRProfileCount[1] = HalpProfileMapping[ProfileSource].NumberOfTicks;
|
||
|
||
//
|
||
// Enable the performance counter interrupt.
|
||
//
|
||
|
||
HalEnableSystemInterrupt ( PC1_VECTOR,
|
||
PROFILE_LEVEL,
|
||
LevelSensitive );
|
||
|
||
} else if (PerformanceCounter == Ev5PerformanceCounter2) {
|
||
|
||
EventCount = (HalpProfileMapping[ProfileSource].EventCount ==
|
||
Ev5CountEvents2xx14) ? Ev5EventCountLow
|
||
: Ev5EventCountHigh;
|
||
|
||
HalpProfileSource2 = ProfileSource;
|
||
HalpUpdatePerformanceCounter( PerformanceCounter,
|
||
MuxControl,
|
||
EventCount );
|
||
|
||
PCRProfileCountReload[2] = HalpProfileMapping[ProfileSource].NumberOfTicks;
|
||
PCRProfileCount[2] = HalpProfileMapping[ProfileSource].NumberOfTicks;
|
||
|
||
//
|
||
// Enable the performance counter interrupt.
|
||
//
|
||
|
||
HalEnableSystemInterrupt ( PC2_VECTOR,
|
||
PROFILE_LEVEL,
|
||
LevelSensitive );
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
HalStopProfileInterrupt (
|
||
KPROFILE_SOURCE ProfileSource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine turns off the profile interrupt.
|
||
|
||
N.B. This routine must be called at PROCLK_LEVEL while holding the
|
||
profile lock.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG PerformanceCounter;
|
||
ULONG Vector;
|
||
|
||
//
|
||
// Check input to see if we are turning off a source that is
|
||
// supported. If it is unsupported, just return.
|
||
//
|
||
|
||
if ((ProfileSource > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) ||
|
||
(!HalpProfileMapping[ProfileSource].Supported)) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Stop the performance counter from interrupting.
|
||
//
|
||
|
||
PerformanceCounter = HalpProfileMapping[ProfileSource].Counter;
|
||
HalpUpdatePerformanceCounter( PerformanceCounter,
|
||
0,
|
||
Ev5CounterDisable );
|
||
|
||
//
|
||
// Disable the performance counter interrupt.
|
||
//
|
||
if (PerformanceCounter == Ev5PerformanceCounter0) {
|
||
|
||
HalDisableSystemInterrupt( PC0_VECTOR, PROFILE_LEVEL );
|
||
|
||
//
|
||
// Clear the current profile count. Can't clear value in PCR
|
||
// since a profile interrupt could be pending or in progress
|
||
// so clear the reload counter.
|
||
//
|
||
|
||
PCRProfileCountReload[0] = 0;
|
||
|
||
} else if (PerformanceCounter == Ev5PerformanceCounter1) {
|
||
|
||
HalDisableSystemInterrupt( PC1_VECTOR, PROFILE_LEVEL );
|
||
|
||
//
|
||
// Clear the current profile count. Can't clear value in PCR
|
||
// since a profile interrupt could be pending or in progress
|
||
// so clear the reload counter.
|
||
//
|
||
|
||
PCRProfileCountReload[1] = 0;
|
||
|
||
} else if (PerformanceCounter == Ev5PerformanceCounter2) {
|
||
|
||
HalDisableSystemInterrupt( PC2_VECTOR, PROFILE_LEVEL );
|
||
|
||
//
|
||
// Clear the current profile count. Can't clear value in PCR
|
||
// since a profile interrupt could be pending or in progress
|
||
// so clear the reload counter.
|
||
//
|
||
|
||
PCRProfileCountReload[2] = 0;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpUpdatePerformanceCounter(
|
||
IN ULONG PerformanceCounter,
|
||
IN ULONG MuxControl,
|
||
IN ULONG EventCount
|
||
)
|
||
//++
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// Write the specified microprocessor internal performance counter.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// PerformanceCounter(a0) - Supplies the number of the performance counter
|
||
// to write.
|
||
//
|
||
// MuxControl(a2) - Supplies the mux control value which selects which
|
||
// type of event to count when the counter is enabled.
|
||
//
|
||
// EventCount(a3) - Supplies the event interval when the counter is
|
||
// enabled.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
{
|
||
PMCTR_21164 PmCtr; // the performance counter register
|
||
ULONG CboxMux1 = 0; // CBOX select 1 mux value
|
||
ULONG CboxMux2 = 0; // CBOX select 2 mux value
|
||
|
||
PmCtr.all = HalpRead21164PerformanceCounter();
|
||
|
||
//
|
||
// Check for special values first:
|
||
//
|
||
|
||
if ( MuxControl >= Ev5PcSpecial ) {
|
||
|
||
switch( MuxControl ) {
|
||
|
||
//
|
||
// Count JsrRet Issued
|
||
//
|
||
|
||
case Ev5JsrRetIssued:
|
||
|
||
PmCtr.Ctl1 = EventCount;
|
||
PmCtr.Sel1 = Ev5FlowChangeInst;
|
||
PmCtr.Sel2 = Ev5PCMispredicts;
|
||
break;
|
||
|
||
//
|
||
// Count CondBr Issued
|
||
//
|
||
|
||
case Ev5CondBrIssued:
|
||
|
||
PmCtr.Ctl1 = EventCount;
|
||
PmCtr.Sel1 = Ev5FlowChangeInst;
|
||
PmCtr.Sel2 = Ev5BRMispredicts;
|
||
break;
|
||
|
||
//
|
||
// Count all flow change inst Issued
|
||
//
|
||
|
||
case Ev5AllFlowIssued:
|
||
|
||
PmCtr.Ctl1 = EventCount;
|
||
PmCtr.Sel1 = Ev5FlowChangeInst;
|
||
|
||
if ( (PmCtr.Sel2 == Ev5PCMispredicts) ||
|
||
(PmCtr.Sel2 == Ev5BRMispredicts)) {
|
||
|
||
PmCtr.Sel2 = Ev5LongStalls;
|
||
|
||
}
|
||
break;
|
||
|
||
//
|
||
// Must be an Scache counter. Select the appropriate counter
|
||
// in Sel1 or Sel2, and pass the CBOX mux value to WritePerfCounter
|
||
//
|
||
|
||
default:
|
||
|
||
if ( MuxControl <= Ev5ScSystemCmdReq ) {
|
||
|
||
PmCtr.Ctl1 = EventCount;
|
||
PmCtr.Sel1 = Ev5CBOXInput1;
|
||
CboxMux1 = MuxControl - Ev5ScMux1;
|
||
|
||
} else if ( MuxControl <= Ev5ScSysReadReq ) {
|
||
|
||
PmCtr.Ctl2 = EventCount;
|
||
PmCtr.Sel2 = Ev5CBOXInput2;
|
||
CboxMux2 = MuxControl - Ev5ScMux2;
|
||
|
||
}
|
||
|
||
} // switch
|
||
|
||
} else if ( PerformanceCounter == Ev5PerformanceCounter0 ) {
|
||
|
||
PmCtr.Ctl0 = EventCount;
|
||
PmCtr.Sel0 = MuxControl;
|
||
|
||
} else if ( PerformanceCounter == Ev5PerformanceCounter1 ) {
|
||
|
||
PmCtr.Ctl1 = EventCount;
|
||
PmCtr.Sel1 = MuxControl;
|
||
|
||
} else if ( PerformanceCounter == Ev5PerformanceCounter2 ) {
|
||
|
||
PmCtr.Ctl2 = EventCount;
|
||
PmCtr.Sel2 = MuxControl;
|
||
|
||
}
|
||
|
||
HalpWrite21164PerformanceCounter(PmCtr.all, CboxMux1, CboxMux2);
|
||
}
|