diff --git a/libco/libco.c b/libco/libco.c index 27a624547..47382a356 100644 --- a/libco/libco.c +++ b/libco/libco.c @@ -21,6 +21,8 @@ #include "ppc64v2.c" #elif defined(_ARCH_PPC) && !defined(__LITTLE_ENDIAN__) #include "ppc.c" + #elif defined(__riscv) + #include "riscv.c" #elif defined(_WIN32) #include "fiber.c" #else diff --git a/libco/riscv.c b/libco/riscv.c new file mode 100644 index 000000000..cc9bf28b9 --- /dev/null +++ b/libco/riscv.c @@ -0,0 +1,150 @@ +#define LIBCO_C +#include "libco.h" +#include "settings.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static thread_local uint64_t co_active_buffer[64]; +static thread_local cothread_t co_active_handle = 0; + +#if __riscv_xlen == 32 +#define I_STORE "sw" +#define I_LOAD "lw" +#elif __riscv_xlen == 64 +#define I_STORE "sd" +#define I_LOAD "ld" +#else +#error Unsupported RISC-V XLEN +#endif + +#if !defined(__riscv_flen) +#define F_STORE "#" +#define F_LOAD "#" +#elif __riscv_flen == 32 +#define F_STORE "fsw" +#define F_LOAD "flw" +#elif __riscv_flen == 64 +#define F_STORE "fsd" +#define F_LOAD "fld" +#else +#error Unsupported RISC-V FLEN +#endif + +__attribute__((naked)) +static void co_swap(cothread_t active, cothread_t previous) { +__asm__( + I_STORE " ra, 0 *8(a1)\n" + I_STORE " sp, 1 *8(a1)\n" + I_STORE " s0, 2 *8(a1)\n" + I_STORE " s1, 3 *8(a1)\n" + I_STORE " s2, 4 *8(a1)\n" + I_STORE " s3, 5 *8(a1)\n" + I_STORE " s4, 6 *8(a1)\n" + I_STORE " s5, 7 *8(a1)\n" + I_STORE " s6, 8 *8(a1)\n" + I_STORE " s7, 9 *8(a1)\n" + I_STORE " s8, 10*8(a1)\n" + I_STORE " s9, 11*8(a1)\n" + I_STORE " s10, 12*8(a1)\n" + I_STORE " s11, 13*8(a1)\n" + + F_STORE " fs0, 14*8(a1)\n" + F_STORE " fs1, 15*8(a1)\n" + F_STORE " fs2, 16*8(a1)\n" + F_STORE " fs3, 17*8(a1)\n" + F_STORE " fs4, 18*8(a1)\n" + F_STORE " fs5, 19*8(a1)\n" + F_STORE " fs6, 20*8(a1)\n" + F_STORE " fs7, 21*8(a1)\n" + F_STORE " fs8, 22*8(a1)\n" + F_STORE " fs9, 23*8(a1)\n" + F_STORE " fs10, 24*8(a1)\n" + F_STORE " fs11, 25*8(a1)\n" + + I_LOAD " ra, 0 *8(a0)\n" + I_LOAD " sp, 1 *8(a0)\n" + I_LOAD " s0, 2 *8(a0)\n" + I_LOAD " s1, 3 *8(a0)\n" + I_LOAD " s2, 4 *8(a0)\n" + I_LOAD " s3, 5 *8(a0)\n" + I_LOAD " s4, 6 *8(a0)\n" + I_LOAD " s5, 7 *8(a0)\n" + I_LOAD " s6, 8 *8(a0)\n" + I_LOAD " s7, 9 *8(a0)\n" + I_LOAD " s8, 10*8(a0)\n" + I_LOAD " s9, 11*8(a0)\n" + I_LOAD " s10, 12*8(a0)\n" + I_LOAD " s11, 13*8(a0)\n" + + F_LOAD " fs0, 14*8(a0)\n" + F_LOAD " fs1, 15*8(a0)\n" + F_LOAD " fs2, 16*8(a0)\n" + F_LOAD " fs3, 17*8(a0)\n" + F_LOAD " fs4, 18*8(a0)\n" + F_LOAD " fs5, 19*8(a0)\n" + F_LOAD " fs6, 20*8(a0)\n" + F_LOAD " fs7, 21*8(a0)\n" + F_LOAD " fs8, 22*8(a0)\n" + F_LOAD " fs9, 23*8(a0)\n" + F_LOAD " fs10, 24*8(a0)\n" + F_LOAD " fs11, 25*8(a0)\n" + + "ret\n" +); +} + +static void co_entrypoint(cothread_t handle) { + uint64_t* buffer = (uint64_t*)handle; + void (*entrypoint)(void) = (void (*)(void))(uintptr_t)buffer[3]; + entrypoint(); + abort(); /* called only if cothread_t entrypoint returns */ +} + +cothread_t co_active() { + if(!co_active_handle) co_active_handle = &co_active_buffer; + return co_active_handle; +} + +cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) { + uint64_t* handle; + if(!co_active_handle) co_active_handle = &co_active_buffer; + + if(handle = (uint64_t*)memory) { + unsigned int offset = (size & ~15); + uint64_t* p = (uint64_t*)((uint8_t*)handle + offset); + *(uintptr_t*)&handle[0] = (uintptr_t)co_entrypoint; /* ra (return address) */ + *(uintptr_t*)&handle[1] = (uintptr_t)p; /* sp (stack pointer) */ + *(uintptr_t*)&handle[2] = (uintptr_t)p; /* s0 (frame pointer) */ + *(uintptr_t*)&handle[3] = (uintptr_t)entrypoint; /* s1 (entry point) */ + } + + return handle; +} + +cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { + void* memory = malloc(size); + if(!memory) return (cothread_t)0; + return co_derive(memory, size, entrypoint); +} + +void co_delete(cothread_t handle) { + free(handle); +} + +void co_switch(cothread_t handle) { + cothread_t co_previous_handle = co_active_handle; + co_swap(co_active_handle = handle, co_previous_handle); +} + +int co_serializable() { + return 1; +} + +#ifdef __cplusplus +} +#endif diff --git a/nall/GNUmakefile b/nall/GNUmakefile index 0016063b0..e05242369 100644 --- a/nall/GNUmakefile +++ b/nall/GNUmakefile @@ -101,6 +101,10 @@ else machine := arm32 else ifneq ($(filter powerpc64-% powerpc64le-%,$(machine_str)),) machine := ppc64 + else ifneq ($(filter riscv64-%,$(machine_str)),) + machine := rv64 + else ifneq ($(filter riscv32-%,$(machine_str)),) + machine := rv32 endif # detect clang with msvc target diff --git a/nall/intrinsics.hpp b/nall/intrinsics.hpp index c3aa3d487..26c2559f6 100644 --- a/nall/intrinsics.hpp +++ b/nall/intrinsics.hpp @@ -188,6 +188,8 @@ namespace nall { static constexpr bool arm32 = 0; static constexpr bool ppc64 = 0; static constexpr bool ppc32 = 0; + static constexpr bool rv64 = 0; + static constexpr bool rv32 = 0; }; #elif defined(__amd64__) || defined(_M_AMD64) #define ARCHITECTURE_AMD64 @@ -201,6 +203,8 @@ namespace nall { static constexpr bool arm32 = 0; static constexpr bool ppc64 = 0; static constexpr bool ppc32 = 0; + static constexpr bool rv64 = 0; + static constexpr bool rv32 = 0; }; #elif defined(__aarch64__) || defined(_M_ARM64) #define ARCHITECTURE_ARM64 @@ -214,6 +218,8 @@ namespace nall { static constexpr bool arm32 = 0; static constexpr bool ppc64 = 0; static constexpr bool ppc32 = 0; + static constexpr bool rv64 = 0; + static constexpr bool rv32 = 0; }; #elif defined(__arm__) #define ARCHITECTURE_ARM32 @@ -224,6 +230,8 @@ namespace nall { static constexpr bool arm32 = 1; static constexpr bool ppc64 = 0; static constexpr bool ppc32 = 0; + static constexpr bool rv64 = 0; + static constexpr bool rv32 = 0; }; #elif defined(__ppc64__) || defined(_ARCH_PPC64) #define ARCHITECTURE_PPC64 @@ -234,6 +242,8 @@ namespace nall { static constexpr bool arm32 = 0; static constexpr bool ppc64 = 1; static constexpr bool ppc32 = 0; + static constexpr bool rv64 = 0; + static constexpr bool rv32 = 0; }; #elif defined(__ppc__) || defined(_ARCH_PPC) || defined(_M_PPC) #define ARCHITECTURE_PPC32 @@ -244,6 +254,32 @@ namespace nall { static constexpr bool arm32 = 0; static constexpr bool ppc64 = 0; static constexpr bool ppc32 = 1; + static constexpr bool rv64 = 0; + static constexpr bool rv32 = 0; + }; +#elif defined(__riscv) && __riscv_xlen == 64 + #define ARCHITECTURE_RV64 + struct Architecture { + static constexpr bool x86 = 0; + static constexpr bool amd64 = 0; + static constexpr bool arm64 = 0; + static constexpr bool arm32 = 0; + static constexpr bool ppc64 = 0; + static constexpr bool ppc32 = 0; + static constexpr bool rv64 = 1; + static constexpr bool rv32 = 0; + }; +#elif defined(__riscv) && __riscv_xlen == 32 + #define ARCHITECTURE_RV32 + struct Architecture { + static constexpr bool x86 = 0; + static constexpr bool amd64 = 0; + static constexpr bool arm64 = 0; + static constexpr bool arm32 = 0; + static constexpr bool ppc64 = 0; + static constexpr bool ppc32 = 0; + static constexpr bool rv64 = 0; + static constexpr bool rv32 = 1; }; #else #error "unable to detect architecture" diff --git a/nall/recompiler/generic/generic.hpp b/nall/recompiler/generic/generic.hpp index 748c735fe..dd102be37 100644 --- a/nall/recompiler/generic/generic.hpp +++ b/nall/recompiler/generic/generic.hpp @@ -3,7 +3,7 @@ #if defined(SLJIT) namespace nall::recompiler { struct generic { - static constexpr bool supported = Architecture::amd64 | Architecture::arm64 | Architecture::ppc64; + static constexpr bool supported = Architecture::amd64 | Architecture::arm64 | Architecture::ppc64 | Architecture::rv64; bump_allocator& allocator; sljit_compiler* compiler = nullptr;