changeset 157:49549739228c

- sparc callback asm and args code (still some stack alignment issues, currently) - doc improvements for sparc callconv
author cslag
date Wed, 28 Dec 2016 16:48:35 -0600
parents 9e4f1355a388
children 51b0a4544d9e
files ToDo doc/manual/callconvs/callconv_sparc.tex dyncall/dyncall_value.h dyncallback/dyncall_args_sparc32.c dyncallback/dyncall_args_sparc32.h dyncallback/dyncall_callback.h dyncallback/dyncall_callback_sparc32.s
diffstat 7 files changed, 79 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/ToDo	Fri Nov 25 18:59:26 2016 +0000
+++ b/ToDo	Wed Dec 28 16:48:35 2016 -0600
@@ -80,7 +80,7 @@
 
 dyncallback:
 ------------
-- add SPARC and SPARC64 callback support
+- add SPARC64 callback support
 - callback_plain's return value not correct anymore on NDS (maybe just broken testcode?),
   see above under 1.0 items
   * check other platforms also, if asm stub initializes retval space, correctly
--- a/doc/manual/callconvs/callconv_sparc.tex	Fri Nov 25 18:59:26 2016 +0000
+++ b/doc/manual/callconvs/callconv_sparc.tex	Wed Dec 28 16:48:35 2016 -0600
@@ -36,7 +36,7 @@
 \item 32 32-bit integer/pointer registers
 \item 32 floating point registers (usable as 8 quad precision, 16 double precision or 32 single precision registers)
 \item 32 registers are accessible at a time (8 are global ones (g*), whereas the rest forms a register window with 8 input (i*), 8 output (o*) and 8 local (l*) ones)
-\item invoking a function shifts the register window, the old output registers become the new input registers (old local and input ones are not accessible anymore)
+\item calling a function shifts the register window, the old output registers become the new input registers (old local and input ones are not accessible anymore)
 \end{itemize}
 
 \begin{table}[h]
@@ -55,13 +55,17 @@
 
 \paragraph{Parameter passing}
 \begin{itemize}
-\item Stack parameter order: right-to-left
-\item Caller cleans up the stack @@@ really?
-\item Stack always aligned to 8 bytes.
+\item stack grows down
+\item stack parameter order: right-to-left
+\item caller cleans up the stack
+\item stack always aligned to 8 bytes
 \item first 6 integers and floats are passed independently in registers using \%o0-\%o5
 \item for every other argument the stack is used
-\item @@@ what about floats, 64bit integers, etc.?
-\item results are returned in \%i0, and structs/unions pass a pointer to them as a hidden stack parameter (see below)
+\item all arguments <= 32 bit are passed as 32 bit values
+\item 64 bit arguments are passed like two consecutive <= 32 bit values
+\item minimum stack size is 64 bytes, b/c stack pointer must always point at enough space to store all \%i* and \%l* registers, used when running out of register windows
+\item if needed, register spill area is adjacent to parameters
+\item results are expected by caller to be returned in \%o0\%o1 (after reg window restore, meaning callee writes to \%i0\%i1) for integers, \%f0/\%f1 for floats, and for structs/unions a pointer to them is used as a hidden stack parameter (see below)
 \end{itemize}
 
 \paragraph{Stack layout}
