changeset 110:9aa75a74614c

- working mips32 eabi callbacks - mips32 eabi doc update - switched some mips32 eabi call assembly to use more portable pseudo instructions for storing floats - fixed weird type use of var declaration in mips callbacks - ToDo update - converted some // comments to old c-style - test code build fix for some test suites on some platforms
author cslag
date Sat, 18 Jun 2016 19:38:22 +0200
parents 9e677d4c0b6b
children 6da2a7ee2a86
files ToDo doc/manual/callconvs/callconv_mips.tex doc/manual/manual_overview.tex dyncall/dyncall_call_mips_eabi_gas.s dyncallback/dyncall_args_mips.c dyncallback/dyncall_args_mips.h dyncallback/dyncall_args_mips_o32.c dyncallback/dyncall_callback_mips_eabi_gas.s test/common/platformInit.h
diffstat 9 files changed, 122 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/ToDo	Sat Jun 11 21:44:38 2016 +0200
+++ b/ToDo	Sat Jun 18 19:38:22 2016 +0200
@@ -35,7 +35,6 @@
   be used to test dycnall bindings
 - pkg-config support?
 - quadmath support (long double)
-- MIPS softfloat support? (-msoft-float)
 
 portasm:
 --------
@@ -43,6 +42,7 @@
 
 dyncall:
 --------
+- where is dyncall_callvm_mips_n32.h? (included by dyncall_callvm_mips_n32.c)
 - support for return values: aggregate return values
 - support for argument values: structures, half-precision, vector types, long double
 - varargs for mips (might exist, but test all ABIs)
@@ -53,6 +53,7 @@
   * bsd
   * linux
 - other syscalls
+- MIPS32 softfloat support (-msoft-float)
 
 dynload:
 --------
@@ -71,8 +72,10 @@
 - 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
-- add MIPS callbacks for eabi, n32, n64
+- add MIPS callbacks for n32, n64
 - finish PPC32 callbacks (see bugs section, below, BSD not working)
+- MIPS32 softfloat support (-msoft-float)
+- test MIPS o32 big endian
 
 bindings:
 ---------
--- a/doc/manual/callconvs/callconv_mips.tex	Sat Jun 11 21:44:38 2016 +0200
+++ b/doc/manual/callconvs/callconv_mips.tex	Sat Jun 18 19:38:22 2016 +0200
@@ -52,7 +52,7 @@
 {\bf \$0}                              & {\bf \$zero}         & Hardware zero \\
 {\bf \$1}                              & {\bf \$at}           & Assembler temporary \\
 {\bf \$2-\$3}                          & {\bf \$v0-\$v1}      & Integer results \\
-{\bf \$4-\$11}                         & {\bf \$a0-\$a7}      & Integer arguments\\
+{\bf \$4-\$11}                         & {\bf \$a0-\$a7}      & Integer arguments, or double precision float arguments\\
 {\bf \$12-\$15,\$24}                   & {\bf \$t4-\$t7,\$t8} & Integer temporaries \\
 {\bf \$25}                             & {\bf \$t9}           & Integer temporary, hold the address of the called function for all PIC calls (by convention) \\
 {\bf \$16-\$23}                        & {\bf \$s0-\$s7}      & Preserved \\
@@ -64,7 +64,7 @@
 {\bf hi, lo}                           &                      & Multiply/divide special registers \\
 {\bf \$f0,\$f2}                        &                      & Float results \\
 {\bf \$f1,\$f3,\$f4-\$f11,\$f20-\$f23} &                      & Float temporaries \\
-{\bf \$f12-\$f19}                      &                      & Float arguments \\
+{\bf \$f12-\$f19}                      &                      & Single precisition float arguments \\
 \end{tabular*}
 \caption{Register usage on MIPS32 EABI calling convention}
 \end{table}
@@ -75,12 +75,13 @@
 \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 8 integers or floats are passed independently in registers using \$a0-\$a7 and \$f12-\$f19, respectively.
