From 8c6fc0c15415b32080a848bbde640e104098cf13 Mon Sep 17 00:00:00 2001 From: Carlos Maiolino Date: Thu, 10 Jul 2025 22:18:39 +0200 Subject: Initial drop Add some riscv code Signed-off-by: Carlos Maiolino --- riscv/riscv-probe/libfemto/drivers/htif.c | 91 ++++++++++++++++++++++++ riscv/riscv-probe/libfemto/drivers/ns16550a.c | 65 +++++++++++++++++ riscv/riscv-probe/libfemto/drivers/semihost.c | 60 ++++++++++++++++ riscv/riscv-probe/libfemto/drivers/sifive_test.c | 28 ++++++++ riscv/riscv-probe/libfemto/drivers/sifive_uart.c | 58 +++++++++++++++ 5 files changed, 302 insertions(+) create mode 100644 riscv/riscv-probe/libfemto/drivers/htif.c create mode 100644 riscv/riscv-probe/libfemto/drivers/ns16550a.c create mode 100644 riscv/riscv-probe/libfemto/drivers/semihost.c create mode 100644 riscv/riscv-probe/libfemto/drivers/sifive_test.c create mode 100644 riscv/riscv-probe/libfemto/drivers/sifive_uart.c (limited to 'riscv/riscv-probe/libfemto/drivers') diff --git a/riscv/riscv-probe/libfemto/drivers/htif.c b/riscv/riscv-probe/libfemto/drivers/htif.c new file mode 100644 index 0000000..ef6995e --- /dev/null +++ b/riscv/riscv-probe/libfemto/drivers/htif.c @@ -0,0 +1,91 @@ +// See LICENSE for license details. + +#ifdef __riscv + +#include "femto.h" +#include "spinlock.h" + +struct { uint32_t arr[2]; } volatile tohost __attribute__((section(".htif"))); +struct { uint32_t arr[2]; } volatile fromhost __attribute__((section(".htif"))); + +static spinlock_t htif_lock = SPINLOCK_INIT; + +static inline void htif_send(uint8_t dev, uint8_t cmd, int64_t data) +{ + /* endian neutral encoding with ordered 32-bit writes */ + union { uint32_t arr[2]; uint64_t val; } encode = { + .val = (uint64_t)dev << 56 | (uint64_t)cmd << 48 | data + }; + tohost.arr[0] = encode.arr[0]; + tohost.arr[1] = encode.arr[1]; +} + +static inline void htif_recv(uint8_t *dev, uint8_t *cmd, int64_t *data) +{ + /* endian neutral decoding with ordered 32-bit reads */ + union { uint32_t arr[2]; uint64_t val; } decode; + decode.arr[0] = fromhost.arr[0]; + decode.arr[1] = fromhost.arr[1]; + *dev = decode.val >> 56; + *cmd = (decode.val >> 48) & 0xff; + *data = decode.val << 16 >> 16; +} + +static int64_t htif_get_fromhost(uint8_t dev, uint8_t cmd) +{ + /* receive data for specified device and command */ + uint8_t rdev, rcmd; + int64_t data; + htif_recv(&rdev, &rcmd, &data); + return rdev == dev && rcmd == cmd ? data : -1; +} + +static void htif_set_tohost(uint8_t dev, uint8_t cmd, int64_t data) +{ + /* send data with specified device and command */ + while (tohost.arr[0]) { + asm volatile ("" : : "r" (fromhost.arr[0])); + asm volatile ("" : : "r" (fromhost.arr[1])); + } + htif_send(dev, cmd, data); +} + +static int htif_getchar() +{ + int ch; + spinlock_lock(&htif_lock); + if ((ch = htif_get_fromhost(1, 0) & 0xff)) { + htif_set_tohost(1, 0, 0); + } + spinlock_unlock(&htif_lock); + return ch; +} + +static int htif_putchar(int ch) +{ + spinlock_lock(&htif_lock); + htif_set_tohost(1, 1, ch & 0xff); + spinlock_unlock(&htif_lock); + return ch & 0xff; +} + +static void htif_poweroff(int status) +{ + for (;;) { + htif_set_tohost(0, 0, 1); + } +} + +console_device_t console_htif = { + NULL, + htif_getchar, + htif_putchar +}; + + +poweroff_device_t poweroff_htif = { + NULL, + htif_poweroff +}; + +#endif diff --git a/riscv/riscv-probe/libfemto/drivers/ns16550a.c b/riscv/riscv-probe/libfemto/drivers/ns16550a.c new file mode 100644 index 0000000..cff5605 --- /dev/null +++ b/riscv/riscv-probe/libfemto/drivers/ns16550a.c @@ -0,0 +1,65 @@ +// See LICENSE for license details. + +#include "femto.h" + +enum { + UART_RBR = 0x00, /* Receive Buffer Register */ + UART_THR = 0x00, /* Transmit Hold Register */ + UART_IER = 0x01, /* Interrupt Enable Register */ + UART_DLL = 0x00, /* Divisor LSB (LCR_DLAB) */ + UART_DLM = 0x01, /* Divisor MSB (LCR_DLAB) */ + UART_FCR = 0x02, /* FIFO Control Register */ + UART_LCR = 0x03, /* Line Control Register */ + UART_MCR = 0x04, /* Modem Control Register */ + UART_LSR = 0x05, /* Line Status Register */ + UART_MSR = 0x06, /* Modem Status Register */ + UART_SCR = 0x07, /* Scratch Register */ + + UART_LCR_DLAB = 0x80, /* Divisor Latch Bit */ + UART_LCR_8BIT = 0x03, /* 8-bit */ + UART_LCR_PODD = 0x08, /* Parity Odd */ + + UART_LSR_DA = 0x01, /* Data Available */ + UART_LSR_OE = 0x02, /* Overrun Error */ + UART_LSR_PE = 0x04, /* Parity Error */ + UART_LSR_FE = 0x08, /* Framing Error */ + UART_LSR_BI = 0x10, /* Break indicator */ + UART_LSR_RE = 0x20, /* THR is empty */ + UART_LSR_RI = 0x40, /* THR is empty and line is idle */ + UART_LSR_EF = 0x80, /* Erroneous data in FIFO */ +}; + +static volatile uint8_t *uart; + +static void ns16550a_init() +{ + uart = (uint8_t *)(void *)getauxval(NS16550A_UART0_CTRL_ADDR); + uint32_t uart_freq = getauxval(UART0_CLOCK_FREQ); + uint32_t baud_rate = getauxval(UART0_BAUD_RATE); + uint32_t divisor = uart_freq / (16 * baud_rate); + uart[UART_LCR] = UART_LCR_DLAB; + uart[UART_DLL] = divisor & 0xff; + uart[UART_DLM] = (divisor >> 8) & 0xff; + uart[UART_LCR] = UART_LCR_PODD | UART_LCR_8BIT; +} + +static int ns16550a_getchar() +{ + if (uart[UART_LSR] & UART_LSR_DA) { + return uart[UART_RBR]; + } else { + return -1; + } +} + +static int ns16550a_putchar(int ch) +{ + while ((uart[UART_LSR] & UART_LSR_RI) == 0); + return uart[UART_THR] = ch & 0xff; +} + +console_device_t console_ns16550a = { + ns16550a_init, + ns16550a_getchar, + ns16550a_putchar +}; diff --git a/riscv/riscv-probe/libfemto/drivers/semihost.c b/riscv/riscv-probe/libfemto/drivers/semihost.c new file mode 100644 index 0000000..9f47834 --- /dev/null +++ b/riscv/riscv-probe/libfemto/drivers/semihost.c @@ -0,0 +1,60 @@ +// See LICENSE for license details. + +#ifdef __riscv + +#include "femto.h" + +enum { + SBI_CONSOLE_PUTCHAR = 1, + SBI_CONSOLE_GETCHAR = 2, + SBI_SHUTDOWN = 8 +}; + +#define __syscall(...) \ + asm volatile ("ecall\n\t" : "+r"(a0) : __VA_ARGS__ : "memory") + +static inline long semihost_call0(long n) +{ + register long a7 __asm__("a7") = n; + register long a0 __asm__("a0"); + __syscall("r"(a7)); + return a0; +} + +static inline long semihost_call1(long n, long a) +{ + register long a7 __asm__("a7") = n; + register long a0 __asm__("a0") = a; + __syscall("r"(a7), "0"(a0)); + return a0; +} + +static int semihost_getchar() +{ + semihost_call0(SBI_CONSOLE_GETCHAR); +} + +static int semihost_putchar(int ch) +{ + semihost_call1(SBI_CONSOLE_PUTCHAR, ch); +} + +static void semihost_poweroff(int status) +{ + semihost_call0(SBI_SHUTDOWN); + __builtin_unreachable(); +} + +console_device_t console_semihost = { + NULL, + semihost_getchar, + semihost_putchar +}; + + +poweroff_device_t poweroff_semihost = { + NULL, + semihost_poweroff +}; + +#endif \ No newline at end of file diff --git a/riscv/riscv-probe/libfemto/drivers/sifive_test.c b/riscv/riscv-probe/libfemto/drivers/sifive_test.c new file mode 100644 index 0000000..1bda9e9 --- /dev/null +++ b/riscv/riscv-probe/libfemto/drivers/sifive_test.c @@ -0,0 +1,28 @@ +// See LICENSE for license details. + +#include "femto.h" + +enum { + SIFIVE_TEST_FAIL = 0x3333, + SIFIVE_TEST_PASS = 0x5555, +}; + +static volatile uint32_t *test; + +static void sifive_test_init() +{ + test = (uint32_t *)(void *)getauxval(SIFIVE_TEST_CTRL_ADDR); +} + +static void sifive_test_poweroff(int status) +{ + *test = SIFIVE_TEST_PASS; + while (1) { + asm volatile(""); + } +} + +poweroff_device_t poweroff_sifive_test = { + sifive_test_init, + sifive_test_poweroff +}; diff --git a/riscv/riscv-probe/libfemto/drivers/sifive_uart.c b/riscv/riscv-probe/libfemto/drivers/sifive_uart.c new file mode 100644 index 0000000..9be877e --- /dev/null +++ b/riscv/riscv-probe/libfemto/drivers/sifive_uart.c @@ -0,0 +1,58 @@ +// See LICENSE for license details. + +#include "femto.h" + +enum { + /* UART Registers */ + UART_REG_TXFIFO = 0, + UART_REG_RXFIFO = 1, + UART_REG_TXCTRL = 2, + UART_REG_RXCTRL = 3, + UART_REG_IE = 4, + UART_REG_IP = 5, + UART_REG_DIV = 6, + + /* TXCTRL register */ + UART_TXEN = 1, + UART_TXSTOP = 2, + + /* RXCTRL register */ + UART_RXEN = 1, + + /* IP register */ + UART_IP_TXWM = 1, + UART_IP_RXWM = 2 +}; + +static volatile int *uart; + +static void sifive_uart_init() +{ + uart = (int *)(void *)getauxval(SIFIVE_UART0_CTRL_ADDR); + uint32_t uart_freq = getauxval(UART0_CLOCK_FREQ); + uint32_t baud_rate = getauxval(UART0_BAUD_RATE); + uint32_t divisor = uart_freq / baud_rate - 1; + uart[UART_REG_DIV] = divisor; + uart[UART_REG_TXCTRL] = UART_TXEN; + uart[UART_REG_RXCTRL] = UART_RXEN; + uart[UART_REG_IE] = 0; +} + +static int sifive_uart_getchar() +{ + int ch = uart[UART_REG_RXFIFO]; + if (ch < 0) return -1; + return ch; +} + +static int sifive_uart_putchar(int ch) +{ + while (uart[UART_REG_TXFIFO] < 0); + return uart[UART_REG_TXFIFO] = ch & 0xff; +} + +console_device_t console_sifive_uart = { + sifive_uart_init, + sifive_uart_getchar, + sifive_uart_putchar +}; -- cgit v1.2.3