Skip to content

Commit

Permalink
Merge pull request #57 from sifive/htif
Browse files Browse the repository at this point in the history
Add support for HTIF interfaces
  • Loading branch information
nategraff-sifive authored Oct 7, 2019
2 parents b16dbc2 + bb7edca commit 56bb58e
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 0 deletions.
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;

0 comments on commit 56bb58e

Please sign in to comment.