This is the mail archive of the libffi-discuss@sourceware.org mailing list for the libffi project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 1/3] MicroBlaze Port


Add support for MicroBlaze Big and Little Endian.

Signed-off-by: Nathan Rossi <nathan.rossi@xilinx.com>
---
 README                     |    2 +
 src/microblaze/ffi.c       |  339 ++++++++++++++++++++++++++++++++++++++++++++
 src/microblaze/ffitarget.h |   53 +++++++
 src/microblaze/sysv.S      |  302 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 696 insertions(+), 0 deletions(-)
 create mode 100644 src/microblaze/ffi.c
 create mode 100644 src/microblaze/ffitarget.h
 create mode 100644 src/microblaze/sysv.S

diff --git a/README b/README
index dc9bf2a..94d2e25 100644
--- a/README
+++ b/README
@@ -62,6 +62,7 @@ tested:
 | IA-64           | Linux            | GCC                     |
 | M68K            | FreeMiNT         | GCC                     |
 | M68K            | RTEMS            | GCC                     |
+| MicroBlaze      | Linux            | GCC                     |
 | MIPS            | IRIX             | GCC                     |
 | MIPS            | Linux            | GCC                     |
 | MIPS            | RTEMS            | GCC                     |
@@ -339,6 +340,7 @@ frv		Anthony Green
 ia64		Hans Boehm
 m32r		Kazuhiro Inaoka
 m68k		Andreas Schwab
+microblaze	Nathan Rossi
 mips		Anthony Green, Casey Marshall
 mips64		David Daney
 pa		Randolph Chung, Dave Anglin, Andreas Tobler
