changeset 653:0c8838766866

- riscv64 support for calls and callbacks (but lacking aggr and syscall support) - thanks Jun Jeon! :) - mark riscv64 as implemented in manual overview
author Tassilo Philipp
date Thu, 07 Mar 2024 17:42:13 +0100
parents e7ffb0fb1520
children 0079a8fa894e
files doc/manual/manual_overview.tex dyncall/dyncall.h dyncall/dyncall_call.S dyncall/dyncall_call_riscv64.S dyncall/dyncall_callvm.c dyncall/dyncall_callvm_riscv64.c dyncall/dyncall_callvm_riscv64.h dyncall/dyncall_macros.h dyncallback/dyncall_args.c dyncallback/dyncall_args_riscv64.c dyncallback/dyncall_callback.c dyncallback/dyncall_callback_arch.S dyncallback/dyncall_callback_riscv64.S dyncallback/dyncall_callback_riscv64.c dyncallback/dyncall_thunk.c dyncallback/dyncall_thunk.h dyncallback/dyncall_thunk_riscv64.c dyncallback/dyncall_thunk_riscv64.h
diffstat 18 files changed, 810 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/doc/manual/manual_overview.tex	Thu Mar 07 14:48:03 2024 +0100
+++ b/doc/manual/manual_overview.tex	Thu Mar 07 17:42:13 2024 +0100
@@ -232,7 +232,7 @@
 \hline
 RISC-V                     &    & \marknotx  & \marknimp  & \marknotx  & \marknotx  & \marknotx  & \marknotx  & \marknotx  & \marknotx  & \marknotx  & \marknotx  & \marknotx  & \marknotx  & \marknotx \\%& \\
 \hline
-RISC-V 64                  &    & \marknotx  & \marknimp  & \marknotx  & \marknimp  & \marknotx  & \marknimp  & \marknotx  & \marknotx  & \marknotx  & \marknotx  & \marknotx  & \marknotx  & \marknotx \\%& \\
+RISC-V 64                  &    & \marknotx  & \markimpl  & \marknotx  & \markimpl  & \markunkn  & \markunkn  & \marknotx  & \marknotx  & \marknotx  & \marknotx  & \marknotx  & \marknotx  & \marknotx \\%& \\
 
 \end{tabular}
 \caption{Supported platforms}%
--- a/dyncall/dyncall.h	Thu Mar 07 14:48:03 2024 +0100
+++ b/dyncall/dyncall.h	Thu Mar 07 17:42:13 2024 +0100
@@ -75,6 +75,7 @@
 #define DC_CALL_C_ARM64                22
 #define DC_CALL_C_PPC64                23
 #define DC_CALL_C_PPC64_LINUX          DC_CALL_C_PPC64 /* alias */
+#define DC_CALL_C_RISCV64              24
 /* syscalls, default */
 #define DC_CALL_SYS_DEFAULT           200
 /* syscalls, platform specific */
--- a/dyncall/dyncall_call.S	Thu Mar 07 14:48:03 2024 +0100
+++ b/dyncall/dyncall_call.S	Thu Mar 07 17:42:13 2024 +0100
@@ -80,6 +80,8 @@
 #    include "dyncall_call_sparc64.s"
 #  elif defined(DC__Arch_Sparc)
 #    include "dyncall_call_sparc.s"
+#  elif defined(DC__Arch_RiscV64)
+#    include "dyncall_call_riscv64.S"
 #  else
 #    error Unsupported Architecture.
 #  endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dyncall/dyncall_call_riscv64.S	Thu Mar 07 17:42:13 2024 +0100
