Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions libco.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
#include "arm.c"
#elif defined(__aarch64__)
#include "aarch64.c"
#elif defined(__riscv) && defined(__riscv_xlen) && \
__riscv_xlen == 64 && !defined(__riscv_abi_rve) && \
!defined(__riscv_float_abi_quad)
#include "riscv64.c"
#elif defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2
#include "ppc64le.c"
#elif defined(_ARCH_PPC) && !defined(__LITTLE_ENDIAN__)
Expand Down
223 changes: 223 additions & 0 deletions riscv64.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
/*
libco.riscv64
license: public domain
*/

#define LIBCO_C
#include "libco.h"
#include "settings.h"

#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif

#if defined(__riscv_float_abi_double) || defined(__riscv_float_abi_single)
#define LIBCO_RISCV64_HARD_FLOAT
#endif

typedef struct {
uintptr_t ra;
uintptr_t sp;
uintptr_t s[12];
#ifdef LIBCO_RISCV64_HARD_FLOAT
uint64_t fs[12];
uintptr_t fcsr;
#endif
void (*entrypoint)(void);
} co_context;

typedef char co_context_ra_offset[(offsetof(co_context, ra) == 0) ? 1 : -1];
typedef char co_context_sp_offset[(offsetof(co_context, sp) == 8) ? 1 : -1];
typedef char co_context_s_offset[(offsetof(co_context, s) == 16) ? 1 : -1];
#ifdef LIBCO_RISCV64_HARD_FLOAT
typedef char co_context_fs_offset[(offsetof(co_context, fs) == 112) ? 1 : -1];
typedef char co_context_fcsr_offset[(offsetof(co_context, fcsr) == 208) ? 1 : -1];
#endif

static thread_local co_context co_active_context;
static thread_local cothread_t co_active_handle;

#if defined(__riscv_float_abi_double)
#define LIBCO_RISCV64_SAVE_FLOAT \
" fsd fs0, 112(a1)\n" \
" fsd fs1, 120(a1)\n" \
" fsd fs2, 128(a1)\n" \
" fsd fs3, 136(a1)\n" \
" fsd fs4, 144(a1)\n" \
" fsd fs5, 152(a1)\n" \
" fsd fs6, 160(a1)\n" \
" fsd fs7, 168(a1)\n" \
" fsd fs8, 176(a1)\n" \
" fsd fs9, 184(a1)\n" \
" fsd fs10, 192(a1)\n" \
" fsd fs11, 200(a1)\n" \
" csrr t0, fcsr\n" \
" sd t0, 208(a1)\n"
#define LIBCO_RISCV64_RESTORE_FLOAT \
" fld fs0, 112(a0)\n" \
" fld fs1, 120(a0)\n" \
" fld fs2, 128(a0)\n" \
" fld fs3, 136(a0)\n" \
" fld fs4, 144(a0)\n" \
" fld fs5, 152(a0)\n" \
" fld fs6, 160(a0)\n" \
" fld fs7, 168(a0)\n" \
" fld fs8, 176(a0)\n" \
" fld fs9, 184(a0)\n" \
" fld fs10, 192(a0)\n" \
" fld fs11, 200(a0)\n" \
" ld t0, 208(a0)\n" \
" csrw fcsr, t0\n"
#elif defined(__riscv_float_abi_single)
#define LIBCO_RISCV64_SAVE_FLOAT \
" fsw fs0, 112(a1)\n" \
" fsw fs1, 120(a1)\n" \
" fsw fs2, 128(a1)\n" \
" fsw fs3, 136(a1)\n" \
" fsw fs4, 144(a1)\n" \
" fsw fs5, 152(a1)\n" \
" fsw fs6, 160(a1)\n" \
" fsw fs7, 168(a1)\n" \
" fsw fs8, 176(a1)\n" \
" fsw fs9, 184(a1)\n" \
" fsw fs10, 192(a1)\n" \
" fsw fs11, 200(a1)\n" \
" csrr t0, fcsr\n" \
" sd t0, 208(a1)\n"
#define LIBCO_RISCV64_RESTORE_FLOAT \
" flw fs0, 112(a0)\n" \
" flw fs1, 120(a0)\n" \
" flw fs2, 128(a0)\n" \
" flw fs3, 136(a0)\n" \
" flw fs4, 144(a0)\n" \
" flw fs5, 152(a0)\n" \
" flw fs6, 160(a0)\n" \
" flw fs7, 168(a0)\n" \
" flw fs8, 176(a0)\n" \
" flw fs9, 184(a0)\n" \
" flw fs10, 192(a0)\n" \
" flw fs11, 200(a0)\n" \
" ld t0, 208(a0)\n" \
" csrw fcsr, t0\n"
#else
#define LIBCO_RISCV64_SAVE_FLOAT
#define LIBCO_RISCV64_RESTORE_FLOAT
#endif

