src/timer/macos/FastTimes.c
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1662 782fd950bd46
equal deleted inserted replaced
1667:1fddae038bc8 1668:4da1ee79c9af
    76    anything before MacOS 9) -- regardless whether we are in Carbon or not! */
    76    anything before MacOS 9) -- regardless whether we are in Carbon or not! */
    77 #define MyLMGetTicks()	(*(volatile UInt32 *) 0x16A)
    77 #define MyLMGetTicks()	(*(volatile UInt32 *) 0x16A)
    78 
    78 
    79 #if GENERATINGPOWERPC
    79 #if GENERATINGPOWERPC
    80 
    80 
    81 static asm UnsignedWide PollRTC (void);
    81 static asm UnsignedWide PollRTC(void);
    82 static asm UnsignedWide PollTBR (void);
    82 static asm UnsignedWide PollTBR(void);
    83 static Ptr FindFunctionInSharedLib (StringPtr libName, StringPtr funcName);
    83 static Ptr FindFunctionInSharedLib(StringPtr libName, StringPtr funcName);
    84 
    84 
    85 static Boolean gInited = false;
    85 static Boolean gInited = false;
    86 static Boolean gNative = false;
    86 static Boolean gNative = false;
    87 static Boolean gUseRTC = false;
    87 static Boolean gUseRTC = false;
    88 static Boolean gUseTBR = false;
    88 static Boolean gUseTBR = false;
    89 static double gScaleUSec = 1.0 / 1000.0;        /* 1 / ( nsec / usec) */
    89 static double gScaleUSec = 1.0 / 1000.0;        /* 1 / ( nsec / usec) */
    90 static double gScaleMSec = 1.0 / 1000000.0;     /* 1 / ( nsec / msec) */
    90 static double gScaleMSec = 1.0 / 1000000.0;     /* 1 / ( nsec / msec) */
    91 
    91 
    92 /* Functions loaded from DriverServicesLib */
    92 /* Functions loaded from DriverServicesLib */
    93 typedef AbsoluteTime (*UpTimeProcPtr) (void);
    93 typedef AbsoluteTime(*UpTimeProcPtr) (void);
    94 typedef Nanoseconds (*A2NSProcPtr) (AbsoluteTime);
    94 typedef Nanoseconds(*A2NSProcPtr) (AbsoluteTime);
    95 static UpTimeProcPtr gUpTime = NULL;
    95 static UpTimeProcPtr gUpTime = NULL;
    96 static A2NSProcPtr gA2NS = NULL;
    96 static A2NSProcPtr gA2NS = NULL;
    97 
    97 
    98 #endif /* GENERATINGPOWERPC */
    98 #endif /* GENERATINGPOWERPC */
    99 
    99 
   100 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   100 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   101 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   101 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   102 
   102 
   103 void
   103 void
   104 FastInitialize ()
   104 FastInitialize()
   105 {
   105 {
   106     SInt32 result;
   106     SInt32 result;
   107 
   107 
   108     if (!gInited) {
   108     if (!gInited) {
   109 
   109 
   113         gNative = gUseRTC = gUseTBR = false;
   113         gNative = gUseRTC = gUseTBR = false;
   114 
   114 
   115         /* We use CFM to find and load needed symbols from shared libraries, so
   115         /* We use CFM to find and load needed symbols from shared libraries, so
   116            the application doesn't have to weak-link them, for convenience.   */
   116            the application doesn't have to weak-link them, for convenience.   */
   117         gUpTime =
   117         gUpTime =
   118             (UpTimeProcPtr) FindFunctionInSharedLib ("\pDriverServicesLib",
   118             (UpTimeProcPtr) FindFunctionInSharedLib("\pDriverServicesLib",
   119                                                      "\pUpTime");
   119                                                     "\pUpTime");
   120         if (gUpTime)
   120         if (gUpTime)
   121             gA2NS = (A2NSProcPtr)
   121             gA2NS = (A2NSProcPtr)
   122                 FindFunctionInSharedLib ("\pDriverServicesLib",
   122                 FindFunctionInSharedLib("\pDriverServicesLib",
   123                                          "\pAbsoluteToNanoseconds");
   123                                         "\pAbsoluteToNanoseconds");
   124         if (!gA2NS)
   124         if (!gA2NS)
   125             gUpTime = nil;      /* Pedantic but necessary */
   125             gUpTime = nil;      /* Pedantic but necessary */
   126 
   126 
   127         if (gUpTime) {
   127         if (gUpTime) {
   128             /* If we loaded UpTime(), then we need to know if the system has
   128             /* If we loaded UpTime(), then we need to know if the system has
   129                a native implementation of the Time Manager. If so, then it's
   129                a native implementation of the Time Manager. If so, then it's
   130                pointless to calculate a scale factor against the missing VIA */
   130                pointless to calculate a scale factor against the missing VIA */
   131 
   131 
   132             /* gestaltNativeTimeMgr = 4 in some future version of the headers */
   132             /* gestaltNativeTimeMgr = 4 in some future version of the headers */
   133             if (!Gestalt (gestaltTimeMgrVersion, &result) &&
   133             if (!Gestalt(gestaltTimeMgrVersion, &result) &&
   134                 (result > gestaltExtendedTimeMgr))
   134                 (result > gestaltExtendedTimeMgr))
   135                 gNative = true;
   135                 gNative = true;
   136         } else {
   136         } else {
   137             /* If no DriverServicesLib, use Gestalt() to get the processor type. 
   137             /* If no DriverServicesLib, use Gestalt() to get the processor type. 
   138                Only NuBus PowerMacs with old System Software won't have DSL, so
   138                Only NuBus PowerMacs with old System Software won't have DSL, so
   139                we know it should either be a 601 or 603. */
   139                we know it should either be a 601 or 603. */
   140 
   140 
   141             /* Use the processor gestalt to determine which register to use */
   141             /* Use the processor gestalt to determine which register to use */
   142             if (!Gestalt (gestaltNativeCPUtype, &result)) {
   142             if (!Gestalt(gestaltNativeCPUtype, &result)) {
   143                 if (result == gestaltCPU601)
   143                 if (result == gestaltCPU601)
   144                     gUseRTC = true;
   144                     gUseRTC = true;
   145                 else if (result > gestaltCPU601)
   145                 else if (result > gestaltCPU601)
   146                     gUseTBR = true;
   146                     gUseTBR = true;
   147             }
   147             }
   151         if ((gUpTime && !gNative) || gUseRTC || gUseTBR) {
   151         if ((gUpTime && !gNative) || gUseRTC || gUseTBR) {
   152             UInt64 tick, usec1, usec2;
   152             UInt64 tick, usec1, usec2;
   153             UnsignedWide wide;
   153             UnsignedWide wide;
   154 
   154 
   155             /* Wait for the beginning of the very next tick */
   155             /* Wait for the beginning of the very next tick */
   156             for (tick = MyLMGetTicks () + 1; tick > MyLMGetTicks (););
   156             for (tick = MyLMGetTicks() + 1; tick > MyLMGetTicks(););
   157 
   157 
   158             /* Poll the selected timer and prepare it (since we have time) */
   158             /* Poll the selected timer and prepare it (since we have time) */
   159             wide = (gUpTime) ? (*gA2NS) ((*gUpTime) ()) :
   159             wide = (gUpTime) ? (*gA2NS) ((*gUpTime) ()) :
   160                 ((gUseRTC) ? PollRTC () : PollTBR ());
   160                 ((gUseRTC) ? PollRTC() : PollTBR());
   161             usec1 = (gUseRTC) ? RTCToNano (wide) : WideTo64bit (wide);
   161             usec1 = (gUseRTC) ? RTCToNano(wide) : WideTo64bit(wide);
   162 
   162 
   163             /* Wait for the exact 60th tick to roll over */
   163             /* Wait for the exact 60th tick to roll over */
   164             while (tick + 60 > MyLMGetTicks ());
   164             while (tick + 60 > MyLMGetTicks());
   165 
   165 
   166             /* Poll the selected timer again and prepare it  */
   166             /* Poll the selected timer again and prepare it  */
   167             wide = (gUpTime) ? (*gA2NS) ((*gUpTime) ()) :
   167             wide = (gUpTime) ? (*gA2NS) ((*gUpTime) ()) :
   168                 ((gUseRTC) ? PollRTC () : PollTBR ());
   168                 ((gUseRTC) ? PollRTC() : PollTBR());
   169             usec2 = (gUseRTC) ? RTCToNano (wide) : WideTo64bit (wide);
   169             usec2 = (gUseRTC) ? RTCToNano(wide) : WideTo64bit(wide);
   170 
   170 
   171             /* Calculate a scale value that will give microseconds per second.
   171             /* Calculate a scale value that will give microseconds per second.
   172                Remember, there are actually 60.15 ticks in a second, not 60.  */
   172                Remember, there are actually 60.15 ticks in a second, not 60.  */
   173             gScaleUSec = (60.0 * 1000000.0) / ((usec2 - usec1) * 60.15);
   173             gScaleUSec = (60.0 * 1000000.0) / ((usec2 - usec1) * 60.15);
   174             gScaleMSec = gScaleUSec / 1000.0;
   174             gScaleMSec = gScaleUSec / 1000.0;
   182 
   182 
   183 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   183 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   184 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   184 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   185 
   185 
   186 UInt64
   186 UInt64
   187 FastMicroseconds ()
   187 FastMicroseconds()
   188 {
   188 {
   189     UnsignedWide wide;
   189     UnsignedWide wide;
   190     UInt64 usec;
   190     UInt64 usec;
   191 
   191 
   192 #if GENERATINGPOWERPC
   192 #if GENERATINGPOWERPC
   193     /* Initialize globals the first time we are called */
   193     /* Initialize globals the first time we are called */
   194     if (!gInited)
   194     if (!gInited)
   195         FastInitialize ();
   195         FastInitialize();
   196 
   196 
   197     if (gNative) {
   197     if (gNative) {
   198         /* Use DriverServices if it's available -- it's fast and compatible */
   198         /* Use DriverServices if it's available -- it's fast and compatible */
   199         wide = (*gA2NS) ((*gUpTime) ());
   199         wide = (*gA2NS) ((*gUpTime) ());
   200         usec = (double) WideTo64bit (wide) * gScaleUSec + 0.5;
   200         usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5;
   201     } else if (gUpTime) {
   201     } else if (gUpTime) {
   202         /* Use DriverServices if it's available -- it's fast and compatible */
   202         /* Use DriverServices if it's available -- it's fast and compatible */
   203         wide = (*gA2NS) ((*gUpTime) ());
   203         wide = (*gA2NS) ((*gUpTime) ());
   204         usec = (double) WideTo64bit (wide) * gScaleUSec + 0.5;
   204         usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5;
   205     } else if (gUseTBR) {
   205     } else if (gUseTBR) {
   206         /* On a recent PowerPC, we poll the TBR directly */
   206         /* On a recent PowerPC, we poll the TBR directly */
   207         wide = PollTBR ();
   207         wide = PollTBR();
   208         usec = (double) WideTo64bit (wide) * gScaleUSec + 0.5;
   208         usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5;
   209     } else if (gUseRTC) {
   209     } else if (gUseRTC) {
   210         /* On a 601, we can poll the RTC instead */
   210         /* On a 601, we can poll the RTC instead */
   211         wide = PollRTC ();
   211         wide = PollRTC();
   212         usec = (double) RTCToNano (wide) * gScaleUSec + 0.5;
   212         usec = (double) RTCToNano(wide) * gScaleUSec + 0.5;
   213     } else
   213     } else
   214 #endif /* GENERATINGPOWERPC */
   214 #endif /* GENERATINGPOWERPC */
   215     {
   215     {
   216         /* If all else fails, suffer the mixed mode overhead */
   216         /* If all else fails, suffer the mixed mode overhead */
   217         Microseconds (&wide);
   217         Microseconds(&wide);
   218         usec = WideTo64bit (wide);
   218         usec = WideTo64bit(wide);
   219     }
   219     }
   220 
   220 
   221     return (usec);
   221     return (usec);
   222 }
   222 }
   223 
   223 
   224 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   224 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   225 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   225 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   226 
   226 
   227 UInt64
   227 UInt64
   228 FastMilliseconds ()
   228 FastMilliseconds()
   229 {
   229 {
   230     UnsignedWide wide;
   230     UnsignedWide wide;
   231     UInt64 msec;
   231     UInt64 msec;
   232 
   232 
   233 #if GENERATINGPOWERPC
   233 #if GENERATINGPOWERPC
   234     /* Initialize globals the first time we are called */
   234     /* Initialize globals the first time we are called */
   235     if (!gInited)
   235     if (!gInited)
   236         FastInitialize ();
   236         FastInitialize();
   237 
   237 
   238     if (gNative) {
   238     if (gNative) {
   239         /* Use DriverServices if it's available -- it's fast and compatible */
   239         /* Use DriverServices if it's available -- it's fast and compatible */
   240         wide = (*gA2NS) ((*gUpTime) ());
   240         wide = (*gA2NS) ((*gUpTime) ());
   241         msec = (double) WideTo64bit (wide) * gScaleMSec + 0.5;
   241         msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5;
   242     } else if (gUpTime) {
   242     } else if (gUpTime) {
   243         /* Use DriverServices if it's available -- it's fast and compatible */
   243         /* Use DriverServices if it's available -- it's fast and compatible */
   244         wide = (*gA2NS) ((*gUpTime) ());
   244         wide = (*gA2NS) ((*gUpTime) ());
   245         msec = (double) WideTo64bit (wide) * gScaleMSec + 0.5;
   245         msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5;
   246     } else if (gUseTBR) {
   246     } else if (gUseTBR) {
   247         /* On a recent PowerPC, we poll the TBR directly */
   247         /* On a recent PowerPC, we poll the TBR directly */
   248         wide = PollTBR ();
   248         wide = PollTBR();
   249         msec = (double) WideTo64bit (wide) * gScaleMSec + 0.5;
   249         msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5;
   250     } else if (gUseRTC) {
   250     } else if (gUseRTC) {
   251         /* On a 601, we can poll the RTC instead */
   251         /* On a 601, we can poll the RTC instead */
   252         wide = PollRTC ();
   252         wide = PollRTC();
   253         msec = (double) RTCToNano (wide) * gScaleMSec + 0.5;
   253         msec = (double) RTCToNano(wide) * gScaleMSec + 0.5;
   254     } else
   254     } else
   255 #endif /* GENERATINGPOWERPC */
   255 #endif /* GENERATINGPOWERPC */
   256     {
   256     {
   257         /* If all else fails, suffer the mixed mode overhead */
   257         /* If all else fails, suffer the mixed mode overhead */
   258         Microseconds (&wide);
   258         Microseconds(&wide);
   259         msec = ((double) WideTo64bit (wide) + 500.0) / 1000.0;
   259         msec = ((double) WideTo64bit(wide) + 500.0) / 1000.0;
   260     }
   260     }
   261 
   261 
   262     return (msec);
   262     return (msec);
   263 }
   263 }
   264 
   264 
   265 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   265 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   266 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   266 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   267 
   267 
   268 StringPtr
   268 StringPtr
   269 FastMethod ()
   269 FastMethod()
   270 {
   270 {
   271     StringPtr method = "\p<Unknown>";
   271     StringPtr method = "\p<Unknown>";
   272 
   272 
   273 #if GENERATINGPOWERPC
   273 #if GENERATINGPOWERPC
   274     /* Initialize globals the first time we are called */
   274     /* Initialize globals the first time we are called */
   275     if (!gInited)
   275     if (!gInited)
   276         FastInitialize ();
   276         FastInitialize();
   277 
   277 
   278     if (gNative) {
   278     if (gNative) {
   279         /* The Time Manager and UpTime() are entirely native on this machine */
   279         /* The Time Manager and UpTime() are entirely native on this machine */
   280         method = "\pNative UpTime()";
   280         method = "\pNative UpTime()";
   281     } else if (gUpTime) {
   281     } else if (gUpTime) {
   301 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   301 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   302 #pragma mark -
   302 #pragma mark -
   303 
   303 
   304 #if GENERATINGPOWERPC
   304 #if GENERATINGPOWERPC
   305 asm static UnsignedWide
   305 asm static UnsignedWide
   306 PollRTC_ ()
   306 PollRTC_()
   307 {
   307 {
   308     entry PollRTC               /* Avoid CodeWarrior glue */
   308     entry PollRTC               /* Avoid CodeWarrior glue */
   309       machine 601 @ AGAIN:mfrtcu r4     /* RTCU = SPR 4 */
   309       machine 601 @ AGAIN:mfrtcu r4     /* RTCU = SPR 4 */
   310       mfrtcl r5                 /* RTCL = SPR 5 */
   310       mfrtcl r5                 /* RTCL = SPR 5 */
   311   mfrtcu r6 cmpw r4, r6 bne @ AGAIN stw r4, 0 (r3) stw r5, 4 (r3) blr}
   311   mfrtcu r6 cmpw r4, r6 bne @ AGAIN stw r4, 0(r3) stw r5, 4(r3) blr}
   312 
   312 
   313 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   313 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   314 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   314 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   315 
   315 
   316 asm static UnsignedWide
   316 asm static UnsignedWide
   317 PollTBR_ ()
   317 PollTBR_()
   318 {
   318 {
   319     entry PollTBR               /* Avoid CodeWarrior glue */
   319     entry PollTBR               /* Avoid CodeWarrior glue */
   320       machine 604 @ AGAIN:mftbu r4      /* TBRU = SPR 268 */
   320       machine 604 @ AGAIN:mftbu r4      /* TBRU = SPR 268 */
   321       mftb r5                   /* TBRL = SPR 269 */
   321       mftb r5                   /* TBRL = SPR 269 */
   322   mftbu r6 cmpw r4, r6 bne @ AGAIN stw r4, 0 (r3) stw r5, 4 (r3) blr}
   322   mftbu r6 cmpw r4, r6 bne @ AGAIN stw r4, 0(r3) stw r5, 4(r3) blr}
   323 
   323 
   324 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   324 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   325 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   325 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
   326 
   326 
   327 static Ptr
   327 static Ptr
   328 FindFunctionInSharedLib (StringPtr libName, StringPtr funcName)
   328 FindFunctionInSharedLib(StringPtr libName, StringPtr funcName)
   329 {
   329 {
   330     OSErr error = noErr;
   330     OSErr error = noErr;
   331     Str255 errorStr;
   331     Str255 errorStr;
   332     Ptr func = NULL;
   332     Ptr func = NULL;
   333     Ptr entry = NULL;
   333     Ptr entry = NULL;
   334     CFragSymbolClass symClass;
   334     CFragSymbolClass symClass;
   335     CFragConnectionID connID;
   335     CFragConnectionID connID;
   336 
   336 
   337     /* Find CFM containers for the current archecture -- CFM-PPC or CFM-68K */
   337     /* Find CFM containers for the current archecture -- CFM-PPC or CFM-68K */
   338     if ( /* error = */ GetSharedLibrary (libName, kCompiledCFragArch,
   338     if ( /* error = */ GetSharedLibrary(libName, kCompiledCFragArch,
   339                                          kLoadCFrag, &connID, &entry,
   339                                         kLoadCFrag, &connID, &entry,
   340                                          errorStr))
   340                                         errorStr))
   341         return (NULL);
   341         return (NULL);
   342     if ( /* error = */ FindSymbol (connID, funcName, &func, &symClass))
   342     if ( /* error = */ FindSymbol(connID, funcName, &func, &symClass))
   343         return (NULL);
   343         return (NULL);
   344 
   344 
   345     return (func);
   345     return (func);
   346 }
   346 }
   347 #endif /* GENERATINGPOWERPC */
   347 #endif /* GENERATINGPOWERPC */