Skip to end of metadata
Go to start of metadata


Some Macs have a diagnostic mode that was apparently used at the factory, and probably by the TechStep diagnostic tool.

The Diagnostic Mode uses the Modem serial port at 9600 baud, 8 data bits, no parity, and 2 stop bits.  Depending on the machine and how the diagnostic mode was entered, the serial port may be outputting something like *APPLE*876543210000*1*.  The *1* there is a machine identifier.  Otherwise, the serial port may not be outputting anything, but will still accept and echo commands.

Below is a table of known identifiers:

Machine Identifiers

1Mac II(256kb ROM family)
4LaserWriter NTX
5LaserWriter NT
7Mac IIci
OIndicates the IIvx family, but the TechStep will dump the byte in memory located at $5f ff ff fc to differentiate between specific models (IIvi, P600)

 The machine will continuously output this string, even as you enter more commands.


At this point, new commands may be entered.  There are 2 classes of commands, those prefixed with a * and those prefixed with a !.


Outputs the version of the Diagnostics and System ROM. For the IIsi ROM, it outputs:

STM Version 2.0, Scott Smyers

ROM Version 7C12F1

 *SService Mode This makes the ROM stop continuously outputting the *APPLE* message. Commands can still be entered. 
*AASCII ModeSome commands take arguments. This tells the ROM that those arguments will be entered in ASCII encoded hexadecimal representation. Leading 0's are not automatically filled, so if you have a command that takes a 2 byte argument, and you want to enter '4', you would enter 0004.
*HHex ModeThis is really binary mode. It specifies that when arguments are provided to commands, they will be binary. This is the default.
*RReturn Status

This will return the current value contained in the ROM's diagnostic status register (D6), along with the current flag settings (bottom word of D7). Output will be in the form of "000000000000", 12 hexadecimal digits. The first 8 digits are the 32bits of the status, and the last 4 digits are the major error code.

The last 16bits (4 hex digits) mean:

Error ValueDescription
1ROM CheckSum
2Initial RAM failure
3RAM Bank A
4RAM Bank B
5RAM Addressing
6VIA1 access
7VIA2 access
8Data bus error accessing RAM
9MMU failure
ANuBus access failure
BSCSI failure
CIWM failure
DSCC failure
EData Bus test failure
10power manager
11Error sizing memory
12SCC IOP failure
13Error with dynamic bus sizing
14Power Manager Turn On
15RAM parity error
30Egret error
*TRun Critical Test

This runs a preprogramed test. It takes 6 bytes of arguments. The first two bytes are the test number to run. The second two bytes indicate the number of times the test should be performed. The third two bytes are options to the test.

Test NumberDescription
0Size Memory

Data Bus Test

This test will write different bit patterns to the 32bits specified in A0 (set with *0) and read back to ensure the data bus works properly.

2Mod3 RAM Test
3Address Line Test
4ROM checksum
5RevMod3 RAM Test
6Extra RAM Test
7ModInv RAM Test
8Size video RAM

Test Options:

Bit #Meaning
12stop on first failure
13loop on failure forever
14store test results in PRAM (for retrieval after booting)
15boot after test is done
*NRun Non-critical Test

Runs non-critical test. It gets run like: *N008400010000

In this case, the 84 represents the test to run in hex, and the 1 represents the number of times the test is to be performed. The test will exit on the first failure. The test returns a code in the form of: 020004030000

Typically test return codes have the top byte representing the phase of the test that had the error, and some portion of the remainder of the value representing expected and actual values for the test. Exact error results vary from test to test. The return value 0xFFFFFFFF0000 usually represents a skipped test. Tests can be skipping for a variety of reasons, including the hardware not being present on the current system.

This is a list of known tests:

Test NumberDescription
0x84-0x86SCC tests

VIA test

0x88general SCSI test
0x95more sound
0x9A53C96 SCSI
0x9B-0x9DSONIC ethernet

*LLoadAddrLoads address to be used by subequent commands (like GetData)

The number of bytes to use for the subsequent command


Tells the ROM to get the specified data (this is a put instead of a get from the perspective of the TechStep). This command takes the data as an argument, with the amount of data having previously been specified by *B, and the ROM puts the data into the address previously specified by *L.

The checksum of the data received is placed in register D6, which is returned by *R

*MMemDumpDumps the memory located at the address previously set by *L, for the number of bytes previously set by *B
*CCheckSumChecksums the memory located at the address previously set by *L, for the number of bytes previously set by *B. The result is stored in D6, which is retrievable with *R
*GExecuteTakes a 32bit argument of the address to jump to. The code is executed via a BSR6 macro
*0LoadA0Takes a 32bit argument, which is first loaded into register D6, then A0
*1LoadA1Takes a 32bit argument, which is first loaded into register D6, then A1
*2SetCacheTakes a 32bit argument, which is loaded into cache control register CACR
*3MMUOffDisables the MMU
*4ClearResultClears the result of any previously performed test
*5StartBootMsgschedules the *APPLE* boot message
*6CPUResetDoes what it says


As an example, to run the ROM test, I would do the following.  Since what gets echoed back is not necessarily what gets entered, I have divided this into two columns.


STM Version 2.0, Scott Smyers

ROM Version 7C12F1



Entering Diagnostic Mode

Diagnostic mode should be entered whenever the machine has a Sad Mac at boot time.  However, there are a couple known ways to force this to occur.  The TechStep uses the ADB method on machines that support it, and the SCSI method on all others (and as a fallback in case of ADB failure).


