From fd708d30ecda1ab46a83cb3af4d0915f88948c5d Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Fri, 26 Feb 2016 17:11:11 -0500 Subject: [PATCH 1/5] draft of cc65-intern document --- doc/cc65-intern.sgml | 138 +++++++++++++++++++++++++++++++++++++++++++ doc/index.sgml | 3 + 2 files changed, 141 insertions(+) create mode 100644 doc/cc65-intern.sgml diff --git a/doc/cc65-intern.sgml b/doc/cc65-intern.sgml new file mode 100644 index 000000000..f3aef939a --- /dev/null +++ b/doc/cc65-intern.sgml @@ -0,0 +1,138 @@ + + +
+cc65 internals +<author><url url="mailto:brad@rainwarrior.ca" name="Brad Smith"> +<date>2016-02-27 + +<abstract> +Internal details of cc65 code generation, +such as calling assembly functions from C. +</abstract> + +<!-- Table of contents --> +<toc> + +<!-- Begin the document --> + + + +<sect>Calling assembly functions from C<p> + +<sect1>Calling conventions<p> + +There are two calling conventions used in cc65: + +<itemize> + <item><tt/cdecl/ - passes all parameters on the C-stack. + <p> + <item><tt/fastcall/ - passes the rightmost parameter in + registers <tt>A/X/sreg</tt> an all others on the C-stack. + <p> +</itemize> + +The default convention is <tt/fastcall/, but this can be changed with +the <tt/--all-cdecl/ command line option. If a convention is specified in +the function's declaration, that convention will be used instead. +Variadic functions will always use <tt/cdecl/ convention. + +If the <tt/--standard/ command line option is used, +the <tt/cdecl/ and <tt/fastcall/ keywords will not be available. +The standard compliant variations <tt/__cdecl__/ and <tt/__fastcall__/ are always available. + +K & R style function prototypes may be used, but they do not alter the calling conventions in any way. + +<sect1>Prologue, before the function call<p> + +If the function is declared as fastcall, the rightmost argument will be loaded into +the <tt>A/X/sreg</tt> registers: + +<itemize> + <item><tt/A/ - 8-bit parameter, or low byte of larger tyes<p> + <item><tt/X/ - 16-bit high byte, or second byte of 32-bits<p> + <item><tt/sreg/ - Zeropage pseudo-register including high 2 bytes of 32-bit parameter<p> +</itemize> + +All other parameters will be pushed to the C-stack from left to right. +The rightmost parameter will have the lowest address on the stack, +and multi-byte parameters will have their least significant byte at the lower address. + +The <tt/Y/ register will contain the number of bytes pushed to the stack for this function, +and the <tt/sp/ pseudo-register is a zeropage pointer to the base of the C-stack. + +Example: +<tscreen><verb> +// C prototype +void foo(unsigned bar, unsigned char baz); + +; C-stack layout within the function: +; +; +------------------+ +; | High byte of bar | +; Offset 2 ->+------------------+ +; | Low byte of bar | +; Offset 1 ->+------------------+ +; | baz | +; Offset 0 ->+------------------+ + +; Example code for accessing bar. The variable is in A/X after this code snippet: +; + ldy #2 ; Offset of high byte of bar + lda (sp),y ; High byte now in A + tax ; High byte now in X + dey ; Offset of low byte of bar + lda (sp),y ; Low byte now in A +</verb></tscreen> + +Variadic functions push all parameters exactly as other <tt/cdecl/ convention functions, +but the value of <tt/Y/ should be used to determine how many bytes of parameters +were placed onto the stack. + +<sect1>Epilogue, after the functiona call<p> + +<sect2>Return requirements</p> + +If the function has a return value, it will appear in the <tt>A/X/sreg</tt> registers. + +Functions with an 8-bit return value (<tt/char/ or <tt/unsigned char/) are expected +to promote this value to a 16-bit integer on return, and store the high byte in <tt/X/. +The compiler will depend on the promoted value in some cases (e.g. implicit conversion to <tt/int/), +and failure to return the high byte in <tt/X/ will cause unexpected errors. +This problem does not apply to the <tt/sreg/ pseudo-register, which is only +used if the return type is 32-bit. + +If the function has a void return type, the compiler will not depend on the result +of <tt>A/X/sreg</tt>, so these may be clobbered by the function. + +The C-stack pointer <tt/sp/ must be restored by the function to its value before the +function call prologue. It may pop all of its parameters from the C-stack +(e.g. using the <tt/runtime/ function <tt/popa/.), +or it could adjust <tt/sp/ directly. +On entry to the function the <tt/Y/ register contains the number of bytes +pushed to the stack, which may be added to <tt/sp/ to restore its original state. + +The internal pseudo-register <tt/regbank/ must not be changed by the function. + +<sect2>Clobbered state</p> + +The <tt/Y/ register may be clobbered by the function. +The compiler will not depend on its state after a function call. + +The <tt>A/X/sreg</tt> registers may be clobbered if any of them +are not used by the return value (see above). + +Many of the internal pseudo-registers used by cc65 are available for +free use by any function called by C, and do not need to be preserved. +Note that if another C function is called from your assembly function, +it may clobber any of these itself: +<itemize> + <item><tt>tmp1 .. tmp4</tt><p> + <item><tt>ptr1 .. ptr4</tt><p> + <item><tt>regsave</tt><p> + <item><tt>sreg</tt> (if unused by return)<p> +</itemize> + + + +</article> + diff --git a/doc/index.sgml b/doc/index.sgml index b6ef06ef9..5b36db6e9 100644 --- a/doc/index.sgml +++ b/doc/index.sgml @@ -58,6 +58,9 @@ <tag><htmlurl url="coding.html" name="coding.html"></tag> Contains hints on creating the most effective code with cc65. + + <tag><htmlurl url="cc65-intern.html" name="cc65-intern.html"></tag> + Describes internal details of cc65, such as calling conventions. <tag><htmlurl url="using-make.html" name="using-make.html"></tag> Build programs, using the GNU Make utility. From 222ab93026cdd03ea85c49a1999f5d568be2efab Mon Sep 17 00:00:00 2001 From: Brad Smith <rainwarrior@gmail.com> Date: Fri, 26 Feb 2016 17:33:46 -0500 Subject: [PATCH 2/5] revise note on prototypes/K&R conventions --- doc/cc65-intern.sgml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/doc/cc65-intern.sgml b/doc/cc65-intern.sgml index f3aef939a..0bcb51cba 100644 --- a/doc/cc65-intern.sgml +++ b/doc/cc65-intern.sgml @@ -40,7 +40,11 @@ If the <tt/--standard/ command line option is used, the <tt/cdecl/ and <tt/fastcall/ keywords will not be available. The standard compliant variations <tt/__cdecl__/ and <tt/__fastcall__/ are always available. -K & R style function prototypes may be used, but they do not alter the calling conventions in any way. +If a function has a prototype, parameters are pushed to the C-stack as their respective types +(i.e. a <tt/char/ parameter will push 1 byte), but if a function has no prototype, default +promotions will apply. This means that with no prototype, <tt/char/ will be promoted +to <tt/int/ and be pushed as 2 bytes. K & R style function prototypes may be used, +but they will function the same as if no prototype was used. <sect1>Prologue, before the function call<p> @@ -57,8 +61,9 @@ All other parameters will be pushed to the C-stack from left to right. The rightmost parameter will have the lowest address on the stack, and multi-byte parameters will have their least significant byte at the lower address. -The <tt/Y/ register will contain the number of bytes pushed to the stack for this function, -and the <tt/sp/ pseudo-register is a zeropage pointer to the base of the C-stack. +The <tt/sp/ pseudo-register is a zeropage pointer to the base of the C-stack. +If the function has no prototype or is variadic +the <tt/Y/ register will contain the number of bytes pushed to the stack for this function. Example: <tscreen><verb> @@ -84,10 +89,6 @@ void foo(unsigned bar, unsigned char baz); lda (sp),y ; Low byte now in A </verb></tscreen> -Variadic functions push all parameters exactly as other <tt/cdecl/ convention functions, -but the value of <tt/Y/ should be used to determine how many bytes of parameters -were placed onto the stack. - <sect1>Epilogue, after the functiona call<p> <sect2>Return requirements</p> @@ -106,10 +107,10 @@ of <tt>A/X/sreg</tt>, so these may be clobbered by the function. The C-stack pointer <tt/sp/ must be restored by the function to its value before the function call prologue. It may pop all of its parameters from the C-stack -(e.g. using the <tt/runtime/ function <tt/popa/.), +(e.g. using the <tt/runtime/ function <tt/popa/), or it could adjust <tt/sp/ directly. -On entry to the function the <tt/Y/ register contains the number of bytes -pushed to the stack, which may be added to <tt/sp/ to restore its original state. +If the function has no prototype, or is variadic the <tt/Y/ register contains the +number of bytes pushed to the stack on entry, which may be added to <tt/sp/ to restore its original state. The internal pseudo-register <tt/regbank/ must not be changed by the function. From 18dec35312ebdd5dc120abeff039d032e316e256 Mon Sep 17 00:00:00 2001 From: Brad Smith <rainwarrior@gmail.com> Date: Wed, 2 Mar 2016 01:58:44 -0500 Subject: [PATCH 3/5] cc65-intern sgml fixes --- doc/cc65-intern.sgml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/cc65-intern.sgml b/doc/cc65-intern.sgml index 0bcb51cba..bfbe4d78e 100644 --- a/doc/cc65-intern.sgml +++ b/doc/cc65-intern.sgml @@ -89,9 +89,9 @@ void foo(unsigned bar, unsigned char baz); lda (sp),y ; Low byte now in A </verb></tscreen> -<sect1>Epilogue, after the functiona call<p> +<sect1>Epilogue, after the function call<p> -<sect2>Return requirements</p> +<sect2>Return requirements<p> If the function has a return value, it will appear in the <tt>A/X/sreg</tt> registers. @@ -114,7 +114,7 @@ number of bytes pushed to the stack on entry, which may be added to <tt/sp/ to r The internal pseudo-register <tt/regbank/ must not be changed by the function. -<sect2>Clobbered state</p> +<sect2>Clobbered state<p> The <tt/Y/ register may be clobbered by the function. The compiler will not depend on its state after a function call. @@ -126,6 +126,7 @@ Many of the internal pseudo-registers used by cc65 are available for free use by any function called by C, and do not need to be preserved. Note that if another C function is called from your assembly function, it may clobber any of these itself: + <itemize> <item><tt>tmp1 .. tmp4</tt><p> <item><tt>ptr1 .. ptr4</tt><p> From 85a58453cb881d92ea51aa927981eae1c4137c9d Mon Sep 17 00:00:00 2001 From: Brad Smith <rainwarrior@gmail.com> Date: Wed, 2 Mar 2016 02:03:23 -0500 Subject: [PATCH 4/5] cc65-intern adjusting mailing address --- doc/cc65-intern.sgml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/cc65-intern.sgml b/doc/cc65-intern.sgml index bfbe4d78e..faa2d5609 100644 --- a/doc/cc65-intern.sgml +++ b/doc/cc65-intern.sgml @@ -2,7 +2,7 @@ <article> <title>cc65 internals -<author><url url="mailto:brad@rainwarrior.ca" name="Brad Smith"> +<author><url url="mailto:bbbradsmith@users.noreply.github.com" name="Brad Smith"> <date>2016-02-27 <abstract> From 97e6a8c5698cad2a62f09b2664ea74e58830b604 Mon Sep 17 00:00:00 2001 From: Brad Smith <rainwarrior@gmail.com> Date: Wed, 2 Mar 2016 21:01:46 -0500 Subject: [PATCH 5/5] cc65-intern update minor change notes from greg-king5 --- doc/cc65-intern.sgml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/cc65-intern.sgml b/doc/cc65-intern.sgml index faa2d5609..231c04544 100644 --- a/doc/cc65-intern.sgml +++ b/doc/cc65-intern.sgml @@ -27,7 +27,7 @@ There are two calling conventions used in cc65: <item><tt/cdecl/ - passes all parameters on the C-stack. <p> <item><tt/fastcall/ - passes the rightmost parameter in - registers <tt>A/X/sreg</tt> an all others on the C-stack. + registers <tt>A/X/sreg</tt> and all others on the C-stack. <p> </itemize> @@ -52,7 +52,7 @@ If the function is declared as fastcall, the rightmost argument will be loaded i the <tt>A/X/sreg</tt> registers: <itemize> - <item><tt/A/ - 8-bit parameter, or low byte of larger tyes<p> + <item><tt/A/ - 8-bit parameter, or low byte of larger types<p> <item><tt/X/ - 16-bit high byte, or second byte of 32-bits<p> <item><tt/sreg/ - Zeropage pseudo-register including high 2 bytes of 32-bit parameter<p> </itemize> @@ -68,7 +68,7 @@ the <tt/Y/ register will contain the number of bytes pushed to the stack for thi Example: <tscreen><verb> // C prototype -void foo(unsigned bar, unsigned char baz); +void cdecl foo(unsigned bar, unsigned char baz); ; C-stack layout within the function: ;