Balance of Power:
 The Power Macintosh: The Next Generation

Dave Evans

The Power Macintosh computer just keeps moving forward. The latest generation
brings greatly improved performance and adds the PCI expansion bus and the PowerPC
603 and 604 processors. Software changes that improve performance include the
following:

I'll describe these new features and discuss how you can maintain compatibility with
the new Power Macintosh computers and with future changes to the Mac OS.

THE IMPROVED EMULATOR

First delivered with the Power Macintosh 9500 computer, the new emulator improves
on the original in one key way: it actually recompiles 680x0 code into native PowerPC
code. Since large portions of the Mac OS are still in 680x0 code, this new emulator
speeds up most common operations and offers significant improvements for 680x0
code with tight loops.

Recompiling doesn't mean converting 680x0 instructions one for one into PowerPC
instructions. Fully emulating a 680x0 instruction still takes a few PowerPC
instructions. But recompiled code is more efficient and optimized. The original
emulator had to decipher each instruction every time it was executed, but recompiled
code from the new emulator is analyzed once and then executed many times.

Because it takes extra time to recompile code, the emulator doesn't immediately
translate all 680x0 code. It operates just like its predecessor until it encounters a
loop or similar repetition. Then, instead of emulating the same code repeatedly, it
translates the instructions into native code and caches the result. Subsequent calls to
that code simply execute the native translation, greatly improving performance.

The cache of translated 680x0 code must stay coherent with memory, much like the
caches on the Motorola 68040 processor. Therefore, whenever your software modifies
code or changes application jump tables, you should flush the instruction cache. (See
the Macintosh Technical Note "Cache as Cache Can" (HW 6) for a more detailed
description of cases where flushing the instruction cache is necessary.) In the past you
could call Gestalt and check the processor type to flush only on a 68040. Since the new
emulator supports only the 68020 instruction set -- and Gestalt will indicate that a
68020 is installed -- you should now flush any time you modify code or change jump
tables.

The best way to flush 680x0 code in the cache is with FlushCodeCacheRange, which
flushes only the invalid portion of the emulator's cache. FlushInstructionCache also
works but can degrade performance by wastefully purging recompiled code that's still
valid. These routines are documented inInside Macintosh: Memory. The C prototype for
FlushCodeCacheRange is as follows:

 

OSErr FlushCodeCacheRange(void *address,
   unsigned long count);

 

In 680x0 assembly, you would use

MyFlushCodeCacheRange Proc
   ; On entry A0 = address, D0 = # of bytes
   ; Trashes A0, A1, D0. Result in D0, Z bit set.
   ;
   movea.l      D0,A1      ; # bytes in A1
   moveq         #$9,D0      ; selector
   _HWPriv               ; A098
   tst.w         D0         ; result == noErr
   rts

 

OTHER SOFTWARE CHANGES

The first Power Macintosh computer ported critical portions of the Macintosh Toolbox
to native PowerPC code. Ultimately we'll take all of the Mac OS native, but for now
we've focused on areas that most increase overall performance. So, starting with the
Power Macintosh 9500, we've added a native Resource Manager, the native Open
Transport networking stack, and native device drivers. I'll discuss each of these in
turn and then mention improvements to the Modern Memory Manager.

Even though many calls to the Resource Manager are bound by I/O bottlenecks, porting
the Resource Manager to native PowerPC code still substantially improves
performance. Often to complete a request the Resource Manager need only look up
existing information and return it, and even if file I/O is required the data is often in
the system disk cache. For these reasons, many Resource Manager calls will execute
much faster on the new machines.

Native Open Transport networking provides a stream-based interface for networking
that's independent of the network protocol. You can now implement a variety of
network solutions without concerning yourself with protocol details. Documentation on
Open Transport is provided on this issue's CD.

Native device drivers provide both a performance improvement and an improved
system programming interface (SPI). This SPI is available with all PCI-based
Macintosh computers, starting with the Power Macintosh 9500. For more information
on these drivers, see the article "Creating PCI Device Drivers" indevelop Issue 22 and
Designing PCI Cards and Drivers for Power Macintosh Computers, available from
Apple Developer Catalog.

Although not new, the native Modern Memory Manager has been improved in two
important ways:

Handles passed to the Memory Manager now go through a rigorous check before they
can affect other Memory Manager data structures; however, without the nearly
foolproof bus error handling, it's a little more likely that you'll pass an invalid
address and crash. If you crash in the MemoryMgr code fragment while testing on the
new Power Macintosh computers, you probably passed an invalid pointer or handle.
You can use the Debugging Modern Memory Manager to aggressively catch these
application errors.

Note also that the bus error handlers would allow system (and even application) heaps
to become corrupted, deteriorating the overall user experience without causing the
machine to crash. This is much less likely to happen now, but if structures do get
corrupted other than by the Memory Manager, a system crash will result.

