mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-22 21:29:50 +00:00
Added example of work-around for passing parameters to call by pointer function.
This commit is contained in:
parent
6fe60c6ad5
commit
66b3daa62f
@ -3248,6 +3248,11 @@ public class TestPrograms {
|
||||
compileAndCompare("pointer-pointer-1.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionPointerParamWorkaround() throws IOException, URISyntaxException {
|
||||
compileAndCompare("function-pointer-param-workaround.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionPointerNoargCall14() throws IOException, URISyntaxException {
|
||||
compileAndCompare("function-pointer-noarg-call-14.c");
|
||||
|
58
src/test/kc/function-pointer-param-workaround.c
Normal file
58
src/test/kc/function-pointer-param-workaround.c
Normal file
@ -0,0 +1,58 @@
|
||||
// Demonstrates work-around for passing parameters to function pointers
|
||||
#pragma target(c64)
|
||||
|
||||
// Save the return address, declare parameter variables
|
||||
#define PARAM_BEGIN volatile unsigned int ret_addr; char param_char; asm { pla sta ret_addr pla sta ret_addr+1 }
|
||||
|
||||
// Restore the return address
|
||||
#define PARAM_END asm { lda ret_addr+1 pha lda ret_addr pha }
|
||||
|
||||
// Declare and pull a char parameter
|
||||
#define PARAM_CHAR(name) asm { pla sta param_char } char name=param_char;
|
||||
|
||||
// Begin passing parameters using the stack. Declares parameter variables.
|
||||
#define CALL_BEGIN char param_char;
|
||||
|
||||
// Pass a char parameter
|
||||
#define CALL_CHAR(name) param_char=name; asm { lda param_char pha }
|
||||
|
||||
char * const SCREEN1 = 0x0400;
|
||||
char * const SCREEN2 = 0x0428;
|
||||
|
||||
volatile char idx1 = 0;
|
||||
volatile char idx2 = 0;
|
||||
|
||||
void fn1() {
|
||||
PARAM_BEGIN;
|
||||
PARAM_CHAR(b);
|
||||
PARAM_CHAR(c);
|
||||
PARAM_END;
|
||||
// Function body
|
||||
SCREEN1[idx1++] = b;
|
||||
SCREEN1[idx1++] = c;
|
||||
}
|
||||
|
||||
void fn2() {
|
||||
PARAM_BEGIN;
|
||||
PARAM_CHAR(b);
|
||||
PARAM_CHAR(c);
|
||||
PARAM_END;
|
||||
// Function body
|
||||
SCREEN2[idx2++] = b;
|
||||
SCREEN2[idx2++] = c;
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
void()* fns[2] = { &fn1, &fn2 };
|
||||
|
||||
for(char i='a';i<='p';i++)
|
||||
for(char j=0;j<2;j++) {
|
||||
CALL_BEGIN;
|
||||
CALL_CHAR(i);
|
||||
CALL_CHAR(j);
|
||||
void()* f = fns[j];
|
||||
(*f)();
|
||||
}
|
||||
|
||||
}
|
162
src/test/ref/function-pointer-param-workaround.asm
Normal file
162
src/test/ref/function-pointer-param-workaround.asm
Normal file
@ -0,0 +1,162 @@
|
||||
// Demonstrates work-around for passing parameters to function pointers
|
||||
// Save the return address, declare parameter variables
|
||||
// Restore the return address
|
||||
// Declare and pull a char parameter
|
||||
// Begin passing parameters using the stack. Declares parameter variables.
|
||||
// Pass a char parameter
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="function-pointer-param-workaround.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(__start)
|
||||
.label SCREEN1 = $400
|
||||
.label SCREEN2 = $428
|
||||
.label idx1 = 4
|
||||
.label idx2 = 5
|
||||
.segment Code
|
||||
__start: {
|
||||
// idx1 = 0
|
||||
lda #0
|
||||
sta.z idx1
|
||||
// idx2 = 0
|
||||
sta.z idx2
|
||||
jsr main
|
||||
rts
|
||||
}
|
||||
fn2: {
|
||||
.label ret_addr = 6
|
||||
.label param_char = 8
|
||||
// PARAM_BEGIN
|
||||
lda #<0
|
||||
sta.z ret_addr
|
||||
sta.z ret_addr+1
|
||||
sta.z param_char
|
||||
pla
|
||||
sta ret_addr
|
||||
pla
|
||||
sta ret_addr+1
|
||||
// PARAM_CHAR
|
||||
pla
|
||||
sta param_char
|
||||
tay
|
||||
pla
|
||||
sta param_char
|
||||
tax
|
||||
// PARAM_END
|
||||
lda ret_addr+1
|
||||
pha
|
||||
lda ret_addr
|
||||
pha
|
||||
// SCREEN2[idx2++] = b
|
||||
// Function body
|
||||
tya
|
||||
ldy.z idx2
|
||||
sta SCREEN2,y
|
||||
// SCREEN2[idx2++] = b;
|
||||
inc.z idx2
|
||||
// SCREEN2[idx2++] = c
|
||||
ldy.z idx2
|
||||
txa
|
||||
sta SCREEN2,y
|
||||
// SCREEN2[idx2++] = c;
|
||||
inc.z idx2
|
||||
// }
|
||||
rts
|
||||
}
|
||||
fn1: {
|
||||
.label ret_addr = 9
|
||||
.label param_char = $b
|
||||
// PARAM_BEGIN
|
||||
lda #<0
|
||||
sta.z ret_addr
|
||||
sta.z ret_addr+1
|
||||
sta.z param_char
|
||||
pla
|
||||
sta ret_addr
|
||||
pla
|
||||
sta ret_addr+1
|
||||
// PARAM_CHAR
|
||||
pla
|
||||
sta param_char
|
||||
tay
|
||||
pla
|
||||
sta param_char
|
||||
tax
|
||||
// PARAM_END
|
||||
lda ret_addr+1
|
||||
pha
|
||||
lda ret_addr
|
||||
pha
|
||||
// SCREEN1[idx1++] = b
|
||||
// Function body
|
||||
tya
|
||||
ldy.z idx1
|
||||
sta SCREEN1,y
|
||||
// SCREEN1[idx1++] = b;
|
||||
inc.z idx1
|
||||
// SCREEN1[idx1++] = c
|
||||
ldy.z idx1
|
||||
txa
|
||||
sta SCREEN1,y
|
||||
// SCREEN1[idx1++] = c;
|
||||
inc.z idx1
|
||||
// }
|
||||
rts
|
||||
}
|
||||
main: {
|
||||
.label param_char = $c
|
||||
.label f = $d
|
||||
.label j = 3
|
||||
.label i = 2
|
||||
lda #'a'
|
||||
sta.z i
|
||||
__b1:
|
||||
// for(char i='a';i<='p';i++)
|
||||
lda #'p'
|
||||
cmp.z i
|
||||
bcs __b4
|
||||
// }
|
||||
rts
|
||||
__b4:
|
||||
lda #0
|
||||
sta.z j
|
||||
__b2:
|
||||
// for(char j=0;j<2;j++)
|
||||
lda.z j
|
||||
cmp #2
|
||||
bcc __b3
|
||||
// for(char i='a';i<='p';i++)
|
||||
inc.z i
|
||||
jmp __b1
|
||||
__b3:
|
||||
// CALL_BEGIN
|
||||
lda #0
|
||||
sta.z param_char
|
||||
// CALL_CHAR
|
||||
lda.z i
|
||||
sta.z param_char
|
||||
pha
|
||||
lda.z j
|
||||
sta.z param_char
|
||||
pha
|
||||
// f = fns[j]
|
||||
lda.z j
|
||||
asl
|
||||
tay
|
||||
lda fns,y
|
||||
sta.z f
|
||||
lda fns+1,y
|
||||
sta.z f+1
|
||||
// (*f)()
|
||||
jsr bi_f
|
||||
// for(char j=0;j<2;j++)
|
||||
inc.z j
|
||||
jmp __b2
|
||||
bi_f:
|
||||
jmp (f)
|
||||
.segment Data
|
||||
fns: .word fn1, fn2
|
||||
}
|
84
src/test/ref/function-pointer-param-workaround.cfg
Normal file
84
src/test/ref/function-pointer-param-workaround.cfg
Normal file
@ -0,0 +1,84 @@
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
[0] phi()
|
||||
to:__start::__init1
|
||||
__start::__init1: scope:[__start] from __start
|
||||
[1] idx1 = 0
|
||||
[2] idx2 = 0
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start::__init1
|
||||
[3] phi()
|
||||
[4] call main
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
[5] return
|
||||
to:@return
|
||||
|
||||
void fn2()
|
||||
fn2: scope:[fn2] from
|
||||
[6] fn2::ret_addr = 0
|
||||
[7] fn2::param_char = 0
|
||||
asm { pla staret_addr pla staret_addr+1 }
|
||||
asm { pla staparam_char }
|
||||
[10] fn2::b#0 = fn2::param_char
|
||||
asm { pla staparam_char }
|
||||
[12] fn2::c#0 = fn2::param_char
|
||||
asm { ldaret_addr+1 pha ldaret_addr pha }
|
||||
[14] SCREEN2[idx2] = fn2::b#0
|
||||
[15] idx2 = ++ idx2
|
||||
[16] SCREEN2[idx2] = fn2::c#0
|
||||
[17] idx2 = ++ idx2
|
||||
to:fn2::@return
|
||||
fn2::@return: scope:[fn2] from fn2
|
||||
[18] return
|
||||
to:@return
|
||||
|
||||
void fn1()
|
||||
fn1: scope:[fn1] from
|
||||
[19] fn1::ret_addr = 0
|
||||
[20] fn1::param_char = 0
|
||||
asm { pla staret_addr pla staret_addr+1 }
|
||||
asm { pla staparam_char }
|
||||
[23] fn1::b#0 = fn1::param_char
|
||||
asm { pla staparam_char }
|
||||
[25] fn1::c#0 = fn1::param_char
|
||||
asm { ldaret_addr+1 pha ldaret_addr pha }
|
||||
[27] SCREEN1[idx1] = fn1::b#0
|
||||
[28] idx1 = ++ idx1
|
||||
[29] SCREEN1[idx1] = fn1::c#0
|
||||
[30] idx1 = ++ idx1
|
||||
to:fn1::@return
|
||||
fn1::@return: scope:[fn1] from fn1
|
||||
[31] return
|
||||
to:@return
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start::@1
|
||||
[32] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@4
|
||||
[33] main::i#2 = phi( main/'a', main::@4/main::i#1 )
|
||||
[34] if(main::i#2<='p') goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[35] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1 main::@3
|
||||
[36] main::j#2 = phi( main::@1/0, main::@3/main::j#1 )
|
||||
[37] if(main::j#2<2) goto main::@3
|
||||
to:main::@4
|
||||
main::@4: scope:[main] from main::@2
|
||||
[38] main::i#1 = ++ main::i#2
|
||||
to:main::@1
|
||||
main::@3: scope:[main] from main::@2
|
||||
[39] main::param_char = 0
|
||||
[40] main::param_char = main::i#2
|
||||
asm { ldaparam_char pha }
|
||||
[42] main::param_char = main::j#2
|
||||
asm { ldaparam_char pha }
|
||||
[44] main::$3 = main::j#2 << 1
|
||||
[45] main::f#0 = main::fns[main::$3]
|
||||
[46] call *main::f#0
|
||||
[47] main::j#1 = ++ main::j#2
|
||||
to:main::@2
|
1058
src/test/ref/function-pointer-param-workaround.log
Normal file
1058
src/test/ref/function-pointer-param-workaround.log
Normal file
File diff suppressed because it is too large
Load Diff
47
src/test/ref/function-pointer-param-workaround.sym
Normal file
47
src/test/ref/function-pointer-param-workaround.sym
Normal file
@ -0,0 +1,47 @@
|
||||
const nomodify byte* SCREEN1 = (byte*) 1024
|
||||
const nomodify byte* SCREEN2 = (byte*) 1064
|
||||
void __start()
|
||||
void fn1()
|
||||
byte fn1::b
|
||||
byte fn1::b#0 reg byte y 1.0
|
||||
byte fn1::c
|
||||
byte fn1::c#0 reg byte x 1.0
|
||||
volatile byte fn1::param_char loadstore zp[1]:11 1.2000000000000002
|
||||
volatile word fn1::ret_addr loadstore zp[2]:9 0.2857142857142857
|
||||
void fn2()
|
||||
byte fn2::b
|
||||
byte fn2::b#0 reg byte y 1.0
|
||||
byte fn2::c
|
||||
byte fn2::c#0 reg byte x 1.0
|
||||
volatile byte fn2::param_char loadstore zp[1]:8 1.2000000000000002
|
||||
volatile word fn2::ret_addr loadstore zp[2]:6 0.2857142857142857
|
||||
volatile byte idx1 loadstore zp[1]:4 1.272727272727273
|
||||
volatile byte idx2 loadstore zp[1]:5 1.272727272727273
|
||||
void main()
|
||||
byte~ main::$3 reg byte a 2002.0
|
||||
void()* main::f
|
||||
void()* main::f#0 f zp[2]:13 1001.0
|
||||
const void()** main::fns[2] = { &fn1, &fn2 }
|
||||
byte main::i
|
||||
byte main::i#1 i zp[1]:2 202.0
|
||||
byte main::i#2 i zp[1]:2 100.3076923076923
|
||||
byte main::j
|
||||
byte main::j#1 j zp[1]:3 2002.0
|
||||
byte main::j#2 j zp[1]:3 500.5
|
||||
volatile byte main::param_char loadstore zp[1]:12 1501.5
|
||||
|
||||
zp[1]:2 [ main::i#2 main::i#1 ]
|
||||
zp[1]:3 [ main::j#2 main::j#1 ]
|
||||
zp[1]:4 [ idx1 ]
|
||||
zp[1]:5 [ idx2 ]
|
||||
zp[2]:6 [ fn2::ret_addr ]
|
||||
zp[1]:8 [ fn2::param_char ]
|
||||
reg byte y [ fn2::b#0 ]
|
||||
reg byte x [ fn2::c#0 ]
|
||||
zp[2]:9 [ fn1::ret_addr ]
|
||||
zp[1]:11 [ fn1::param_char ]
|
||||
reg byte y [ fn1::b#0 ]
|
||||
reg byte x [ fn1::c#0 ]
|
||||
zp[1]:12 [ main::param_char ]
|
||||
reg byte a [ main::$3 ]
|
||||
zp[2]:13 [ main::f#0 ]
|
Loading…
Reference in New Issue
Block a user