summaryrefslogtreecommitdiff
path: root/software
diff options
context:
space:
mode:
authorMegan Wachs <megan@sifive.com>2016-07-20 23:59:02 +0000
committerMegan Wachs <megan@sifive.com>2016-07-26 08:40:12 -0700
commit2887165ae2990e7f93038f3220ed74ee429b5244 (patch)
tree13c4cb83e47d6ab390e0465e883acf0973611e8e /software
parenta2d28c8318ab3ed40b3674aeee8b9487a3129f15 (diff)
Initial Checkin
Diffstat (limited to 'software')
-rw-r--r--software/demo_gpio/Makefile9
-rw-r--r--software/demo_gpio/demo_gpio.c182
-rw-r--r--software/shared/Makefile.shared47
-rw-r--r--software/shared/drivers_sifive/plic.c123
-rw-r--r--software/shared/drivers_sifive/plic.h70
l---------software/shared/entry.S1
-rw-r--r--software/shared/gpio.h10
-rw-r--r--software/shared/init.c48
l---------software/shared/link.lds1
-rw-r--r--software/shared/shared.h73
-rw-r--r--software/shared/spi.h8
-rw-r--r--software/shared/syscall.c206
-rw-r--r--software/shared/uart.h12
13 files changed, 790 insertions, 0 deletions
diff --git a/software/demo_gpio/Makefile b/software/demo_gpio/Makefile
new file mode 100644
index 0000000..5f201a2
--- /dev/null
+++ b/software/demo_gpio/Makefile
@@ -0,0 +1,9 @@
+#See LICENSE for license details.
+
+TARGET=demo_gpio
+CFLAGS += -g
+CDEFINES += -DUSE_PLIC -DUSE_M_TIME
+
+SWDIR = ../
+
+include $(SWDIR)/shared/Makefile.shared
diff --git a/software/demo_gpio/demo_gpio.c b/software/demo_gpio/demo_gpio.c
new file mode 100644
index 0000000..3b0b6f5
--- /dev/null
+++ b/software/demo_gpio/demo_gpio.c
@@ -0,0 +1,182 @@
+// See LICENSE for license details.
+
+#include <stdio.h>
+
+#include "shared.h"
+#include "plic.h"
+#include <string.h>
+
+void reset_demo (void);
+
+// Structures for registering different interrupt handlers
+// for different parts of the application.
+typedef void (*function_ptr_t) (void);
+
+void no_interrupt_handler (void) {};
+
+function_ptr_t g_ext_interrupt_handlers[9];
+
+function_ptr_t g_m_timer_interrupt_handler = no_interrupt_handler;
+
+// Instance data for the PLIC.
+
+plic_instance_t g_plic;
+
+// Simple variables for LEDs, buttons, etc.
+volatile unsigned int* g_outputs = (unsigned int *) (GPIO_BASE_ADDR + GPIO_OUT_OFFSET);
+volatile unsigned int* g_inputs = (unsigned int *) (GPIO_BASE_ADDR + GPIO_IN_OFFSET);
+volatile unsigned int* g_tristates = (unsigned int *) (GPIO_BASE_ADDR + GPIO_TRI_OFFSET);
+
+
+/*Entry Point for PLIC Interrupt Handler*/
+void handle_m_ext_interrupt(){
+ plic_source int_num = PLIC_claim_interrupt(&g_plic);
+ if ((int_num >=1 ) && (int_num <= 8)) {
+ g_ext_interrupt_handlers[int_num]();
+ }
+ else {
+ _exit(1 + (uintptr_t) int_num);
+ }
+ PLIC_complete_interrupt(&g_plic, int_num);
+}
+
+
+/*Entry Point for Machine Timer Interrupt Handler*/
+void handle_m_time_interrupt(){
+
+ clear_csr(mie, MIP_MTIP);
+
+ // Reset the timer for 3s in the future.
+ // This also clears the existing timer interrupt.
+
+ volatile uint64_t * mtime = (uint64_t*) MTIME_ADDR;
+ volatile uint64_t * mtimecmp = (uint64_t*) MTIMECMP_BASE_ADDR;
+ uint64_t now = *mtime;
+ uint64_t then = now + 3 * CLOCK_FREQUENCY / RTC_PRESCALER;
+ *mtimecmp = then;
+
+ // read the current value of the LEDS and invert them.
+ uint32_t leds = *g_outputs;
+
+ *g_outputs = (~leds) & ((0xF << RED_LEDS_OFFSET) |
+ (0xF << GREEN_LEDS_OFFSET) |
+ (0xF << BLUE_LEDS_OFFSET));
+
+
+ // Re-enable the timer interrupt.
+ set_csr(mie, MIP_MTIP);
+
+}
+
+
+/*Entry Point for Machine Timer Interrupt Handler*/
+void handle_m_timer_interrupt(){
+ g_m_timer_interrupt_handler();
+}
+
+const char * instructions_msg = " \
+\n\
+ SIFIVE, INC.\n\
+\n\
+ 5555555555555555555555555\n\
+ 5555 5555\n\
+ 5555 5555\n\
+ 5555 5555\n\
+ 5555 5555555555555555555555\n\
+ 5555 555555555555555555555555\n\
+ 5555 5555\n\
+ 5555 5555\n\
+ 5555 5555\n\
+5555555555555555555555555555 55555\n\
+ 55555 555555555 55555\n\
+ 55555 55555 55555\n\
+ 55555 5 55555\n\
+ 55555 55555\n\
+ 55555 55555\n\
+ 55555 55555\n\
+ 55555 55555\n\
+ 55555 55555\n\
+ 555555555\n\
+ 55555\n\
+ 5\n\
+\n\
+ SiFive E-Series Coreplex Demo on Arty Board\n \
+ \n\
+ ";
+
+void print_instructions() {
+
+ write (STDOUT_FILENO, instructions_msg, strlen(instructions_msg));
+
+}
+
+void button_0_handler(void) {
+
+ // Rainbow LEDs!
+ * g_outputs = (0x9 << RED_LEDS_OFFSET) | (0xA << GREEN_LEDS_OFFSET) | (0xC << BLUE_LEDS_OFFSET);
+
+};
+
+
+void reset_demo (){
+
+ // Disable the machine & timer interrupts until setup is done.
+
+ clear_csr(mie, MIP_MEIP);
+ clear_csr(mie, MIP_MTIP);
+
+ g_ext_interrupt_handlers[INT_DEVICE_BUTTON_0] = button_0_handler;
+ g_ext_interrupt_handlers[INT_DEVICE_BUTTON_1] = no_interrupt_handler;
+ g_ext_interrupt_handlers[INT_DEVICE_BUTTON_2] = no_interrupt_handler;
+ g_ext_interrupt_handlers[INT_DEVICE_BUTTON_3] = no_interrupt_handler;
+ g_ext_interrupt_handlers[INT_DEVICE_JA_7] = no_interrupt_handler;
+ g_ext_interrupt_handlers[INT_DEVICE_JA_8] = no_interrupt_handler;
+ g_ext_interrupt_handlers[INT_DEVICE_JA_9] = no_interrupt_handler;
+ g_ext_interrupt_handlers[INT_DEVICE_JA_10] = no_interrupt_handler;
+
+ print_instructions();
+
+ PLIC_enable_interrupt (&g_plic, INT_DEVICE_BUTTON_0);
+
+ // Set the machine timer to go off in 3 seconds.
+ // The
+ volatile uint64_t * mtime = (uint64_t*) MTIME_ADDR;
+ volatile uint64_t * mtimecmp = (uint64_t*) MTIMECMP_BASE_ADDR;
+ uint64_t now = *mtime;
+ uint64_t then = now + 3*CLOCK_FREQUENCY / RTC_PRESCALER;
+ *mtimecmp = then;
+
+ // Enable the Machine-External bit in MIE
+ set_csr(mie, MIP_MEIP);
+
+ // Enable the Machine-Timer bit in MIE
+ set_csr(mie, MIP_MTIP);
+
+ // Enable interrupts in general.
+ set_csr(mstatus, MSTATUS_MIE);
+
+}
+
+int main(int argc, char **argv)
+{
+ // Set up the GPIOs such that the inputs' tristate are set.
+ // The boot ROM actually does this, but still good.
+
+ * g_tristates = (0xF << BUTTONS_OFFSET) | (0xF << SWITCHES_OFFSET) | (0xF << JA_IN_OFFSET);
+
+ * g_outputs = (0xF << RED_LEDS_OFFSET);
+
+
+ /**************************************************************************
+ * Set up the PLIC
+ *
+ *************************************************************************/
+ PLIC_init(&g_plic, PLIC_BASE_ADDR, PLIC_NUM_SOURCES, PLIC_NUM_PRIORITIES);
+
+ reset_demo();
+
+ while (1);
+
+ return 0;
+
+}
diff --git a/software/shared/Makefile.shared b/software/shared/Makefile.shared
new file mode 100644
index 0000000..5817826
--- /dev/null
+++ b/software/shared/Makefile.shared
@@ -0,0 +1,47 @@
+# See LICENSE for license details.
+
+SHARED_DIR = $(SWDIR)/shared
+
+ASM_SRCS += $(SHARED_DIR)/entry.S
+
+C_SRCS += $(SHARED_DIR)/init.c
+C_SRCS += $(SHARED_DIR)/syscall.c
+C_SRCS += $(SHARED_DIR)/drivers_sifive/plic.c
+
+LINKER_SCRIPT := $(SHARED_DIR)/link.lds
+HEADERS += $(SHARED_DIR)/*.h
+
+C_SRCS += $(TARGET).c
+
+INCLUDES += -I .
+INCLUDES += -I $(SHARED_DIR)
+INCLUDES += -I $(SWDIR)/../riscv-tests/env
+INCLUDES += -I$(SHARED_DIR)/drivers_sifive/
+
+CC = $(SWDIR)/../toolchain/bin/riscv32-unknown-elf-gcc
+
+CFLAGS += $(CDEFINES)
+
+LDFLAGS := -T $(LINKER_SCRIPT) -nostdlib -nostartfiles -lc -lgcc
+LDFLAGS += -L$(SHARED_DIR)
+LDFLAGS += -L$(SHARED_DIR)/drivers
+LDFLAGS += -L$(SHARED_DIR)/hal
+
+ASM_OBJS := $(patsubst %.S,%.o,$(ASM_SRCS))
+C_OBJS := $(patsubst %.c,%.o,$(C_SRCS))
+
+$(TARGET): $(ASM_OBJS) $(C_OBJS) $(LINKER_SCRIPT)
+ $(CC) $(CFLAGS) $(INCLUDES) $(C_OBJS) $(ASM_OBJS) -o $@ $(LDFLAGS)
+
+$(ASM_OBJS): %.o: %.S $(HEADERS)
+ $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
+
+$(C_OBJS): %.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
+
+all: default
+
+clean:
+ rm -f $(TARGET) *.o $(SHARED_DIR)/*.o $(SHARED_DIR)/drivers/*/*.o $(SHARED_DIR)/drivers_sifive/*.o
+
+.PHONY: clean all default
diff --git a/software/shared/drivers_sifive/plic.c b/software/shared/drivers_sifive/plic.c
new file mode 100644
index 0000000..ec0c178
--- /dev/null
+++ b/software/shared/drivers_sifive/plic.c
@@ -0,0 +1,123 @@
+// See LICENSE for license details.
+
+#include "plic.h"
+#include "encoding.h"
+#include <string.h>
+
+
+// Note that there are no assertions or bounds checking on these
+// parameter values.
+
+void volatile_memzero(uint8_t * base, unsigned int size){
+
+ volatile uint8_t * ptr;
+ for (ptr = base; ptr < (base + size); ptr++){
+ *ptr = 0;
+ }
+}
+
+void PLIC_init (
+ plic_instance_t * this_plic,
+ uintptr_t base_addr,
+ uint32_t num_sources,
+ uint32_t num_priorities
+ ){
+
+ this_plic->base_addr = base_addr;
+ this_plic->num_sources = num_sources;
+ this_plic->num_priorities = num_priorities;
+
+ // Disable all interrupts (don't assume that these registers are reset).
+ unsigned long hart_id = read_csr(mhartid);
+ volatile_memzero((uint8_t*) (this_plic->base_addr +
+ PLIC_ENABLE_OFFSET +
+ (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET)),
+ (num_sources + 8) / 8);
+
+ // Set all priorities to 0 (equal priority -- don't assume that these are reset).
+ volatile_memzero ((uint8_t *)(this_plic->base_addr +
+ PLIC_PRIORITY_OFFSET),
+ (num_sources + 1) << PLIC_PRIORITY_SHIFT_PER_SOURCE);
+
+ // Set the threshold to 0.
+ volatile plic_threshold* threshold = (plic_threshold*)
+ (this_plic->base_addr +
+ PLIC_THRESHOLD_OFFSET +
+ (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET));
+
+ *threshold = 0;
+
+}
+
+void PLIC_set_threshold (plic_instance_t * this_plic, plic_threshold threshold){
+
+ unsigned long hart_id = read_csr(mhartid);
+ volatile plic_threshold* threshold_ptr = (plic_threshold*) (this_plic->base_addr +
+ PLIC_THRESHOLD_OFFSET +
+ (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET));
+
+ *threshold_ptr = threshold;
+
+}
+
+
+void PLIC_enable_interrupt (plic_instance_t * this_plic, plic_source source){
+
+ unsigned long hart_id = read_csr(mhartid);
+ volatile uint8_t * current_ptr = (volatile uint8_t *)(this_plic->base_addr +
+ PLIC_ENABLE_OFFSET +
+ (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET) +
+ (source >> 3));
+ uint8_t current = *current_ptr;
+ current = current | ( 1 << (source & 0x7));
+ *current_ptr = current;
+
+}
+
+void PLIC_disable_interrupt (plic_instance_t * this_plic, plic_source source){
+
+ unsigned long hart_id = read_csr(mhartid);
+ volatile uint8_t * current_ptr = (volatile uint8_t *) (this_plic->base_addr +
+ PLIC_ENABLE_OFFSET +
+ (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET) +
+ (source >> 3));
+ uint8_t current = *current_ptr;
+ current = current & ~(( 1 << (source & 0x7)));
+ *current_ptr = current;
+
+}
+
+void PLIC_set_priority (plic_instance_t * this_plic, plic_source source, plic_priority priority){
+
+ if (this_plic->num_priorities > 0) {
+ volatile plic_priority * priority_ptr = (volatile plic_priority *)
+ (this_plic->base_addr +
+ PLIC_PRIORITY_OFFSET +
+ (source << PLIC_PRIORITY_SHIFT_PER_SOURCE));
+ *priority_ptr = priority;
+ }
+}
+
+plic_source PLIC_claim_interrupt(plic_instance_t * this_plic){
+
+ unsigned long hart_id = read_csr(mhartid);
+
+ volatile plic_source * claim_addr = (volatile plic_source * )
+ (this_plic->base_addr +
+ PLIC_CLAIM_OFFSET +
+ (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET));
+
+ return *claim_addr;
+
+}
+
+void PLIC_complete_interrupt(plic_instance_t * this_plic, plic_source source){
+
+ unsigned long hart_id = read_csr(mhartid);
+ volatile plic_source * claim_addr = (volatile plic_source *) (this_plic->base_addr +
+ PLIC_CLAIM_OFFSET +
+ (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET));
+ *claim_addr = source;
+
+}
+
diff --git a/software/shared/drivers_sifive/plic.h b/software/shared/drivers_sifive/plic.h
new file mode 100644
index 0000000..14118a5
--- /dev/null
+++ b/software/shared/drivers_sifive/plic.h
@@ -0,0 +1,70 @@
+// See LICENSE for license details.
+
+#ifndef PLIC_H
+#define PLIC_H
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <unistd.h>
+
+
+#include "encoding.h"
+
+// 32 bits per source
+#define PLIC_PRIORITY_OFFSET 0x0000UL
+#define PLIC_PRIORITY_SHIFT_PER_SOURCE 2
+// 1 bit per source (1 address)
+#define PLIC_PENDING_OFFSET 0x1000UL
+#define PLIC_PENDING_SHIFT_PER_SOURCE 0
+
+//0x80 per target
+#define PLIC_ENABLE_OFFSET 0x2000UL
+#define PLIC_ENABLE_SHIFT_PER_TARGET 7
+
+
+#define PLIC_THRESHOLD_OFFSET 0x200000UL
+#define PLIC_CLAIM_OFFSET 0x200004UL
+#define PLIC_THRESHOLD_SHIFT_PER_TARGET 12
+#define PLIC_CLAIM_SHIFT_PER_TARGET 12
+
+#define PLIC_MAX_SOURCE 1023
+#define PLIC_SOURCE_MASK 0x3FF
+
+#define PLIC_MAX_TARGET 15871
+#define PLIC_TARGET_MASK 0x3FFF
+
+
+typedef struct __plic_instance_t
+{
+ uintptr_t base_addr;
+
+ uint32_t num_sources;
+ uint32_t num_priorities;
+
+} plic_instance_t;
+
+typedef uint32_t plic_source;
+typedef uint32_t plic_priority;
+typedef uint32_t plic_threshold;
+
+void PLIC_init (
+ plic_instance_t * this_plic,
+ uintptr_t base_addr,
+ uint32_t num_sources,
+ uint32_t num_priorities
+ );
+
+void PLIC_enable_interrupt (plic_instance_t * this_plic, plic_source source);
+
+void PLIC_disable_interrupt (plic_instance_t * this_plic, plic_source source);
+
+void PLIC_set_priority (plic_instance_t * this_plic, plic_source source, plic_priority priority);
+
+plic_source PLIC_claim_interrupt(plic_instance_t * this_plic);
+
+void PLIC_complete_interrupt(plic_instance_t * this_plic, plic_source source);
+
+void PLIC_set_threshold(plic_instance_t * this_plic, plic_threshold threshold);
+
+#endif
diff --git a/software/shared/entry.S b/software/shared/entry.S
new file mode 120000
index 0000000..11f412b
--- /dev/null
+++ b/software/shared/entry.S
@@ -0,0 +1 @@
+../../riscv-tests/debug/programs/entry.S \ No newline at end of file
diff --git a/software/shared/gpio.h b/software/shared/gpio.h
new file mode 100644
index 0000000..ed48255
--- /dev/null
+++ b/software/shared/gpio.h
@@ -0,0 +1,10 @@
+// See LICENSE for license details.
+
+#ifndef SIFIVE_GPIO_H
+#define SIFIVE_GPIO_H
+
+#define GPIO_IN_OFFSET 0
+#define GPIO_OUT_OFFSET 0
+#define GPIO_TRI_OFFSET 4
+
+#endif
diff --git a/software/shared/init.c b/software/shared/init.c
new file mode 100644
index 0000000..ab790b2
--- /dev/null
+++ b/software/shared/init.c
@@ -0,0 +1,48 @@
+// See LICENSE for license details.
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "encoding.h"
+#include "shared.h"
+
+int main(void);
+
+#ifdef USE_PLIC
+extern void handle_m_ext_interrupt();
+#endif
+
+
+#ifdef USE_M_TIME
+extern void handle_m_time_interrupt();
+#endif
+
+
+void _init(void)
+{
+
+ exit(main());
+}
+
+uintptr_t handle_trap(uintptr_t mcause, uintptr_t epc)
+{
+ if (0){
+#ifdef USE_PLIC
+ // External Machine-Level Interrupt from PLIC
+ }else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT)) {
+ handle_m_ext_interrupt();
+#endif
+#ifdef USE_M_TIME
+ // External Machine-Level Interrupt from PLIC
+ }else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER)) {
+ handle_m_time_interrupt();
+#endif
+ }
+ else{
+ write(1, "trap\n", 5);
+ _exit(1 + mcause);
+ }
+ return epc;
+}
diff --git a/software/shared/link.lds b/software/shared/link.lds
new file mode 120000
index 0000000..013b6cb
--- /dev/null
+++ b/software/shared/link.lds
@@ -0,0 +1 @@
+../../riscv-tests/debug/targets/m2gl_m2s/link.lds \ No newline at end of file
diff --git a/software/shared/shared.h b/software/shared/shared.h
new file mode 100644
index 0000000..e8f3bf4
--- /dev/null
+++ b/software/shared/shared.h
@@ -0,0 +1,73 @@
+// See LICENSE for license details.
+
+#ifndef SIFIVE_SHARED_H
+#define SIFIVE_SHARED_H
+
+#include "uart.h"
+#include "gpio.h"
+#include "plic.h"
+
+// Some things missing from the official encoding.h
+#define MCAUSE_INT 0x80000000
+#define MCAUSE_CAUSE 0x7FFFFFFF
+
+/****************************************************************************
+ * Platform definitions
+ *****************************************************************************/
+
+#define MTIMECMP_BASE_ADDR 0x44004000UL
+#define MTIME_ADDR 0x4400BFF8UL
+#define PLIC_BASE_ADDR 0x40000000UL
+#define UART_BASE_ADDR 0x48000000UL
+#define GPIO_BASE_ADDR 0x48002000UL
+#define SPI_BASE_ADDR 0x48001000UL
+
+
+/****************************************************************************
+ * Clock Parameters
+ *****************************************************************************/
+
+#define RTC_PRESCALER 100
+#define CLOCK_FREQUENCY 62500000
+
+/****************************************************************************
+ * GPIO Connections
+ *****************************************************************************/
+
+
+// Each of these OFFSETS holds 4 bits.
+
+#define RED_LEDS_OFFSET 0
+#define GREEN_LEDS_OFFSET 4
+#define BLUE_LEDS_OFFSET 8
+#define JA_OUT_OFFSET 12 // JA Pins 1-4 are outputs.
+
+#define BUTTONS_OFFSET 16
+#define SWITCHES_OFFSET 20
+#define JA_IN_OFFSET 24 // JA Pins 7-10 are inputs.
+// reserved input offset 38 // Tied to zero.
+
+/****************************************************************************
+ * External Interrupts handled by PLIC.
+ *****************************************************************************/
+
+// Interrupt devices
+#define INT_DEVICE_BUTTON_0 1
+#define INT_DEVICE_BUTTON_1 2
+#define INT_DEVICE_BUTTON_2 3
+#define INT_DEVICE_BUTTON_3 4
+
+#define INT_DEVICE_JA_7 5
+#define INT_DEVICE_JA_8 6
+#define INT_DEVICE_JA_9 7
+#define INT_DEVICE_JA_10 8
+
+
+// Setting these correctly makes the initialization scripts
+// run faster.
+#define PLIC_NUM_SOURCES 31
+#define PLIC_NUM_PRIORITIES 0
+
+void write_hex(int fd, uint32_t hex);
+
+#endif
diff --git a/software/shared/spi.h b/software/shared/spi.h
new file mode 100644
index 0000000..9c974c1
--- /dev/null
+++ b/software/shared/spi.h
@@ -0,0 +1,8 @@
+// See LICENSE for license details.
+
+#ifndef SIFIVE_SPI_H
+#define SIFIVE_SPI_H
+
+//TODO
+
+#endif
diff --git a/software/shared/syscall.c b/software/shared/syscall.c
new file mode 100644
index 0000000..2e4199f
--- /dev/null
+++ b/software/shared/syscall.c
@@ -0,0 +1,206 @@
+// See LICENSE for license details.
+
+/* This is an incomplete version of a syscall library,
+ * which really only supports simple reads and writes over UART.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/times.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "encoding.h"
+
+#include "shared.h"
+
+volatile uint64_t tohost __attribute__((aligned(64)));
+volatile uint64_t fromhost __attribute__((aligned(64)));
+
+void write_hex(int fd, uint32_t hex){
+ uint8_t ii;
+ uint8_t jj;
+ char towrite;
+ write( fd , "0x", 2 );
+ for (ii = 8 ; ii > 0; ii--){
+ jj = ii-1;
+ uint8_t digit = ((hex & (0xF << (jj*4))) >> (jj*4));
+ towrite = digit < 0xA ? ('0' + digit) : ('A' + (digit - 0xA));
+ write( fd, &towrite, 1);
+ }
+
+}
+
+
+void _exit(int code)
+{
+ volatile uint32_t* leds = (uint32_t*) (GPIO_BASE_ADDR + GPIO_OUT_OFFSET);
+ const char * message = "\nProgam has exited with code:";
+
+ *leds = (~(code));
+
+ write(STDERR_FILENO, message, strlen(message));
+ write_hex(STDERR_FILENO, code);
+
+ while (1);
+
+}
+
+void *sbrk(ptrdiff_t incr)
+{
+ // extern char _end[];
+ // extern char _heap_end[];
+ // static char *curbrk = _end;
+
+ // if ((curbrk + incr < _end) || (curbrk + incr > _heap_end))
+ return NULL - 1;
+
+ // curbrk += incr;
+ //return curbrk - incr;
+}
+
+static int stub(int err)
+{
+ errno = err;
+ return -1;
+}
+
+int open(const char* name, int flags, int mode)
+{
+ return stub(ENOENT);
+}
+
+int openat(int dirfd, const char* name, int flags, int mode)
+{
+ return stub(ENOENT);
+}
+
+int close(int fd)
+{
+ return stub(EBADF);
+}
+
+int execve(const char* name, char* const argv[], char* const env[])
+{
+ return stub(ENOMEM);
+}
+
+int fork()
+{
+ return stub(EAGAIN);
+}
+
+int fstat(int fd, struct stat *st)
+{
+ if (isatty(fd)) {
+ st->st_mode = S_IFCHR;
+ return 0;
+ }
+
+ return stub(EBADF);
+}
+
+int getpid()
+{
+ return 1;
+}
+
+int isatty(int fd)
+{
+ if (fd == STDOUT_FILENO || fd == STDERR_FILENO)
+ return 1;
+
+ errno = EBADF;
+ return 0;
+}
+
+int kill(int pid, int sig)
+{
+ return stub(EINVAL);
+}
+
+int link(const char *old_name, const char *new_name)
+{
+ return stub(EMLINK);
+}
+
+off_t lseek(int fd, off_t ptr, int dir)
+{
+ if (isatty(fd))
+ return 0;
+
+ return stub(EBADF);
+}
+
+ssize_t read(int fd, void* ptr, size_t len)
+{
+ int i;
+ uint8_t * current = (uint8_t*) ptr;
+ volatile uint8_t * uart_rx = (uint8_t*) (UART_BASE_ADDR + UART_RX_OFFSET);
+ volatile uint32_t * uart_rx_cnt = (uint32_t*) (UART_BASE_ADDR + UART_RX_COUNT_OFFSET);
+
+ ssize_t result = 0;
+
+ if (isatty(fd)) {
+
+ for (current = (uint8_t*) ptr;
+ (current < ((uint8_t*) ptr) + len) && (*uart_rx_cnt > 0);
+ current ++){
+ *current = *uart_rx;
+ result ++;
+ }
+ return result;
+
+ }
+
+ return stub(EBADF);
+}
+
+int stat(const char* file, struct stat* st)
+{
+ return stub(EACCES);
+}
+
+clock_t times(struct tms* buf)
+{
+ return stub(EACCES);
+}
+
+int unlink(const char* name)
+{
+ return stub(ENOENT);
+}
+
+int wait(int* status)
+{
+ return stub(ECHILD);
+}
+
+ssize_t write(int fd, const void* ptr, size_t len)
+{
+
+ const uint8_t * current = (const char*) ptr;
+ volatile uint32_t * uart_tx_count = (uint32_t*) (UART_BASE_ADDR + UART_TX_COUNT_OFFSET);
+ volatile uint8_t * uart_tx = (uint8_t*) (UART_BASE_ADDR + UART_TX_OFFSET);
+
+ size_t jj;
+ if (isatty(fd)) {
+
+ for (jj = 0; jj < len; jj++){
+
+ while ((*uart_tx_count) < 1);
+ *uart_tx = current[jj];
+
+ if (current[jj] == '\n'){
+ while ((*uart_tx_count) < 1);
+ *uart_tx = '\r';
+ }
+ }
+ return len;
+ }
+ return stub(EBADF);
+}
diff --git a/software/shared/uart.h b/software/shared/uart.h
new file mode 100644
index 0000000..e97ef8b
--- /dev/null
+++ b/software/shared/uart.h
@@ -0,0 +1,12 @@
+// See LICENSE for license details.
+
+#ifndef SIFIVE_UART_H
+#define SIFIVE_UART_H
+
+#define UART_RX_OFFSET 0
+#define UART_TX_OFFSET 0
+#define UART_TX_COUNT_OFFSET 0x4
+#define UART_RX_COUNT_OFFSET 0x8
+#define UART_DIVIDER_OFFSET 0xC
+
+#endif