+\item Stack always aligned to 8 bytes
+\item first 8 integers (<= 32bit) are passed in registers \$a0-\$a7
+\item first 8 single precision floating point arguments are passed in registers \$f12-\$f19
 \item if either integer or float registers are used up, the stack is used
-\item 64-bit integers or floats are passed on two integer registers starting at an even register number, skipping one odd register.
-\item \$a0-\$a7 and \$f12-\$f19 are not required to be preserved.
-\item results are returned in \$v0 (32-bit), \$v0 and \$v1 (64-bit), \$f0 or \$f0 and \$f2 (2 $\times$ 32 bit float e.g. complex).
+\item 64-bit integers or double precision floats are passed on two general purpose registers starting at an even register number, skipping one odd register
+\item \$a0-\$a7 and \$f12-\$f19 are not required to be preserved
+\item results are returned in \$v0 (32-bit), \$v0 and \$v1 (64-bit), \$f0 or \$f0 and \$f2 (2 $\times$ 32 bit float e.g. complex)
 \end{itemize}
 
 \paragraph{Stack layout}
--- a/doc/manual/manual_overview.tex	Sat Jun 11 21:44:38 2016 +0200
+++ b/doc/manual/manual_overview.tex	Sat Jun 18 19:38:22 2016 +0200
@@ -172,7 +172,7 @@
 {\bf Plan 9 / 9front}          & \marknimp                    & \marknimp                  & \marknotx                    & \marknimp                   & \marknotx                     & \marknotx                     & \marknimp                      & \marknotx                        & \marknotx                   & \marknotx                   & \markcmpl                  & \marknimp                  & \marknotx                      & \marknimp                    & \marknotx                      \\
 {\bf Haiku / BeOS}             & \marknotx                    & \marknotx                  & \marknotx                    & \marknotx                   & \marknotx                     & \marknotx                     & \marknotx                      & \marknotx                        & \marknotx                   & \marknotx                   & \markcmpl                  & \marknotx                  & \marknotx                      & \marknotx                    & \marknotx                      \\
 {\bf Minix}                    & \marknotx                    & \markunkn                  & \marknotx                    & \marknotx                   & \marknotx                     & \marknotx                     & \marknotx                      & \marknotx                        & \marknotx                   & \marknotx                   & \markcmpl                  & \marknotx                  & \marknotx                      & \marknotx                    & \marknotx                      \\
-{\bf Playstation Portable}     & \marknotx                    & \marknotx                  & \marknotx                    & \markimpl                   & \marknotx                     & \marknotx                     & \marknotx                      & \marknotx                        & \marknotx                   & \marknotx                   & \marknotx                  & \marknotx                  & \marknotx                      & \marknotx                    & \marknotx                      \\
+{\bf Playstation Portable}     & \marknotx                    & \marknotx                  & \marknotx                    & \markcmpl                   & \marknotx                     & \marknotx                     & \marknotx                      & \marknotx                        & \marknotx                   & \marknotx                   & \marknotx                  & \marknotx                  & \marknotx                      & \marknotx                    & \marknotx                      \\
 {\bf Nintendo DS}              & \marknotx                    & \markcmpl                  & \marknotx                    & \marknotx                   & \marknotx                     & \marknotx                     & \marknotx                      & \marknotx                        & \marknotx                   & \marknotx                   & \marknotx                  & \marknotx                  & \marknotx                      & \marknotx                    & \marknotx                      \\
 \end{tabular}
 \caption{Supported platforms}%
--- a/dyncall/dyncall_call_mips_eabi_gas.s	Sat Jun 11 21:44:38 2016 +0200
+++ b/dyncall/dyncall_call_mips_eabi_gas.s	Sat Jun 18 19:38:22 2016 +0200
@@ -37,7 +37,7 @@
 
 dcCall_mips_eabi:
 	/* $4 target function */
