aboutsummaryrefslogtreecommitdiffstats
path: root/distrib/sdl-1.2.15/src/timer/macos
diff options
context:
space:
mode:
Diffstat (limited to 'distrib/sdl-1.2.15/src/timer/macos')
-rw-r--r--distrib/sdl-1.2.15/src/timer/macos/FastTimes.c352
-rw-r--r--distrib/sdl-1.2.15/src/timer/macos/FastTimes.h27
-rw-r--r--distrib/sdl-1.2.15/src/timer/macos/SDL_MPWtimer.c152
-rw-r--r--distrib/sdl-1.2.15/src/timer/macos/SDL_systimer.c186
4 files changed, 717 insertions, 0 deletions
diff --git a/distrib/sdl-1.2.15/src/timer/macos/FastTimes.c b/distrib/sdl-1.2.15/src/timer/macos/FastTimes.c
new file mode 100644
index 0000000..2da74b7
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/timer/macos/FastTimes.c
@@ -0,0 +1,352 @@
+/* File "FastTimes.c" - Original code by Matt Slot <fprefect@ambrosiasw.com> */
+/* Created 4/24/99 - This file is hereby placed in the public domain */
+/* Updated 5/21/99 - Calibrate to VIA, add TBR support, renamed functions */
+/* Updated 10/4/99 - Use AbsoluteToNanoseconds() in case Absolute = double */
+/* Updated 2/15/00 - Check for native Time Manager, no need to calibrate */
+/* Updated 2/19/00 - Fixed default value for gScale under native Time Mgr */
+/* Updated 3/21/00 - Fixed ns conversion, create 2 different scale factors */
+/* Updated 5/03/00 - Added copyright and placed into PD. No code changes */
+/* Updated 8/01/00 - Made "Carbon-compatible" by replacing LMGetTicks() */
+
+/* This file is Copyright (C) Matt Slot, 1999-2012. It is hereby placed into
+ the public domain. The author makes no warranty as to fitness or stability */
+
+#include <Gestalt.h>
+#include <LowMem.h>
+#include <CodeFragments.h>
+#include <DriverServices.h>
+#include <Timer.h>
+
+#include "FastTimes.h"
+
+#ifdef TARGET_CPU_PPC
+#undef GENERATINGPOWERPC /* stop whining */
+#define GENERATINGPOWERPC TARGET_CPU_PPC
+#endif
+
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+/*
+ On 680x0 machines, we just use Microseconds().
+
+ On PowerPC machines, we try several methods:
+ * DriverServicesLib is available on all PCI PowerMacs, and perhaps
+ some NuBus PowerMacs. If it is, we use UpTime() : Overhead = 2.1 µsec.
+ * The PowerPC 601 has a built-in "real time clock" RTC, and we fall
+ back to that, accessing it directly from asm. Overhead = 1.3 µsec.
+ * Later PowerPCs have an accurate "time base register" TBR, and we
+ fall back to that, access it from PowerPC asm. Overhead = 1.3 µsec.
+ * We can also try Microseconds() which is emulated : Overhead = 36 µsec.
+
+ On PowerPC machines, we avoid the following:
+ * OpenTransport is available on all PCI and some NuBus PowerMacs, but it
+ uses UpTime() if available and falls back to Microseconds() otherwise.
+ * InputSprocket is available on many PowerMacs, but again it uses
+ UpTime() if available and falls back to Microseconds() otherwise.
+
+ Another PowerPC note: certain configurations, especially 3rd party upgrade
+ cards, may return inaccurate timings for the CPU or memory bus -- causing
+ skew in various system routines (up to 20% drift!). The VIA chip is very
+ accurate, and it's the basis for the Time Manager and Microseconds().
+ Unfortunately, it's also very slow because the MacOS has to (a) switch to
+ 68K and (b) poll for a VIA event.
+
+ We compensate for the drift by calibrating a floating point scale factor
+ between our fast method and the accurate timer at startup, then convert
+ each sample quickly on the fly. I'd rather not have the initialization
+ overhead -- but it's simply necessary for accurate timing. You can drop
+ it down to 30 ticks if you prefer, but that's as low as I'd recommend.
+
+ Under MacOS 9, "new world" Macs (iMacs, B+W G3s and G+W G4s) have a native
+ Time Manager implementation: UpTime(), Microseconds(), and TickCount() are
+ all based on the same underlying counter. This makes it silly to calibrate
+ UpTime() against TickCount(). We now check for this feature using Gestalt(),
+ and skip the whole calibration step if possible.
+
+*/
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+
+#define RTCToNano(w) ((double) (w).hi * 1000000000.0 + (double) (w).lo)
+#define WideTo64bit(w) (*(UInt64 *) &(w))
+
+/* LMGetTicks() is not in Carbon and TickCount() has a fair bit of overhead,
+ so for speed we always read lowmem directly. This is a Mac OS X no-no, but
+ it always work on those systems that don't have a native Time Manager (ie,
+ anything before MacOS 9) -- regardless whether we are in Carbon or not! */
+#define MyLMGetTicks() (*(volatile UInt32 *) 0x16A)
+
+#if GENERATINGPOWERPC
+
+static asm UnsignedWide PollRTC(void);
+static asm UnsignedWide PollTBR(void);
+static Ptr FindFunctionInSharedLib(StringPtr libName, StringPtr funcName);
+
+static Boolean gInited = false;
+static Boolean gNative = false;
+static Boolean gUseRTC = false;
+static Boolean gUseTBR = false;
+static double gScaleUSec = 1.0 / 1000.0; /* 1 / ( nsec / usec) */
+static double gScaleMSec = 1.0 / 1000000.0; /* 1 / ( nsec / msec) */
+
+/* Functions loaded from DriverServicesLib */
+typedef AbsoluteTime (*UpTimeProcPtr)(void);
+typedef Nanoseconds (*A2NSProcPtr)(AbsoluteTime);
+static UpTimeProcPtr gUpTime = NULL;
+static A2NSProcPtr gA2NS = NULL;
+
+#endif /* GENERATINGPOWERPC */
+
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+
+void FastInitialize() {
+ SInt32 result;
+
+ if (!gInited) {
+
+#if GENERATINGPOWERPC
+
+ /* Initialize the feature flags */
+ gNative = gUseRTC = gUseTBR = false;
+
+ /* We use CFM to find and load needed symbols from shared libraries, so
+ the application doesn't have to weak-link them, for convenience. */
+ gUpTime = (UpTimeProcPtr) FindFunctionInSharedLib(
+ "\pDriverServicesLib", "\pUpTime");
+ if (gUpTime) gA2NS = (A2NSProcPtr) FindFunctionInSharedLib(
+ "\pDriverServicesLib", "\pAbsoluteToNanoseconds");
+ if (!gA2NS) gUpTime = nil; /* Pedantic but necessary */
+
+ if (gUpTime) {
+ /* If we loaded UpTime(), then we need to know if the system has
+ a native implementation of the Time Manager. If so, then it's
+ pointless to calculate a scale factor against the missing VIA */
+
+ /* gestaltNativeTimeMgr = 4 in some future version of the headers */
+ if (!Gestalt(gestaltTimeMgrVersion, &result) &&
+ (result > gestaltExtendedTimeMgr))
+ gNative = true;
+ }
+ else {
+ /* If no DriverServicesLib, use Gestalt() to get the processor type.
+ Only NuBus PowerMacs with old System Software won't have DSL, so
+ we know it should either be a 601 or 603. */
+
+ /* Use the processor gestalt to determine which register to use */
+ if (!Gestalt(gestaltNativeCPUtype, &result)) {
+ if (result == gestaltCPU601) gUseRTC = true;
+ else if (result > gestaltCPU601) gUseTBR = true;
+ }
+ }
+
+ /* Now calculate a scale factor to keep us accurate. */
+ if ((gUpTime && !gNative) || gUseRTC || gUseTBR) {
+ UInt64 tick, usec1, usec2;
+ UnsignedWide wide;
+
+ /* Wait for the beginning of the very next tick */
+ for(tick = MyLMGetTicks() + 1; tick > MyLMGetTicks(); );
+
+ /* Poll the selected timer and prepare it (since we have time) */
+ wide = (gUpTime) ? (*gA2NS)((*gUpTime)()) :
+ ((gUseRTC) ? PollRTC() : PollTBR());
+ usec1 = (gUseRTC) ? RTCToNano(wide) : WideTo64bit(wide);
+
+ /* Wait for the exact 60th tick to roll over */
+ while(tick + 60 > MyLMGetTicks());
+
+ /* Poll the selected timer again and prepare it */
+ wide = (gUpTime) ? (*gA2NS)((*gUpTime)()) :
+ ((gUseRTC) ? PollRTC() : PollTBR());
+ usec2 = (gUseRTC) ? RTCToNano(wide) : WideTo64bit(wide);
+
+ /* Calculate a scale value that will give microseconds per second.
+ Remember, there are actually 60.15 ticks in a second, not 60. */
+ gScaleUSec = (60.0 * 1000000.0) / ((usec2 - usec1) * 60.15);
+ gScaleMSec = gScaleUSec / 1000.0;
+ }
+
+#endif /* GENERATINGPOWERPC */
+
+ /* We've initialized our globals */
+ gInited = true;
+ }
+ }
+
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+
+UInt64 FastMicroseconds() {
+ UnsignedWide wide;
+ UInt64 usec;
+
+#if GENERATINGPOWERPC
+ /* Initialize globals the first time we are called */
+ if (!gInited) FastInitialize();
+
+ if (gNative) {
+ /* Use DriverServices if it's available -- it's fast and compatible */
+ wide = (*gA2NS)((*gUpTime)());
+ usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5;
+ }
+ else if (gUpTime) {
+ /* Use DriverServices if it's available -- it's fast and compatible */
+ wide = (*gA2NS)((*gUpTime)());
+ usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5;
+ }
+ else if (gUseTBR) {
+ /* On a recent PowerPC, we poll the TBR directly */
+ wide = PollTBR();
+ usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5;
+ }
+ else if (gUseRTC) {
+ /* On a 601, we can poll the RTC instead */
+ wide = PollRTC();
+ usec = (double) RTCToNano(wide) * gScaleUSec + 0.5;
+ }
+ else
+#endif /* GENERATINGPOWERPC */
+ {
+ /* If all else fails, suffer the mixed mode overhead */
+ Microseconds(&wide);
+ usec = WideTo64bit(wide);
+ }
+
+ return(usec);
+ }
+
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+
+UInt64 FastMilliseconds() {
+ UnsignedWide wide;
+ UInt64 msec;
+
+#if GENERATINGPOWERPC
+ /* Initialize globals the first time we are called */
+ if (!gInited) FastInitialize();
+
+ if (gNative) {
+ /* Use DriverServices if it's available -- it's fast and compatible */
+ wide = (*gA2NS)((*gUpTime)());
+ msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5;
+ }
+ else if (gUpTime) {
+ /* Use DriverServices if it's available -- it's fast and compatible */
+ wide = (*gA2NS)((*gUpTime)());
+ msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5;
+ }
+ else if (gUseTBR) {
+ /* On a recent PowerPC, we poll the TBR directly */
+ wide = PollTBR();
+ msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5;
+ }
+ else if (gUseRTC) {
+ /* On a 601, we can poll the RTC instead */
+ wide = PollRTC();
+ msec = (double) RTCToNano(wide) * gScaleMSec + 0.5;
+ }
+ else
+#endif /* GENERATINGPOWERPC */
+ {
+ /* If all else fails, suffer the mixed mode overhead */
+ Microseconds(&wide);
+ msec = ((double) WideTo64bit(wide) + 500.0) / 1000.0;
+ }
+
+ return(msec);
+ }
+
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+
+StringPtr FastMethod() {
+ StringPtr method = "\p<Unknown>";
+
+#if GENERATINGPOWERPC
+ /* Initialize globals the first time we are called */
+ if (!gInited) FastInitialize();
+
+ if (gNative) {
+ /* The Time Manager and UpTime() are entirely native on this machine */
+ method = "\pNative UpTime()";
+ }
+ else if (gUpTime) {
+ /* Use DriverServices if it's available -- it's fast and compatible */
+ method = "\pUpTime()";
+ }
+ else if (gUseTBR) {
+ /* On a recent PowerPC, we poll the TBR directly */
+ method = "\pPowerPC TBR";
+ }
+ else if (gUseRTC) {
+ /* On a 601, we can poll the RTC instead */
+ method = "\pPowerPC RTC";
+ }
+ else
+#endif /* GENERATINGPOWERPC */
+ {
+ /* If all else fails, suffer the mixed mode overhead */
+ method = "\pMicroseconds()";
+ }
+
+ return(method);
+ }
+
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+#pragma mark -
+
+#if GENERATINGPOWERPC
+asm static UnsignedWide PollRTC_() {
+entry PollRTC /* Avoid CodeWarrior glue */
+ machine 601
+@AGAIN:
+ mfrtcu r4 /* RTCU = SPR 4 */
+ mfrtcl r5 /* RTCL = SPR 5 */
+ mfrtcu r6
+ cmpw r4,r6
+ bne @AGAIN
+ stw r4,0(r3)
+ stw r5,4(r3)
+ blr
+ }
+
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+
+asm static UnsignedWide PollTBR_() {
+entry PollTBR /* Avoid CodeWarrior glue */
+ machine 604
+@AGAIN:
+ mftbu r4 /* TBRU = SPR 268 */
+ mftb r5 /* TBRL = SPR 269 */
+ mftbu r6
+ cmpw r4,r6
+ bne @AGAIN
+ stw r4,0(r3)
+ stw r5,4(r3)
+ blr
+ }
+
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+
+static Ptr FindFunctionInSharedLib(StringPtr libName, StringPtr funcName) {
+ OSErr error = noErr;
+ Str255 errorStr;
+ Ptr func = NULL;
+ Ptr entry = NULL;
+ CFragSymbolClass symClass;
+ CFragConnectionID connID;
+
+ /* Find CFM containers for the current archecture -- CFM-PPC or CFM-68K */
+ if (/* error = */ GetSharedLibrary(libName, kCompiledCFragArch,
+ kLoadCFrag, &connID, &entry, errorStr)) return(NULL);
+ if (/* error = */ FindSymbol(connID, funcName, &func, &symClass))
+ return(NULL);
+
+ return(func);
+ }
+#endif /* GENERATINGPOWERPC */
diff --git a/distrib/sdl-1.2.15/src/timer/macos/FastTimes.h b/distrib/sdl-1.2.15/src/timer/macos/FastTimes.h
new file mode 100644
index 0000000..d25744c
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/timer/macos/FastTimes.h
@@ -0,0 +1,27 @@
+/* File "FastTimes.h" - Original code by Matt Slot <fprefect@ambrosiasw.com> */
+#include "SDL_config.h"
+/* Created 4/24/99 - This file is hereby placed in the public domain */
+/* Updated 5/21/99 - Calibrate to VIA, add TBR support, renamed functions */
+/* Updated 10/4/99 - Use AbsoluteToNanoseconds() in case Absolute = double */
+/* Updated 2/15/00 - Check for native Time Manager, no need to calibrate */
+/* Updated 3/21/00 - Fixed ns conversion, create 2 different scale factors */
+/* Updated 5/03/00 - Added copyright and placed into PD. No code changes */
+
+/* This file is Copyright (C) Matt Slot, 1999-2012. It is hereby placed into
+ the public domain. The author makes no warranty as to fitness or stability */
+
+#ifndef __FAST_TIMES_HEADER__
+#define __FAST_TIMES_HEADER__
+
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+
+extern void FastInitialize(void);
+extern UInt64 FastMicroseconds(void);
+extern UInt64 FastMilliseconds(void);
+extern StringPtr FastMethod(void);
+
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
+
+#endif /* __FAST_TIMES_HEADER__ */
diff --git a/distrib/sdl-1.2.15/src/timer/macos/SDL_MPWtimer.c b/distrib/sdl-1.2.15/src/timer/macos/SDL_MPWtimer.c
new file mode 100644
index 0000000..114b6c7
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/timer/macos/SDL_MPWtimer.c
@@ -0,0 +1,152 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2012 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifdef SDL_TIMER_MACOS
+
+#include <Types.h>
+#include <Timer.h>
+#include <OSUtils.h>
+#include <Gestalt.h>
+#include <Processes.h>
+
+#include <LowMem.h>
+
+#include "SDL_timer.h"
+#include "../SDL_timer_c.h"
+
+#define MS_PER_TICK (1000/60) /* MacOS tick = 1/60 second */
+
+/* Note: This is only a step above the original 1/60s implementation.
+ * For a good implementation, see FastTimes.[ch], by Matt Slot.
+ */
+#define USE_MICROSECONDS
+#define WideTo64bit(w) (*(UInt64 *) &(w))
+
+UInt64 start;
+
+void SDL_StartTicks(void)
+{
+#ifdef USE_MICROSECONDS
+ UnsignedWide now;
+
+ Microseconds(&now);
+ start = WideTo64bit(now);
+#else
+ /* FIXME: Should we implement a wrapping algorithm, like Win32? */
+#endif
+}
+
+Uint32 SDL_GetTicks(void)
+{
+#ifdef USE_MICROSECONDS
+ UnsignedWide now;
+
+ Microseconds(&now);
+ return (Uint32)((WideTo64bit(now)-start)/1000);
+#else
+ return(LMGetTicks()*MS_PER_TICK);
+#endif
+}
+
+void SDL_Delay(Uint32 ms)
+{
+#ifdef USE_MICROSECONDS
+ Uint32 end_ms;
+
+ end_ms = SDL_GetTicks() + ms;
+ do {
+ /* FIXME: Yield CPU? */ ;
+ } while ( SDL_GetTicks() < end_ms );
+#else
+ UInt32 unused; /* MJS */
+ Delay(ms/MS_PER_TICK, &unused);
+#endif
+}
+
+
+/* Data to handle a single periodic alarm */
+typedef struct _ExtendedTimerRec
+{
+ TMTask tmTask;
+ ProcessSerialNumber taskPSN;
+} ExtendedTimerRec, *ExtendedTimerPtr;
+
+static ExtendedTimerRec gExtendedTimerRec;
+
+
+int SDL_SYS_TimerInit(void)
+{
+ /* We don't need a setup? */
+ return(0);
+}
+
+void SDL_SYS_TimerQuit(void)
+{
+ /* We don't need a cleanup? */
+ return;
+}
+
+/* Our Stub routine to set up and then call the real routine. */
+pascal void TimerCallbackProc(TMTaskPtr tmTaskPtr)
+{
+ Uint32 ms;
+
+ WakeUpProcess(&((ExtendedTimerPtr) tmTaskPtr)->taskPSN);
+
+ ms = SDL_alarm_callback(SDL_alarm_interval);
+ if ( ms ) {
+ SDL_alarm_interval = ROUND_RESOLUTION(ms);
+ PrimeTime((QElemPtr)&gExtendedTimerRec.tmTask,
+ SDL_alarm_interval);
+ } else {
+ SDL_alarm_interval = 0;
+ }
+}
+
+int SDL_SYS_StartTimer(void)
+{
+ /*
+ * Configure the global structure that stores the timing information.
+ */
+ gExtendedTimerRec.tmTask.qLink = NULL;
+ gExtendedTimerRec.tmTask.qType = 0;
+ gExtendedTimerRec.tmTask.tmAddr = NewTimerUPP(TimerCallbackProc);
+ gExtendedTimerRec.tmTask.tmCount = 0;
+ gExtendedTimerRec.tmTask.tmWakeUp = 0;
+ gExtendedTimerRec.tmTask.tmReserved = 0;
+ GetCurrentProcess(&gExtendedTimerRec.taskPSN);
+
+ /* Install the task record */
+ InsXTime((QElemPtr)&gExtendedTimerRec.tmTask);
+
+ /* Go! */
+ PrimeTime((QElemPtr)&gExtendedTimerRec.tmTask, SDL_alarm_interval);
+ return(0);
+}
+
+void SDL_SYS_StopTimer(void)
+{
+ RmvTime((QElemPtr)&gExtendedTimerRec.tmTask);
+}
+
+#endif /* SDL_TIMER_MACOS */
diff --git a/distrib/sdl-1.2.15/src/timer/macos/SDL_systimer.c b/distrib/sdl-1.2.15/src/timer/macos/SDL_systimer.c
new file mode 100644
index 0000000..7a8063e
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/timer/macos/SDL_systimer.c
@@ -0,0 +1,186 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2012 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifdef SDL_TIMER_MACOS
+
+#include <Types.h>
+#include <Timer.h>
+#include <OSUtils.h>
+#include <Gestalt.h>
+#include <Processes.h>
+
+#include <LowMem.h>
+
+#include "SDL_timer.h"
+#include "../SDL_timer_c.h"
+
+#include "FastTimes.h"
+
+#if TARGET_API_MAC_CARBON
+#define NewTimerProc NewTimerUPP
+#endif
+
+#define MS_PER_TICK (1000.0/60.0) /* MacOS tick = 1/60 second */
+
+
+#define kTwoPower32 (4294967296.0) /* 2^32 */
+
+static double start_tick;
+static int is_fast_inited = 0;
+
+void SDL_StartTicks(void)
+{
+ if ( ! is_fast_inited ) // important to check or FastTime may hang machine!
+ SDL_SYS_TimerInit();
+
+ start_tick = FastMicroseconds();
+}
+
+Uint32 SDL_GetTicks(void)
+{
+
+ if ( ! is_fast_inited )
+ SDL_SYS_TimerInit();
+
+ return FastMilliseconds();
+}
+
+void SDL_Delay(Uint32 ms)
+{
+ Uint32 stop, now;
+
+ stop = SDL_GetTicks() + ms;
+ do {
+ #if TARGET_API_MAC_CARBON
+ MPYield();
+ #else
+ SystemTask();
+ #endif
+
+ now = SDL_GetTicks();
+
+ } while ( stop > now );
+}
+
+/*
+void SDL_StartTicks(void)
+{
+ // FIXME: Should we implement a wrapping algorithm, like Win32?
+}
+
+Uint32 SDL_GetTicks(void)
+{
+ UnsignedWide ms;
+
+ Microseconds (&ms);
+
+ return ( ms.lo / 1000 );
+}
+
+void SDL_Delay(Uint32 ms)
+{
+
+ UnsignedWide microsecs;
+ UInt32 stop;
+
+ Microseconds (&microsecs);
+
+ stop = microsecs.lo + (ms * 1000);
+
+ while ( stop > microsecs.lo ) {
+
+ SystemTask ();
+
+ Microseconds (&microsecs);
+ }
+
+}*/
+
+/* Data to handle a single periodic alarm */
+typedef struct _ExtendedTimerRec
+{
+ TMTask tmTask;
+ ProcessSerialNumber taskPSN;
+} ExtendedTimerRec, *ExtendedTimerPtr;
+
+static ExtendedTimerRec gExtendedTimerRec;
+
+
+int SDL_SYS_TimerInit(void)
+{
+ FastInitialize ();
+ is_fast_inited = 1;
+
+ return(0);
+}
+
+void SDL_SYS_TimerQuit(void)
+{
+ /* We don't need a cleanup? */
+ return;
+}
+
+/* Our Stub routine to set up and then call the real routine. */
+pascal void TimerCallbackProc(TMTaskPtr tmTaskPtr)
+{
+ Uint32 ms;
+
+ WakeUpProcess(&((ExtendedTimerPtr) tmTaskPtr)->taskPSN);
+
+ ms = SDL_alarm_callback(SDL_alarm_interval);
+ if ( ms ) {
+ SDL_alarm_interval = ROUND_RESOLUTION(ms);
+ PrimeTime((QElemPtr)&gExtendedTimerRec.tmTask,
+ SDL_alarm_interval);
+ } else {
+ SDL_alarm_interval = 0;
+ }
+}
+
+int SDL_SYS_StartTimer(void)
+{
+ /*
+ * Configure the global structure that stores the timing information.
+ */
+ gExtendedTimerRec.tmTask.qLink = NULL;
+ gExtendedTimerRec.tmTask.qType = 0;
+ gExtendedTimerRec.tmTask.tmAddr = NewTimerProc(TimerCallbackProc);
+ gExtendedTimerRec.tmTask.tmCount = 0;
+ gExtendedTimerRec.tmTask.tmWakeUp = 0;
+ gExtendedTimerRec.tmTask.tmReserved = 0;
+ GetCurrentProcess(&gExtendedTimerRec.taskPSN);
+
+ /* Install the task record */
+ InsXTime((QElemPtr)&gExtendedTimerRec.tmTask);
+
+ /* Go! */
+ PrimeTime((QElemPtr)&gExtendedTimerRec.tmTask, SDL_alarm_interval);
+ return(0);
+}
+
+void SDL_SYS_StopTimer(void)
+{
+ RmvTime((QElemPtr)&gExtendedTimerRec.tmTask);
+}
+
+#endif /* SDL_TIMER_MACOS */