--- a/dyncall/dyncall_value.h	Fri Nov 25 18:59:26 2016 +0000
+++ b/dyncall/dyncall_value.h	Wed Dec 28 16:48:35 2016 -0600
@@ -50,7 +50,7 @@
 {
 /* dyncallback assembly pulls value directly from DCValue structs, without   */
 /* knowledge about types used, so lay it out as needed at compile time, here */
-#if defined(DC__Endian_BIG) && (defined(DC__Arch_PPC32) || defined(DC__Arch_MIPS))
+#if defined(DC__Endian_BIG) && (defined(DC__Arch_PPC32) || defined(DC__Arch_MIPS) || defined(DC__Arch_Sparc))
   DCbool      B;
   struct { DCchar  c_pad[3]; DCchar  c; };
   struct { DCuchar C_pad[3]; DCuchar C; };
@@ -58,7 +58,7 @@
   struct { DCshort S_pad;    DCshort S; };
   DCint       i;
   DCuint      I;
-#elif defined(DC__Endian_BIG) && (defined(DC__Arch_PPC64) || defined(DC__Arch_MIPS64))
+#elif defined(DC__Endian_BIG) && (defined(DC__Arch_PPC64) || defined(DC__Arch_MIPS64) || defined(DC__Arch_Sparcv9))
   struct { DCbool  B_pad;    DCbool  B; };
   struct { DCchar  c_pad[7]; DCchar  c; };
   struct { DCuchar C_pad[7]; DCuchar C; };
--- a/dyncallback/dyncall_args_sparc32.c	Fri Nov 25 18:59:26 2016 +0000
+++ b/dyncallback/dyncall_args_sparc32.c	Wed Dec 28 16:48:35 2016 -0600
@@ -6,7 +6,7 @@
  Description: Callback's Arguments VM - Implementation for sparc32 - not yet
  License:
 
-   Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
+   Copyright (c) 2007-2016 Daniel Adler <dadler@uni-goettingen.de>,
                            Tassilo Philipp <tphilipp@potion-studios.com>
 
    Permission to use, copy, modify, and distribute this software for any
@@ -26,10 +26,23 @@
 
 #include "dyncall_args_sparc32.h"
 
-DCint       dcbArgInt      (DCArgs* p) { return 0; }
-DCuint      dcbArgUInt     (DCArgs* p) { return 0; }
-DCulonglong dcbArgULongLong(DCArgs* p) { return 0; }
+static void* sparc_word(DCArgs* args)
+{
+  return args->arg_ptr++;
+}
+
+static void* sparc_dword(DCArgs* args)
+{
+  void *p = args->arg_ptr;
+  args->arg_ptr += 2;
+  return p;
+}
+
+DCuint      dcbArgUInt     (DCArgs* p) { return *(DCuint*)sparc_word(p); }
+DCulonglong dcbArgULongLong(DCArgs* p) { return *(DCulonglong*)sparc_dword(p); }
+
 DClonglong  dcbArgLongLong (DCArgs* p) { return (DClonglong)dcbArgULongLong(p); }
+DCint       dcbArgInt      (DCArgs* p) { return (DCint)     dcbArgUInt(p); }
 DClong      dcbArgLong     (DCArgs* p) { return (DClong)    dcbArgUInt(p); }
 DCulong     dcbArgULong    (DCArgs* p) { return (DCulong)   dcbArgUInt(p); }
 DCchar      dcbArgChar     (DCArgs* p) { return (DCchar)    dcbArgUInt(p); }
@@ -38,5 +51,7 @@
 DCushort    dcbArgUShort   (DCArgs* p) { return (DCushort)  dcbArgUInt(p); }
 DCbool      dcbArgBool     (DCArgs* p) { return (DCbool)    dcbArgUInt(p); }
 DCpointer   dcbArgPointer  (DCArgs* p) { return (DCpointer) dcbArgUInt(p); }
-DCdouble    dcbArgDouble   (DCArgs* p) { return 0.0; }
-DCfloat     dcbArgFloat    (DCArgs* p) { return 0.0f; }
+
+DCdouble    dcbArgDouble   (DCArgs* p) { return *(DCdouble*)sparc_dword(p); }
+DCfloat     dcbArgFloat    (DCArgs* p) { return *(DCfloat*) sparc_word(p); }
+
--- a/dyncallback/dyncall_args_sparc32.h	Fri Nov 25 18:59:26 2016 +0000
+++ b/dyncallback/dyncall_args_sparc32.h	Wed Dec 28 16:48:35 2016 -0600
@@ -31,7 +31,7 @@
 
 struct DCArgs
 {
-  int dummy;
+  int *arg_ptr;
 };
 
 #endif /* DYNCALLBACK_ARGS_SPARC32_H */
--- a/dyncallback/dyncall_callback.h	Fri Nov 25 18:59:26 2016 +0000
+++ b/dyncallback/dyncall_callback.h	Wed Dec 28 16:48:35 2016 -0600
@@ -6,7 +6,7 @@
  Description: Callback - Interface
  License:
 
-   Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
+   Copyright (c) 2007-2016 Daniel Adler <dadler@uni-goettingen.de>,
                            Tassilo Philipp <tphilipp@potion-studios.com>
 
    Permission to use, copy, modify, and distribute this software for any
@@ -44,7 +44,6 @@
 void        dcbFreeCallback(DCCallback* pcb);
 void*       dcbGetUserData (DCCallback* pcb);
 
-
 #ifdef __cplusplus
 }
 #endif 
--- a/dyncallback/dyncall_callback_sparc32.s	Fri Nov 25 18:59:26 2016 +0000
+++ b/dyncallback/dyncall_callback_sparc32.s	Wed Dec 28 16:48:35 2016 -0600
@@ -29,8 +29,50 @@
 	$i0+28 -> userdata
 */
 
+.text
 .globl dcCallbackThunkEntry
+
+/* Called by thunk - thunk stores pointer to DCCallback */
+/* in %g1, and pointer to called function in %g2        */
 dcCallbackThunkEntry:
-	jmpl %i7 + 8, %g0			/* Return from proc. */
+
+	/* Prolog. */
+	/* Frame size of 80b comes from needing storage space for the following: */
+	/*   DCargs(sparc_req_reg_save_area:64 + argptr:4) + pad:4 + retval:8 */
+	save %sp, -80, %sp
+
+	/* Spill register args. */
+	st   %i0, [ %fp + 68 ]  /* reg arg 0 */
+	st   %i1, [ %fp + 72 ]  /* reg arg 1 */
+	st   %i2, [ %fp + 76 ]  /* reg arg 2 */
+	st   %i3, [ %fp + 80 ]  /* reg arg 3 */
+	st   %i4, [ %fp + 84 ]  /* reg arg 4 */
+	st   %i5, [ %fp + 88 ]  /* reg arg 5 */
+	add  %fp, 68, %l0
+	st   %l0, [ %sp + 64 ]  /* init arg_ptr */
+
+	/* Zero retval store (for data < word size). */
+	st   %g0, [ %sp + 72 ]
+	st   %g0, [ %sp + 76 ]
+
+	/* Prepare callback handler call. */
+	mov  %g1, %o0           /* Param 0 = DCCallback*, %g1 holds ptr to thunk */
+	add  %sp, 64, %o1       /* Param 1 = DCArgs* (ptr to struct with args ptr */
+	add  %sp, 72, %o2       /* Param 2 = results ptr to 8b of local stack data */
+	ld   [ %g1 + 28 ], %o3  /* Param 3 = userdata ptr */
+
+	ld   [ %g1 + 24 ], %l0
+	call %l0
 	nop
 
+	/* Put retval in %i0/%i1 (to be in caller's %o0/%o1), and %f0/%f1. */
+	ld   [ %sp + 72 ], %i0
+	ld   [ %sp + 76 ], %i1
+	ld   [ %sp + 72 ], %f0
+	ld   [ %sp + 76 ], %f1
+
+	/* Epilog. */
+	restore                 /* unshift reg window */
+	retl                    /* Return from proc. -- jmpl %i7 + 8, %g0 */
+	nop
+