I have a function that should be callable with the following syntax:
void __fastcall__ initSIDplayer1(uint8_t a);
The __fastcall__
modifier here means that the argument is passed in the Accu instead of the software stack. The address is given as 16-bit address, for example, 0x1000 for a SID player file that is loaded with or before the main program.
I have used the following line to define the function with the specified address:
static void __fastcall__ (*initSIDplayer1)(uint8_t)=(const void *)0x1000;
The approach works, but the compiler generates a lot of code in comparison to the statically defined function initSIDplayer1
:
;
; code generated for initSIDplayer1(1);
;
lda #$61
jsr _initSIDplayer
;
; code generated for initSIDplayer2('a');
;
lda _initSIDplayer2
ldx _initSIDplayer2+1
jsr pushax
lda #$61
pha
ldy #$00
lda (sp),y
sta jmpvec+1
iny
lda (sp),y
sta jmpvec+2
pla
jsr jmpvec
jsr incsp2
The generated code for initSIDplayer2 writes the target address into memory (using two stack operations) and then jumps to that memory address-1 where it executes another jmp. This is a very flexible, but slow and cumbersome approach.
How do I need to write the function definition with the given address so that the compiler translates it into a simple jsr ADDR
call like with initSIDplayer1
?
I know that this can be also done with inline assembler or an external assembler file, but I would be interested in the C code syntax.
For completeness, this is the minimum test program:
#include <stdint.h>
void __fastcall__ initSIDplayer1(uint8_t a);
static void __fastcall__ (*initSIDplayer2)(uint8_t)=(const void *)0xFFD2;
void main() {
initSIDplayer1('a');
initSIDplayer2('a');
}
I compiled it with cc65 function.c
which generates an .s
file.
.o
file? AFAIR cc65 only delivers a.s
(to be later assembled using ca65, wouldn't it? Did you maybe use cl65 instead?.segment "DATA"
) as that's why it builds the jump table from before jumping. It essentially ignores theconst
part. Now we only need to look why.