!lm12
!rm75
Implementing New Opcodes Using 'BRK'.......Bob Sander-Cederlof

If you have the Autostart ROM, you can control what happens when a BRK instruction is executed.  If you do nothing, a BRK will cause entry into the Apple Monitor, and the register contents will be displayed.  But (if you have the Autostart Monitor) by a small amount of programming you can make the BRK do marvelous things.

Like simulate neat instructions from the 6809, which are not in the 6502.  I am thinking particularly of the LEAX instruction, which loads the effective address into a 16-bit register; of the BSR, which enters a subroutine like JSR, but with a relative address; and BRA, which is a relatively addressed JMP.  With these three instructions you can write position-independent programs (programs that execute properly without any modification regardless of where they are loaded in memory).

I am thinking of these because of an article by A. Sato in "Lab Letters" (a publication of ESD Laboratories in Tokyo, JAPAN) Volume 6 No. 1, pages 91-93.  It is all written in Japanese (see example below), but I think I deciphered what he is saying.

When a BRK instruction is executed, the program is interrupted as though a Non-Maskable Interrupt (NMI) occurred.  The B bit in the status register is set, so the Apple can tell that the interrupt was caused by BRK rather than some external event.  After making this determination, the Autostart Monitor performs a "JMP ($3F0)" instruction.  This means that you can get control by placing the address of your own program into $3F0 and $3F1.  The monitor initialization process puts the address $FA59 there.

By the time the monitor branches to the BRK processor (its own or yours) all the registers have been saved.  The address of the BRK instruction plus 2 (PC) has been saved at $3A and $3B; the registers A, X, Y, P (status), and S (stack pointer) have been saved in $45 through $49, respectively.

In the program below, lines 1180-1230 will set up the BRK-vector at $3F0 and $3F1 to point to your own BRK processor.  Lines 1250-1320 back up the PC value by one, to point at the byte immediately following the BRK instruction.  At this point I can decide what to do about the BRK.

Since I want to simulate the operation of LEAX, BSR, and BRA, I will use the BRK instruction to introduce a pseudo instruction of three bytes.  I decided to copy A. Sato on this.  LEAX is a BRK instruction followed by LDX from an absolute address.  This is $AE in hexadecimal, followed by a 16-bit value representing a relative address.  BSR is BRK followed by a JSR instruction ($20) and a relative address; BRA is BRK followed by a JMP instruction ($4C) and a relative address.

Looking back at the program, lines 1310 and 1320 store the address of the secondary opcode byte into PNTR and PNTR+1.  These two bytes are inside an instruction at line 1760.  I didn't want to use any page-zero space, so I had to resort to this kind of self-modifying code.  While we are here, lines 1750-1780 pick up the byte whose address is in PNTR.  Lines 1710-1740 increment PNTR.  If we call GET.THIS.BYTE, it just picks up the byte currently pointed at.  If we call GET.NEXT.BYTE, it increments the pointer and gets the next byte.

Lines 1330-1370 pick up the three bytes which follow the BRK.  The opcode byte is saved in the Y-register.  Lines 1380-1450 compute the effective address, by adding the actual address of the instruction to the relative address inside the instruction.

Lines 1470-1540 classify the opcode; if it is one of the three we have implemented, it branches to the appropriate code.  If not, it jumps back into the monitor and processes the BRK in the normal monitor way.

Lines 1560-1690 implement the three opcodes BSR, BRA, and LEAX.
