19682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* File "FastTimes.c" - Original code by Matt Slot <fprefect@ambrosiasw.com>  */
29682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Created 4/24/99    - This file is hereby placed in the public domain       */
39682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Updated 5/21/99    - Calibrate to VIA, add TBR support, renamed functions  */
49682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Updated 10/4/99    - Use AbsoluteToNanoseconds() in case Absolute = double */
59682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Updated 2/15/00    - Check for native Time Manager, no need to calibrate   */
69682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Updated 2/19/00    - Fixed default value for gScale under native Time Mgr  */
79682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Updated 3/21/00    - Fixed ns conversion, create 2 different scale factors */
89682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Updated 5/03/00    - Added copyright and placed into PD. No code changes   */
99682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Updated 8/01/00    - Made "Carbon-compatible" by replacing LMGetTicks()    */
109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* This file is Copyright (C) Matt Slot, 1999-2012. It is hereby placed into
129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   the public domain. The author makes no warranty as to fitness or stability */
139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <Gestalt.h>
159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <LowMem.h>
169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <CodeFragments.h>
179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <DriverServices.h>
189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <Timer.h>
199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "FastTimes.h"
219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef TARGET_CPU_PPC
239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#undef GENERATINGPOWERPC /* stop whining */
249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#define GENERATINGPOWERPC TARGET_CPU_PPC
259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/*
309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	On 680x0 machines, we just use Microseconds().
319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	On PowerPC machines, we try several methods:
339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  * DriverServicesLib is available on all PCI PowerMacs, and perhaps
349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    some NuBus PowerMacs. If it is, we use UpTime() : Overhead = 2.1 �sec.
359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  * The PowerPC 601 has a built-in "real time clock" RTC, and we fall
369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    back to that, accessing it directly from asm. Overhead = 1.3 �sec.
379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  * Later PowerPCs have an accurate "time base register" TBR, and we
389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    fall back to that, access it from PowerPC asm. Overhead = 1.3 �sec.
399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  * We can also try Microseconds() which is emulated : Overhead = 36 �sec.
409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	On PowerPC machines, we avoid the following:
429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  * OpenTransport is available on all PCI and some NuBus PowerMacs, but it
439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    uses UpTime() if available and falls back to Microseconds() otherwise.
449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  * InputSprocket is available on many PowerMacs, but again it uses
459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    UpTime() if available and falls back to Microseconds() otherwise.
469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Another PowerPC note: certain configurations, especially 3rd party upgrade
489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cards, may return inaccurate timings for the CPU or memory bus -- causing
499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	skew in various system routines (up to 20% drift!). The VIA chip is very
509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	accurate, and it's the basis for the Time Manager and Microseconds().
519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Unfortunately, it's also very slow because the MacOS has to (a) switch to
529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	68K and (b) poll for a VIA event.
539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	We compensate for the drift by calibrating a floating point scale factor
559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	between our fast method and the accurate timer at startup, then convert
569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	each sample quickly on the fly. I'd rather not have the initialization
579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	overhead -- but it's simply necessary for accurate timing. You can drop
589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	it down to 30 ticks if you prefer, but that's as low as I'd recommend.
599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Under MacOS 9, "new world" Macs (iMacs, B+W G3s and G+W G4s) have a native
619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Time Manager implementation: UpTime(), Microseconds(), and TickCount() are
629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	all based on the same underlying counter. This makes it silly to calibrate
639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	UpTime() against TickCount(). We now check for this feature using Gestalt(),
649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	and skip the whole calibration step if possible.
659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall*/
679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#define RTCToNano(w)	((double) (w).hi * 1000000000.0 + (double) (w).lo)
719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#define WideTo64bit(w)	(*(UInt64 *) &(w))
729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* LMGetTicks() is not in Carbon and TickCount() has a fair bit of overhead,
749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   so for speed we always read lowmem directly. This is a Mac OS X no-no, but
759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   it always work on those systems that don't have a native Time Manager (ie,
769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   anything before MacOS 9) -- regardless whether we are in Carbon or not! */
779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#define MyLMGetTicks()	(*(volatile UInt32 *) 0x16A)
789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if GENERATINGPOWERPC
809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic asm UnsignedWide PollRTC(void);
829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic asm UnsignedWide PollTBR(void);
839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic Ptr FindFunctionInSharedLib(StringPtr libName, StringPtr funcName);
849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic Boolean			gInited = false;
869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic Boolean			gNative = false;
879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic Boolean			gUseRTC = false;
889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic Boolean			gUseTBR = false;
899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic double			gScaleUSec = 1.0 / 1000.0;    /* 1 / ( nsec / usec) */
909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic double			gScaleMSec = 1.0 / 1000000.0; /* 1 / ( nsec / msec) */
919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Functions loaded from DriverServicesLib */
939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Halltypedef AbsoluteTime 	(*UpTimeProcPtr)(void);
949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Halltypedef Nanoseconds 	(*A2NSProcPtr)(AbsoluteTime);
959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic UpTimeProcPtr 	gUpTime = NULL;
969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic A2NSProcPtr 		gA2NS = NULL;
979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif /* GENERATINGPOWERPC */
999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
1019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
1029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallvoid FastInitialize() {
1049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SInt32			result;
1059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (!gInited) {
1079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if GENERATINGPOWERPC
1099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Initialize the feature flags */
1119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		gNative = gUseRTC = gUseTBR = false;
1129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* We use CFM to find and load needed symbols from shared libraries, so
1149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		   the application doesn't have to weak-link them, for convenience.   */
1159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		gUpTime = (UpTimeProcPtr) FindFunctionInSharedLib(
1169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				"\pDriverServicesLib", "\pUpTime");
1179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (gUpTime) gA2NS = (A2NSProcPtr) FindFunctionInSharedLib(
1189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				"\pDriverServicesLib", "\pAbsoluteToNanoseconds");
1199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (!gA2NS) gUpTime = nil; /* Pedantic but necessary */
1209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (gUpTime) {
1229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			/* If we loaded UpTime(), then we need to know if the system has
1239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			   a native implementation of the Time Manager. If so, then it's
1249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			   pointless to calculate a scale factor against the missing VIA */
1259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			/* gestaltNativeTimeMgr = 4 in some future version of the headers */
1279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if (!Gestalt(gestaltTimeMgrVersion, &result) &&
1289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					(result > gestaltExtendedTimeMgr))
1299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				gNative = true;
1309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
1319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		  else {
1329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			/* If no DriverServicesLib, use Gestalt() to get the processor type.
1339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			   Only NuBus PowerMacs with old System Software won't have DSL, so
1349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			   we know it should either be a 601 or 603. */
1359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			/* Use the processor gestalt to determine which register to use */
1379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		 	if (!Gestalt(gestaltNativeCPUtype, &result)) {
1389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				if (result == gestaltCPU601) gUseRTC = true;
1399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				  else if (result > gestaltCPU601) gUseTBR = true;
1409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				}
1419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
1429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Now calculate a scale factor to keep us accurate. */
1449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ((gUpTime && !gNative) || gUseRTC || gUseTBR) {
1459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			UInt64			tick, usec1, usec2;
1469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			UnsignedWide	wide;
1479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			/* Wait for the beginning of the very next tick */
1499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			for(tick = MyLMGetTicks() + 1; tick > MyLMGetTicks(); );
1509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			/* Poll the selected timer and prepare it (since we have time) */
1529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			wide = (gUpTime) ? (*gA2NS)((*gUpTime)()) :
1539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					((gUseRTC) ? PollRTC() : PollTBR());
1549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			usec1 = (gUseRTC) ? RTCToNano(wide) : WideTo64bit(wide);
1559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			/* Wait for the exact 60th tick to roll over */
1579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			while(tick + 60 > MyLMGetTicks());
1589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			/* Poll the selected timer again and prepare it  */
1609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			wide = (gUpTime) ? (*gA2NS)((*gUpTime)()) :
1619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					((gUseRTC) ? PollRTC() : PollTBR());
1629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			usec2 = (gUseRTC) ? RTCToNano(wide) : WideTo64bit(wide);
1639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			/* Calculate a scale value that will give microseconds per second.
1659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			   Remember, there are actually 60.15 ticks in a second, not 60.  */
1669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			gScaleUSec = (60.0 * 1000000.0) / ((usec2 - usec1) * 60.15);
1679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			gScaleMSec = gScaleUSec / 1000.0;
1689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
1699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif /* GENERATINGPOWERPC */
1719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* We've initialized our globals */
1739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		gInited = true;
1749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
1759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
1769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
1789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
1799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse HallUInt64 FastMicroseconds() {
1819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	UnsignedWide	wide;
1829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	UInt64			usec;
1839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if GENERATINGPOWERPC
1859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Initialize globals the first time we are called */
1869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (!gInited) FastInitialize();
1879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (gNative) {
1899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Use DriverServices if it's available -- it's fast and compatible */
1909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		wide = (*gA2NS)((*gUpTime)());
1919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5;
1929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
1939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  else if (gUpTime) {
1949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Use DriverServices if it's available -- it's fast and compatible */
1959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		wide = (*gA2NS)((*gUpTime)());
1969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5;
1979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
1989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  else if (gUseTBR) {
1999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* On a recent PowerPC, we poll the TBR directly */
2009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		wide = PollTBR();
2019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5;
2029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  else if (gUseRTC) {
2049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* On a 601, we can poll the RTC instead */
2059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		wide = PollRTC();
2069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		usec = (double) RTCToNano(wide) * gScaleUSec + 0.5;
2079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  else
2099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif /* GENERATINGPOWERPC */
2109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		{
2119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* If all else fails, suffer the mixed mode overhead */
2129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		Microseconds(&wide);
2139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		usec = WideTo64bit(wide);
2149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(usec);
2179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
2189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
2209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
2219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse HallUInt64 FastMilliseconds() {
2239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	UnsignedWide	wide;
2249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	UInt64			msec;
2259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if GENERATINGPOWERPC
2279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Initialize globals the first time we are called */
2289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (!gInited) FastInitialize();
2299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (gNative) {
2319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Use DriverServices if it's available -- it's fast and compatible */
2329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		wide = (*gA2NS)((*gUpTime)());
2339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5;
2349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  else if (gUpTime) {
2369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Use DriverServices if it's available -- it's fast and compatible */
2379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		wide = (*gA2NS)((*gUpTime)());
2389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5;
2399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  else if (gUseTBR) {
2419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* On a recent PowerPC, we poll the TBR directly */
2429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		wide = PollTBR();
2439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5;
2449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  else if (gUseRTC) {
2469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* On a 601, we can poll the RTC instead */
2479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		wide = PollRTC();
2489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		msec = (double) RTCToNano(wide) * gScaleMSec + 0.5;
2499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  else
2519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif /* GENERATINGPOWERPC */
2529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		{
2539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* If all else fails, suffer the mixed mode overhead */
2549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		Microseconds(&wide);
2559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		msec = ((double) WideTo64bit(wide) + 500.0) / 1000.0;
2569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(msec);
2599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
2609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
2629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
2639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse HallStringPtr FastMethod() {
2659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	StringPtr	method = "\p<Unknown>";
2669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if GENERATINGPOWERPC
2689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Initialize globals the first time we are called */
2699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (!gInited) FastInitialize();
2709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (gNative) {
2729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* The Time Manager and UpTime() are entirely native on this machine */
2739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		method = "\pNative UpTime()";
2749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  else if (gUpTime) {
2769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Use DriverServices if it's available -- it's fast and compatible */
2779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		method = "\pUpTime()";
2789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  else if (gUseTBR) {
2809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* On a recent PowerPC, we poll the TBR directly */
2819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		method = "\pPowerPC TBR";
2829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  else if (gUseRTC) {
2849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* On a 601, we can poll the RTC instead */
2859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		method = "\pPowerPC RTC";
2869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	  else
2889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif /* GENERATINGPOWERPC */
2899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		{
2909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* If all else fails, suffer the mixed mode overhead */
2919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		method = "\pMicroseconds()";
2929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(method);
2959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
2969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
2989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
2999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#pragma mark -
3009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if GENERATINGPOWERPC
3029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallasm static UnsignedWide PollRTC_() {
3039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallentry PollRTC /* Avoid CodeWarrior glue */
3049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	machine 601
3059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall@AGAIN:
3069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mfrtcu	r4 /* RTCU = SPR 4 */
3079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mfrtcl	r5 /* RTCL = SPR 5 */
3089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mfrtcu	r6
3099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmpw	r4,r6
3109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	bne		@AGAIN
3119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	stw		r4,0(r3)
3129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	stw		r5,4(r3)
3139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	blr
3149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
3159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
3179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
3189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallasm static UnsignedWide PollTBR_() {
3209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallentry PollTBR /* Avoid CodeWarrior glue */
3219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	machine 604
3229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall@AGAIN:
3239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mftbu	r4 /* TBRU = SPR 268 */
3249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mftb	r5 /* TBRL = SPR 269 */
3259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mftbu	r6
3269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmpw	r4,r6
3279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	bne		@AGAIN
3289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	stw		r4,0(r3)
3299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	stw		r5,4(r3)
3309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	blr
3319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
3329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
3349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
3359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic Ptr FindFunctionInSharedLib(StringPtr libName, StringPtr funcName) {
3379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	OSErr				error = noErr;
3389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Str255				errorStr;
3399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Ptr					func = NULL;
3409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Ptr					entry = NULL;
3419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	CFragSymbolClass	symClass;
3429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	CFragConnectionID	connID;
3439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Find CFM containers for the current archecture -- CFM-PPC or CFM-68K */
3459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (/* error = */ GetSharedLibrary(libName, kCompiledCFragArch,
3469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			kLoadCFrag, &connID, &entry, errorStr)) return(NULL);
3479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (/* error = */ FindSymbol(connID, funcName, &func, &symClass))
3489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(NULL);
3499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(func);
3519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
3529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif /* GENERATINGPOWERPC */
353