- 	/* $5 register data */
+	/* $5 register data */
 	/* $6 stack size */
 	/* $7 stack data */
 	addiu	$sp,$sp,-16
@@ -46,7 +46,7 @@
 	sw	$fp,0($sp)
 
 	move	$fp,$sp
-	
+
 	move	$2, $0
 	add	$2, 8
 	neg	$2
@@ -57,9 +57,9 @@
 	move	$12,$4		/* target function */
 	move	$13,$5		/* register data   */
 	move    $16,$6		/* stack size      */
-	
+
 	sub	$sp,$sp,$16	/* allocate stack frame */
-	
+
 	/* copy stack data */
 
 .next:
@@ -73,8 +73,8 @@
 	addiu	$sp,$sp, 4
 	j	.next
 	nop
-	
-.skip:	
+
+.skip:
 
 	sub	$sp,$sp,$16
 
@@ -91,14 +91,14 @@
 
 	/* load single-precision floating pointer parameter registers */
 
-	lwc1	$f12, 32($13)
-	lwc1	$f13, 36($13)
-	lwc1	$f14, 40($13)
-	lwc1	$f15, 44($13)
-	lwc1	$f16, 48($13)
-	lwc1	$f17, 52($13)
-	lwc1	$f18, 56($13)
-	lwc1	$f19, 60($13)	
+	l.s	$f12, 32($13)
+	l.s	$f13, 36($13)
+	l.s	$f14, 40($13)
+	l.s	$f15, 44($13)
+	l.s	$f16, 48($13)
+	l.s	$f17, 52($13)
+	l.s	$f18, 56($13)
+	l.s	$f19, 60($13)
 
 	jal	$12
 	nop
--- a/dyncallback/dyncall_args_mips.c	Sat Jun 11 21:44:38 2016 +0200
+++ b/dyncallback/dyncall_args_mips.c	Sat Jun 18 19:38:22 2016 +0200
@@ -42,13 +42,14 @@
 DCulonglong dcbArgULongLong(DCArgs* p)
 {
   DCulonglong value;
-  p->reg_count.i += (p->reg_count.i & 1); // Skip one reg if not aligned.
+  p->reg_count.i += (p->reg_count.i & 1);         /* Skip one reg if not aligned. */
+  p->stackptr += ((DCulong)p->stackptr & 4) & -4; /* 64bit values are also always aligned on stack */
 #if defined(DC__Endian_LITTLE)
+  value  = dcbArgUInt(p);
+  value |= ((DCulonglong)dcbArgUInt(p)) << 32;
+#else
   value  = ((DCulonglong)dcbArgUInt(p)) << 32;
   value |= dcbArgUInt(p);
-#else
-  value  = dcbArgUInt(p);
-  value |= ((DCulonglong)dcbArgUInt(p)) << 32;
 #endif
   return value;
 }