@@ -0,0 +1,124 @@
+/*
+
+ Package: dyncall
+ Library: dyncall
+ File: dyncall/dyncall_call_riscv64.S
+ Description: Call Kernel for RISCV64 Architecture
+ License:
+
+   Copyright (c) 2023 Jun Jeon <yjeon@netflix.com>
+
+   Permission to use, copy, modify, and distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+
+/* ============================================================================
+   DynCall Call Kernel for RISCV64 Architecture 
+   ----------------------------------------------------------------------------
+   C Interface:
+     dcCall_riscv64 (DCpointer target, DCpointer data, DCsize size, DCfloat* regdata);
+*/
+
+.text
+/*
+   DynCall Back-End riscv64
+   
+   Supports:
+   - arch=rv64g, abi=lp64d
+*/ 
+
+.globl dcCall_riscv64
+dcCall_riscv64:
+.align 2
+
+/* input:
+     a0: target   (address of target)
+     a1: data     (address of stack copy data)
+     a2: size     (number of 'pair' 16-byte units)
+     a3: regdata  (address of register data)
+*/
+
+/* prolog: */
+
+	add  sp, sp, -16 /* alloc frame */
+	sd   ra, 0(sp)   /* save ret addr */
+	sd   s0, 8(sp)   /* save stk ptr */
+	mv   s0, sp      /* set cur stk ptr */
+
+/* load 64-bit floating-point registers */
+        
+	fld  fa0, 0(a3)
+	fld  fa1, 8(a3)
+	fld  fa2, 16(a3)
+	fld  fa3, 24(a3)
+	fld  fa4, 32(a3)
+	fld  fa5, 40(a3)
+	fld  fa6, 48(a3)
+	fld  fa7, 56(a3)
+
+/* copy to stack */
+
+	sub  sp, sp, a2     /* create call-frame */
+	
+	mv   t1, zero       /* t1: cnt = 0 */
+	mv   t2, a1         /* t2: read pointer = data */
+	mv   t3, sp         /* t3: write pointer = sp */
+
+.next:
+	bge  t1, a2, .done
+	
+	ld   t4, 0(t2)      /* read 8b from mem */
+	sd   t4, 0(t3)      /* write 8b to mem */
+
+	/* advance the pointers */
+	add  t2, t2, 8
+	add  t3, t3, 8
+	add  t1, t1, 8
+
+	j    .next
+
+.done:
+
+/* rescue temp int registers */
+
+	mv   t1, a0         /* t1: target */
+	add  t2, a3, 64     /* t2: integer reg buffer */
+
+/* load 64-bit integer registers ( 8 x 64-bit ) */
+
+	/* load register set */
+
+	ld   a0, 0(t2)
+	ld   a1, 8(t2)
+	ld   a2, 16(t2)
+	ld   a3, 24(t2)
+	ld   a4, 32(t2)
+	ld   a5, 40(t2)
+	ld   a6, 48(t2)
+	ld   a7, 56(t2)
+
+/* call target: */
+
+	jalr ra, 0(t1)
+
+/* epilog: */
+
+	mv   sp, s0
+
+	ld   ra, 0(sp)
+	ld   s0, 8(sp)
+	add  sp, sp, 16
+
+	ret
+
--- a/dyncall/dyncall_callvm.c	Thu Mar 07 14:48:03 2024 +0100
+++ b/dyncall/dyncall_callvm.c	Thu Mar 07 17:42:13 2024 +0100
@@ -6,7 +6,7 @@
  Description: auto-select default callvm (includes other C sources).
  License:
 
-   Copyright (c) 2007-2018 Daniel Adler <dadler@uni-goettingen.de>, 
+   Copyright (c) 2007-2024 Daniel Adler <dadler@uni-goettingen.de>, 
                            Tassilo Philipp <tphilipp@potion-studios.com>
 
    Permission to use, copy, modify, and distribute this software for any
@@ -69,8 +69,8 @@
 #  include "dyncall_callvm_sparc.c"
 #elif defined(DC__Arch_Sparc64)
 #  include "dyncall_callvm_sparc64.c"
