Function Indirection

I am aware of four known ways to handle function indirection with the 65816/Apple IIgs. As none of them were appropriate for LCC-816, I’ve also devised a new method. I can’t claim it is novel but I am unaware of any previous usage.

Self-Modifying Code

The simplest and most performant way, used by assembly language programmers, is to simply use self-modifying code.

    lda function
    sta @sm+1
    lda function+1
    sta @sm+2
@sm jsl $000000

ORCA/Pascal also uses self-modifying code for object indirection calls with optimize flag $0020.

JSL Via RTL

ORCA/C and ORCA/Pascal manipulate the stack and dispatch via an RTL.

    ldx function+2
    lda function
    phx   
    pha   
    lda 1,s
    dec a
    pha   
    sep #$20
    longa off
    longi on
    lda 5,s
    sta 3,s
    lda #^@return
    sta 6,s
    rep #$20
    longa on
    longi on
    lda #@return
    sta 4,s
    rtl 
@return  
    ...

JML

ORCA/Modula2 uses JML [address] to dispatch. However, JML [address] is utterly broken and always reads from an absolute address in bank 0. Thus, to make use of it, self-modifying code is used.

    lda >function+2
    tay   
    lda >function
    tyx   
    sta <tmp
    stx <tmp+2
    phb   
    phk   
    plb   
    ldy #$0000
    tdc   
    clc   
    adc #tmp
    per @sm
    sta ($01,s),y
    pla   
    plb   
    phk   
    per @return
@sm     
    jml [$0000]
@return

JML (Revisted)

JML [address] and JMP (address) always read from bank 0 and are generally unusable in GS/OS since you don’t know where your stack/direct page will be. But the GS/OS loader knows where your stack is and will tell you if you ask nicely. The key is to create a named stack/direct page segment. Whenever and wherever you refer to the label, the GS/OS relocator will update it to the actual location in memory.

MyDP    STACK
    ds 1024
    ENDSTACK
...
    ; create rtl address
    phk
    per @return-1
    lda function
    sta MyDP
    lda function+2
    sta MyDP+2
    jml [|MyDP]
@return

(That will use DP location 0-3.)

Function Stub

The 65816 has an instruction that pushes the return address on the stack – JSL. We can load the address into the a/x registers and call a trampoline function to dispatch to the real function.

    lda function
    ldx function+2
    jsl __jsl_ax
    ...
__jsl_ax
    short x
    phx
    long x
    dec
    pha
    rtl

This is the method LCC-816 uses. This is primarily for the benefit of the optimizer – self modifying code and screwing around with the stack make it hard to reason about. But you have to admit it looks a lot nicer, too!

MPW PascalIIgs uses this technique as well, though I was not aware of that when I discovered it.

Near Functions

LCC-816 supports near functions, which are always within the same bank and use JSR/RTS for dispatch and return instead of JSL/RTL. This makes function indirection easier – JSR (absolute,X) can be used.

    ldx function
    jsr ($0000,x)