Documentation of the new feature:
http://cc65.github.io/doc/cc65.html#ss7.17That looks nice. I think it could use a little clarification of how the function is called. What does an example "trampoline" routine look like? It says the bank parameter is in tmp4, and the address of the function is in ptr4, but that doesn't really tell the whole story.
I'd imagine it is something like this:
- 1. Temporarily preserve A/X/Y (arguments) if overwritten by bankswitch.
- 2. Preserve current bank on the stack.
- 3. Perform the bankswitch using tmp4.
- 4. Restore A/X/Y if needed.
- 5. Call the function via ptr4.
- 6. Temporarily preserve A/X (return) if overwritten by bankswitch.
- 7. Fetch the original bank from the stack and bankswitch.
- 8. Restore A/X if needed.
- 9. Return.
Would this be a valid trampoline function?
Code:
trampoline:
; preserve A/X arguments
sta tmp1
stx tmp2
; remember current bank
lda current_bank
pha
; bankswitch (UNROM style)
lda tmp4
tax
sta bank_table, X
; call function
lda tmp1
ldx tmp2
jsr @call
; preserve A/X
sta tmp1
stx tmp2
; restore original bank
pla
tax
sta bank_table, X
; restore A/X return value
lda tmp1
ldx tmp2
rts
@call:
jmp (ptr4)
You said in some of the
github comments that your trampoline is only 10 bytes though. How did you manage that? (Are you implicitly only allowing void functions with no arguments?)
It also seems prudent to put the CRT in a fixed bank (e.g. 16/16 mapper arrangement, UNROM). I saw some comments about putting the trampoline in RAM, but I think 32k banks would be a hassle anyway. You'd have to jump through a few hoops to get the CRT linked in more than one place, probably not worth the effort.