-#elif defined(DC__Arch_RiscV)
-#  include "dyncall_callvm_riscv.c"
+#elif defined(DC__Arch_RiscV64)
+#  include "dyncall_callvm_riscv64.c"
 #else
 #  error unsupported platform
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dyncall/dyncall_callvm_riscv64.c	Thu Mar 07 17:42:13 2024 +0100
@@ -0,0 +1,252 @@
+/*
+
+ Package: dyncall
+ Library: dyncall
+ File: dyncall/dyncall_callvm_riscv64.c
+ Description: RISC-V ABI implementation
+ License:
+
+   Copyright (c) 2023 Jun Jeon <yjeon@netflix.com>
+
+   Permission to use, copy, modify, and distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+
+#include "dyncall_callvm_riscv64.h"
+#include "dyncall_alloc.h"
+
+
+void dcCall_riscv64(DCpointer target, DCpointer data, DCsize size, DCpointer regdata);
+
+
+static void reset(DCCallVM* in_p)
+{
+  DCCallVM_riscv64* p = (DCCallVM_riscv64*)in_p;
+  p->i = 0;
+  p->f = 0;
+  dcVecReset(&p->mVecHead);
+  /* single precision fp values in 64b float registers require all 32 high bits *
+   * to be set: set all bits on init, will be overwritten when doubles are used */
+  for(int i=0; i<RISCV_NUM_FLOAT_REGISTERS; ++i)
+    p->u.I[i] = -1;
+}
+
+
+static void deinit(DCCallVM* in_self)
+{
+  dcFreeMem(in_self);
+}
+
+
+
+static void a_i64(DCCallVM* in_self, DClonglong x)
+{
+  DCCallVM_riscv64* p = (DCCallVM_riscv64*)in_self;
+  if (p->i < RISCV_NUM_INT_REGISTERS) {
+    p->I[p->i] = x;
+    p->i++;
+  } else {
+    dcVecAppend(&p->mVecHead, &x, sizeof(DClonglong));
+  }
+}
+
+static void a_bool    (DCCallVM* self, DCbool    x) { a_i64(self, (DClonglong)x); }
+static void a_char    (DCCallVM* self, DCchar    x) { a_i64(self, x); }
+static void a_short   (DCCallVM* self, DCshort   x) { a_i64(self, x); }
+static void a_int     (DCCallVM* self, DCint     x) { a_i64(self, x); }
+static void a_long    (DCCallVM* self, DClong    x) { a_i64(self, x); }
+static void a_pointer (DCCallVM* self, DCpointer x) { a_i64(self, (DClonglong) x ); }
+
+static void a_float(DCCallVM* in_p, DCfloat x)
+{
+  DCCallVM_riscv64* p = (DCCallVM_riscv64*)in_p;
+
+  if (p->f < RISCV_NUM_FLOAT_REGISTERS) {
+    /* trivial case; just use float arg reg */
+    p->u.S[p->f << 1] = x;
+    ++p->f;
+  } else if (p->i < RISCV_NUM_INT_REGISTERS) {
+    /* risc-v will use int arg reg to pass float args */
+    p->I[p->i] = (unsigned)*(DCint*)&x;
+    ++p->i;
+  } else {
+    /* now everything has to go on stack */
+    dcVecAppend(&p->mVecHead, &x, sizeof(DCfloat));
+    dcVecSkip(&p->mVecHead, 4);        /* align to 8-bytes */
+  }
+}
+
+static void a_double(DCCallVM* in_p, DCdouble x)
+{
+  DCCallVM_riscv64* p = (DCCallVM_riscv64*)in_p;
+  if (p->f < RISCV_NUM_FLOAT_REGISTERS) {
+    /* trivial case; just use float arg reg */
+    p->u.D[p->f] = x;
+    ++p->f;
+  } else if (p->i < RISCV_NUM_INT_REGISTERS) {
+    /* risc-v will use int arg reg to pass float args */
+    p->I[p->i] = *(DClonglong*)&x;
+    ++p->i;
+  } else {
+    /* now everything has to go on stack */
+    dcVecAppend(&p->mVecHead, &x, sizeof(DCdouble));
+  }
+}
+
+
+/* for variadic args, push everything onto stack, according to the RISC-V calling convention */
+
+static void var_i64(DCCallVM* in_self, DClonglong x)
+{
+  DCCallVM_riscv64* p = (DCCallVM_riscv64*)in_self;
+  /* first use int registers, then spill over onto stack */
+  if (p->i < RISCV_NUM_INT_REGISTERS) {
+    p->I[p->i] = *(DClonglong*)&x;
+    p->i++;
+  } else {
+    dcVecAppend(&p->mVecHead, &x, sizeof(DClonglong));
+  }
+}
+
+static void var_bool    (DCCallVM* self, DCbool    x) { var_i64(self, (DClonglong)x); }
+static void var_char    (DCCallVM* self, DCchar    x) { var_i64(self, (DClonglong)x); }
+static void var_short   (DCCallVM* self, DCshort   x) { var_i64(self, (DClonglong)x); }
+static void var_int     (DCCallVM* self, DCint     x) { var_i64(self, (DClonglong)x); }
+static void var_long    (DCCallVM* self, DClong    x) { var_i64(self, (DClonglong)x); }
+static void var_pointer (DCCallVM* self, DCpointer x) { var_i64(self, (DClonglong)x); }
+
+static void var_double(DCCallVM* in_p, DCdouble x)
+{
+  DCCallVM_riscv64* p = (DCCallVM_riscv64*)in_p;
+  /* first use int registers, then spill over onto stack */
+  if (p->i < RISCV_NUM_INT_REGISTERS) {
+    p->I[p->i] = *(DClonglong*)&x;
+    p->i++;
+  } else {
+    dcVecAppend(&p->mVecHead, &x, sizeof(DCdouble));
+  }
+}
+
+static void var_float(DCCallVM* in_p, DCfloat x)
+{
+  var_double(in_p, (DCdouble)x);
+}
+
+
+void call(DCCallVM* in_p, DCpointer target)
+{
+  DCCallVM_riscv64* p = (DCCallVM_riscv64*)in_p;
+
+  /*
+  ** copy 'size' argument is given in number of 16-byte 'pair' blocks.
+     sp is always 16-byte aligned
+     ref: https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf, page 3
+  */
+  dcCall_riscv64(target, dcVecData(&p->mVecHead), ( dcVecSize(&p->mVecHead) + 15 ) & -16, &p->u.S[0]);
+}
+
+static void mode(DCCallVM* in_self, DCint mode);
+
+DCCallVM_vt vt_riscv64 =
+{
+  &deinit
+, &reset
+, &mode
+, &a_bool
+, &a_char
+, &a_short
+, &a_int
+, &a_long
+, &a_i64
+, &a_float
+, &a_double
+, &a_pointer
+, NULL /* argAggr */
+, (DCvoidvmfunc*)       &call
+, (DCboolvmfunc*)       &call
+, (DCcharvmfunc*)       &call
+, (DCshortvmfunc*)      &call
+, (DCintvmfunc*)        &call
+, (DClongvmfunc*)       &call
+, (DClonglongvmfunc*)   &call
+, (DCfloatvmfunc*)      &call
+, (DCdoublevmfunc*)     &call
+, (DCpointervmfunc*)    &call
+, NULL /* callAggr */
+, NULL /* beginAggr */
+};
+
+DCCallVM_vt vt_riscv64_varargs =
+{
+  &deinit
+, &reset
+, &mode
+, &var_bool
+, &var_char
+, &var_short
+, &var_int
+, &var_long
+, &var_i64
+, &var_float
+, &var_double
+, &var_pointer
+, NULL /* argAggr */
+, (DCvoidvmfunc*)       &call
+, (DCboolvmfunc*)       &call
+, (DCcharvmfunc*)       &call
+, (DCshortvmfunc*)      &call
+, (DCintvmfunc*)        &call
+, (DClongvmfunc*)       &call
+, (DClonglongvmfunc*)   &call
+, (DCfloatvmfunc*)      &call
+, (DCdoublevmfunc*)     &call
+, (DCpointervmfunc*)    &call
+, NULL /* callAggr */
+, NULL /* beginAggr */
+};
+
+static void mode(DCCallVM* in_self, DCint mode)
+{
+  DCCallVM_riscv64* self = (DCCallVM_riscv64*)in_self;
+  DCCallVM_vt* vt;
+
+  switch(mode) {
+    case DC_CALL_C_DEFAULT:
+    case DC_CALL_C_RISCV64:
+    case DC_CALL_C_ELLIPSIS:
+      vt = &vt_riscv64;
+      break;
+    case DC_CALL_C_ELLIPSIS_VARARGS:
+      vt = &vt_riscv64_varargs;
+      break;
+    default:
+      self->mInterface.mError = DC_ERROR_UNSUPPORTED_MODE;
+      return;
+  }
+  dc_callvm_base_init(&self->mInterface, vt);
+}
+
+/* Public API. */
+DCCallVM* dcNewCallVM(DCsize size)
+{
+  DCCallVM_riscv64* p = (DCCallVM_riscv64*)dcAllocMem(sizeof(DCCallVM_riscv64)+size);
+
+  mode((DCCallVM*)p, DC_CALL_C_DEFAULT);
+
+  dcVecInit(&p->mVecHead, size);
+  reset((DCCallVM*)p);
+
+  return (DCCallVM*)p;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dyncall/dyncall_callvm_riscv64.h	Thu Mar 07 17:42:13 2024 +0100
@@ -0,0 +1,49 @@
+/*
+
+ Package: dyncall
+ Library: dyncall
+ File: dyncall/dyncall_callvm_riscv64.h
+ Description: 
+ License:
+
+   Copyright (c) 2023 Jun Jeon <yjeon@netflix.com>
+
+   Permission to use, copy, modify, and distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+#ifndef DYNCALL_CALLVM_RISCV64_H
+#define DYNCALL_CALLVM_RISCV64_H
+
+#include "dyncall_callvm.h"
+#include "dyncall_vector.h"
+
+#define RISCV_NUM_INT_REGISTERS   8
+#define RISCV_NUM_FLOAT_REGISTERS 8
+
+typedef struct
+{
+  DCCallVM mInterface;
+  unsigned int i;  /* int register counter */
+  unsigned int f;  /* float register counter */
+  union {          /* float register buffer */
+    DCfloat    S[RISCV_NUM_FLOAT_REGISTERS << 1];
+    DCdouble   D[RISCV_NUM_FLOAT_REGISTERS];
+    DClonglong I[RISCV_NUM_FLOAT_REGISTERS]; /* helper */
+  } u;
+  DCulonglong I[RISCV_NUM_INT_REGISTERS]; /* int register buffer */
+  DCVecHead mVecHead; /* argument buffer head */
+} DCCallVM_riscv64;
+
+#endif /* DYNCALL_CALLVM_RISCV64_H */
+
--- a/dyncall/dyncall_macros.h	Thu Mar 07 14:48:03 2024 +0100
+++ b/dyncall/dyncall_macros.h	Thu Mar 07 17:42:13 2024 +0100
@@ -207,6 +207,14 @@
 # else
 #  define DC__Arch_Sparc
 # endif