diff --git a/src/microblaze/ffi.c b/src/microblaze/ffi.c
new file mode 100644
index 0000000..86ea37d
--- /dev/null
+++ b/src/microblaze/ffi.c
@@ -0,0 +1,339 @@
+/* -----------------------------------------------------------------------
+   ffi.c - Copyright (c) 2012, 2013 Xilinx, Inc
+
+   MicroBlaze Foreign Function Interface
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+   DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+extern void ffi_call_SYSV(void (*)(void*, extended_cif*), extended_cif*,
+		unsigned int, unsigned int, unsigned int*, void (*fn)(void),
+		unsigned int, unsigned int);
+
+extern void ffi_closure_SYSV(void);
+
+#define WORD_SIZE			sizeof(unsigned int)
+#define ARGS_REGISTER_SIZE	(WORD_SIZE * 6)
+#define WORD_ALIGN(x)		ALIGN(x, WORD_SIZE)
+
+/* ffi_prep_args is called by the assembly routine once stack space
+   has been allocated for the function's arguments */
+void ffi_prep_args(void* stack, extended_cif* ecif)
+{
+	unsigned int i;
+	ffi_type** p_arg;
+	void** p_argv;
+	void* stack_args_p = stack;
+
+	p_argv = ecif->avalue;
+
+	if (ecif == NULL || ecif->cif == NULL) {
+		return; /* no description to prepare */
+	}
+
+	if ((ecif->cif->rtype != NULL) &&
+			(ecif->cif->rtype->type == FFI_TYPE_STRUCT))
+	{
+		/* if return type is a struct which is referenced on the stack/reg5,
+		 * by a pointer. Stored the return value pointer in r5.
+		 */
+		char* addr = stack_args_p;
+		memcpy(addr, &(ecif->rvalue), WORD_SIZE);
+		stack_args_p += WORD_SIZE;
+	}
+
+	if (ecif->avalue == NULL) {
+		return; /* no arguments to prepare */
+	}
+
+	for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
+			i++, p_arg++)
+	{
+		size_t size = (*p_arg)->size;
+		int type = (*p_arg)->type;
+		void* value = p_argv[i];
+		char* addr = stack_args_p;
+		int aligned_size = WORD_ALIGN(size);
+
+		/* force word alignment on the stack */
+		stack_args_p += aligned_size;
+		
+		switch (type)
+		{
+			case FFI_TYPE_UINT8:
+				*(unsigned int *)addr = (unsigned int)*(UINT8*)(value);
+				break;
+			case FFI_TYPE_SINT8:
+				*(signed int *)addr = (signed int)*(SINT8*)(value);
+				break;
+			case FFI_TYPE_UINT16:
+				*(unsigned int *)addr = (unsigned int)*(UINT16*)(value);
+				break;
+			case FFI_TYPE_SINT16:
+				*(signed int *)addr = (signed int)*(SINT16*)(value);
+				break;
+			case FFI_TYPE_STRUCT:
+#if __BIG_ENDIAN__
+				/*
+				 * MicroBlaze toolchain appears to emit:
+				 * bsrli r5, r5, 8 (caller)
+				 * ...
+				 * <branch to callee>
+				 * ...
+				 * bslli r5, r5, 8 (callee)
+				 * 
+				 * For structs like "struct a { uint8_t a[3]; };", when passed
+				 * by value.
+				 *
+				 * Structs like "struct b { uint16_t a; };" are also expected
+				 * to be packed strangely in registers.
+				 *
+				 * This appears to be because the microblaze toolchain expects
+				 * "struct b == uint16_t", which is only any issue for big
+				 * endian.
+				 *
+				 * The following is a work around for big-endian only, for the
+				 * above mentioned case, it will re-align the contents of a
+				 * <= 3-byte struct value.
+				 */
+				if (size < WORD_SIZE)
+				{
+					if (size == 1) {
+						*(unsigned int *)addr =
+								(unsigned int)*(UINT8*)(value);
+					} else if (size == 2) {
+						*(unsigned int *)addr =
+								(unsigned int)*(UINT16*)(value);
+					} else {
+						*(unsigned int *)addr =
+								((unsigned int)*(UINT32*)(value)) >> 8;
+					}
+					break;
+				}
+#endif
+			case FFI_TYPE_SINT32:
+			case FFI_TYPE_UINT32:
+			case FFI_TYPE_FLOAT:
+			case FFI_TYPE_SINT64:
+			case FFI_TYPE_UINT64:
+			case FFI_TYPE_DOUBLE:
+			default:
+				memcpy(addr, value, aligned_size);
+		}
+	}
+}
+
+ffi_status ffi_prep_cif_machdep(ffi_cif* cif)
+{
+	/* check ABI */
+	switch (cif->abi)
+	{
+		case FFI_SYSV:
+			break;
+		default:
+			return FFI_BAD_ABI;
+	}
+	return FFI_OK;
+}
+
+void ffi_call(ffi_cif* cif, void (*fn)(void), void* rvalue, void** avalue)
+{
+	extended_cif ecif;
+	ecif.cif = cif;
+	ecif.avalue = avalue;
+
+	/* If the return value is a struct and we don't have a return */
+	/* value address then we need to make one */
+	if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
+		ecif.rvalue = alloca(cif->rtype->size);
+	} else {
+		ecif.rvalue = rvalue;
+	}
+
+	switch (cif->abi)
+	{
+	case FFI_SYSV:
+		ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags,
+				ecif.rvalue, fn, cif->rtype->type, cif->rtype->size);
+		break;
+	default:
+		FFI_ASSERT(0);
+		break;
+	}
+}
+
+void ffi_closure_call_SYSV(void* register_args, void* stack_args,
+			ffi_closure* closure, void* rvalue,
+			unsigned int* rtype, unsigned int* rsize)
+{
+	/* prepare arguments for closure call */
+	ffi_cif* cif = closure->cif;
+	ffi_type** arg_types = cif->arg_types;
+
+	/* re-allocate data for the args. This needs to be done in order to keep
+	 * multi-word objects (e.g. structs) in contigious memory. Callers are not
+	 * required to store the value of args in the lower 6 words in the stack
+	 * (although they are allocated in the stack).
+	 */
+	char* stackclone = alloca(cif->bytes);
+	void** avalue = alloca(cif->nargs * sizeof(void*));
+	void* struct_rvalue = NULL;
+	char* ptr = stackclone;
+	int i;
+
+	/* copy registers into stack clone */
+	int registers_used = cif->bytes;
+	if (registers_used > ARGS_REGISTER_SIZE) {
+		registers_used = ARGS_REGISTER_SIZE;
+	}
+	memcpy(stackclone, register_args, registers_used);
+
+	/* copy stack allocated args into stack clone */
+	if (cif->bytes > ARGS_REGISTER_SIZE) {
+		int stack_used = cif->bytes - ARGS_REGISTER_SIZE;
+		memcpy(stackclone + ARGS_REGISTER_SIZE, stack_args, stack_used);
+	}
+
+	/* preserve struct type return pointer passing */
+	if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
+		struct_rvalue = *((void**)ptr);
+		ptr += WORD_SIZE;
+	}
+
+	/* populate arg pointer list */
+	for (i = 0; i < cif->nargs; i++)
+	{
+		switch (arg_types[i]->type)
+		{
+			case FFI_TYPE_SINT8:
+			case FFI_TYPE_UINT8:
+#ifdef __BIG_ENDIAN__
+				avalue[i] = ptr + 3;
+#else
+				avalue[i] = ptr;
+#endif
+				break;
+			case FFI_TYPE_SINT16:
+			case FFI_TYPE_UINT16:
+#ifdef __BIG_ENDIAN__
+				avalue[i] = ptr + 2;
+#else
+				avalue[i] = ptr;
+#endif
+				break;
+			case FFI_TYPE_STRUCT:
+#if __BIG_ENDIAN__
+				/*
+				 * Work around strange ABI behaviour.
+				 * (see info in ffi_prep_args)
+				 */
+				if (arg_types[i]->size < WORD_SIZE)
+				{
+					if (arg_types[i]->size == 1) {
+						*(unsigned int *)ptr =
+								((unsigned int)*(UINT32*)(ptr)) << 24;
+					} else if (arg_types[i]->size == 2) {
+						*(unsigned int *)ptr =
+								((unsigned int)*(UINT32*)(ptr)) << 16;
+					} else {
+						*(unsigned int *)ptr =
+								((unsigned int)*(UINT32*)(ptr)) << 8;
+					}
+				}
+#endif
+				avalue[i] = (void*)ptr;
+				break;
+			case FFI_TYPE_UINT64:
+			case FFI_TYPE_SINT64:
+			case FFI_TYPE_DOUBLE:
+				avalue[i] = ptr;
+				break;
+			case FFI_TYPE_SINT32:
+			case FFI_TYPE_UINT32:
+			case FFI_TYPE_FLOAT:
+			default:
+				/* default 4-byte argument */
+				avalue[i] = ptr;
+				break;
+		}
+		ptr += WORD_ALIGN(arg_types[i]->size);
+	}
+
+	/* set the return type info passed back to the wrapper */
+	*rsize = cif->rtype->size;
+	*rtype = cif->rtype->type;
+	if (struct_rvalue != NULL) {
+		closure->fun(cif, struct_rvalue, avalue, closure->user_data);
+		/* copy struct return pointer value into function return value */
+		*((void**)rvalue) = struct_rvalue;
+	} else {
+		closure->fun(cif, rvalue, avalue, closure->user_data);
+	}
+}
+
+ffi_status ffi_prep_closure_loc(
+		ffi_closure* closure, ffi_cif* cif,
+		void (*fun)(ffi_cif*, void*, void**, void*),
+		void* user_data, void* codeloc)
+{
+	unsigned long* tramp = (unsigned long*)&(closure->tramp[0]);
+	unsigned long cls = (unsigned long)codeloc;
+	unsigned long fn = 0;
+	unsigned long fn_closure_call_sysv = (unsigned long)ffi_closure_call_SYSV;
+
+	closure->cif = cif;
+	closure->fun = fun;
+	closure->user_data = user_data;
+
+	switch (cif->abi)
+	{
+	case FFI_SYSV:
+		fn = (unsigned long)ffi_closure_SYSV;
+
+		/* load r11 (temp) with fn */
+		/* imm fn(upper) */
+		tramp[0] = 0xb0000000 | ((fn >> 16) & 0xffff);
+		/* addik r11, r0, fn(lower) */
+		tramp[1] = 0x31600000 | (fn & 0xffff);
+
+		/* load r12 (temp) with cls */
+		/* imm cls(upper) */
+		tramp[2] = 0xb0000000 | ((cls >> 16) & 0xffff);
+		/* addik r12, r0, cls(lower) */
+		tramp[3] = 0x31800000 | (cls & 0xffff);
+
+		/* load r3 (temp) with ffi_closure_call_SYSV */
+		/* imm fn_closure_call_sysv(upper) */
+		tramp[4] = 0xb0000000 | ((fn_closure_call_sysv >> 16) & 0xffff);
+		/* addik r3, r0, fn_closure_call_sysv(lower) */
+		tramp[5] = 0x30600000 | (fn_closure_call_sysv & 0xffff);
+		/* branch/jump to address stored in r11 (fn) */
+		tramp[6] = 0x98085800; /* bra r11 */
+
+		break;
+	default:
+		return FFI_BAD_ABI;
+	}
+	return FFI_OK;
+}
diff --git a/src/microblaze/ffitarget.h b/src/microblaze/ffitarget.h
new file mode 100644
index 0000000..c6fa5a4
--- /dev/null
+++ b/src/microblaze/ffitarget.h
@@ -0,0 +1,53 @@
+/* -----------------------------------------------------------------------
+   ffitarget.h - Copyright (c) 2012, 2013 Xilinx, Inc
+
+   Target configuration macros for MicroBlaze.
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+   DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#ifndef LIBFFI_TARGET_H
+#define LIBFFI_TARGET_H
+
+#ifndef LIBFFI_H
+#error "Please do not include ffitarget.h directly into your source.  Use ffi.h instead."
+#endif
+
+#ifndef LIBFFI_ASM
+typedef unsigned long			ffi_arg;
+typedef signed long			ffi_sarg;
+
+typedef enum ffi_abi {
+	FFI_FIRST_ABI = 0,
+	FFI_SYSV,
+	FFI_LAST_ABI,
+	FFI_DEFAULT_ABI = FFI_SYSV
+} ffi_abi;
+#endif
+
+/* Definitions for closures */
+
+#define FFI_CLOSURES 1
+#define FFI_NATIVE_RAW_API 0
+
+#define FFI_TRAMPOLINE_SIZE (4*8)
+
+#endif
diff --git a/src/microblaze/sysv.S b/src/microblaze/sysv.S
new file mode 100644
index 0000000..7a195a6
--- /dev/null
+++ b/src/microblaze/sysv.S
@@ -0,0 +1,302 @@
+/* -----------------------------------------------------------------------
+   sysv.S - Copyright (c) 2012, 2013 Xilinx, Inc
+
+   MicroBlaze Foreign Function Interface
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+   DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+	/*
+	 * arg[0] (r5)  = ffi_prep_args,
+	 * arg[1] (r6)  = &ecif,
+	 * arg[2] (r7)  = cif->bytes,
+	 * arg[3] (r8)  = cif->flags,
+	 * arg[4] (r9)  = ecif.rvalue,
+	 * arg[5] (r10) = fn
+	 * arg[6] (sp[0]) = cif->rtype->type
+	 * arg[7] (sp[4]) = cif->rtype->size
+	 */
+	.text
+	.globl ffi_call_SYSV
+	.type ffi_call_SYSV, @function
+ffi_call_SYSV:
+	/* push callee saves */
+	addik r1, r1, -20
+	swi r19, r1, 0 /* Frame Pointer */
+	swi r20, r1, 4 /* PIC register */
+	swi r21, r1, 8 /* PIC register */
+	swi r22, r1, 12 /* save for locals */
+	swi r23, r1, 16 /* save for locals */
+	
+	/* save the r5-r10 registers in the stack */
+	addik r1, r1, -24 /* increment sp to store 6x 32-bit words */
+	swi r5, r1, 0
+	swi r6, r1, 4
+	swi r7, r1, 8
+	swi r8, r1, 12
+	swi r9, r1, 16
+	swi r10, r1, 20
+
+	/* save function pointer */
+	addik r3, r5, 0 /* copy ffi_prep_args into r3 */
+	addik r22, r1, 0 /* save sp for unallocated args into r22 (callee-saved) */
+	addik r23, r10, 0 /* save function address into r23 (callee-saved) */
+
+	/* prepare stack with allocation for n (bytes = r7) args */
+	rsub r1, r7, r1 /* subtract bytes from sp */
+
+	/* prep args for ffi_prep_args call */
+	addik r5, r1, 0 /* store stack pointer into arg[0] */
+	/* r6 still holds ecif for arg[1] */
+
+	/* Call ffi_prep_args(stack, &ecif). */
+	addik r1, r1, -4
+	swi r15, r1, 0 /* store the link register in the frame */
+	brald r15, r3
+	nop /* branch has delay slot */
+	lwi r15, r1, 0
+	addik r1, r1, 4 /* restore the link register from the frame */
+	/* returns calling stack pointer location */
+
+	/* prepare args for fn call, prep_args populates them onto the stack */
+	lwi r5, r1, 0 /* arg[0] */
+	lwi r6, r1, 4 /* arg[1] */
+	lwi r7, r1, 8 /* arg[2] */
+	lwi r8, r1, 12 /* arg[3] */
+	lwi r9, r1, 16 /* arg[4] */
+	lwi r10, r1, 20 /* arg[5] */
+
+	/* call (fn) (...). */
+	addik r1, r1, -4
+	swi r15, r1, 0 /* store the link register in the frame */
+	brald r15, r23
+	nop /* branch has delay slot */
+	lwi r15, r1, 0
+	addik r1, r1, 4 /* restore the link register from the frame */
+
+	/* Remove the space we pushed for the args. */
+	addik r1, r22, 0 /* restore old SP */
+
+	/* restore this functions parameters */
+	lwi r5, r1, 0 /* arg[0] */
+	lwi r6, r1, 4 /* arg[1] */
+	lwi r7, r1, 8 /* arg[2] */
+	lwi r8, r1, 12 /* arg[3] */
+	lwi r9, r1, 16 /* arg[4] */
+	lwi r10, r1, 20 /* arg[5] */
+	addik r1, r1, 24 /* decrement sp to de-allocate 6x 32-bit words */
+
+	/* If the return value pointer is NULL, assume no return value. */
+	beqi r9, ffi_call_SYSV_end
+
+	lwi r22, r1, 48 /* get return type (20 for locals + 28 for arg[6]) */
+	lwi r23, r1, 52 /* get return size (20 for locals + 32 for arg[7])  */
+	
+	/* Check if return type is actually a struct, do nothing */
+	rsubi r11, r22, FFI_TYPE_STRUCT
+	beqi r11, ffi_call_SYSV_end
+
+	/* Return 8bit */
+	rsubi r11, r23, 1
+	beqi r11, ffi_call_SYSV_store8
+
+	/* Return 16bit */
+	rsubi r11, r23, 2
+	beqi r11, ffi_call_SYSV_store16
+
+	/* Return 32bit */
+	rsubi r11, r23, 4
+	beqi r11, ffi_call_SYSV_store32
+
+	/* Return 64bit */
+	rsubi r11, r23, 8
+	beqi r11, ffi_call_SYSV_store64
+
+	/* Didnt match anything */
+	bri ffi_call_SYSV_end
+
+ffi_call_SYSV_store64:
+	swi r3, r9, 0 /* store word r3 into return value */
+	swi r4, r9, 4 /* store word r4 into return value */
+	bri ffi_call_SYSV_end
+
+ffi_call_SYSV_store32:
+	swi r3, r9, 0 /* store word r3 into return value */
+	bri ffi_call_SYSV_end
+
+ffi_call_SYSV_store16:
+#ifdef __BIG_ENDIAN__
+	shi r3, r9, 2 /* store half-word r3 into return value */
+#else
+	shi r3, r9, 0 /* store half-word r3 into return value */
+#endif
+	bri ffi_call_SYSV_end
+
+ffi_call_SYSV_store8:
+#ifdef __BIG_ENDIAN__
+	sbi r3, r9, 3 /* store byte r3 into return value */
+#else
+	sbi r3, r9, 0 /* store byte r3 into return value */
+#endif
+	bri ffi_call_SYSV_end
+
+ffi_call_SYSV_end:
+	/* callee restores */
+	lwi r19, r1, 0 /* frame pointer */
+	lwi r20, r1, 4 /* PIC register */
+	lwi r21, r1, 8 /* PIC register */
+	lwi r22, r1, 12
+	lwi r23, r1, 16
+	addik r1, r1, 20
+
+	/* return from sub-routine (with delay slot) */
+	rtsd r15, 8
+	nop
+
+	.size ffi_call_SYSV, . - ffi_call_SYSV
+
+/* ------------------------------------------------------------------------- */
+
+	/*
+	 * args passed into this function, are passed down to the callee.
+	 * this function is the target of the closure trampoline, as such r12 is 
+	 * a pointer to the closure object.
+	 */
+	.text
+	.globl ffi_closure_SYSV
+	.type ffi_closure_SYSV, @function
+ffi_closure_SYSV:
+	/* push callee saves */
+	addik r11, r1, 28 /* save stack args start location (excluding regs/link) */
+	addik r1, r1, -12
+	swi r19, r1, 0 /* Frame Pointer */
+	swi r20, r1, 4 /* PIC register */
+	swi r21, r1, 8 /* PIC register */
+
+	/* store register args on stack */
+	addik r1, r1, -24
+	swi r5, r1, 0
+	swi r6, r1, 4
+	swi r7, r1, 8
+	swi r8, r1, 12
+	swi r9, r1, 16
+	swi r10, r1, 20
+
+	/* setup args */
+	addik r5, r1, 0 /* register_args */
+	addik r6, r11, 0 /* stack_args */
+	addik r7, r12, 0 /* closure object */
+	addik r1, r1, -8 /* allocate return value */
+	addik r8, r1, 0 /* void* rvalue */
+	addik r1, r1, -8 /* allocate for reutrn type/size values */
+	addik r9, r1, 0 /* void* rtype */
+	addik r10, r1, 4 /* void* rsize */
+
+	/* call the wrap_call function */
+	addik r1, r1, -28 /* allocate args + link reg */
+	swi r15, r1, 0 /* store the link register in the frame */
+	brald r15, r3
+	nop /* branch has delay slot */
+	lwi r15, r1, 0
+	addik r1, r1, 28 /* restore the link register from the frame */
+
+ffi_closure_SYSV_prepare_return:
+	lwi r9, r1, 0 /* rtype */
+	lwi r10, r1, 4 /* rsize */
+	addik r1, r1, 8 /* de-allocate return info values */
+
+	/* Check if return type is actually a struct, store 4 bytes */
+	rsubi r11, r9, FFI_TYPE_STRUCT
+	beqi r11, ffi_closure_SYSV_store32
+
+	/* Return 8bit */
+	rsubi r11, r10, 1
+	beqi r11, ffi_closure_SYSV_store8
+
+	/* Return 16bit */
+	rsubi r11, r10, 2
+	beqi r11, ffi_closure_SYSV_store16
+
+	/* Return 32bit */
+	rsubi r11, r10, 4
+	beqi r11, ffi_closure_SYSV_store32
+
+	/* Return 64bit */
+	rsubi r11, r10, 8
+	beqi r11, ffi_closure_SYSV_store64
+
+	/* Didnt match anything */
+	bri ffi_closure_SYSV_end
+
+ffi_closure_SYSV_store64:
+	lwi r3, r1, 0 /* store word r3 into return value */
+	lwi r4, r1, 4 /* store word r4 into return value */
+	/* 64 bits == 2 words, no sign extend occurs */
+	bri ffi_closure_SYSV_end
+
+ffi_closure_SYSV_store32:
+	lwi r3, r1, 0 /* store word r3 into return value */
+	/* 32 bits == 1 word, no sign extend occurs */
+	bri ffi_closure_SYSV_end
+
+ffi_closure_SYSV_store16:
+#ifdef __BIG_ENDIAN__
+	lhui r3, r1, 2 /* store half-word r3 into return value */
+#else
+	lhui r3, r1, 0 /* store half-word r3 into return value */
+#endif
+	rsubi r11, r9, FFI_TYPE_SINT16
+	bnei r11, ffi_closure_SYSV_end
+	sext16 r3, r3 /* fix sign extend of sint8 */
+	bri ffi_closure_SYSV_end
+
+ffi_closure_SYSV_store8:
+#ifdef __BIG_ENDIAN__
+	lbui r3, r1, 3 /* store byte r3 into return value */
+#else
+	lbui r3, r1, 0 /* store byte r3 into return value */
+#endif
+	rsubi r11, r9, FFI_TYPE_SINT8
+	bnei r11, ffi_closure_SYSV_end
+	sext8 r3, r3 /* fix sign extend of sint8 */
+	bri ffi_closure_SYSV_end
+
+ffi_closure_SYSV_end:
+	addik r1, r1, 8 /* de-allocate return value */
+
+	/* de-allocate stored args */
+	addik r1, r1, 24
+
+	/* callee restores */
+	lwi r19, r1, 0 /* frame pointer */
+	lwi r20, r1, 4 /* PIC register */
+	lwi r21, r1, 8 /* PIC register */
+	addik r1, r1, 12
+
+	/* return from sub-routine (with delay slot) */
+	rtsd r15, 8
+	nop
+
+	.size ffi_closure_SYSV, . - ffi_closure_SYSV
-- 
1.7.5.4



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]