From 3cf0ee6d428d1eb6348fa0ee6c2e3c7f8a746363 Mon Sep 17 00:00:00 2001 From: Zihao Yu Date: Tue, 3 Aug 2021 20:12:28 +0800 Subject: [PATCH] add spike --- am/include/arch/spike.h | 7 +++ am/src/platform/dummy/cte.c | 19 ++++++ am/src/platform/dummy/ioe.c | 11 ++++ am/src/platform/dummy/mpe.c | 17 ++++++ am/src/platform/dummy/trm.c | 10 ++++ am/src/platform/dummy/vme.c | 18 ++++++ am/src/spike/atomic.h | 78 +++++++++++++++++++++++++ am/src/spike/htif.c | 111 ++++++++++++++++++++++++++++++++++++ am/src/spike/htif.h | 24 ++++++++ am/src/spike/ioe.c | 27 +++++++++ am/src/spike/linker.ld | 35 ++++++++++++ am/src/spike/start.S | 8 +++ am/src/spike/timer.c | 30 ++++++++++ am/src/spike/trm.c | 34 +++++++++++ scripts/spike.mk | 19 ++++++ 15 files changed, 448 insertions(+) create mode 100644 am/include/arch/spike.h create mode 100644 am/src/platform/dummy/cte.c create mode 100644 am/src/platform/dummy/ioe.c create mode 100644 am/src/platform/dummy/mpe.c create mode 100644 am/src/platform/dummy/trm.c create mode 100644 am/src/platform/dummy/vme.c create mode 100644 am/src/spike/atomic.h create mode 100644 am/src/spike/htif.c create mode 100644 am/src/spike/htif.h create mode 100644 am/src/spike/ioe.c create mode 100644 am/src/spike/linker.ld create mode 100644 am/src/spike/start.S create mode 100644 am/src/spike/timer.c create mode 100644 am/src/spike/trm.c create mode 100644 scripts/spike.mk diff --git a/am/include/arch/spike.h b/am/include/arch/spike.h new file mode 100644 index 0000000..f894606 --- /dev/null +++ b/am/include/arch/spike.h @@ -0,0 +1,7 @@ +#ifndef ARCH_H__ +#define ARCH_H__ + +struct Context { +}; + +#endif diff --git a/am/src/platform/dummy/cte.c b/am/src/platform/dummy/cte.c new file mode 100644 index 0000000..c3094ab --- /dev/null +++ b/am/src/platform/dummy/cte.c @@ -0,0 +1,19 @@ +#include + +bool cte_init(Context*(*handler)(Event, Context*)) { + return false; +} + +Context *kcontext(Area kstack, void (*entry)(void *), void *arg) { + return NULL; +} + +void yield() { +} + +bool ienabled() { + return false; +} + +void iset(bool enable) { +} diff --git a/am/src/platform/dummy/ioe.c b/am/src/platform/dummy/ioe.c new file mode 100644 index 0000000..369ab7e --- /dev/null +++ b/am/src/platform/dummy/ioe.c @@ -0,0 +1,11 @@ +#include +#include + +static void fail(void *buf) { panic("access nonexist register"); } + +bool ioe_init() { + return false; +} + +void ioe_read (int reg, void *buf) { fail(buf); } +void ioe_write(int reg, void *buf) { fail(buf); } diff --git a/am/src/platform/dummy/mpe.c b/am/src/platform/dummy/mpe.c new file mode 100644 index 0000000..6715aa2 --- /dev/null +++ b/am/src/platform/dummy/mpe.c @@ -0,0 +1,17 @@ +#include + +bool mpe_init(void (*entry)()) { + return false; +} + +int cpu_count() { + return 1; +} + +int cpu_current() { + return 0; +} + +int atomic_xchg(int *addr, int newval) { + return 0; +} diff --git a/am/src/platform/dummy/trm.c b/am/src/platform/dummy/trm.c new file mode 100644 index 0000000..3fd84e2 --- /dev/null +++ b/am/src/platform/dummy/trm.c @@ -0,0 +1,10 @@ +#include + +Area heap = RANGE(NULL, NULL); + +void putch(char ch) { +} + +void halt(int code) { + while (1); +} diff --git a/am/src/platform/dummy/vme.c b/am/src/platform/dummy/vme.c new file mode 100644 index 0000000..5134154 --- /dev/null +++ b/am/src/platform/dummy/vme.c @@ -0,0 +1,18 @@ +#include + +bool vme_init(void* (*pgalloc_f)(int), void (*pgfree_f)(void*)) { + return false; +} + +void protect(AddrSpace *as) { +} + +void unprotect(AddrSpace *as) { +} + +void map(AddrSpace *as, void *va, void *pa, int prot) { +} + +Context *ucontext(AddrSpace *as, Area kstack, void *entry) { + return NULL; +} diff --git a/am/src/spike/atomic.h b/am/src/spike/atomic.h new file mode 100644 index 0000000..eca1320 --- /dev/null +++ b/am/src/spike/atomic.h @@ -0,0 +1,78 @@ +// See LICENSE for license details. + +#ifndef _RISCV_ATOMIC_H +#define _RISCV_ATOMIC_H + +//#include "config.h" +//#include "encoding.h" + +// Currently, interrupts are always disabled in M-mode. +#define disable_irqsave() (0) +#define enable_irqrestore(flags) ((void) (flags)) + +typedef struct { int lock; } spinlock_t; +#define SPINLOCK_INIT {0} + +#define mb() asm volatile ("fence" ::: "memory") +#define atomic_set(ptr, val) (*(volatile typeof(*(ptr)) *)(ptr) = val) +#define atomic_read(ptr) (*(volatile typeof(*(ptr)) *)(ptr)) + +#ifdef __riscv_atomic +# define atomic_add(ptr, inc) __sync_fetch_and_add(ptr, inc) +# define atomic_or(ptr, inc) __sync_fetch_and_or(ptr, inc) +# define atomic_swap(ptr, swp) __sync_lock_test_and_set(ptr, swp) +# define atomic_cas(ptr, cmp, swp) __sync_val_compare_and_swap(ptr, cmp, swp) +#else +# define atomic_binop(ptr, inc, op) ({ \ + long flags = disable_irqsave(); \ + typeof(*(ptr)) res = atomic_read(ptr); \ + atomic_set(ptr, op); \ + enable_irqrestore(flags); \ + res; }) +# define atomic_add(ptr, inc) atomic_binop(ptr, inc, res + (inc)) +# define atomic_or(ptr, inc) atomic_binop(ptr, inc, res | (inc)) +# define atomic_swap(ptr, inc) atomic_binop(ptr, inc, (inc)) +# define atomic_cas(ptr, cmp, swp) ({ \ + long flags = disable_irqsave(); \ + typeof(*(ptr)) res = *(volatile typeof(*(ptr)) *)(ptr); \ + if (res == (cmp)) *(volatile typeof(ptr))(ptr) = (swp); \ + enable_irqrestore(flags); \ + res; }) +#endif + +static inline int spinlock_trylock(spinlock_t* lock) +{ + int res = atomic_swap(&lock->lock, -1); + mb(); + return res; +} + +static inline void spinlock_lock(spinlock_t* lock) +{ + do + { + while (atomic_read(&lock->lock)) + ; + } while (spinlock_trylock(lock)); +} + +static inline void spinlock_unlock(spinlock_t* lock) +{ + mb(); + atomic_set(&lock->lock,0); +} + +static inline long spinlock_lock_irqsave(spinlock_t* lock) +{ + long flags = disable_irqsave(); + spinlock_lock(lock); + return flags; +} + +static inline void spinlock_unlock_irqrestore(spinlock_t* lock, long flags) +{ + spinlock_unlock(lock); + enable_irqrestore(flags); +} + +#endif diff --git a/am/src/spike/htif.c b/am/src/spike/htif.c new file mode 100644 index 0000000..f56ba8f --- /dev/null +++ b/am/src/spike/htif.c @@ -0,0 +1,111 @@ +// See LICENSE for license details. + +#include "htif.h" +#include "atomic.h" +#include + +extern uint64_t __htif_base; +volatile uint64_t tohost __attribute__((section(".htif"))); +volatile uint64_t fromhost __attribute__((section(".htif"))); +volatile int htif_console_buf; +static spinlock_t htif_lock = SPINLOCK_INIT; + +#define TOHOST(base_int) (uint64_t *)(base_int + TOHOST_OFFSET) +#define FROMHOST(base_int) (uint64_t *)(base_int + FROMHOST_OFFSET) + +#define TOHOST_OFFSET ((uintptr_t)tohost - (uintptr_t)__htif_base) +#define FROMHOST_OFFSET ((uintptr_t)fromhost - (uintptr_t)__htif_base) + +static void __check_fromhost() +{ + uint64_t fh = fromhost; + if (!fh) + return; + fromhost = 0; + + // this should be from the console + assert(FROMHOST_DEV(fh) == 1); + switch (FROMHOST_CMD(fh)) { + case 0: + htif_console_buf = 1 + (uint8_t)FROMHOST_DATA(fh); + break; + case 1: + break; + default: + assert(0); + } +} + +static void __set_tohost(uintptr_t dev, uintptr_t cmd, uintptr_t data) +{ + while (tohost) + __check_fromhost(); + tohost = TOHOST_CMD(dev, cmd, data); +} + +int htif_console_getchar() +{ +#if __riscv_xlen == 32 + // HTIF devices are not supported on RV32 + return -1; +#endif + + spinlock_lock(&htif_lock); + __check_fromhost(); + int ch = htif_console_buf; + if (ch >= 0) { + htif_console_buf = -1; + __set_tohost(1, 0, 0); + } + spinlock_unlock(&htif_lock); + + return ch - 1; +} + +static void do_tohost_fromhost(uintptr_t dev, uintptr_t cmd, uintptr_t data) +{ + spinlock_lock(&htif_lock); + __set_tohost(dev, cmd, data); + + while (1) { + uint64_t fh = fromhost; + if (fh) { + if (FROMHOST_DEV(fh) == dev && FROMHOST_CMD(fh) == cmd) { + fromhost = 0; + break; + } + __check_fromhost(); + } + } + spinlock_unlock(&htif_lock); +} + +void htif_syscall(uintptr_t arg) +{ + do_tohost_fromhost(0, 0, arg); +} + +void htif_console_putchar(uint8_t ch) +{ +#if __riscv_xlen == 32 + // HTIF devices are not supported on RV32, so proxy a write system call + volatile uint64_t magic_mem[8]; + magic_mem[0] = SYS_write; + magic_mem[1] = 1; + magic_mem[2] = (uintptr_t)&ch; + magic_mem[3] = 1; + do_tohost_fromhost(0, 0, (uintptr_t)magic_mem); +#else + spinlock_lock(&htif_lock); + __set_tohost(1, 1, ch); + spinlock_unlock(&htif_lock); +#endif +} + +void htif_poweroff() +{ + while (1) { + fromhost = 0; + tohost = 1; + } +} diff --git a/am/src/spike/htif.h b/am/src/spike/htif.h new file mode 100644 index 0000000..73967d8 --- /dev/null +++ b/am/src/spike/htif.h @@ -0,0 +1,24 @@ +// See LICENSE for license details. + +#ifndef _RISCV_HTIF_H +#define _RISCV_HTIF_H + +#include + +#if __riscv_xlen == 64 +# define TOHOST_CMD(dev, cmd, payload) \ + (((uint64_t)(dev) << 56) | ((uint64_t)(cmd) << 48) | (uint64_t)(payload)) +#else +# define TOHOST_CMD(dev, cmd, payload) ({ \ + if ((dev) || (cmd)) __builtin_trap(); \ + (payload); }) +#endif +#define FROMHOST_DEV(fromhost_value) ((uint64_t)(fromhost_value) >> 56) +#define FROMHOST_CMD(fromhost_value) ((uint64_t)(fromhost_value) << 8 >> 56) +#define FROMHOST_DATA(fromhost_value) ((uint64_t)(fromhost_value) << 16 >> 16) + +void htif_console_putchar(uint8_t); +int htif_console_getchar(); +void htif_poweroff() __attribute__((noreturn)); + +#endif diff --git a/am/src/spike/ioe.c b/am/src/spike/ioe.c new file mode 100644 index 0000000..8ab29fc --- /dev/null +++ b/am/src/spike/ioe.c @@ -0,0 +1,27 @@ +#include +#include + +void __am_timer_init(); +void __am_timer_rtc(AM_TIMER_RTC_T *); +void __am_timer_uptime(AM_TIMER_UPTIME_T *); + +static void __am_timer_config(AM_TIMER_CONFIG_T *cfg) { cfg->present = true; cfg->has_rtc = true; } + +typedef void (*handler_t)(void *buf); +static void *lut[128] = { + [AM_TIMER_CONFIG] = __am_timer_config, + [AM_TIMER_RTC ] = __am_timer_rtc, + [AM_TIMER_UPTIME] = __am_timer_uptime, +}; + +static void fail(void *buf) { panic("access nonexist register"); } + +bool ioe_init() { + for (int i = 0; i < LENGTH(lut); i++) + if (!lut[i]) lut[i] = fail; + __am_timer_init(); + return true; +} + +void ioe_read (int reg, void *buf) { ((handler_t)lut[reg])(buf); } +void ioe_write(int reg, void *buf) { ((handler_t)lut[reg])(buf); } diff --git a/am/src/spike/linker.ld b/am/src/spike/linker.ld new file mode 100644 index 0000000..9db82aa --- /dev/null +++ b/am/src/spike/linker.ld @@ -0,0 +1,35 @@ +ENTRY(_start) + +SECTIONS { + . = 0x80000000; + .text : { + *(entry) + *(.text*) + } + etext = .; + _etext = .; + .rodata : { + *(.rodata*) + } + .htif : { + PROVIDE(__htif_base = . ); + *(.htif) + } + .data : { + *(.data) + } + edata = .; + _data = .; + .bss : { + _bss_start = .; + *(.bss*) + *(.sbss*) + *(.scommon) + } + _stack_top = ALIGN(0x1000); + . = _stack_top + 0x8000; + _stack_pointer = .; + end = .; + _end = .; + _heap_start = ALIGN(0x1000); +} diff --git a/am/src/spike/start.S b/am/src/spike/start.S new file mode 100644 index 0000000..3e56e5c --- /dev/null +++ b/am/src/spike/start.S @@ -0,0 +1,8 @@ +.section entry, "ax" +.globl _start +.type _start, @function + +_start: + mv s0, zero + la sp, _stack_pointer + jal _trm_init diff --git a/am/src/spike/timer.c b/am/src/spike/timer.c new file mode 100644 index 0000000..abe6783 --- /dev/null +++ b/am/src/spike/timer.c @@ -0,0 +1,30 @@ +#include + +static uint64_t boot_time = 0; + +#define CLINT_MMIO 0x2000000ul +#define TIME_BASE 0xbff8 + +static uint64_t read_time() { + uint32_t lo = *(volatile uint32_t *)(CLINT_MMIO + TIME_BASE + 0); + uint32_t hi = *(volatile uint32_t *)(CLINT_MMIO + TIME_BASE + 4); + uint64_t time = ((uint64_t)hi << 32) | lo; + return time / 10; +} + +void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) { + uptime->us = read_time() - boot_time; +} + +void __am_timer_init() { + boot_time = read_time(); +} + +void __am_timer_rtc(AM_TIMER_RTC_T *rtc) { + rtc->second = 0; + rtc->minute = 0; + rtc->hour = 0; + rtc->day = 0; + rtc->month = 0; + rtc->year = 1900; +} diff --git a/am/src/spike/trm.c b/am/src/spike/trm.c new file mode 100644 index 0000000..b193bc9 --- /dev/null +++ b/am/src/spike/trm.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include "htif.h" + +extern char _heap_start; +int main(const char *args); + +extern char _pmem_start; +#define PMEM_SIZE (128 * 1024 * 1024) +#define PMEM_END ((uintptr_t)0x80000000 + PMEM_SIZE) + +Area heap = RANGE(&_heap_start, PMEM_END); +#ifndef MAINARGS +#define MAINARGS "" +#endif +static const char mainargs[] = MAINARGS; + +void putch(char ch) { + htif_console_putchar(ch); +} + +void halt(int code) { + printf("Exit with code = %d\n", code); + htif_poweroff(); + + // should not reach here + while (1); +} + +void _trm_init() { + int ret = main(mainargs); + halt(ret); +} diff --git a/scripts/spike.mk b/scripts/spike.mk new file mode 100644 index 0000000..ca4b918 --- /dev/null +++ b/scripts/spike.mk @@ -0,0 +1,19 @@ +include $(AM_HOME)/scripts/isa/riscv64.mk + +AM_SRCS := spike/trm.c \ + spike/ioe.c \ + spike/timer.c \ + spike/start.S \ + spike/htif.S \ + platform/dummy/cte.c \ + platform/dummy/vme.c \ + platform/dummy/mpe.c \ + +CFLAGS += -fdata-sections -ffunction-sections +LDFLAGS += -T $(AM_HOME)/am/src/spike/linker.ld +LDFLAGS += --gc-sections -e _start + +CFLAGS += -DMAINARGS=\"$(mainargs)\" +.PHONY: $(AM_HOME)/am/src/spike/trm.c + +image: $(IMAGE).elf