Software - Where-Am-I routines

On the 65816, when the location of a program is not known until run time, the program can use PER and PHK to determine where it is. On the 6502 and 65C02, the WHEREAMI routine can be used for this purpose.

Using JSR

One way to implement WHEREAMI is to place it routine at known location (e.g. in ROM) and call it via JSR, i.e.:

HERE JSR WHEREAMI1

The JSR pushes HERE+2 onto the stack, then WHEREAMI gets the return address (HERE+2) from the stack. It is often useful to return an offset from the address of the JSR rather than just the address of the JSR plus two, i.e. HERE+2+constant rather than HERE+2. So WHEREAMI1 returns HERE+2+A in A (low byte) and Y (high byte). Note that X is overwritten.

WHEREAMI2 is an alternate entry point that returns HERE+2+A+C and is useful if the value of the carry is known prior to the JSR.

WHEREAMI1 CLC
WHEREAMI2 TSX
          INX
          ADC $100,X ; add lo byte of return address
          INX
          LDY $100,X ; hi byte of return address
          BCC SKIP
          INY
SKIP      RTS

WHEREAMI works for all values of S (the stack pointer). In most cases, S will have been initialized to $FF; then, by the time the TSX is executed S will be less than $FE, so the two INXs could be eliminated by using $101,X and $102,X. This only saves 2 bytes and 4 cycles, though.

Using BRK

Using JSR requires that WHEREAMI be at a known address. An alternative is to use BRK, i.e.

HERE BRK

The BRK handler below returns HERE+2+A in A (low byte) and Y (high byte). Again, X is overwritten. Also, note that RTI skips the byte after the BRK instruction, i.e. RTI returns to HERE+2 rather than HERE+1.

;
     CLC
     TSX
     INX
     INX
     ADC $100,X ; add lo byte of return address
     INX
     LDY $100,X ; hi byte of return address
     BCC SKIP
     INY
SKIP RTI

Again the INXs could be eliminated, assuming that S is less than $FD.

Using a RAM buffer

Another option is to store a routine at a known, but safe, location, and then JSR to that location. For example, a program is usually not going to be on the zero page, so it would be safe to store a short routine there, and JSR to it. If necessary, those zero page locations could be saved (on the stack), then restored when finished.

The routine below needs a 4-byte safe location. The usual reason to find HERE+2 is to store it in a zero page pointer. If the next two zero page locations are also available, then the pointer (and the following two locations) could be used as the safe area.

Another usually safe location is the bottom of page 1, (i.e. starting at $100), because (1) a program will usually not be there, (2) the stack pointer is usually initialized to start at the top of page 1 (i.e. $1FF), and (3) stack usage will usually not be so heavy as to extend all the way down to $100.

After:

; At LOC to LOC+3, store:
;   LDA $100,X
;   RTS
;
     LDA #$BD
     STA LOC
     LDA #1
     STA LOC+2
     LSR       ; A = $00, sets carry
     STA LOC+1
     LDA #$60
     STA LOC+3
     TSX
     DB  $90   ; BCC (skips the CLC, since the carry is set)
LOOP CLC
     TAY
HERE JSR LOC
     DEX
     BCS LOOP

A contains the high byte of HERE+2, and Y contains the low byte of HERE+2

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License