+#elif defined(__riscv)
+# if __riscv_xlen == 32
+#  define DC__Arch_RiscV32
+# elif __riscv_xlen == 64
+#  define DC__Arch_RiscV64
+# elif __riscv_xlen == 128
+#  define DC__Arch_RiscV128
+# endif
 #endif
 
 
@@ -298,15 +306,16 @@
 
 /* -- Endianness detection ------------------------------------------ */
 
-#if defined(DC__Arch_Intel_x86) || defined(DC__Arch_AMD64) /* always little */
+#if defined(DC__Arch_Intel_x86) || defined(DC__Arch_AMD64)                                  /* always little */
 # define DC__Endian_LITTLE
-#elif defined(DC__Arch_Sparc)                              /* always purely big until v9 */
+#elif defined(DC__Arch_Sparc)                                                               /* always purely big until v9 */
 # define DC__Endian_BIG
-#else                                                      /* all others are bi-endian */
+#elif defined(DC__Arch_RiscV32) || defined(DC__Arch_RiscV64) || defined(DC__Arch_RiscV128)  /* always little */
+# define DC__Endian_LITTLE
+#else                                                                                       /* all others are bi-endian */
 /* @@@check flags used on following bi-endianness archs:
 DC__Arch_Itanium
 DC__Arch_PPC32
-DC__Arch_PPC64
 DC__Arch_SuperH
 */
 # if (defined(DC__Arch_PPC64) && (DC__ABI_PPC64_ELF_V == 1)) || defined(MIPSEB) || defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || defined(__ARMEB__) || defined(__AARCH64EB__)