Also available starting with the latest Power Macintosh machines is support for very
large hard disk volumes. In the past, only 2-gigabyte volumes were allowed; then with
System 7.5 we relaxed that restriction to 4-gigabyte volumes. But many of you were
still hungry for more, so now we allow up to 2 terabytes (that's 2000 gigabytes) of
file system address space per volume. Unless you're developing utilities and drivers
compatible with the new volume sizes, though, you really don't need to pay attention to
the new large-volume support, because the API remains unchanged. The only time an
application might want to take advantage of the new support is when it wants to know
before attempting to save to disk whether there's enough free space on the volume.
Even in this case, the application won't be able to save a file bigger than the existing
limit of 2 GB, and the old version of GetVInfo will return values that are "high-water
marked" at 2 GB for compatibility reasons, even if more space is available.

If you really do want to know how much space is available, you can do so through an
extension to the File Manager API. We extended the API because the existing 32-bit
size information was too small to address volumes and files larger than 4 GB. You'll
use the following new routine to get 64-bit sizes:

 

pascal OSErr PBXGetVolInfo(XVolumeParam
               paramBlock, Boolean async);

 

 

This routine takes an extended VolumeParam structure, named XVolumeParam, which
you'll find declared in an updated Files.h interface file on the CD. Before using this
routine, be sure to call Gestalt with the gestaltFSAttr selector; if the response
parameter has the gestaltFSSupports2TBVolumes bit set, the new routine is available.
Note that there are also extended Read and Write calls for drivers that want to support
volumes larger than 4 GB.

PCI AND NUBUS

Starting with the PCI-based Power Macintosh computers, support for the
NuBus(TM)-specific Slot Manager goes away. Some applications used to call the Slot
Manager directly to get video and other device information. This will no longer work,
so we've provided better methods: the Display Manager API has been extended for all
the video device information you'll need, and the new Name Registry API will give you
device information independent of the specific expansion bus implementation.

One example of the improved Display Manager API is the way you get display modes for
video devices. With the Slot Manager this took a lot of code, but the Display Manager
gives you one encompassing routine:

 

pascal OSErr DMNewDisplayModeList(
               GDHandle theGDevice,
               unsigned long reserved,
               unsigned long *modeCount,
               DMListType *theDisplayModeList,
               unsigned long modeListFlags);

 

 

With this and other new Display Manager routines, you can avoid the Slot Manager
altogether when gathering display information. But if you must access other device
information, you can use the bus-neutral Name Registry, which manages a tree of
device objects that you can access as a linked list. Look for the new header files
(Displays.h and NameRegistry.h) on this issue's CD.

MAINTAINING COMPATIBILITY

As Apple improves the Mac OS, compatibility with the documented APIs and SPIs is
ensured -- but don't assume that if your application runs fine on existing machines, it
will continue to do so in the future. We can't ensure complete compatibility if
application code makes invalid assumptions or uses unsupported parts of the Mac OS.
There are some things you can do to help ensure that your applications will run on
future versions of the Mac OS.  First, use only the officially documented APIs. For
example, don't assume that the Z status bit will be set correctly on exit from a trap
unless it's documented. As we take more traps native, the 680x0 status register
becomes irrelevant and such checks break. Here's an example of 680x0 code that now
breaks because it assumes the Z status bit will be set by Get1Resource:

 

move.l      #'DAVE',-(sp)
clr.w      -(sp)
_Get1Resource
beq.s      error         ; BAD!

 

 

You also shouldn't expect results in registers if the trap isn't documented to return
them there. It's true that some traps used to accidentally exit with useful data in
register D0 or A0, but if that's not documented as part of the API it won't be supported
in the future.

Second, test your software using EvenBetterBusError, the Debugging Modern Memory
Manager, and any other debugging tools that are appropriate (look in the Testing &
Debugging folder on the CD). Stress-testing your software with these tools will catch
many errors that otherwise would go unnoticed. EvenBetterBusError catches most
stray references to nil, such as writing to location 0 or using nil pointers and handles.
The Debugging Modern Memory Manager catches those occasions when you damage a
heap or pass invalid addresses.

Finally, as I've said in previous columns, don't use RS/6000 POWER instructions in
your native code. Although the PowerPC 601 processor supports many of them, the
new 603 and 604 processors do not. We've made an attempt to emulate the POWER
instructions in software for these new processors, but this emulation is very
expensive. When a 603 or 604 encounters one  of these now-illegal instructions, it
stops everything and calls our new illegal-instruction handler, which recognizes the
instruction that was used and attempts to use a valid one instead. This operation is very
time consuming; if your performance-critical code includes POWER instructions,
you'll see a severe slowdown. As described in this column in develop Issue 21, you
should use the DumpXCOFF tool to check your code for any POWER instructions.

NEW DIRECTIONS

Apple will continue to take advantage of RISC technology and will both improve existing
performance and add new functionality. Make sure your code uses documented
interfaces so that it will stay compatible and run on future generations of the Power
Macintosh. And be sure to check out Open Transport and PCI device drivers -- they're
exciting new directions that will take you closer to the next generation of the Mac OS
today.

DAVE EVANS and fellow Apple engineer Rus Maxham rode 2000 miles on their
motorcycles this summer. They journeyed through the lush Central Valley of
California, the blistering heat of the southern Arizona deserts, and the neon glitz of Las
Vegas. Along the way they enjoyed the camaraderie of fellow bikers and were rescued in
their hour of need by a sympathetic motorcycling couple who housed them as Rus
rebuilt his BMW's rear drive assembly.*

Thanks to Bill Knott, Eric Traut, and Jack Valois for reviewing this column.*

Special thanks to Randy and Peggy Marlatt of Flagstaff, Arizona, for road support.*