comparison src/timer/macos/FastTimes.c @ 1662:782fd950bd46 SDL-1.3

Revamp of the video system in progress - adding support for multiple displays, multiple windows, and a full video mode selection API. WARNING: None of the video drivers have been updated for the new API yet! The API is still under design and very fluid. The code is now run through a consistent indent format: indent -i4 -nut -nsc -br -ce The headers are being converted to automatically generate doxygen documentation.
author Sam Lantinga <slouken@libsdl.org>
date Sun, 28 May 2006 13:04:16 +0000
parents 14717b52abc0
children 4da1ee79c9af
comparison
equal deleted inserted replaced
1661:281d3f4870e5 1662:782fd950bd46
18 #include <Timer.h> 18 #include <Timer.h>
19 19
20 #include "FastTimes.h" 20 #include "FastTimes.h"
21 21
22 #ifdef TARGET_CPU_PPC 22 #ifdef TARGET_CPU_PPC
23 #undef GENERATINGPOWERPC /* stop whining */ 23 #undef GENERATINGPOWERPC /* stop whining */
24 #define GENERATINGPOWERPC TARGET_CPU_PPC 24 #define GENERATINGPOWERPC TARGET_CPU_PPC
25 #endif 25 #endif
26 26
27 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ 27 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
28 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ 28 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
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 FastInitialize() { 103 void
104 SInt32 result; 104 FastInitialize ()
105 105 {
106 if (!gInited) { 106 SInt32 result;
107 107
108 #if GENERATINGPOWERPC 108 if (!gInited) {
109 109
110 /* Initialize the feature flags */ 110 #if GENERATINGPOWERPC
111 gNative = gUseRTC = gUseTBR = false; 111
112 112 /* Initialize the feature flags */
113 /* We use CFM to find and load needed symbols from shared libraries, so 113 gNative = gUseRTC = gUseTBR = false;
114 the application doesn't have to weak-link them, for convenience. */ 114
115 gUpTime = (UpTimeProcPtr) FindFunctionInSharedLib( 115 /* We use CFM to find and load needed symbols from shared libraries, so
116 "\pDriverServicesLib", "\pUpTime"); 116 the application doesn't have to weak-link them, for convenience. */
117 if (gUpTime) gA2NS = (A2NSProcPtr) FindFunctionInSharedLib( 117 gUpTime =
118 "\pDriverServicesLib", "\pAbsoluteToNanoseconds"); 118 (UpTimeProcPtr) FindFunctionInSharedLib ("\pDriverServicesLib",
119 if (!gA2NS) gUpTime = nil; /* Pedantic but necessary */ 119 "\pUpTime");
120 120 if (gUpTime)
121 if (gUpTime) { 121 gA2NS = (A2NSProcPtr)
122 /* If we loaded UpTime(), then we need to know if the system has 122 FindFunctionInSharedLib ("\pDriverServicesLib",
123 a native implementation of the Time Manager. If so, then it's 123 "\pAbsoluteToNanoseconds");
124 pointless to calculate a scale factor against the missing VIA */ 124 if (!gA2NS)
125 125 gUpTime = nil; /* Pedantic but necessary */
126 /* gestaltNativeTimeMgr = 4 in some future version of the headers */ 126
127 if (!Gestalt(gestaltTimeMgrVersion, &result) && 127 if (gUpTime) {
128 (result > gestaltExtendedTimeMgr)) 128 /* If we loaded UpTime(), then we need to know if the system has
129 gNative = true; 129 a native implementation of the Time Manager. If so, then it's
130 } 130 pointless to calculate a scale factor against the missing VIA */
131 else { 131
132 /* If no DriverServicesLib, use Gestalt() to get the processor type. 132 /* gestaltNativeTimeMgr = 4 in some future version of the headers */
133 Only NuBus PowerMacs with old System Software won't have DSL, so 133 if (!Gestalt (gestaltTimeMgrVersion, &result) &&
134 we know it should either be a 601 or 603. */ 134 (result > gestaltExtendedTimeMgr))
135 135 gNative = true;
136 /* Use the processor gestalt to determine which register to use */ 136 } else {
137 if (!Gestalt(gestaltNativeCPUtype, &result)) { 137 /* If no DriverServicesLib, use Gestalt() to get the processor type.
138 if (result == gestaltCPU601) gUseRTC = true; 138 Only NuBus PowerMacs with old System Software won't have DSL, so
139 else if (result > gestaltCPU601) gUseTBR = true; 139 we know it should either be a 601 or 603. */
140 } 140
141 } 141 /* Use the processor gestalt to determine which register to use */
142 142 if (!Gestalt (gestaltNativeCPUtype, &result)) {
143 /* Now calculate a scale factor to keep us accurate. */ 143 if (result == gestaltCPU601)
144 if ((gUpTime && !gNative) || gUseRTC || gUseTBR) { 144 gUseRTC = true;
145 UInt64 tick, usec1, usec2; 145 else if (result > gestaltCPU601)
146 UnsignedWide wide; 146 gUseTBR = true;
147 147 }
148 /* Wait for the beginning of the very next tick */ 148 }
149 for(tick = MyLMGetTicks() + 1; tick > MyLMGetTicks(); ); 149
150 150 /* Now calculate a scale factor to keep us accurate. */
151 /* Poll the selected timer and prepare it (since we have time) */ 151 if ((gUpTime && !gNative) || gUseRTC || gUseTBR) {
152 wide = (gUpTime) ? (*gA2NS)((*gUpTime)()) : 152 UInt64 tick, usec1, usec2;
153 ((gUseRTC) ? PollRTC() : PollTBR()); 153 UnsignedWide wide;
154 usec1 = (gUseRTC) ? RTCToNano(wide) : WideTo64bit(wide); 154
155 155 /* Wait for the beginning of the very next tick */
156 /* Wait for the exact 60th tick to roll over */ 156 for (tick = MyLMGetTicks () + 1; tick > MyLMGetTicks (););
157 while(tick + 60 > MyLMGetTicks()); 157
158 158 /* Poll the selected timer and prepare it (since we have time) */
159 /* Poll the selected timer again and prepare it */ 159 wide = (gUpTime) ? (*gA2NS) ((*gUpTime) ()) :
160 wide = (gUpTime) ? (*gA2NS)((*gUpTime)()) : 160 ((gUseRTC) ? PollRTC () : PollTBR ());
161 ((gUseRTC) ? PollRTC() : PollTBR()); 161 usec1 = (gUseRTC) ? RTCToNano (wide) : WideTo64bit (wide);
162 usec2 = (gUseRTC) ? RTCToNano(wide) : WideTo64bit(wide); 162
163 163 /* Wait for the exact 60th tick to roll over */
164 /* Calculate a scale value that will give microseconds per second. 164 while (tick + 60 > MyLMGetTicks ());
165 Remember, there are actually 60.15 ticks in a second, not 60. */ 165
166 gScaleUSec = (60.0 * 1000000.0) / ((usec2 - usec1) * 60.15); 166 /* Poll the selected timer again and prepare it */
167 gScaleMSec = gScaleUSec / 1000.0; 167 wide = (gUpTime) ? (*gA2NS) ((*gUpTime) ()) :
168 } 168 ((gUseRTC) ? PollRTC () : PollTBR ());
169 169 usec2 = (gUseRTC) ? RTCToNano (wide) : WideTo64bit (wide);
170 #endif /* GENERATINGPOWERPC */ 170
171 171 /* Calculate a scale value that will give microseconds per second.
172 /* We've initialized our globals */ 172 Remember, there are actually 60.15 ticks in a second, not 60. */
173 gInited = true; 173 gScaleUSec = (60.0 * 1000000.0) / ((usec2 - usec1) * 60.15);
174 } 174 gScaleMSec = gScaleUSec / 1000.0;
175 } 175 }
176 176 #endif /* GENERATINGPOWERPC */
177 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ 177
178 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ 178 /* We've initialized our globals */
179 179 gInited = true;
180 UInt64 FastMicroseconds() { 180 }
181 UnsignedWide wide; 181 }
182 UInt64 usec; 182
183 183 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
184 #if GENERATINGPOWERPC 184 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
185 /* Initialize globals the first time we are called */ 185
186 if (!gInited) FastInitialize(); 186 UInt64
187 187 FastMicroseconds ()
188 if (gNative) { 188 {
189 /* Use DriverServices if it's available -- it's fast and compatible */ 189 UnsignedWide wide;
190 wide = (*gA2NS)((*gUpTime)()); 190 UInt64 usec;
191 usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5; 191
192 } 192 #if GENERATINGPOWERPC
193 else if (gUpTime) { 193 /* Initialize globals the first time we are called */
194 /* Use DriverServices if it's available -- it's fast and compatible */ 194 if (!gInited)
195 wide = (*gA2NS)((*gUpTime)()); 195 FastInitialize ();
196 usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5; 196
197 } 197 if (gNative) {
198 else if (gUseTBR) { 198 /* Use DriverServices if it's available -- it's fast and compatible */
199 /* On a recent PowerPC, we poll the TBR directly */ 199 wide = (*gA2NS) ((*gUpTime) ());
200 wide = PollTBR(); 200 usec = (double) WideTo64bit (wide) * gScaleUSec + 0.5;
201 usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5; 201 } else if (gUpTime) {
202 } 202 /* Use DriverServices if it's available -- it's fast and compatible */
203 else if (gUseRTC) { 203 wide = (*gA2NS) ((*gUpTime) ());
204 /* On a 601, we can poll the RTC instead */ 204 usec = (double) WideTo64bit (wide) * gScaleUSec + 0.5;
205 wide = PollRTC(); 205 } else if (gUseTBR) {
206 usec = (double) RTCToNano(wide) * gScaleUSec + 0.5; 206 /* On a recent PowerPC, we poll the TBR directly */
207 } 207 wide = PollTBR ();
208 else 208 usec = (double) WideTo64bit (wide) * gScaleUSec + 0.5;
209 #endif /* GENERATINGPOWERPC */ 209 } else if (gUseRTC) {
210 { 210 /* On a 601, we can poll the RTC instead */
211 /* If all else fails, suffer the mixed mode overhead */ 211 wide = PollRTC ();
212 Microseconds(&wide); 212 usec = (double) RTCToNano (wide) * gScaleUSec + 0.5;
213 usec = WideTo64bit(wide); 213 } else
214 } 214 #endif /* GENERATINGPOWERPC */
215 215 {
216 return(usec); 216 /* If all else fails, suffer the mixed mode overhead */
217 } 217 Microseconds (&wide);
218 218 usec = WideTo64bit (wide);
219 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ 219 }
220 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ 220
221 221 return (usec);
222 UInt64 FastMilliseconds() { 222 }
223 UnsignedWide wide; 223
224 UInt64 msec; 224 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
225 225 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
226 #if GENERATINGPOWERPC 226
227 /* Initialize globals the first time we are called */ 227 UInt64
228 if (!gInited) FastInitialize(); 228 FastMilliseconds ()
229 229 {
230 if (gNative) { 230 UnsignedWide wide;
231 /* Use DriverServices if it's available -- it's fast and compatible */ 231 UInt64 msec;
232 wide = (*gA2NS)((*gUpTime)()); 232
233 msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5; 233 #if GENERATINGPOWERPC
234 } 234 /* Initialize globals the first time we are called */
235 else if (gUpTime) { 235 if (!gInited)
236 /* Use DriverServices if it's available -- it's fast and compatible */ 236 FastInitialize ();
237 wide = (*gA2NS)((*gUpTime)()); 237
238 msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5; 238 if (gNative) {
239 } 239 /* Use DriverServices if it's available -- it's fast and compatible */
240 else if (gUseTBR) { 240 wide = (*gA2NS) ((*gUpTime) ());
241 /* On a recent PowerPC, we poll the TBR directly */ 241 msec = (double) WideTo64bit (wide) * gScaleMSec + 0.5;
242 wide = PollTBR(); 242 } else if (gUpTime) {
243 msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5; 243 /* Use DriverServices if it's available -- it's fast and compatible */
244 } 244 wide = (*gA2NS) ((*gUpTime) ());
245 else if (gUseRTC) { 245 msec = (double) WideTo64bit (wide) * gScaleMSec + 0.5;
246 /* On a 601, we can poll the RTC instead */ 246 } else if (gUseTBR) {
247 wide = PollRTC(); 247 /* On a recent PowerPC, we poll the TBR directly */
248 msec = (double) RTCToNano(wide) * gScaleMSec + 0.5; 248 wide = PollTBR ();
249 } 249 msec = (double) WideTo64bit (wide) * gScaleMSec + 0.5;
250 else 250 } else if (gUseRTC) {
251 #endif /* GENERATINGPOWERPC */ 251 /* On a 601, we can poll the RTC instead */
252 { 252 wide = PollRTC ();
253 /* If all else fails, suffer the mixed mode overhead */ 253 msec = (double) RTCToNano (wide) * gScaleMSec + 0.5;
254 Microseconds(&wide); 254 } else
255 msec = ((double) WideTo64bit(wide) + 500.0) / 1000.0; 255 #endif /* GENERATINGPOWERPC */
256 } 256 {
257 257 /* If all else fails, suffer the mixed mode overhead */
258 return(msec); 258 Microseconds (&wide);
259 } 259 msec = ((double) WideTo64bit (wide) + 500.0) / 1000.0;
260 260 }
261 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ 261
262 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ 262 return (msec);
263 263 }
264 StringPtr FastMethod() { 264
265 StringPtr method = "\p<Unknown>"; 265 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
266 266 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
267 #if GENERATINGPOWERPC 267
268 /* Initialize globals the first time we are called */ 268 StringPtr
269 if (!gInited) FastInitialize(); 269 FastMethod ()
270 270 {
271 if (gNative) { 271 StringPtr method = "\p<Unknown>";
272 /* The Time Manager and UpTime() are entirely native on this machine */ 272
273 method = "\pNative UpTime()"; 273 #if GENERATINGPOWERPC
274 } 274 /* Initialize globals the first time we are called */
275 else if (gUpTime) { 275 if (!gInited)
276 /* Use DriverServices if it's available -- it's fast and compatible */ 276 FastInitialize ();
277 method = "\pUpTime()"; 277
278 } 278 if (gNative) {
279 else if (gUseTBR) { 279 /* The Time Manager and UpTime() are entirely native on this machine */
280 /* On a recent PowerPC, we poll the TBR directly */ 280 method = "\pNative UpTime()";
281 method = "\pPowerPC TBR"; 281 } else if (gUpTime) {
282 } 282 /* Use DriverServices if it's available -- it's fast and compatible */
283 else if (gUseRTC) { 283 method = "\pUpTime()";
284 /* On a 601, we can poll the RTC instead */ 284 } else if (gUseTBR) {
285 method = "\pPowerPC RTC"; 285 /* On a recent PowerPC, we poll the TBR directly */
286 } 286 method = "\pPowerPC TBR";
287 else 287 } else if (gUseRTC) {
288 #endif /* GENERATINGPOWERPC */ 288 /* On a 601, we can poll the RTC instead */
289 { 289 method = "\pPowerPC RTC";
290 /* If all else fails, suffer the mixed mode overhead */ 290 } else
291 method = "\pMicroseconds()"; 291 #endif /* GENERATINGPOWERPC */
292 } 292 {
293 293 /* If all else fails, suffer the mixed mode overhead */
294 return(method); 294 method = "\pMicroseconds()";
295 } 295 }
296
297 return (method);
298 }
296 299
297 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ 300 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
298 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ 301 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
299 #pragma mark - 302 #pragma mark -
300 303
301 #if GENERATINGPOWERPC 304 #if GENERATINGPOWERPC
302 asm static UnsignedWide PollRTC_() { 305 asm static UnsignedWide
303 entry PollRTC /* Avoid CodeWarrior glue */ 306 PollRTC_ ()
304 machine 601 307 {
305 @AGAIN: 308 entry PollRTC /* Avoid CodeWarrior glue */
306 mfrtcu r4 /* RTCU = SPR 4 */ 309 machine 601 @ AGAIN:mfrtcu r4 /* RTCU = SPR 4 */
307 mfrtcl r5 /* RTCL = SPR 5 */ 310 mfrtcl r5 /* RTCL = SPR 5 */
308 mfrtcu r6 311 mfrtcu r6 cmpw r4, r6 bne @ AGAIN stw r4, 0 (r3) stw r5, 4 (r3) blr}
309 cmpw r4,r6 312
310 bne @AGAIN 313 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
311 stw r4,0(r3) 314 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
312 stw r5,4(r3) 315
313 blr 316 asm static UnsignedWide
314 } 317 PollTBR_ ()
315 318 {
316 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ 319 entry PollTBR /* Avoid CodeWarrior glue */
317 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ 320 machine 604 @ AGAIN:mftbu r4 /* TBRU = SPR 268 */
318 321 mftb r5 /* TBRL = SPR 269 */
319 asm static UnsignedWide PollTBR_() { 322 mftbu r6 cmpw r4, r6 bne @ AGAIN stw r4, 0 (r3) stw r5, 4 (r3) blr}
320 entry PollTBR /* Avoid CodeWarrior glue */ 323
321 machine 604 324 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
322 @AGAIN: 325 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
323 mftbu r4 /* TBRU = SPR 268 */ 326
324 mftb r5 /* TBRL = SPR 269 */ 327 static Ptr
325 mftbu r6 328 FindFunctionInSharedLib (StringPtr libName, StringPtr funcName)
326 cmpw r4,r6 329 {
327 bne @AGAIN 330 OSErr error = noErr;
328 stw r4,0(r3) 331 Str255 errorStr;
329 stw r5,4(r3) 332 Ptr func = NULL;
330 blr 333 Ptr entry = NULL;
331 } 334 CFragSymbolClass symClass;
332 335 CFragConnectionID connID;
333 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ 336
334 /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ 337 /* Find CFM containers for the current archecture -- CFM-PPC or CFM-68K */
335 338 if ( /* error = */ GetSharedLibrary (libName, kCompiledCFragArch,
336 static Ptr FindFunctionInSharedLib(StringPtr libName, StringPtr funcName) { 339 kLoadCFrag, &connID, &entry,
337 OSErr error = noErr; 340 errorStr))
338 Str255 errorStr; 341 return (NULL);
339 Ptr func = NULL; 342 if ( /* error = */ FindSymbol (connID, funcName, &func, &symClass))
340 Ptr entry = NULL; 343 return (NULL);
341 CFragSymbolClass symClass; 344
342 CFragConnectionID connID; 345 return (func);
343 346 }
344 /* Find CFM containers for the current archecture -- CFM-PPC or CFM-68K */ 347 #endif /* GENERATINGPOWERPC */
345 if (/* error = */ GetSharedLibrary(libName, kCompiledCFragArch, 348 /* vi: set ts=4 sw=4 expandtab: */
346 kLoadCFrag, &connID, &entry, errorStr)) return(NULL);
347 if (/* error = */ FindSymbol(connID, funcName, &func, &symClass))
348 return(NULL);
349
350 return(func);
351 }
352 #endif /* GENERATINGPOWERPC */