--- a/dyncallback/dyncall_args.c	Thu Mar 07 14:48:03 2024 +0100
+++ b/dyncallback/dyncall_args.c	Thu Mar 07 17:42:13 2024 +0100
@@ -57,5 +57,7 @@
 #  else
 #    include "dyncall_args_arm64.c"
 #  endif
+#elif defined(DC__Arch_RiscV64)
+#  include "dyncall_args_riscv64.c"
 #endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dyncallback/dyncall_args_riscv64.c	Thu Mar 07 17:42:13 2024 +0100
@@ -0,0 +1,82 @@
+/*
+
+ Package: dyncall
+ Library: dyncallback
+ File: dyncallback/dyncall_args_riscv64.c
+ Description: Callback's Arguments VM - Implementation for RISCV64
+ License:
+
+   Copyright (c) 2023 Jun Jeon <yjeon@netflix.com>
+
+   Permission to use, copy, modify, and distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+#include "dyncall_args.h"
+
+#include <stdint.h>
+
+typedef union {
+  struct { double value; } d;
+  struct { float  value; } f;
+} DCFPU_t;
+
+struct DCArgs
+{
+  /* buffers and stack-pointer: */
+  uint64_t  I[8];
+  DCFPU_t   F[8];
+  uint64_t* sp;
+  
+  /* counters: */
+  int i;
+  int f;
+};
+
+DClonglong dcbArgLongLong (DCArgs* p) {
+  return  (p->i < 8) ? p->I[p->i++] : *(p->sp)++;
+}
+
+DCdouble  dcbArgDouble (DCArgs* p) {
+  if (p->f < 8)
+    return p->F[p->f++].d.value;
+  else if (p->i < 8)
+    return ((DCFPU_t*)&(p->I[p->i++]))->d.value;
+  else
+    return *(double*)(p->sp++);
+}
+DCfloat   dcbArgFloat  (DCArgs* p) {
+  if (p->f < 8)
+    return p->F[p->f++].f.value;
+  else if (p->i < 8)
+    return ((DCFPU_t*)&(p->I[p->i++]))->f.value;
+  else
+    return *(float*)(p->sp++);
+}
+
+
+DClong      dcbArgLong     (DCArgs* p) { return (DClong)   dcbArgLongLong(p); }
+DCint       dcbArgInt      (DCArgs* p) { return (DCint)    dcbArgLongLong(p); }
+DCshort     dcbArgShort    (DCArgs* p) { return (DCshort)  dcbArgLongLong(p); }
+DCchar      dcbArgChar     (DCArgs* p) { return (DCchar)   dcbArgLongLong(p); }
+DCbool      dcbArgBool     (DCArgs* p) { return dcbArgLongLong(p) & 0x1; }
+DCpointer   dcbArgPointer  (DCArgs* p) { return (DCpointer)dcbArgLongLong(p); }
+
+DCuint      dcbArgUInt     (DCArgs* p) { return (DCuint)     dcbArgInt(p);      }
+DCuchar     dcbArgUChar    (DCArgs* p) { return (DCuchar)    dcbArgChar(p);     }
+DCushort    dcbArgUShort   (DCArgs* p) { return (DCushort)   dcbArgShort(p);    }
+DCulong     dcbArgULong    (DCArgs* p) { return (DCulong)    dcbArgLong(p);     }
+DCulonglong dcbArgULongLong(DCArgs* p) { return (DCulonglong)dcbArgLongLong(p); }
+
+DCpointer   dcbArgAggr     (DCArgs* p, DCpointer target)                   { /* @@@AGGR not impl */ return NULL; }
+void        dcbReturnAggr  (DCArgs *args, DCValue *result, DCpointer ret)  { /* @@@AGGR not impl */ }
+
--- a/dyncallback/dyncall_callback.c	Thu Mar 07 14:48:03 2024 +0100
+++ b/dyncallback/dyncall_callback.c	Thu Mar 07 17:42:13 2024 +0100
@@ -46,6 +46,8 @@
 #include "dyncall_callback_sparc64.c"
 #elif defined(DC__Arch_ARM64)
 #include "dyncall_callback_arm64.c"
