Add OpenRISC support
authorSebastian Macke <sebastian@macke.de>
Sat, 27 Sep 2014 00:19:15 +0000 (00:19 +0000)
committerSebastian Macke <sebastian@macke.de>
Sat, 27 Sep 2014 00:56:56 +0000 (00:56 +0000)
This patch adds support for the OpenRISC architecture.
(http://opencores.org/or1k/Main_Page)

This patch has been tested under Linux with QEMU-user emulation support.
- 32 Bit
- big endian
- delayed instructions
This is the only available configuration under Linux.

The description of the ABI can be found on the official website.

Is passes the testsuite except of the unwindtest_ffi_call.cc
testcase, which seems to be a problem of gcc and not libffi.
Some testcases of the gcc testsuite still fail.

Signed-off-by: Sebastian Macke <sebastian@macke.de>
Makefile.am
README
configure.ac
src/or1k/ffi.c [new file with mode: 0644]
src/or1k/ffitarget.h [new file with mode: 0644]
src/or1k/sysv.S [new file with mode: 0644]

index 1dcdc81..0e40451 100644 (file)
@@ -24,6 +24,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj                    \
         src/microblaze/ffi.c src/microblaze/sysv.S                     \
         src/microblaze/ffitarget.h                                     \
         src/nios2/ffi.c src/nios2/ffitarget.h src/nios2/sysv.S         \
+        src/or1k/ffi.c src/or1k/ffitarget.h src/or1k/sysv.S            \
         src/powerpc/ffi.c src/powerpc/ffi_powerpc.h                    \
         src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c               \
         src/powerpc/sysv.S src/powerpc/linux64.S                       \
@@ -169,6 +170,9 @@ endif
 if NIOS2
 nodist_libffi_la_SOURCES += src/nios2/sysv.S src/nios2/ffi.c
 endif
+if OR1K
+nodist_libffi_la_SOURCES += src/or1k/sysv.S src/or1k/ffi.c
+endif
 if POWERPC
 nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S
 endif
diff --git a/README b/README
index 765e8d7..44c070a 100644 (file)
--- a/README
+++ b/README
@@ -74,6 +74,7 @@ tested:
 | MIPS64          | Linux            | GCC                     |
 | Moxie           | Bare metal       | GCC                     |
 | Nios II         | Linux            | GCC                     |
+| OpenRISC        | Linux            | GCC                     |
 | PowerPC 32-bit  | AIX              | IBM XL C                |
 | PowerPC 64-bit  | AIX              | IBM XL C                |
 | PowerPC         | AMIGA            | GCC                     |
index 4c3922f..4a44bff 100644 (file)
@@ -230,6 +230,10 @@ case "$host" in
        TARGET=NIOS2; TARGETDIR=nios2
        ;;
 
+  or1k*-linux*)
+       TARGET=OR1K; TARGETDIR=or1k
+       ;;
+
   powerpc*-*-linux* | powerpc-*-sysv*)
        TARGET=POWERPC; TARGETDIR=powerpc
        HAVE_LONG_DOUBLE_VARIANT=1
@@ -312,6 +316,7 @@ AM_CONDITIONAL(MICROBLAZE, test x$TARGET = xMICROBLAZE)
 AM_CONDITIONAL(METAG, test x$TARGET = xMETAG)
 AM_CONDITIONAL(MOXIE, test x$TARGET = xMOXIE)
 AM_CONDITIONAL(NIOS2, test x$TARGET = xNIOS2)
+AM_CONDITIONAL(OR1K, test x$TARGET = xOR1K)
 AM_CONDITIONAL(POWERPC, test x$TARGET = xPOWERPC)
 AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX)
 AM_CONDITIONAL(POWERPC_DARWIN, test x$TARGET = xPOWERPC_DARWIN)
