aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjohannst <johannes.stoelp@gmail.com>2021-06-09 23:05:05 +0200
committerjohannst <johannes.stoelp@gmail.com>2021-06-09 23:05:05 +0200
commit2e4a31287705d8437cddd109c12b7e11825192bc (patch)
tree448157595deb0b6441abebff45990dc9bd3558e6
parent0db708a285c74526ebcce31a10f5730f3f715d61 (diff)
downloadmatcha-threads-2e4a31287705d8437cddd109c12b7e11825192bc.tar.gz
matcha-threads-2e4a31287705d8437cddd109c12b7e11825192bc.zip
added riscv64
-rw-r--r--Makefile14
-rw-r--r--README.md4
-rw-r--r--lib/Makefile4
-rw-r--r--lib/arch/api.h2
-rw-r--r--lib/arch/riscv64/README.md12
-rw-r--r--lib/arch/riscv64/init_stack.cc39
-rw-r--r--lib/arch/riscv64/thread_create.s19
-rw-r--r--lib/arch/riscv64/yield.s63
8 files changed, 156 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 5c110ec..57bfb22 100644
--- a/Makefile
+++ b/Makefile
@@ -6,6 +6,8 @@ ifeq ($(ARCH),arm64)
PREFIX := aarch64-linux-gnu-
else ifeq ($(ARCH),arm)
PREFIX := arm-linux-gnueabi-
+else ifeq ($(ARCH),riscv64)
+PREFIX := riscv64-linux-gnu-
endif
CXX := $(PREFIX)g++
@@ -35,6 +37,11 @@ else ifeq ($(ARCH),arm)
-L /usr/arm-linux-gnueabi \
-E LD_LIBRARY_PATH=/usr/arm-linux-gnueabi/lib \
$<
+else ifeq ($(ARCH),riscv64)
+ qemu-riscv64 \
+ -L /usr/riscv64-linux-gnu \
+ -E LD_LIBRARY_PATH=/usr/riscv64-linux-gnu/lib \
+ $<
else
$<
endif
@@ -54,6 +61,13 @@ else ifeq ($(ARCH),arm)
-g 1234 \
$< &
gdb-multiarch -ex 'target remote :1234' -ex 'b main' -ex 'c' $<
+else ifeq ($(ARCH),riscv64)
+ qemu-riscv64 \
+ -L /usr/riscv64-linux-gnu \
+ -E LD_LIBRARY_PATH=/usr/riscv64-linux-gnu/lib \
+ -g 1234 \
+ $< &
+ gdb-multiarch -ex 'target remote :1234' -ex 'b main' -ex 'c' $<
else
which cgdb && cgdb --ex 'start' $< \
|| gdb --ex 'start' $<
diff --git a/README.md b/README.md
index e7ec89d..ac73b38 100644
--- a/README.md
+++ b/README.md
@@ -79,6 +79,10 @@ The `armv7a` demo can be run as
```bash
make ARCH=arm demo1
```
+The `riscv64` demo can be run as
+```bash
+make ARCH=riscv64 demo1
+```
> Before starting to compile & run for a different architecture the the current
> build artifacts should be removed via `make clean`.
diff --git a/lib/Makefile b/lib/Makefile
index ab51aa8..6171ac2 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,4 +1,4 @@
-# Copyright (c) 2020 Johannes Stoelp
+# Copyright (c) 2021 Johannes Stoelp
ARCH ?= x86_64
@@ -8,6 +8,8 @@ else ifeq ($(ARCH),arm64)
PREFIX := aarch64-linux-gnu-
else ifeq ($(ARCH),arm)
PREFIX := arm-linux-gnueabi-
+else ifeq ($(ARCH),riscv64)
+PREFIX := riscv64-linux-gnu-
else
$(error Unsupported architecture ARCH=$(ARCH))
endif
diff --git a/lib/arch/api.h b/lib/arch/api.h
index 3dd5c92..1b421cb 100644
--- a/lib/arch/api.h
+++ b/lib/arch/api.h
@@ -12,6 +12,8 @@ static_assert(false, "Matcha Threads only supported on Linux!");
// fall-through: arm64 support
#elif defined(__arm__)
// fall-through: armv7 support
+#elif defined(__riscv) && __riscv_xlen == 64
+// fall-through: riscv64 support
#else
static_assert(false, "Unsupported architecture!");
#endif
diff --git a/lib/arch/riscv64/README.md b/lib/arch/riscv64/README.md
new file mode 100644
index 0000000..517ddb2
--- /dev/null
+++ b/lib/arch/riscv64/README.md
@@ -0,0 +1,12 @@
+# riscv64 (RISC-V ELF)
+Provide an implementation of the platform specific API as required in
+[`api.h`](../api.h) according to the `RISC-V ELF ABI`.
+
+## Notes: RISC-V ABI
+- Integer/pointer arguments via `x10 - x17`
+- Integer/pointer return values via `x10` - `x11`
+- Callee saved registers `x2`, `x8` - `x9`, `x18` - `x27`, `f8` - `f9`, `f18` - `f27`
+
+## References
+- [RISC-V ABI](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md)
+- [RISC-V asm manual](https://github.com/riscv/riscv-asm-manual/blob/master/riscv-asm.md)
diff --git a/lib/arch/riscv64/init_stack.cc b/lib/arch/riscv64/init_stack.cc
new file mode 100644
index 0000000..94dab1c
--- /dev/null
+++ b/lib/arch/riscv64/init_stack.cc
@@ -0,0 +1,39 @@
+/* Copyright (c) 2021 Johannes Stoelp */
+
+#include <cassert>
+#include <cstdint> // uintN_t
+
+extern "C" void thread_create();
+
+void* init_stack(void* stack_ptr, void (*entry)(void*), const void* ctx) {
+ static_assert(sizeof(uint64_t) == sizeof(std::uintptr_t), "Pointer must be 64bit!");
+
+ // Setup initial stack frame which will be popped when yielding
+ // first time into the thread.
+ // Basic idea is to yield into Thread::entry() function which will
+ // then call the user function.
+
+ uint64_t* stack = static_cast<uint64_t*>(stack_ptr);
+ // Arguments for `thread_create`.
+ *(--stack) = reinterpret_cast<uint64_t>(ctx);
+ *(--stack) = reinterpret_cast<uint64_t>(entry);
+
+ // Yield epilogue.
+ *(--stack) = reinterpret_cast<uint64_t>(thread_create); // Return address (ra)
+
+ // Callee saved registers.
+ *(--stack) = static_cast<uint64_t>(0); // x8
+ *(--stack) = static_cast<uint64_t>(0); // x9
+ *(--stack) = static_cast<uint64_t>(0); // x18
+ *(--stack) = static_cast<uint64_t>(0); // x19
+ *(--stack) = static_cast<uint64_t>(0); // x20
+ *(--stack) = static_cast<uint64_t>(0); // x21
+ *(--stack) = static_cast<uint64_t>(0); // x22
+ *(--stack) = static_cast<uint64_t>(0); // x23
+ *(--stack) = static_cast<uint64_t>(0); // x24
+ *(--stack) = static_cast<uint64_t>(0); // x25
+ *(--stack) = static_cast<uint64_t>(0); // x26
+ *(--stack) = static_cast<uint64_t>(0); // x27
+
+ return static_cast<void*>(stack);
+}
diff --git a/lib/arch/riscv64/thread_create.s b/lib/arch/riscv64/thread_create.s
new file mode 100644
index 0000000..68c09cd
--- /dev/null
+++ b/lib/arch/riscv64/thread_create.s
@@ -0,0 +1,19 @@
+# Copyright (c) 2021 Johannes Stoelp
+
+ .section .text, "ax", @progbits
+
+ # extern "C" void thread_create();
+ .global thread_create
+ .type thread_create, @function
+thread_create:
+ .cfi_startproc
+ ld a0, 8(sp)
+ ld x5, 0(sp)
+
+ jalr x5
+
+ # FIXME: no return from thread after user fn finished.
+1:
+ j 1b
+ .cfi_endproc
+ .size thread_create, .-thread_create
diff --git a/lib/arch/riscv64/yield.s b/lib/arch/riscv64/yield.s
new file mode 100644
index 0000000..985cb52
--- /dev/null
+++ b/lib/arch/riscv64/yield.s
@@ -0,0 +1,63 @@
+# Copyright (c) 2021 Johannes Stoelp
+
+ .macro push reg
+ addi sp, sp, -8
+ sd \reg, 0(sp)
+ .endm
+
+ .macro pop reg
+ ld \reg, 0(sp)
+ addi sp, sp, 8
+ .endm
+
+ .section .text, "ax", @progbits
+
+ # extern "C" void yield(const void* new_stack, void** old_stack);
+ # ^^^^^^^^^ ^^^^^^^^^
+ # a0 (x10) a1 (x11)
+ .global yield
+ .type yield, @function
+yield:
+ .cfi_startproc
+ # save return address
+ push ra
+
+ # push callee saved registers
+ push x8
+ push x9
+ push x18
+ push x19
+ push x20
+ push x21
+ push x22
+ push x23
+ push x24
+ push x25
+ push x26
+ push x27
+
+ # arg0: a0 holds new stack
+ # arg1: a1 holds addr to location current stack must be saved
+ sd sp, 0(a1) # save current stack ptr
+ mv sp, a0 # switch to new stack ptr
+
+ # pop callee saved registers
+ pop x27
+ pop x26
+ pop x25
+ pop x24
+ pop x23
+ pop x22
+ pop x21
+ pop x20
+ pop x19
+ pop x18
+ pop x9
+ pop x8
+
+ # restore return address
+ pop ra
+
+ ret
+ .cfi_endproc
+ .size yield, .-yield