To enter the diagnostic mode, line PA0 of VIA1 (that's data register A, pin 0) needs to be grounded. This pin is exposed on the edge connector on the logic board on at least the IIx, IIci, and IIsi. Here is a picture of VIA1 on the IIx, with the PA0 pin labeled. Find this IC on your motherboard, and check for continuity between this pin and pads on the edge connector to find which pin on your logic board is the appropriate one:

IIx VIAs.jpg

When the system boots with this pin pulled to ground, the system will chime, but not display any video.


On machines with the Egret ADB transceiver (>= IIsi?), diagnostic mode can be entered via ADB.  Unfortunately, this can't be done with a normal keyboard, and requires a special device to send the proper code.  Here is a Saleae Logic capture of the sequence: TechStep ADB TM Enter.logicdata

To summarize, it follows the following steps:

  1. Start with the machine off
  2. Power on the machine via ADB by bringing the POWER.ON line low
  3. Once +5V comes on, release the POWER.ON line, allowing it to be pulled high by the host.  This usually takes ~200ms
  4. Give the machine some time to boot.  ~800ms
  5. Lower the POWER.ON line again
  6. Wait for the host to issue a TALK to address 2 (keyboard), register 2 (modifier keys)
  7. Respond with 0xE6
  8. For the next 10 TALK addr 2 reg 2 requests, respond with 0xEE.
  9. The computer should give bad chimes and be in diagnostic mode.

The TechStep presents a hard disk to the host at SCSI ID 6.  The "disk" consists of 5 blocks of 512 bytes, with block 0 consisting of the driver descriptor record, blocks 1-3 consisting of an Apple Partition Map that has a fake Apple_HFS volume, and an Apple_Driver partition.  The Apple_Driver partition and block 0 point to block 4 for the driver.  The driver consists of the following code as captured while booting a Performa 600 into diagnostic mode from a TechStep via SCSI:

move.a.w #$4000,a7       ; putting a new value in the stack pointer
movel #$8046fc, (a7+) ; putting something on the stack
pmove (a6), tc ; functionally disables translation, forcing 32bit mode, for the following instruction
movea.l #$50f26000, a7 ; RBV VIA2 address for vBuf2
moveb #$47, (a7+)
movea.w #9984, a7
movew #8193, d0
movec d0, cacr ; instruction cache and write allocate only
movel #504462720, d7 ; d7 is used in diagnostic mode to keep some flags, so presumably this is just initializing things
movel $7c, d0 ; The following two lines setup the NMI exception handler for trap 15
movel d0, $bc ;
trap #15 ; equivalent of NMI?
ori.b #0, d0 ; probably bad. this is just 0x0000, so kinda not trusting anything after that trap
movea.w #$4000, a7
move.l #8388608, (a7+)

Essentially, this is a fancy way of hitting the NMI button.  This image contains the 5 blocks the TechStep sends: techstep_disk.dsk  This is for a IIvx, IIvi, or Performa 600.

The pseudo-disk the TechStep presents seems to be different depending on the machine it is configured to be talking to.  Here is one for a IIci: techstep_iici_disk.dsk


Hitting the Programmer's Interrupt switch shortly after powering the machine on, such as when the cursor is displayed but before booting is attempted, will cause the machine to have the "chimes of death" and display a Sad Mac.

On later machines that don't have a programmer's switch, pressing cmd-power can have the same effect.

Sample TechStep Transaction

Below are some sample transactions observed from the TechStep.  In these tables, even if the protocol is in binary mode (*H was specified), I am writing the hexadecimal notation as if it were in ASCII (*A) mode.  This means it will always have two characters per byte, I'm not omitting leading 0's.

When arguments are specified to commands, the arguments are loaded into register D1.  If more than 4 bytes are specified, the first four bytes are usually read in, then transferred to another register (D0 in the case of *T), and then the remaining bytes are read into D1.  So for instance, if *200000000 is specified to load the value into register A1, the value is also loaded into D1 as a side effect, which can be used by subsequent commands that don't explicitly take arguments, like *3.

The TechStep does not send CR or LF, although the ROM will ignore them if sent.  The TechStep will, by default, send them when it echos commands back.


This conversation seems to precede any other actual tests being performed, just to verify communication is fine:

*A Enter ASCII Mode
*H Enter binary mode
*4 Clears any existing status value
*000000000 The command is 0, which means to load the following value into A0. Since we're in binary mode (*H above), the value is four bytes of zeros.

Command is *T, which means to execute the specified test. The argument is 2 bytes of test number, 2 bytes of number of times to run the test, and 2 bytes of options. Again, since we're in binary mode, the argument is specified as binary of test #1, 1 iteration, and an option of 1.

Test #1 tests the data bus.

*R Requests the return value of the test
 000000000000*RThe computer sends the return value before echoing the command. We're in binary mode, so the return code is binary, consisting of 6 bytes of 0's (if successful).
TechStep Requests CPUID on IIsi
*L00044000 Says to load the address 0x00044000
*B0008 Specifies a byte count of 8

Puts the specified data (8 bytes as specified by the earlier *B) at the address specified by the previous *L.

Disassembles as:

MOVEA.L #$000E0000,SP


Basically put 0x000E0000 on the stack and return

*G00044000 Execute via BSR6 starting at the address specified
 *GEchos after execution is complete
 000001DC0000*R000001DC is the contents of D6, which is the checksum from *D earlier. The trailing 0000 is the lower word of D7.
*200000000 Sets CACR to 0
*3 Disables MMU
*000000000 Loads A0 with 0's
*T000100010001 Run databus test once
*004000000 Loads A0 with 0x04000000

STM Version 2.0, Scott Smyers

ROM Version 7C12F1


*5 Start continuously outputting the boot message (*APPLE*000000000000*C*)
*S Stop continuously outputting the boot message.



  • None