//#*********************************************************************** // // 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. // //#*********************************************************************** #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 // // Register Definitions // .set Microsecs, r.3 .set TimerLo , r.4 // MUST be same as defined in PXCLKSUP.S .set TimerHi , r.5 // MUST be same as defined in PXCLKSUP.S .set EndTimerLo, r.6 .set EndTimerHi, r.7 .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 // mullw EndTimerLo,Microsecs,Temp mulhwu. EndTimerHi,Microsecs,Temp bne Shift20Bits lis Temp,(1000000 >> 16) // Divide by 1,000,000 ori Temp,Temp,(1000000 & 0xFFFF) divwu EndTimerLo,EndTimerLo,Temp b Add64Bits // // The 32 MSBs are non-zero. // Instead of performing a 64-bit division, we shift right by 20 // bits (equivalent to dividing by 1,048576). Then we add back in 1/16th // of the shifted amount. The accuracy achieved by this method is: // // 1,000,000 // --------- * 1.0625 = 101.3 % of desired value. // 1,048,576 // Shift20Bits: mr Temp,EndTimerHi rlwinm EndTimerLo,EndTimerLo,32-20,20,31 rlwinm EndTimerHi,EndTimerHi,32-20,20,31 rlwimi EndTimerLo,Temp,32-20,0,19 rlwinm Temp2,EndTimerLo,32-4,4,31 rlwinm Temp,EndTimerHi,32-4,4,31 rlwimi Temp2,EndTimerHi,32-4,0,3 addc EndTimerLo,EndTimerLo,Temp2 adde EndTimerHi,EndTimerHi,Temp // // Compute EndTimer // Add64Bits: addc EndTimerLo,EndTimerLo,TimerLo adde EndTimerHi,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) WaitOnUIP1: li r.6,0x0A // check and wait on busy flag stb r.6,CMOS_INDEX(IO_Base) sync lbz r.7,CMOS_DATA(IO_Base) // Read CMOS data andi. r.7, r.7, 0x0080 bgt WaitOnUIP1 li r.3,RTC_SECOND // Read seconds from CMOS RTC stb r.3,CMOS_INDEX(IO_Base) // Write CMOS index sync lbz r.4,CMOS_DATA(IO_Base) // Read CMOS data WaitForTick1: li r.6,0x0A // check and wait on busy flag stb r.6,CMOS_INDEX(IO_Base) sync lbz r.7,CMOS_DATA(IO_Base) // Read CMOS data andi. r.7, r.7, 0x0080 bgt WaitForTick1 li r.3,RTC_SECOND // Read seconds from CMOS RTC stb r.3,CMOS_INDEX(IO_Base) // Write CMOS index sync 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.6,0x0A // check and wait on busy flag stb r.6,CMOS_INDEX(IO_Base) sync lbz r.7,CMOS_DATA(IO_Base) // Read CMOS data andi. r.7, r.7, 0x0080 bgt WaitForTick2 li r.4,RTC_SECOND // Read seconds from CMOS RTC stb r.4,CMOS_INDEX(IO_Base) // Write CMOS index sync 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)