Hardware Error in ALL 6502 Chips!

INTERFACE, the newsletter of Rockwell International (P. O. Box 3669, RC 55, Anaheim, CA 92803), Issue No. 2, is the source for the following information.  It should be noted by all Apple owners working in assembly language, because it could cause an almost unfindable bug!

There is an error in the JUMP INDIRECT instruction of ALL 6500 family CPU chips, no matter where they were made.  This means the error is present in ALL APPLES.  This fatal error occurs only when the low byte of the indirect pointer location happens to be $FF, as in JMP ($08FF).  Normally, the processor should fetch the low-order address byte from location $08FF, increment the program counter to $0900, and then fecth the high-order address byte from $0900.  Instead, the high-order byte of the program counter never gets incremented!  The high-order address byte gets loaded from $0800 instead of $0900!  For this reason, your program should NEVER include an instruction of the type JMP ($xxFF).

Try this example to satisfy yourself that you understand the problem:  insert the following data from the monitor.

       *800:09
       *810:6C FF 08   (this is JMP ($08FF)
       *8FF:50 0A      (pointer
       *A50:00         (BRK instruction we SHOULD reach)
       *950:00         (BRK instruction we DO reach!)

Execute the instruction at $0810 by typing 810G.  If the JMP indirect worked correctly, it would branch to location $0A50 and execute the BRK instruction there.  However, since the JMP indirect instruction has this serious flaw, it will actually branch to the BRK instruction at $0950!

Since it is very difficult to predict the final address of all pointers in a large assembly language program, unless they are all grouped in a block at the beginning of the program, I suggest that you take special measures to protect yourself against this hardware problem.  (One measure, of course, was suggested in that sentence.)  My favorite method is to avoid using the JMP indirect instruction.  It takes too long to set it up in most cases anyway.  I prefer to push the branch address (less one) onto the stack, and RTS to effect the branch.  This allows me to create the effect of an indexed JMP.  For example, suppose a command character is being decoded.  I process it into a value in the A-register between 0 and N-1 (for N commands), and do the following:

       ASL             Double to create index
       TAX                     for address table
       LDA JUMP.TABLE+1,X      High order byte
       PHA                     of branch address
       LDA JUMP.TABLE,X        Low order byte
       PHA                     of branch address
       RTS

The jump table looks like this:

       JUMP.TABLE
               .DA COMMANDA-1  The "-1" is
               .DA COMMANDB-1  on each line
               .DA COMMANDC-1  because the RTS
               .DA COMMANDD-1  adds one before
               et cetera       branching.

This trick was described by Steve Wozniak in an article in BYTE magazine back in 1977 or 1978.  It is also used by him in the Apple monitor code, and in SWEET-16.  In both of these cases, he has arranged all the command processors to be in the same page, so that the high order byte of the address can be loaded into the A-register with a load-A-immediate, and the jump table can be only one-byte-per-command.  See your Apple ROMs at locations $FFBE-FFCB (jump table at $FFE3-FFF9) and in SWEET-16 at $F69E, F6A0, F684-F6B8 (jump table at $F6E3-F702).

You can extend this idea of an indexed JMP instruction into a simulated indexed JSR instruction.  All you have to do is first push onto the stack the return address (less one), and then the branch address (less one).  I use this trick in the Message.Printer program described elsewhere in this issue.