+#elif defined(DC__Arch_RiscV64)
+#include "dyncall_callback_riscv64.c"
 #else
 #error unsupported platform
 #endif
--- a/dyncallback/dyncall_callback_arch.S	Thu Mar 07 14:48:03 2024 +0100
+++ b/dyncallback/dyncall_callback_arch.S	Thu Mar 07 17:42:13 2024 +0100
@@ -86,6 +86,8 @@
 #    include "dyncall_callback_sparc64.s"
 #  elif defined(DC__Arch_ARM64)
 #    include "dyncall_callback_arm64.S"
+#  elif defined(DC__Arch_RiscV64)
+#    include "dyncall_callback_riscv64.S"
 #  endif
 #endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dyncallback/dyncall_callback_riscv64.S	Thu Mar 07 17:42:13 2024 +0100
@@ -0,0 +1,132 @@
+/*
+
+ Package: dyncall
+ Library: dyncallback
+ File: dyncallback/dyncall_callback_riscv64.S
+ Description: Callback Thunk - Implementation for RISCV64
+ License:
+
+   Copyright (c) 2023 Jun Jeon <yjeon@netflix.com>
+
+   Permission to use, copy, modify, and distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+/* struct DCCallback
+     type       off   size
+     ---------|------|------
+     DCThunk  |   0  |  32
+     handler  |  32  |   8
+     userdata |  40  |   8
+*/
+
+.align 4
+.globl dcCallbackThunkEntry
+dcCallbackThunkEntry:
+
+/* called from dcbInitThunk() in dyncall_thunk_riscv64.c */
+
+/* input:
+    t5: DCCallback* pcb
+    a0..a7   ?? GP regs
+    fa0..fa7 ?? FP/SIMD regs
+    sp...    ?? arguments on stack
+
+   locals:
+     type       off   size
+     ---------|------|------
+     Frame        0     16
+     DCArgs      16    144
+     DCValue    160     16
+
+     size              176
+     aligned           176
+
+   ra - ret addr
+   s0/fp - frame ptr
+
+   locals:
+      t0: orig sp
+      t1: DCArgs* args
+*/
+
+	mv  t0, sp
+
+	add sp, sp, -176
+
+	/* save ra and s0 */
+	sd  ra, 0(sp)
+	sd  s0, 8(sp)
+
+	/* save frame ptr */
+	mv  s0, sp
+
+	add t1, s0, 16
+
+	/* just saving everything on stack, as defined in DCArgs in dyncall_args_riscv64.c */
+
+/* save regs */
+
+	sd  a0, 0(t1)
+	sd  a1, 8(t1)
+	sd  a2, 16(t1)
+	sd  a3, 24(t1)
+	sd  a4, 32(t1)
+	sd  a5, 40(t1)
+	sd  a6, 48(t1)
+	sd  a7, 56(t1)
+
+	fsd fa0, 64(t1)
+	fsd fa1, 72(t1)
+	fsd fa2, 80(t1)
+	fsd fa3, 88(t1)
+	fsd fa4, 96(t1)
+	fsd fa5, 104(t1)
+	fsd fa6, 112(t1)
+	fsd fa7, 120(t1)
+
+	sd  t0, 128(t1)   /* sp=sp */
+	sd  zero, 136(t1) /* i=f=0 */
+
+/* call handler/callback */
+
+	mv   a0, t5      /* DCCallback* pcb      */
+	add  a1, s0, 16  /* DCArgs*     args     */
+	add  a2, s0, 160 /* DCValue*    result   */
+	ld   a3, 40(t5)  /* void*       userdata */
+
+	ld   t2, 32(t5)
+	jalr ra, 0(t2)
+
+	and  t3, a0, 255
+	add  t4, zero, 'f'  /* single precition floats are sign extended on    */
+	beq  t3, t4, .retf  /* riscv with the D extension, handle specifically */
+	add  t4, zero, 'd'
+	beq  t3, t4, .retd
+
+.reti:
+	ld   a0, 160(s0)
+	j    .ret
+.retf:
+	flw  fa0, 160(s0)
+	j    .ret
+.retd:
+	fld  fa0, 160(s0)
+.ret:
+	/* recover ra and s0 */
+	ld   ra, 0(sp)
+	ld   s0, 8(sp)
+
+	add  sp, sp, 176
+	ret
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dyncallback/dyncall_callback_riscv64.c	Thu Mar 07 17:42:13 2024 +0100
@@ -0,0 +1,66 @@
+/*
+
+ Package: dyncall
+ Library: dyncallback
+ File: dyncallback/dyncall_callback_riscv64.c
+ Description: Callback - Implementation for RISCV64
+ License:
+
+   Copyright (c) 2023 Jun Jeon <yjeon@netflix.com>
+
+   Permission to use, copy, modify, and distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+
+#include "dyncall_callback.h"
+#include "dyncall_alloc_wx.h"
+#include "dyncall_thunk.h"
+
+/* Callback symbol. */
+extern void dcCallbackThunkEntry();
+
+struct DCCallback               /*  off  size */
+{                               /* ----|----- */
+  DCThunk            thunk;     /*   0     32 */
+  DCCallbackHandler* handler;   /*  32      8 */
+  void*              userdata;  /*  40      8 */
+};                              /* total   48 */ 
+                                /* aligned 48 */ 
+
+void dcbInitCallback2(DCCallback* pcb, const DCsigchar* signature, DCCallbackHandler* handler, void* userdata, DCaggr *const * aggrs)
+{
+  pcb->handler = handler;
+  pcb->userdata = userdata;
+}
+
+DCCallback* dcbNewCallback2(const DCsigchar* signature, DCCallbackHandler* handler, void* userdata, DCaggr *const * aggrs)
+{
+  int err;
+  DCCallback* pcb;
+  err = dcAllocWX(sizeof(DCCallback), (void**) &pcb);
+  if(err)
+    return NULL;
+
+  dcbInitCallback2(pcb, signature, handler, userdata, aggrs);
+  dcbInitThunk(&pcb->thunk, dcCallbackThunkEntry);
+
+  err = dcInitExecWX(pcb, sizeof(DCCallback));
+  if(err) {
+    dcFreeWX(pcb, sizeof(DCCallback));
+    return NULL;
+  }
+
+  return pcb;
+}
+
--- a/dyncallback/dyncall_thunk.c	Thu Mar 07 14:48:03 2024 +0100
+++ b/dyncallback/dyncall_thunk.c	Thu Mar 07 17:42:13 2024 +0100
@@ -51,5 +51,7 @@
 #include "dyncall_thunk_sparc64.c"
 #elif defined(DC__Arch_ARM64)
 #include "dyncall_thunk_arm64.c"
