Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for HTIF interfaces #57

Merged
merged 4 commits into from
Oct 7, 2019
Merged
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
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ nobase_include_HEADERS = \
metal/drivers/sifive_trace.h \
metal/drivers/sifive_uart0.h \
metal/drivers/sifive_wdog0.h \
metal/drivers/ucb_htif0.h \
metal/machine/inline.h \
metal/machine/platform.h \
metal/button.h \
Expand Down Expand Up @@ -185,6 +186,7 @@ libriscv__mmachine__@MACHINE_NAME@_a_SOURCES = \
src/drivers/sifive_trace.c \
src/drivers/sifive_uart0.c \
src/drivers/sifive_wdog0.c \
src/drivers/ucb_htif0.c \
src/button.c \
src/cache.c \
src/clock.c \
Expand Down
21 changes: 21 additions & 0 deletions Makefile.in

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions metal/drivers/ucb_htif0.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */

#ifndef METAL__DRIVERS__UCB_HTIF0_H
#define METAL__DRIVERS__UCB_HTIF0_H

#include <metal/compiler.h>
#include <metal/shutdown.h>
#include <metal/uart.h>

struct __metal_driver_vtable_ucb_htif0_shutdown {
const struct __metal_shutdown_vtable shutdown;
};

struct __metal_driver_vtable_ucb_htif0_uart {
const struct metal_uart_vtable uart;
};

struct __metal_driver_ucb_htif0;

void __metal_driver_ucb_htif0_exit(const struct __metal_shutdown *test,
int code) __attribute__((noreturn));

void __metal_driver_ucb_htif0_init(struct metal_uart *uart, int baud_rate);
int __metal_driver_ucb_htif0_putc(struct metal_uart *uart, int c);
int __metal_driver_ucb_htif0_getc(struct metal_uart *uart, int *c);
int __metal_driver_ucb_htif0_get_baud_rate(struct metal_uart *guart);
int __metal_driver_ucb_htif0_set_baud_rate(struct metal_uart *guart,
int baud_rate);
struct metal_interrupt *
__metal_driver_ucb_htif0_interrupt_controller(struct metal_uart *uart);
int __metal_driver_ucb_htif0_get_interrupt_id(struct metal_uart *uart);

__METAL_DECLARE_VTABLE(__metal_driver_vtable_ucb_htif0_shutdown)

__METAL_DECLARE_VTABLE(__metal_driver_vtable_ucb_htif0_uart)

struct __metal_driver_ucb_htif0_shutdown {
struct __metal_shutdown shutdown;
const struct __metal_driver_vtable_ucb_htif0_shutdown *vtable;
};

struct __metal_driver_ucb_htif0_uart {
struct metal_uart uart;
const struct __metal_driver_vtable_ucb_htif0_uart *vtable;
};

#endif
128 changes: 128 additions & 0 deletions src/drivers/ucb_htif0.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */

#include <metal/machine/platform.h>

#ifdef METAL_UCB_HTIF0

#include <metal/drivers/ucb_htif0.h>
#include <metal/io.h>
#include <stddef.h>
#include <stdint.h>

#define FINISHER_OFFSET 0

volatile uint64_t fromhost __attribute__((aligned(4096)));
volatile uint64_t tohost __attribute__((aligned(4096)));

#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)

static void __check_fromhost() {
uint64_t fh = fromhost;
if (!fh)
return;
fromhost = 0;
}

static void __set_tohost(uintptr_t dev, uintptr_t cmd, uintptr_t data) {
while (tohost)
__check_fromhost();
tohost = TOHOST_CMD(dev, cmd, data);
}

static void do_tohost_fromhost(uintptr_t dev, uintptr_t cmd, uintptr_t data) {
__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();
}
}
}

void __metal_driver_ucb_htif0_init(struct metal_uart *uart, int baud_rate) {}

void __metal_driver_ucb_htif0_exit(const struct __metal_shutdown *sd,
int code) {
volatile uint64_t magic_mem[8];
magic_mem[0] = 93; // SYS_exit
magic_mem[1] = code;
magic_mem[2] = 0;
magic_mem[3] = 0;

do_tohost_fromhost(0, 0, (uintptr_t)magic_mem);

while (1) {
// loop forever
}
}

int __metal_driver_ucb_htif0_putc(struct metal_uart *htif, int c) {
volatile uint64_t magic_mem[8];
magic_mem[0] = 64; // SYS_write
magic_mem[1] = 1;
magic_mem[2] = (uintptr_t)&c;
magic_mem[3] = 1;

do_tohost_fromhost(0, 0, (uintptr_t)magic_mem);

return 0;
}

int __metal_driver_ucb_htif0_getc(struct metal_uart *htif, int *c) {
return -1;
}

int __metal_driver_ucb_htif0_get_baud_rate(struct metal_uart *guart) {
return 0;
}

int __metal_driver_ucb_htif0_set_baud_rate(struct metal_uart *guart,
int baud_rate) {
return 0;
}

struct metal_interrupt *
__metal_driver_ucb_htif0_interrupt_controller(struct metal_uart *uart) {
return NULL;
}

int __metal_driver_ucb_htif0_get_interrupt_id(struct metal_uart *uart) {
return -1;
}

__METAL_DEFINE_VTABLE(__metal_driver_vtable_ucb_htif0_shutdown) = {
.shutdown.exit = &__metal_driver_ucb_htif0_exit,
};

__METAL_DEFINE_VTABLE(__metal_driver_vtable_ucb_htif0_uart) = {
.uart.init = __metal_driver_ucb_htif0_init,
.uart.putc = __metal_driver_ucb_htif0_putc,
.uart.getc = __metal_driver_ucb_htif0_getc,
.uart.get_baud_rate = __metal_driver_ucb_htif0_get_baud_rate,
.uart.set_baud_rate = __metal_driver_ucb_htif0_set_baud_rate,
.uart.controller_interrupt = __metal_driver_ucb_htif0_interrupt_controller,
.uart.get_interrupt_id = __metal_driver_ucb_htif0_get_interrupt_id,
};

#endif /* METAL_UCB_HTIF0 */

typedef int no_empty_translation_units;