]> git.sur5r.net Git - cc65/blob - doc/cc65-intern.sgml
Merge pull request #688 from ops/cbmkernalasm
[cc65] / doc / cc65-intern.sgml
1 <!doctype linuxdoc system>
2
3 <article>
4 <title>cc65 internals
5 <author><url url="mailto:bbbradsmith@users.noreply.github.com" name="Brad Smith">
6 <date>2016-02-27
7
8 <abstract>
9 Internal details of cc65 code generation,
10 such as calling assembly functions from C.
11 </abstract>
12
13 <!-- Table of contents -->
14 <toc>
15
16 <!-- Begin the document -->
17
18
19
20 <sect>Calling assembly functions from C<p>
21
22 <sect1>Calling conventions<p>
23
24 There are two calling conventions used in cc65:
25
26 <itemize>
27   <item><tt/cdecl/ - passes all parameters on the C-stack.
28   <p>
29   <item><tt/fastcall/ - passes the rightmost parameter in
30   registers <tt>A/X/sreg</tt> and all others on the C-stack.
31   <p>
32 </itemize>
33
34 The default convention is <tt/fastcall/, but this can be changed with
35 the <tt/--all-cdecl/ command line option. If a convention is specified in
36 the function's declaration, that convention will be used instead.
37 Variadic functions will always use <tt/cdecl/ convention.
38
39 If the <tt/--standard/ command line option is used,
40 the <tt/cdecl/ and <tt/fastcall/ keywords will not be available.
41 The standard compliant variations <tt/__cdecl__/ and <tt/__fastcall__/ are always available.
42
43 If a function has a prototype, parameters are pushed to the C-stack as their respective types
44 (i.e. a <tt/char/ parameter will push 1 byte), but if a function has no prototype, default
45 promotions will apply. This means that with no prototype, <tt/char/ will be promoted
46 to <tt/int/ and be pushed as 2 bytes. K &amp; R style function prototypes may be used,
47 but they will function the same as if no prototype was used.
48
49 <sect1>Prologue, before the function call<p>
50
51 If the function is declared as fastcall, the rightmost argument will be loaded into
52 the <tt>A/X/sreg</tt> registers:
53
54 <itemize>
55   <item><tt/A/ - 8-bit parameter, or low byte of larger types<p>
56   <item><tt/X/ - 16-bit high byte, or second byte of 32-bits<p>
57   <item><tt/sreg/ - Zeropage pseudo-register including high 2 bytes of 32-bit parameter<p>
58 </itemize>
59
60 All other parameters will be pushed to the C-stack from left to right.
61 The rightmost parameter will have the lowest address on the stack,
62 and multi-byte parameters will have their least significant byte at the lower address.
63
64 The <tt/sp/ pseudo-register is a zeropage pointer to the base of the C-stack.
65 If the function has no prototype or is variadic
66 the <tt/Y/ register will contain the number of bytes pushed to the stack for this function.
67
68 Example:
69 <tscreen><verb>
70 // C prototype
71 void cdecl foo(unsigned bar, unsigned char baz);
72
73 ; C-stack layout within the function:
74 ;
75 ;            +------------------+
76 ;            | High byte of bar |
77 ; Offset 2 ->+------------------+
78 ;            | Low byte of bar  |
79 ; Offset 1 ->+------------------+
80 ;            | baz              |
81 ; Offset 0 ->+------------------+
82
83 ; Example code for accessing bar. The variable is in A/X after this code snippet:
84 ;
85     ldy     #2      ; Offset of high byte of bar
86     lda     (sp),y  ; High byte now in A
87     tax             ; High byte now in X
88     dey             ; Offset of low byte of bar
89     lda     (sp),y  ; Low byte now in A
90 </verb></tscreen>
91
92 <sect1>Epilogue, after the function call<p>
93
94 <sect2>Return requirements<p>
95
96 If the function has a return value, it will appear in the <tt>A/X/sreg</tt> registers.
97
98 Functions with an 8-bit return value (<tt/char/ or <tt/unsigned char/) are expected
99 to promote this value to a 16-bit integer on return, and store the high byte in <tt/X/.
100 The compiler will depend on the promoted value in some cases (e.g. implicit conversion to <tt/int/),
101 and failure to return the high byte in <tt/X/ will cause unexpected errors.
102 This problem does not apply to the <tt/sreg/ pseudo-register, which is only
103 used if the return type is 32-bit.
104
105 If the function has a void return type, the compiler will not depend on the result
106 of <tt>A/X/sreg</tt>, so these may be clobbered by the function.
107
108 The C-stack pointer <tt/sp/ must be restored by the function to its value before the
109 function call prologue. It may pop all of its parameters from the C-stack
110 (e.g. using the <tt/runtime/ function <tt/popa/),
111 or it could adjust <tt/sp/ directly.
112 If the function has no prototype, or is variadic the <tt/Y/ register contains the
113 number of bytes pushed to the stack on entry, which may be added to <tt/sp/ to restore its original state.
114
115 The internal pseudo-register <tt/regbank/ must not be changed by the function.
116
117 <sect2>Clobbered state<p>
118
119 The <tt/Y/ register may be clobbered by the function.
120 The compiler will not depend on its state after a function call.
121
122 The <tt>A/X/sreg</tt> registers may be clobbered if any of them
123 are not used by the return value (see above).
124
125 Many of the internal pseudo-registers used by cc65 are available for
126 free use by any function called by C, and do not need to be preserved.
127 Note that if another C function is called from your assembly function,
128 it may clobber any of these itself:
129
130 <itemize>
131   <item><tt>tmp1 .. tmp4</tt><p>
132   <item><tt>ptr1 .. ptr4</tt><p>
133   <item><tt>regsave</tt><p>
134   <item><tt>sreg</tt> (if unused by return)<p>
135 </itemize>
136
137
138
139 </article>
140