@@ -67,7 +68,7 @@
 {
   DCfloat result;
   if(p->reg_count.f < DCARGS_MIPS_NUM_FREGS)
-    result = (DCfloat)p->freg_data[p->reg_count.f++];
+    result = p->freg_data[p->reg_count.f++];
   else {
     result = *((DCfloat*)p->stackptr);
     p->stackptr += sizeof(DCfloat);
@@ -78,16 +79,9 @@
 {
   union {
     DCdouble result;
-    DCfloat  f[2];
+    DCulonglong i;
   } d;
-  p->reg_count.f += (p->reg_count.f & 1); // Skip one reg if not aligned.
-#if defined(DC__Endian_LITTLE)
-  d.f[0] = dcbArgFloat(p);
-  d.f[1] = dcbArgFloat(p);
-#else
-  d.f[1] = dcbArgFloat(p);
-  d.f[0] = dcbArgFloat(p);
-#endif
+  d.i = dcbArgULongLong(p); /* those are passed via int regs */
   return d.result;
 }
 
--- a/dyncallback/dyncall_args_mips.h	Sat Jun 11 21:44:38 2016 +0200
+++ b/dyncallback/dyncall_args_mips.h	Sat Jun 18 19:38:22 2016 +0200
@@ -41,7 +41,7 @@
 	DCfloat freg_data[DCARGS_MIPS_NUM_FREGS];
 	struct { DCshort i; DCshort f; } reg_count;
 #endif
-	unsigned DCchar* stackptr;
+	DCuchar* stackptr;
 };
 
 #endif /* DYNCALLBACK_ARGS_MIPS_H */
--- a/dyncallback/dyncall_args_mips_o32.c	Sat Jun 11 21:44:38 2016 +0200
+++ b/dyncallback/dyncall_args_mips_o32.c	Sat Jun 18 19:38:22 2016 +0200
@@ -29,7 +29,7 @@
 DCint dcbArgInt(DCArgs* p)
 {
   DCint value;
-  p->freg_count = 2; // first int will disable float reg use.
+  p->freg_count = 2; /* first int will disable float reg use. */
   value = *((int*)p->stackptr);
   p->stackptr += sizeof(int);
   return value;
@@ -39,7 +39,7 @@
 DCulonglong dcbArgULongLong(DCArgs* p)
 {
   DCulonglong value;
-  p->stackptr += ((int)p->stackptr & 4); // Skip one slot if not aligned.
+  p->stackptr += ((int)p->stackptr & 4); /* Skip one slot if not aligned. */
 #if defined(DC__Endian_LITTLE)
   value  = dcbArgUInt(p);
   value |= ((DCulonglong)dcbArgUInt(p)) << 32;
@@ -64,11 +64,11 @@
 {
   DCfloat result;
   if(p->freg_count < 2) {
-	// Stored float regs (max 2) are always 8b aligned. The way we look them up,
-	// relative to a diverging p->stackptr, we need consider this. Only works
-	// with up to two float args, which is all we need. Hacky, but saves us
-	// from one more variable and more bookkeeping in DCArgs.
-    result = ((DCfloat*)(p->stackptr + ((int)p->stackptr & 4)) - 4) // '-4' b/c those regs are stored right before the args
+	/* Stored float regs (max 2) are always 8b aligned. The way we look them up, */
+	/* relative to a diverging p->stackptr, we need consider this. Only works    */
+	/* with up to two float args, which is all we need. Hacky, but saves us      */
+	/* from one more variable and more bookkeeping in DCArgs.                    */
+    result = ((DCfloat*)(p->stackptr + ((int)p->stackptr & 4)) - 4) /* '-4' b/c those regs are stored right before the args */
 #if defined(DC__Endian_LITTLE)
       [0];
 #else
@@ -87,14 +87,14 @@
     DCdouble result;
     DCfloat f[2];
   } d;
-  p->stackptr += ((int)p->stackptr & 4); // Skip one slot if not aligned.
+  p->stackptr += ((int)p->stackptr & 4); /* Skip one slot if not aligned. */
   if(p->freg_count < 2) {
-    //result = *((DCdouble*)p->stackptr-2); this changes the value, slightly
-    d.f[0] = ((DCfloat*)p->stackptr-4)[0]; // '-4' b/c those regs are stored right before the args
+    /*result = *((DCdouble*)p->stackptr-2); this changes the value, slightly*/
+    d.f[0] = ((DCfloat*)p->stackptr-4)[0]; /* '-4' b/c those regs are stored right before the args */
     d.f[1] = ((DCfloat*)p->stackptr-4)[1];
     ++p->freg_count;
   } else {
-    //result = *((DCdouble*)p->stackptr); this changes the value, slightly
+    /*result = *((DCdouble*)p->stackptr); this changes the value, slightly*/
     d.f[0] = ((DCfloat*)p->stackptr)[0];
     d.f[1] = ((DCfloat*)p->stackptr)[1];
   }
--- a/dyncallback/dyncall_callback_mips_eabi_gas.s	Sat Jun 11 21:44:38 2016 +0200
+++ b/dyncallback/dyncall_callback_mips_eabi_gas.s	Sat Jun 18 19:38:22 2016 +0200
@@ -22,7 +22,78 @@
 
 */
 
-.text
-.globl dcCallbackThunkEntry
+	/* input:
+		$t4    -> thunk
+		$t4+20 -> cb handler
+		$t4+24 -> userdata
+	*/
+
+	.text
+	.globl dcCallbackThunkEntry
+	.ent   dcCallbackThunkEntry
+
+/* Called by thunk - thunk stores pointer to DCCallback in $12 ($t4), and */
+/* pointer to called function in $25 ($t9, required for PIC)              */
 dcCallbackThunkEntry:
+	.set    noreorder
 
+	/* Prolog. */
+	/* Frame size of 88b comes from following: */
+	/*   DCargs(fregs:32 + iregs:32 + regcounts:4 + stackptr:4) + retval:8 + ra:4 (+ pad:4) */
+	subu  $sp, 88       /* open frame */
+	sw    $ra, 84($sp)  /* save link register */
+
+	.frame $fp,88,$31   /* specify our frame: fp,size,lr; creates virt $fp */
+	                    /* code below doesn't use $fp though, as n/a with -O1 */
+	/* Init return value */
+	sw $zero, 72($sp)
+	sw $zero, 76($sp)
+
+	/* Store float and int args where our DCargs member arrays are, in local area. */
+	sw  $4,    0($sp)
+	sw  $5,    4($sp)
+	sw  $6,    8($sp)
+	sw  $7,   12($sp)
+	sw  $8,   16($sp)
+	sw  $9,   20($sp)
+	sw $10,   24($sp)
+	sw $11,   28($sp)
+	s.s $f12, 32($sp)
+	s.s $f13, 36($sp)
+	s.s $f14, 40($sp)
+	s.s $f15, 44($sp)
+	s.s $f16, 48($sp)
+	s.s $f17, 52($sp)
+	s.s $f18, 56($sp)
+	s.s $f19, 60($sp)
+
+	/* Init DCarg's reg_counts and stackptr. */
+	sw $zero, 64($sp) /* reg_count */
+	addiu $4, $sp, 88
+	sw    $4, 68($sp) /* stackptr */
+
+	/* Prepare callback handler call. */
+	move  $4, $12       /* Param 0 = DCCallback*, $12 ($t4) holds pointer to thunk */
+	move  $5, $sp       /* Param 1 = DCArgs*, pointer to where pointer to args is stored */
+	addiu $6, $sp, 72   /* Param 2 = results pointer to 8b of local data on stack */
+	lw    $7, 24($12)   /* Param 3 = userdata pointer */
+
+	lw    $25, 20($12)  /* store handler entry in $25 ($t9), required for PIC */
+	jalr  $25           /* jump */
+	nop                 /* branch delay nop */
+
+	/* Copy result in corresponding registers $2-$3 ($v0-$v1) and $f0 */
+	lw     $2, 72($sp)
+	lw     $3, 76($sp)
+	l.d   $f0, 72($sp)
+
+	/* Epilog. Tear down frame and return. */
+	lw    $ra, 84($sp)  /* restore return address */
+	addiu $sp, $sp, 88  /* close frame */
+	j     $ra           /* return */
+	nop                 /* branch delay nop */
+
+	.set    reorder
+	.end    dcCallbackThunkEntry
+	.ident  "handwritten"
+
--- a/test/common/platformInit.h	Sat Jun 11 21:44:38 2016 +0200
+++ b/test/common/platformInit.h	Sat Jun 18 19:38:22 2016 +0200
@@ -37,6 +37,7 @@
 #  include <pspkernel.h>
 #  include <pspdebug.h>
 #  include <pspdisplay.h>
+#  include <stdio.h>
 #  define printf pspDebugScreenPrintf
 /* All other platforms, usually just pulling in standard headers and empty init function. */
 #else