diff --git a/src/or1k/ffi.c b/src/or1k/ffi.c
new file mode 100644 (file)
index 0000000..2bad938
--- /dev/null
@@ -0,0 +1,328 @@
+/* -----------------------------------------------------------------------
+   ffi.c - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de>
+
+   OpenRISC 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"
+
+/* ffi_prep_args is called by the assembly routine once stack space
+   has been allocated for the function's arguments */
+
+void* ffi_prep_args(char *stack, extended_cif *ecif)
+{
+  char *stacktemp = stack;
+  int i, s;
+  ffi_type **arg;
+  int count = 0;
+  int nfixedargs;
+  
+  nfixedargs = ecif->cif->nfixedargs;
+  arg = ecif->cif->arg_types;
+  void **argv = ecif->avalue;
+
+  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
+    {
+      *(void **) stack = ecif->rvalue;
+      stack += 4;
+      count = 4;
+    } 
+  for(i=0; i<ecif->cif->nargs; i++)
+  {
+
+    /* variadic args are saved on stack */
+    if ((nfixedargs == 0) && (count < 24))
+      {
+        count = 24;
+        stack = stacktemp + 24;        
+      }
+    nfixedargs--;
+
+    s = 4;
+    switch((*arg)->type) 
+      {
+      case FFI_TYPE_STRUCT:
+        *(void **)stack = *argv;
+        break;
+
+      case FFI_TYPE_SINT8:
+        *(signed int *) stack = (signed int)*(SINT8 *)(* argv);
+        break;
+
+      case FFI_TYPE_UINT8:
+        *(unsigned int *) stack = (unsigned int)*(UINT8 *)(* argv);
+        break;
+
+      case FFI_TYPE_SINT16:
+        *(signed int *) stack = (signed int)*(SINT16 *)(* argv);
+        break;
+
+      case FFI_TYPE_UINT16:
+        *(unsigned int *) stack = (unsigned int)*(UINT16 *)(* argv);
+        break;
+
+      case FFI_TYPE_SINT32:
+      case FFI_TYPE_UINT32:
+      case FFI_TYPE_FLOAT:
+      case FFI_TYPE_POINTER:
+        *(int *)stack = *(int*)(*argv);
+        break;
+
+      default: /* 8 byte types */
+        if (count == 20) /* never split arguments */
+          {
+            stack += 4;
+            count += 4;
+          }  
+        s = (*arg)->size;
+        memcpy(stack, *argv, s);
+        break;
+      }
+
+    stack += s;
+    count += s;
+    argv++;
+    arg++;
+  }
+  return stacktemp + ((count>24)?24:0);
+}
+
+extern void ffi_call_SYSV(unsigned,
+                          extended_cif *,
+                          void *(*)(int *, extended_cif *),
+                          unsigned *,
+                          void (*fn)(void),
+                          unsigned);
+
+
+void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+  int i;
+  int size;
+  ffi_type **arg;
+
+  /* Calculate size to allocate on stack */
+
+  for(i = 0, arg = cif->arg_types, size=0; i < cif->nargs; i++, arg++)
+    {
+      if ((*arg)->type == FFI_TYPE_STRUCT)
+        size += 4;
+      else
+      if ((*arg)->size <= 4)
+        size += 4;
+      else
+        size += 8;
+    }
+
+  /* for variadic functions more space is needed on the stack */
+  if (cif->nargs != cif->nfixedargs)
+    size += 24;
+
+  if (cif->rtype->type == FFI_TYPE_STRUCT)
+    size += 4;
+
+
+  extended_cif ecif;
+  ecif.cif = cif;
+  ecif.avalue = avalue;
+  ecif.rvalue = rvalue;
+
+  switch (cif->abi) 
+  {
+    case FFI_SYSV:
+      ffi_call_SYSV(size, &ecif, ffi_prep_args, rvalue, fn, cif->flags);
+      break;
+    default:
+      FFI_ASSERT(0);
+      break;
+  }
+}
+
+
+void ffi_closure_SYSV(unsigned long r3, unsigned long r4, unsigned long r5, 
+                      unsigned long r6, unsigned long r7, unsigned long r8)
+{
+  register int *sp __asm__ ("r17");
+  register int *r13 __asm__ ("r13");
+
+  ffi_closure* closure = (ffi_closure*) r13;
+  char *stack_args = sp;
+
+  /* Lay the register arguments down in a continuous chunk of memory.  */
+  unsigned register_args[6] =
+    { r3, r4, r5, r6, r7, r8 };
+
+  /* Pointer to a struct return value.  */
+  void *struct_rvalue = (void *) r3;
+
+  ffi_cif *cif = closure->cif;
+  ffi_type **arg_types = cif->arg_types;
+  void **avalue = alloca (cif->nargs * sizeof(void *));
+  char *ptr = (char *) register_args;
+  int count = 0;
+  int nfixedargs = cif->nfixedargs;
+  int i;
+
+  /* preserve struct type return pointer passing */
+
+  if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) 
+  {
+    ptr += 4;
+    count = 4;
+  }
+
+  /* Find the address of each argument.  */
+  for (i = 0; i < cif->nargs; i++)
+    {
+
+      /* variadic args are saved on stack */
+      if ((nfixedargs == 0) && (count < 24))
+        {
+          ptr = stack_args;
+          count = 24;
+        }
+      nfixedargs--;
+
+      switch (arg_types[i]->type)
+        {
+        case FFI_TYPE_SINT8:
+        case FFI_TYPE_UINT8:
+          avalue[i] = ptr + 3;
+          break;
+
+        case FFI_TYPE_SINT16:
+        case FFI_TYPE_UINT16:
+          avalue[i] = ptr + 2;
+          break;
+
+        case FFI_TYPE_SINT32:
+        case FFI_TYPE_UINT32:
+        case FFI_TYPE_FLOAT:
+        case FFI_TYPE_POINTER:
+          avalue[i] = ptr;
+          break;
+
+        case FFI_TYPE_STRUCT:
+          avalue[i] = *(void**)ptr;
+          break;
+
+        default:
+          /* 8-byte values  */
+
+          /* arguments are never splitted */
+          if (ptr == &register_args[5])
+            ptr = stack_args;
+          avalue[i] = ptr;
+          ptr += 4;
+          count += 4;
+          break;
+        }
+      ptr += 4;
+      count += 4;
+
+      /* If we've handled more arguments than fit in registers,
+         start looking at the those passed on the stack.  */
+
+      if (count == 24)
+        ptr = stack_args;
+    }
+
+  if (cif->rtype && (cif->rtype->type == FFI_TYPE_STRUCT))
+    {
+      (closure->fun) (cif, struct_rvalue, avalue, closure->user_data);
+    } else
+    {
+      long long rvalue;
+      (closure->fun) (cif, &rvalue, avalue, closure->user_data);
+      if (cif->rtype)
+        asm ("l.ori r12, %0, 0x0\n l.lwz r11, 0(r12)\n l.lwz r12, 4(r12)" : : "r" (&rvalue));      
+    }
+}
+
+
+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 short *tramp = (unsigned short *) closure->tramp;
+  unsigned long fn = (unsigned long) ffi_closure_SYSV;
+  unsigned long cls = (unsigned long) codeloc;
+
+  if (cif->abi != FFI_SYSV)
+    return FFI_BAD_ABI;
+
+  closure->cif = cif;
+  closure->user_data = user_data;
+  closure->fun = fun;
+
+  /* write pointers to temporary registers */
+  tramp[0] = (0x6 << 10) | (13 << 5); /* l.movhi r13, ... */
+  tramp[1] = cls >> 16;
+  tramp[2] = (0x2a << 10) | (13 << 5) | 13; /* l.ori r13, r13, ... */
+  tramp[3] = cls & 0xFFFF;
+
+  tramp[4] = (0x6 << 10) | (15 << 5); /* l.movhi r15, ... */
+  tramp[5] = fn >> 16;
+  tramp[6] = (0x2a << 10) | (15 << 5) | 15; /* l.ori r15, r15 ... */
+  tramp[7] = fn & 0xFFFF;
+
+  tramp[8] = (0x11 << 10); /* l.jr r15 */
+  tramp[9] = 15 << 11;
+
+  tramp[10] = (0x2a << 10) | (17 << 5) | 1; /* l.ori r17, r1, ... */
+  tramp[11] = 0x0;
+
+  return FFI_OK;
+}
+
+
+ffi_status ffi_prep_cif_machdep (ffi_cif *cif)
+{
+  cif->flags = 0;
+       
+  /* structures are returned as pointers */
+  if (cif->rtype->type == FFI_TYPE_STRUCT)
+    cif->flags = FFI_TYPE_STRUCT;
+  else 
+  if (cif->rtype->size > 4)
+    cif->flags = FFI_TYPE_UINT64;
+
+  cif->nfixedargs = cif->nargs;
+
+  return FFI_OK;
+}
+
+
+ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
+         unsigned int nfixedargs, unsigned int ntotalargs)
+{
+  ffi_status status;
+
+  status = ffi_prep_cif_machdep (cif);
+  cif->nfixedargs = nfixedargs;
+  return status;
+} 
diff --git a/src/or1k/ffitarget.h b/src/or1k/ffitarget.h
new file mode 100644 (file)
index 0000000..e55da28
--- /dev/null
@@ -0,0 +1,58 @@
+/* -----------------------------------------------------------------------
+   ffitarget.h - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de>
+
+   OpenRISC Target configuration macros
+
+   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
+
+/* ---- System specific configurations ----------------------------------- */
+
+#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 (24)
+
+#define FFI_TARGET_SPECIFIC_VARIADIC 1
+#define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs;
+
+#endif
+
diff --git a/src/or1k/sysv.S b/src/or1k/sysv.S
new file mode 100644 (file)
index 0000000..df6570b
--- /dev/null
@@ -0,0 +1,107 @@
+/* -----------------------------------------------------------------------
+   sysv.S - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de>
+
+   OpenRISC 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>
+
+.text
+       .globl ffi_call_SYSV
+       .type ffi_call_SYSV, @function
+/*
+  r3: size to allocate on stack
+  r4: extended cif structure
+  r5: function pointer ffi_prep_args
+  r6: ret address
+  r7: function to call
+  r8: flag for return type
+*/
+
+ffi_call_SYSV:
+       /* Store registers used on stack */
+       l.sw -4(r1), r9 /* return address */
+       l.sw -8(r1), r1 /* stack address */
+       l.sw -12(r1), r14 /* callee saved registers */
+       l.sw -16(r1), r16
+       l.sw -20(r1), r18 
+       l.sw -24(r1), r20
+
+       l.ori r14, r1, 0x0 /* save stack pointer */
+       l.addi r1, r1, -24
+
+       l.ori r16, r7, 0x0 /* save function address */
+       l.ori r18, r6, 0x0 /* save ret address */
+       l.ori r20, r8, 0x0 /* save flag */
+
+       l.sub r1, r1, r3 /* reserve space on stack */
+
+       /* Call ffi_prep_args */
+       l.ori r3, r1, 0x0  /* first argument stack address, second already ecif */
+       l.jalr r5
+       l.nop
+
+       /* Load register arguments and call*/
+
+       l.lwz r3, 0(r1)
+       l.lwz r4, 4(r1)
+       l.lwz r5, 8(r1)
+       l.lwz r6, 12(r1)
+       l.lwz r7, 16(r1)
+       l.lwz r8, 20(r1)
+       l.ori r1, r11, 0x0 /* new stack pointer */
+       l.jalr r16
+       l.nop
+       
+       /* handle return values */
+
+       l.sfeqi r20, FFI_TYPE_STRUCT
+       l.bf ret  /* structs don't return an rvalue */
+       l.nop
+
+       /* copy ret address */
+
+       l.sfeqi r20, FFI_TYPE_UINT64
+       l.bnf four_byte_ret  /* 8 byte value is returned */
+       l.nop
+
+       l.sw 4(r18), r12
+
+four_byte_ret:
+       l.sw 0(r18), r11
+
+ret:
+       /* return */
+       l.ori r1, r14, 0x0 /* reset stack pointer */
+       l.lwz r9, -4(r1)
+       l.lwz r1, -8(r1)
+       l.lwz r14, -12(r1)
+       l.lwz r16, -16(r1)
+       l.lwz r18, -20(r1)
+       l.lwz r20, -24(r1)
+       l.jr r9
+       l.nop
+
+.size ffi_call_SYSV, .-ffi_call_SYSV