+#elif defined(DC__Arch_RiscV64)
+#include "dyncall_thunk_riscv64.c"
 #endif
 
--- a/dyncallback/dyncall_thunk.h	Thu Mar 07 14:48:03 2024 +0100
+++ b/dyncallback/dyncall_thunk.h	Thu Mar 07 17:42:13 2024 +0100
@@ -48,6 +48,7 @@
  ** arm:  r12
  ** arm64: x9
  ** mips:  t4
+ ** riscv: t5
  **
  **/
 
@@ -81,6 +82,8 @@
 #include "dyncall_thunk_sparc64.h"
 #elif defined (DC__Arch_ARM64)
 #include "dyncall_thunk_arm64.h"
+#elif defined (DC__Arch_RiscV64)
+#include "dyncall_thunk_riscv64.h"
 #endif
 
 #ifdef __cplusplus
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dyncallback/dyncall_thunk_riscv64.c	Thu Mar 07 17:42:13 2024 +0100
@@ -0,0 +1,38 @@
+/*
+
+ Package: dyncall
+ Library: dyncallback
+ File: dyncallback/dyncall_thunk_riscv64.c
+ Description: Thunk - Implementation for RISCV64
+ License:
+
+   Copyright (c) 2023 Jun Jeon <yjeon@netflix.com>
+
+   Permission to use, copy, modify, and distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+
+
+#include "dyncall_thunk.h"
+
+void dcbInitThunk(DCThunk* p, void (*entry)())
+{
+  /* t5 - thunk register */
+  p->code[0] = 0x00000f17; /* auipc t5, 0                 */
+  p->code[1] = 0x010f3f83; /* ld    t6, 16(t5)            */
+  p->code[2] = 0x000f8067; /* jr    t6 (= jalr x0, 0(t6)) */
+  p->code[3] = 0x00000013; /* nop      (= addi x0, x0, 0) */
+  p->entry   = entry;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dyncallback/dyncall_thunk_riscv64.h	Thu Mar 07 17:42:13 2024 +0100
@@ -0,0 +1,36 @@
+/*
+
+ Package: dyncall
+ Library: dyncallback
+ File: dyncallback/dyncall_thunk_riscv64.h
+ Description: Thunk - Header for RISCV64
+ License:
+
+   Copyright (c) 2023 Jun Jeon <yjeon@netflix.com>
+
+   Permission to use, copy, modify, and distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+#ifndef DYNCALL_THUNK_RISCV64_H
+#define DYNCALL_THUNK_RISCV64_H
+
+struct DCThunk_          /* off  size */
+{                        /* ----|---- */
+  unsigned int code[4];  /*   0   16  */
+  void (*entry)();       /*  16    8  */
+  void* reserved;        /*  24    8  */
+};                       /*  32 total */
+
+#endif /* DYNCALL_THUNK_RISCV64_H */
+