NT4/private/ntos/nthals/halfire/ppc/pxstall.s
2020-09-30 17:12:29 +02:00

391 lines
11 KiB
ArmAsm

//#***********************************************************************
//
//
//
//
// Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file
// contains copyrighted material. Use of this file is restricted
// by the provisions of a Motorola Software License Agreement.
//
// Copyright 1993 International Buisness Machines Corporation.
// All Rights Reserved.
//
// This file contains copyrighted material. Use of this file is
// restricted by the provisions of a Motorola/IBM Joint Software
// License Agreement.
//
// File Name:
// PXSTALL.S
//
// Functions:
// KeStallExecutionProcessor
// HalpCalibrateStall
//
// History:
// 21-Sep-1993 Steve Johns
// Original Version
// 24-Dec-1993 Peter Johnston
// Adapted to 601 HAL in an attempt to avoid having different
// versions if at all possible. Original was designed for both
// 601 and 603 but had some 601 difficulties.
// 17-Jan-1994 Steve Johns
// Changed to treat 601 vs PowerPC time base differences more
// transparently.
//
//#***********************************************************************
/*
* Copyright (c) 1995 FirePower Systems, Inc.
* DO NOT DISTRIBUTE without permission
*
* $RCSfile: pxstall.s $
* $Revision: 1.6 $
* $Date: 1996/01/11 07:13:48 $
* $Locker: $
*/
#include "kxppc.h"
#define ERRATA603 TRUE
#define RTCU 4
#define RTCL 5
#define CMOS_INDEX 0x70
#define CMOS_DATA 0x71
#define RTC_SECOND 0x80
.extern HalpPerformanceFrequency
.extern HalpIoControlBase
.extern ..HalpDivide
//
// Register Definitions
//
.set Microsecs, r.3
.set TimerLo , r.6 // MUST be same as defined in PXCLKSUP.S
.set TimerHi , r.7 // MUST be same as defined in PXCLKSUP.S
.set EndTimerLo, r.3
.set EndTimerHi, r.4
.set Temp , r.8
.set Temp2 , r.9
.set IO_Base , r.10
//#***********************************************************************
//
// Synopsis:
// VOID KeStallExecutionProcessor(
// ULONG Microseconds)
//
// Purpose:
// This function stalls the execution at least the specified number
// of microseconds, but not substantially longer.
//
// Returns:
// Nothing.
//
// Global Variables Referenced:
// HalpPerformanceFrequency
//#***********************************************************************
SPECIAL_ENTRY(KeStallExecutionProcessor)
mflr r.0 // Save Link Register
PROLOGUE_END(KeStallExecutionProcessor)
cmpli 0,0,Microsecs,0 // if (Microseconds == 0)
beqlr- // return;
bl ..HalpGetTimerRoutine // Get appropriate timer routine
//
// Read START time
//
bctrl // ReadPerformanceCounter();
//
// Get PerformanceCounter frequency
//
lwz Temp,[toc]HalpPerformanceFrequency(r.toc)
lwz Temp,0(Temp)
//
// Compute: (Microseconds * PerformanceFrequency) / 1,000,000
//
mulhwu. EndTimerHi,Microsecs,Temp
mullw EndTimerLo,Microsecs,Temp
LWI (r.5, 1000000)
bl ..HalpDivide
//
// Account for software overhead
//
.set Overhead, 30
cmpwi r.3, Overhead
ble SkipOverhead
addi r.3, r.3, -Overhead // Reduce delay
SkipOverhead:
//
// Add delay to start time
//
addc EndTimerLo, TimerLo, r.3
addze EndTimerHi, TimerHi
//
// while (ReadPerformanceCounter() < EndTimer);
//
StallLoop:
bctrl // ReadPerformanceCounter();
cmpl 0,0,TimerHi,EndTimerHi // Is TimerHi >= EndTimerHi ?
blt- StallLoop // No
bgt+ StallExit // Yes
cmpl 0,0,TimerLo,EndTimerLo // Is TimerLo >= EndTimerLo ?
blt StallLoop // Branch if not
StallExit:
mtlr r.0 // Restore Link Register
SPECIAL_EXIT(KeStallExecutionProcessor)
//
// This routine is the ReadPerformanceCounter routine for the 601 processor.
// The 601 RTC counts discontinuously (1 is added to RTCU when the value in
// RTCL passes 999,999,999). This routine converts the RTC count to a
// continuous 64-bit count by calculating:
//
// ((RTC.HighPart * 1,000,000,000) + RTC.LowPart) / 128
//
//
LEAF_ENTRY (ReadRTC)
mfspr TimerHi,RTCU // Read the RTC registers coherently
mfspr TimerLo,RTCL
mfspr Temp,RTCU
cmpl 0,0,TimerHi,Temp
bne- ..ReadRTC
lis Temp,(1000000000 >> 16) // RTC.HighPart * 1,000,000
ori Temp,Temp,(1000000000 & 0xFFFF)
mullw Temp2,Temp,TimerHi
mulhwu Temp,Temp,TimerHi
addc TimerLo,Temp2,TimerLo // + RTC.LowPart
addze TimerHi,Temp
//
// Each tick increments the RTC by 128, so let's divide that out.
//
mr Temp,TimerHi // Divide 64-bit value by 128
rlwinm TimerLo,TimerLo,32-7,7,31
rlwinm TimerHi,TimerHi,32-7,7,31
rlwimi TimerLo,Temp,32-7,0,6
LEAF_EXIT (ReadRTC)
//
// This routine is the ReadPerformanceCounter routine for PowerPC
// architectures (not the 601).
//
LEAF_ENTRY (ReadTB)
mftbu TimerHi // Read the TB registers coherently
mftb TimerLo
#if ERRATA603
mftb TimerLo
mftb TimerLo
mftb TimerLo
#endif
mftbu Temp
cmpl 0,0,Temp,TimerHi
bne- ..ReadTB
LEAF_EXIT (ReadTB)
//
// Returns in the Count Register the entry point for the routine
// that reads the appropriate Performance Counter (ReadRTC or ReadTB).
//
// Called from KeQueryPerformanceCounter and KeStallExecutionProcessor
//
LEAF_ENTRY (HalpGetTimerRoutine)
mfpvr Temp // Read Processor Version Register
rlwinm Temp,Temp,16,16,31
cmpli 0,0,Temp,1 // Are we running on an MPC601 ?
lwz Temp,[toc]ReadTB(r.toc)
bne+ GetEntryPoint // Branch if not
lwz Temp,[toc]ReadRTC(r.toc)
GetEntryPoint:
lwz Temp,0(Temp) // Get addr to ReadRTC or ReadTB
mtctr Temp
LEAF_EXIT (HalpGetTimerRoutine)
//
// Returns the number of performance counter ticks/second.
//
// The DECREMENTER is clocked at the same rate as the PowerPC Time Base (TB)
// and the POWER RTC. The POWER RTC is supposed to be clocked at 7.8125 MHz,
// but on early prototypes of the Sandalfoot platform, this is not true).
// In either case, to keep the calibration routine simple and generic, we
// will determine the DECREMENTER clock rate by counting ticks for exactly
// 1 second (as measured against the CMOS RealTimeClock). We then use that
// value in the KeStallExecutionProcessor() and KeQueryPerformanceCounter()
//
LEAF_ENTRY(HalpCalibrateTB)
// Get base address of ISA I/O space so we can talk to the CMOS RTC
lwz IO_Base,[toc]HalpIoControlBase(r.toc)
lwz IO_Base,0(IO_Base)
li r.3,RTC_SECOND // Read seconds from CMOS RTC
stb r.3,CMOS_INDEX(IO_Base) // Write CMOS index
eieio
lbz r.4,CMOS_DATA(IO_Base) // Read CMOS data
WaitForTick1:
li r.3,RTC_SECOND // Read seconds from CMOS RTC
stb r.3,CMOS_INDEX(IO_Base) // Write CMOS index
eieio
lbz r.3,CMOS_DATA(IO_Base) // Read CMOS data
cmpl 0,0,r.3,r.4 // Loop until it changes
beq+ WaitForTick1
li r.4,-1 // Start the decrementer at max. count
mtdec r.4
#if ERRATA603
isync
#endif
WaitForTick2:
li r.4,RTC_SECOND // Read seconds from CMOS RTC
stb r.4,CMOS_INDEX(IO_Base) // Write CMOS index
eieio
lbz r.4,CMOS_DATA(IO_Base) // Read CMOS data
cmpl 0,0,r.3,r.4
beq+ WaitForTick2
mfdec r.3 // Read the decrementer
neg r.3,r.3 // Compute delta ticks
mfpvr Temp // Read Processor Version Register
rlwinm Temp,Temp,16,16,31
cmpli 0,0,Temp,1 // if (CPU != 601)
bnelr // return(r.3);
//
// On the 601, the DECREMENTER decrements every ns, so the 7 LSBs are
// not implemented.
//
rlwinm r.3,r.3,32-7,7,31 // Divide count by 128
LEAF_EXIT(HalpCalibrateTB)
LEAF_ENTRY(HalpCalibrateTBPStack)
#define NVRAM_INDEX_LO 0x74
#define NVRAM_INDEX_HI 0x75
#define NVRAM_DATA 0x77
#define RTC_OFFSET 0x1ff8
#define RTC_CONTROL 0x0
// *BJ* Fix later.
#undef RTC_SECOND
#define RTC_SECOND 0x1
#define RTC_MINUTE 0x2
#define SYNCHRONIZE \
lwz Temp,[toc]HalpIoControlBase(r.toc);\
stw Temp,[toc]HalpIoControlBase(r.toc);\
nop;\
sync
// Get base address of ISA I/O space so we can talk to the CMOS RTC
lwz IO_Base,[toc]HalpIoControlBase(r.toc)
lwz IO_Base,0(IO_Base)
li r.3,RTC_OFFSET+ RTC_SECOND // Read seconds from CMOS RTC
stb r.3,NVRAM_INDEX_LO(IO_Base) // Write CMOS index lo
rlwinm r.3,r.3,32-8,24,31 // Shift > 8 and mask 0xff
stb r.3,NVRAM_INDEX_HI(IO_Base) // Write CMOS index hi
SYNCHRONIZE
lbz r.3,NVRAM_DATA(IO_Base) // Read CMOS data
WaitForTick0.Ps:
li r.4,RTC_OFFSET+ RTC_SECOND // Read seconds from CMOS RTC
stb r.4,NVRAM_INDEX_LO(IO_Base) // Write CMOS index lo
rlwinm r.4,r.4,32-8,24,31 // Shift > 8 and mask 0xff
stb r.4,NVRAM_INDEX_HI(IO_Base) // Write CMOS index hi
SYNCHRONIZE
lbz r.4,NVRAM_DATA(IO_Base) // Read CMOS data
cmpl 0,0,r.3,r.4 // Loop until it changes
beq+ WaitForTick0.Ps
WaitForTick1.Ps:
li r.3,RTC_OFFSET+ RTC_SECOND // Read seconds from CMOS RTC
stb r.3,NVRAM_INDEX_LO(IO_Base) // Write CMOS index lo
rlwinm r.3,r.3,32-8,24,31 // Shift > 8 and mask 0xff
stb r.3,NVRAM_INDEX_HI(IO_Base) // Write CMOS index hi
SYNCHRONIZE
lbz r.3,NVRAM_DATA(IO_Base) // Read CMOS data
cmpl 0,0,r.3,r.4 // Loop until it changes
beq+ WaitForTick1.Ps
li r.4,-1 // Start the decrementer at max. count
mtdec r.4
#if ERRATA603
isync
#endif
WaitForTick2.Ps:
li r.4,RTC_OFFSET+ RTC_SECOND // Read seconds from CMOS RTC
stb r.4,NVRAM_INDEX_LO(IO_Base) // Write CMOS index lo
rlwinm r.4,r.4,32-8,24,31 // Shift > 8 and mask 0xff
stb r.4,NVRAM_INDEX_HI(IO_Base) // Write CMOS index hi
SYNCHRONIZE
lbz r.4,NVRAM_DATA(IO_Base) // Read CMOS data
cmpl 0,0,r.3,r.4
beq+ WaitForTick2.Ps
mfdec r.3 // Read the decrementer
neg r.3,r.3 // Compute delta ticks
mfpvr Temp // Read Processor Version Register
rlwinm Temp,Temp,16,16,31
cmpli 0,0,Temp,1 // if (CPU != 601)
bnelr // return(r.3);
//
// On the 601, the DECREMENTER decrements every ns, so the 7 LSBs are
// not implemented.
//
rlwinm r.3,r.3,32-7,7,31 // Divide count by 128
LEAF_EXIT(HalpCalibrateTBPStack)