Longtime readers will remember that the IBM PC started out as an 8088 machine. Over time, it and the countless clones that followed grew to be 286 machines, then 386 machines, then 486 machines, then Pentium machines. With the arrival of NT, the notion of a PC clone has blurred. Machines have appeared that look to the casual observer like a high-end PC clone, but inside beats the heart of an Alpha, a Mips processor, a PowerPC, or possibly even an Intel processor.
The incursion of non-Intel CPUs into what had been a virtually all-Intel world continues to assault applications developers with a series of problems--which are, happily, closely pursued by solutions. A similar production is unfolding on the Macintosh stage, heralded by the advent of the PowerPC-toting Power Macs. Up to now, the Macintosh was a 680x0 (abbreviated as 68K hereafter) platform, and the installed base of applications software--never mind the Mac OS and Toolbox code--is a gigantic body of 68K-based code that no sane person would simply discard as a casualty necessarily incurred on the road to RISC.
ANSI C Is King
The name of the game is C. When the first edition of Inside Macintosh appeared, the language that was used to describe data structures and call sequences was Pascal. This is no longer the case, however; C is the lingua franca when working with Power Macs.
To be accurate, ANSI C is the language to use with Power Macs. To non-Mac programmers, this may seem to be a given: If you say "C," you really mean "ANSI C." Not so among Mac programmers; nonstandard constructs not only were encouraged to flourish, but in some cases were required. For example, some Toolbox routines expect--and return--parameters in registers; others use a Pascal calling convention, which places parameters atop the stack and the return address beneath.
While compiler designers can provide "wrapper" code to insulate the C program from these peculiar calling conventions, if a programmer wanted to hook a Toolbox call (i.e., provide his or her own code to replace the Toolbox routine), he or she was frequently forced into assembly language. Consequently, Mac C compilers often allowed in-line assembly code. For example, Symantec's Think C provides a non-ANSI asm{ ... } construct that permits the programmer to commingle C and assembly.
The requirement for ANSI compliance not only provides a framework by which the Mac's API can be rigorously defined, but it can also produce some performance gains. For instance, a lazy programmer might be tempted to ignore placing a return type on a function declaration for a routine that returns no value:
sillyFunc(long *x)
{ *x=*x+12;
}
In this case, the C compiler--assuming it's lax enough to permit this--will assume that noValFunction() returns an argument of type int so the compiler will emit code to return an int derived from the value of the last statement executed in the function. It's better to define the function's return type:
void sillyFunc(long *x) ...
so the compiler won't generate the unneeded code.
Finally, if you want to lessen the programming work you'll have to do to verify that your application runs on all Macs, you should remove any explicit dependence on the size of the int data type. On 68K Macs, depending on the compiler, an int could be 2 or 4 bytes (some compilers provide switches that let you toggle between the two). On the PowerPC, an int is always 4 bytes.
Preliminary Apple documentation relating to the porting process recommends you use variables of type int only to access the "natural word size" of the machine, such as the declaration of a variable used only as the index in a for loop. Use short for 2-byte integers and long for 4-byte integers.
Floating Point
Programmers familiar with SANE (Standard Apple Numeric Environment) will be saddened to know that the 64-bit comp (short for computational) data type and the 80-bit extended floating-point type are not supported on Power Macs. (The comp data type was basically a 64-bit signed integer, with the added advantage that it could return a NaN [not a number] value, useful in indicating arithmetic exceptions. The comp data type performed exact arithmetic, such as is required in accounting.) This "out with the old, in with the new" campaign is necessary because the PowerPC chip's integrated FPU handles single- and double-precision numbers (32 and 64 bits, respectively) as native data types.
What made the 80-bit extended format useful was the fact that single-precision, double-precision, and comp types could be converted to the 80-bit extended type with no loss of precision. This simplified the mixing of operands of different types. In fact, the SANE package used the extended type for all its internal calculations. Ironically, the Apple Numerics Manual referred to the single-precision, double-precision, and comp types as "application types" rather than as arithmetic types; they were deemed to have value as space-saving data structures rather than as data structures to be used during calculations.
Fortunately, if you need the precision, Power Macs do support a 128-bit long double. You will, however, pay a speed penalty; operations performed on long doubles are handled in emulation fashion rather than by the PowerPC's FPU.
Code Fragments
If you set your Wayback Machine to a little over 10 years ago, when the Macintosh was first introduced, you'll recall that the machine was delivered to the world with 128 KB of RAM. Although that was a respectable amount of RAM at that time, Mac engineers realized that an application would require more RAM than might be left free after the operating system had taken what it needed. They therefore designed the system so that applications consisted of relocatable chunks of code called segments. And, because of the limitation on the relative jump instruction within the 68000 CPU, the size of a segment was fixed at 32 KB. Although the operating system handled the headaches of loading and unloading segments, it was nonetheless left to the programmer to tell the Mac OS when a particular segment was free to be discarded (using the UnloadSeg trap).
With the introduction of Power Macs, what had been a code segment now becomes a code fragment. This is not, however, a simple change in nomenclature. Code fragments can extend beyond 32 KB, they can possess local data, and they carry named entry points. An application is really just a code fragment; when an application loads on a Power Mac, the Mac OS also loads all code fragments holding routines referenced by the application and binds the references (this is done by a new Toolbox service, the Code Fragment Manager). Code fragments are therefore very similar to dynamically linked libraries.
Note that the programmer no longer needs to get involved with memory management issues (i.e., which fragments are free to be unloaded). The reason for this, of course, is that the PowerPC has its own virtual MMU (memory management unit), so the entire mechanism for memory management moves into the operating system, where it belongs.
Mixed-Mode Programming
As I mentioned at the outset, Apple has done much work to make the transition to the PowerPC world as easy as possible. Specifically, Power Macs provide a 68K emulator that can make the machine look to the outside world like a 68020-based Mac. Actually, it looks sort of like a 68040 minus the 68040's integrated MMU and FPU. However, Apple discourages developers from presuming any instructions beyond those supported by the 68020.
This protects all the work that's been done to create the existing 68K code base. However, it would be crazy if the system ran only in emulated fashion. Not only would that guarantee less-than-optimum performance, but no smooth transition to native PowerPC applications would be possible.
Apple engineers, looking at the Mac's Toolbox code, were staring at the same porting problems that any other Mac developer would be faced with during the transition. Not only would rewriting all that code take lots of time, programmers, and money, but the process would likely introduce bugs in routines that had long since been cleansed. So, Apple programmers rewrote only critical, often-called Toolbox routines in PowerPC code, leaving the rest in 68K code. These latter routines are executed by the Power Macs' 68K emulator.
Consequently, a given Toolbox routine might be written in PowerPC code, or it might be in 68K code (and therefore require the emulator). Since it would be unimaginable to place upon the programmer the job of determining--at run time--the machine-code type of a particular routine, Apple designed the Mixed Mode Manager and armed programmers with the UPP (Universal Procedure Pointer). It works as follows.
Any exported routine in a code fragment (i.e., a routine that can be called from outside the fragment) is accessed via a UPP. Setting up the UPP is the job of the caller (i.e., the caller calls the exported routine through the UPP). If the exported routine is composed of 68K code, then the UPP consists of just a typical pointer to the address of the routine's entry point. However, if the exported routine is composed of PowerPC code, the UPP is a data structure (called a routine descriptor), typically about 32 bytes in size, headed by a trap word that leads into the Mixed Mode Manager.
Consequently, calling the UPP either leads your program directly to the 68K code or transfers control to the Mixed Mode Manager. It is the Mixed Mode Manager's job to deduce where the application is coming from and where it's going to and to determine if a switch from native PowerPC code to the 68K emulator (or back) is needed. Note that this also requires moving arguments around (e.g., from registers to the stack) so that the called routine finds data where it expects it.
Happily, C/C++ compilers for PowerPC Macs already provide functions and macros that automate the process of building UPPs. Apple guidelines suggest that, wherever your code uses a ProcPtr, you replace it with a UniversalProcPtr.
A Stroke of Genius
Faced with the admittedly daunting task of shepherding a well-established system into an entirely new processor architecture, Apple appears to be doing a remarkable job of accommodating developers during the transition. Admittedly, the transition isn't trouble-free; I have my own pile of C code that I'll have to sift through via search-and-replace and turn every int into short.
On the bright side, my opinion is that the Mixed Mode Manager (with its accompanying UPPs) is something of a stroke of genius. What it provides is a way for Apple to continue to move more of the Toolbox to native code, and programmers will see the benefits without having to make any alterations of their own.
Of course, it also means that as you target those routines that will yield the greatest performance if converted to PowerPC code, you'll be doing some code-tweaking for a while. But you're used to that, right?