asm(
".text\n"
".p2align 2\n"
".globl co_switch_riscv64\n"
".type co_switch_riscv64, @function\n"
"co_switch_riscv64:\n"
" sd ra, 0(a1)\n"
" sd sp, 8(a1)\n"
" sd s0, 16(a1)\n"
" sd s1, 24(a1)\n"
" sd s2, 32(a1)\n"
" sd s3, 40(a1)\n"
" sd s4, 48(a1)\n"
" sd s5, 56(a1)\n"
" sd s6, 64(a1)\n"
" sd s7, 72(a1)\n"
" sd s8, 80(a1)\n"
" sd s9, 88(a1)\n"
" sd s10, 96(a1)\n"
" sd s11, 104(a1)\n"
LIBCO_RISCV64_SAVE_FLOAT
" ld ra, 0(a0)\n"
" ld sp, 8(a0)\n"
" ld s0, 16(a0)\n"
" ld s1, 24(a0)\n"
" ld s2, 32(a0)\n"
" ld s3, 40(a0)\n"
" ld s4, 48(a0)\n"
" ld s5, 56(a0)\n"
" ld s6, 64(a0)\n"
" ld s7, 72(a0)\n"
" ld s8, 80(a0)\n"
" ld s9, 88(a0)\n"
" ld s10, 96(a0)\n"
" ld s11, 104(a0)\n"
LIBCO_RISCV64_RESTORE_FLOAT
" ret\n"
".size co_switch_riscv64, .-co_switch_riscv64\n"
".previous\n"
);

void co_switch_riscv64(cothread_t handle, cothread_t current);

static void co_entry_trampoline(void)
{
co_context *context;

context = (co_context *)co_active_handle;
context->entrypoint();
abort();
}

cothread_t co_active(void)
{
if (!co_active_handle) {
co_active_handle = &co_active_context;
}

return co_active_handle;
}

cothread_t co_create(unsigned int size, void (*entrypoint)(void),
size_t *out_size)
{
size_t context_size;
size_t stack_size;
size_t total_size;
co_context *context;

context_size = (sizeof(co_context) + 15) & ~(size_t)15;

if ((size_t)size > SIZE_MAX - 15) {
return 0;
}

stack_size = ((size_t)size + 15) & ~(size_t)15;
if (stack_size > SIZE_MAX - context_size) {
return 0;
}

total_size = context_size + stack_size;
context = (co_context *)malloc(total_size);
if (!context) {
return 0;
}

memset(context, 0, context_size);
context->ra = (uintptr_t)co_entry_trampoline;
context->sp = (uintptr_t)context + total_size;
context->entrypoint = entrypoint;

*out_size = total_size;
return (cothread_t)context;
}

void co_delete(cothread_t handle)
{
free(handle);
}

void co_switch(cothread_t handle)
{
cothread_t previous_handle;

previous_handle = co_active();
co_active_handle = handle;
co_switch_riscv64(handle, previous_handle);
}

#ifdef __cplusplus
}
#endif