summaryrefslogtreecommitdiff
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
parenta2d28c8318ab3ed40b3674aeee8b9487a3129f15 (diff)
Initial Checkin
-rw-r--r--.gitmodules2
-rw-r--r--Makefile88
-rw-r--r--README.md44
-rw-r--r--bitfile/README.md7
-rw-r--r--bootrom/bram.mk79
-rw-r--r--bootrom/common/bram.ld40
-rw-r--r--bootrom/common/mem.awk63
-rw-r--r--bootrom/demo/Makefile5
-rw-r--r--bootrom/demo/demo.S71
-rw-r--r--bootrom/demo/hello_msg.txt37
m---------openocd0
m---------riscv-gnu-toolchain0
m---------riscv-tests0
-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
26 files changed, 1218 insertions, 8 deletions
diff --git a/.gitmodules b/.gitmodules
index 9527506..c870132 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -9,4 +9,4 @@
url = http://github.com/sifive/riscv-binutils-gdb.git
[submodule "riscv-tests"]
path = riscv-tests
- url = http://github.com/timsifive/riscv-tests
+ url = http://github.com/riscv/riscv-tests.git
diff --git a/Makefile b/Makefile
index 9d81d77..ac1f9b6 100644
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,36 @@ srcdir := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
srcdir := $(srcdir:/=)
wrkdir := $(CURDIR)/work
+#############################################################
+# Prints help message
+#############################################################
+
+.PHONY: help
+help :
+ @echo " SiFive Freedom E Software Development Kit "
+ @echo " Makefile targets:"
+ @echo ""
+ @echo " tools:"
+ @echo " Install compilation & debugging tools"
+ @echo ""
+ @echo " fpga [BOOTROM=demo]:"
+ @echo " Rebuild the image (including Boot SW) to"
+ @echo " reprogram the FPGA. "
+ @echo ""
+ @echo " software [PROGRAM=demo_gpio]:"
+ @echo " Build a software program to load with the"
+ @echo " debugger."
+ @echo ""
+ @echo " run_debug [PROGRAM=demo_gpio]:"
+ @echo " Launch the debugging tools to load or"
+ @echo " debug running programs."
+ @echo ""
+ @echo " For more information, visit dev.sifive.com"
+
+#############################################################
+# This section is for tool installation
+#############################################################
+
toolchain_srcdir := $(srcdir)/riscv-gnu-toolchain
toolchain32_wrkdir := $(wrkdir)/riscv32-gnu-toolchain
toolchain64_wrkdir := $(wrkdir)/riscv64-gnu-toolchain
@@ -23,10 +53,11 @@ target32 := riscv32-unknown-linux-gnu
.PHONY: all
-all: $(hex)
+all: tools
@echo All done.
tools: tools64 tools32 openocd gdb
+ @echo All Tools Installed
tools64: $(toolchain_dest)/bin/$(target64)-gcc
tools32: $(toolchain_dest)/bin/$(target32)-gcc
@@ -43,7 +74,6 @@ $(toolchain_dest)/bin/$(target32)-gcc: $(toolchain_srcdir)
cd $(toolchain32_wrkdir); $(toolchain_srcdir)/configure --prefix=$(toolchain_dest) --with-arch=RV32IMA
$(MAKE) -C $(toolchain32_wrkdir)
-
$(openocd_dest)/bin/openocd: $(openocd_srcdir)
mkdir -p $(openocd_wrkdir)
cd $(openocd_srcdir); \
@@ -60,11 +90,55 @@ $(gdb_dest)/bin/$(target64)-gdb : $(gdb_srcdir)
$(MAKE) -C $(gdb_wrkdir) install
+.PHONY: uninstall
+uninstall:
+ rm -rf -- $(toolchain_dest)
+
+#############################################################
+# This Section is for MCS File Generation (
+#############################################################
+
+BOOTROM ?= demo
+BOOTROM_DIR = $(srcdir)/bootrom/$(BOOTROM)/
+
+.PHONY:
+fpga:
+ cd $(BOOTROM_DIR);\
+ make mcs
+
+fpga_clean:
+ cd $(BOOTROM_DIR);\
+ make clean
+
+#############################################################
+# This Section is for Software (non-boot) compilation
+#############################################################
+
+PROGRAM ?= demo_gpio
+PROGRAM_DIR = $(srcdir)/software/$(PROGRAM)
+
+.PHONY: software
+software:
+ cd $(PROGRAM_DIR);\
+ make
+
+software_clean:
+ cd $(PROGRAM_DIR);\
+ make clean
+
+#############################################################
+# This Section is for launching the debugger
+#############################################################
+OPENOCD = $(toolchain_dest)/bin/openocd
+OPENOCDARGS += -f $(srcdir)/riscv-tests/debug/targets/m2gl_m2s/openocd.cfg
+
+GDB = $(toolchain_dest)/bin/riscv64-unknown-elf-gdb
+GDBARGS += -ex "target extended-remote localhost:3333"
+
+run_debug:
+ $(OPENOCD) $(OPENOCDARGS) &
+ $(GDB) $(PROGRAM_DIR)/$(PROGRAM) $(GDBARGS)
+
.PHONY: clean
clean:
rm -rf -- $(wrkdir)
-
-
-.PHONY: superclean
-superclean:
- rm -rf -- $(toolchain_dest)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c7aae18
--- /dev/null
+++ b/README.md
@@ -0,0 +1,44 @@
+# README #
+
+This repository, maintained by SiFive, Inc, makes it easy to get started developing software for the Freedom E RISC-V platform.
+
+### Contents ###
+
+* RISC-V Software Toolchain
+* RISC-V Debugging Toolchain
+* FPGA Toolchain Commands (Specific to the Freedom E300 Arty Development Kit).
+
+### Setting up the SDK ###
+
+First, clone this repository:
+
+```
+git clone --recursive http://github.com/sifive/freedom-e-sdk.git
+```
+
+Next, build the tools:
+
+```
+cd freedom-e-sdk
+make tools
+```
+
+To compile a bare-metal RISC-V program:
+
+```
+cd freedom-e-sdk
+make software [PROGRAM=demo_gpio]
+```
+
+To see additional options:
+
+```
+cd freedom-e-sdk
+make help
+```
+
+### For More Information ###
+
+Documentation, Forums, and much more available at
+
+[dev.sifive.com](http://dev.sifive.com) \ No newline at end of file
diff --git a/bitfile/README.md b/bitfile/README.md
new file mode 100644
index 0000000..8dbf9c5
--- /dev/null
+++ b/bitfile/README.md
@@ -0,0 +1,7 @@
+Download the bitfile and associated files from:
+
+https://dev.sifive.com/develop/freedom-e300-arty-dev-kit/
+
+Place them in the freedom-e-sdk/bitfile/ directory.
+
+
diff --git a/bootrom/bram.mk b/bootrom/bram.mk
new file mode 100644
index 0000000..2c7875a
--- /dev/null
+++ b/bootrom/bram.mk
@@ -0,0 +1,79 @@
+ifndef _BRAM_MK
+_BRAM_MK := # defined
+
+BRAM_ADDR := 0x1000
+
+BASEDIR := $(dir $(lastword $(MAKEFILE_LIST)))
+BASEDIR := $(BASEDIR:/=)
+DATADIR := $(BASEDIR)/common
+
+LDSCRIPT := $(DATADIR)/bram.ld
+MEMSCRIPT := $(DATADIR)/mem.awk
+
+BITFILEDIR := $(BASEDIR)/../bitfile
+BITFILE_VERSION ?= 0-1
+
+BITFILE := $(BITFILEDIR)/freedom-e300-arty-$(BITFILE_VERSION).bit
+CFGFILE := $(BITFILEDIR)/FreedomE-$(BITFILE_VERSION).cfg
+MEMINFO := $(BITFILEDIR)/freedom-e300-arty-$(BITFILE_VERSION).mmi
+BRAM_INST := `cat $(BITFILEDIR)/freedom-e300-arty-$(BITFILE_VERSION)-bootrom.txt`
+
+XLEN = 32
+BRAM_WIDTH=64
+
+all: mcs
+
+$(BITFILE):
+ @echo "In order to get Version $(BITFILE_VERSION) of the bitfile:"
+ @echo ""
+ @cat $(BITFILEDIR)/README.md
+
+CC := ../../toolchain/bin/riscv$(XLEN)-unknown-elf-gcc
+UPDATEMEM ?= updatemem
+
+CDEFINES += -DCFG_STRING=\"$(CFGFILE)\"
+
+CFLAGS ?= -m$(XLEN) -O2 -std=c11 -pedantic -Wall \
+ -nostartfiles -fno-common -mcmodel=medany -g \
+ $(CDEFINES)
+
+LDFLAGS ?= -T$(LDSCRIPT) -static -nostdlib
+OBJCOPY ?= objcopy
+elf: $(PROG).elf
+hex: $(PROG).hex
+mem: $(PROG).impl.mem
+mcs: $(PROG).mcs
+
+$(PROG).elf: $(SRCS) $(EXTRAS) $(CFGFILE)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(SRCS)
+
+$(PROG).hex: $(PROG).elf
+ $(OBJCOPY) -S -O verilog --change-addresses -$(BRAM_ADDR) $< $@
+
+# Manually reverse the byte order due to limitations in UpdateMEM.
+# Per UG898: "When UpdateMEM inputs data, it takes data from data input
+# files in Bit Lane sized chunks from the most right value first to the
+# left most. For example, if the first 64 bits of input data are
+# 0xB47DDE02826A8419 then the value 0xB4 is the first value to be set
+# into a Block RAM."
+$(PROG).impl.mem: $(PROG).hex $(MEMSCRIPT)
+ awk -v WIDTH=$(BRAM_WIDTH) -v REVERSE=1 -f $(MEMSCRIPT) $< > $@
+
+.PHONY: $(PROG).mcs
+$(PROG).mcs : $(BITFILE) $(PROG).impl.mem
+ @echo ""
+ @echo ""
+ @echo "TO COMPLETE THE BUILD OF $(PROG).mcs, "
+ @echo "ENTER THE FOLLOWING IN THE VIVADO TCL WINDOW:"
+ @echo ""
+ @echo "cd `pwd`"
+ @echo ""
+ @echo "exec $(UPDATEMEM) -meminfo $(MEMINFO) -data $(PROG).impl.mem -proc $(BRAM_INST) -bit $(BITFILE) --out $(PROG).bit -force"
+ @echo ""
+ @echo "write_cfgmem -format mcs -interface spix4 -size 16 -loadbit {up 0x0 $(PROG).bit} -file $(PROG).mcs -force"
+ @echo ""
+
+clean:
+ rm -f -- $(foreach ext,elf hex impl.mem bit mcs,$(PROG).$(ext))
+
+endif # _BRAM_MK
diff --git a/bootrom/common/bram.ld b/bootrom/common/bram.ld
new file mode 100644
index 0000000..45df67f
--- /dev/null
+++ b/bootrom/common/bram.ld
@@ -0,0 +1,40 @@
+OUTPUT_ARCH("riscv")
+ENTRY(_start)
+
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x00001000, LENGTH = 4K
+ ram (rwx) : ORIGIN = 0x80000000, LENGTH = 256M
+}
+
+SECTIONS
+{
+ PROVIDE(_rom = ORIGIN(rom));
+ PROVIDE(_rom_end = _rom + LENGTH(rom));
+ PROVIDE(_ram = ORIGIN(ram));
+ PROVIDE(_ram_end = _ram + LENGTH(ram));
+
+ .text : {
+ PROVIDE(_ftext = .);
+ *(.text.init)
+ *(.text .text.* .gnu.linkonce.t.*)
+ PROVIDE(_etext = .);
+ } > rom
+
+ .rodata : {
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ } > rom
+
+ .bss : ALIGN(8) {
+ PROVIDE(_fbss = .);
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ . = ALIGN(8);
+ PROVIDE(_ebss = .);
+ } > ram
+
+ . += 0x1000;
+ PROVIDE(_sp = NEXT(0x1000));
+
+ PROVIDE(_end = .);
+}
diff --git a/bootrom/common/mem.awk b/bootrom/common/mem.awk
new file mode 100644
index 0000000..3003b56
--- /dev/null
+++ b/bootrom/common/mem.awk
@@ -0,0 +1,63 @@
+BEGIN {
+ RS = ORS = "\r\n"
+ addr = 0
+ buf = ""
+ limit = (WIDTH > 0 ? WIDTH / 4 : 16)
+ print "@00000000"
+}
+
+# Portable strtonum() replacement
+function atoi(str, x, n, i, b, c) {
+ if (str ~ /^0[0-7]*$/) {
+ i = 2
+ b = 8
+ } else if (str ~ /^0[xX][[:xdigit:]]+$/) {
+ i = 3
+ b = 16
+ } else {
+ return str
+ }
+
+ x = 0
+ n = length(str)
+ for (; i <= n; i++) {
+ c = tolower(substr(str, i , 1))
+ c = index("123456789abcdef", c)
+ x = (x * b) + c
+ }
+ return x
+}
+
+function out(x) {
+ addr++
+ buf = (REVERSE ? buf x : x buf)
+ if (length(buf) >= limit) {
+ print buf
+ buf = ""
+ }
+}
+
+function pad(n) {
+ while (addr < n) {
+ out("00")
+ }
+}
+
+match($1, /^@[[:xdigit:]]+/) {
+ pad(atoi("0x" substr($1, RSTART+1, RLENGTH-1)))
+ next
+}
+
+{
+ for (i = 1; i <= NF; i++) {
+ out($i)
+ }
+}
+
+END {
+ align = limit / 2
+ pad(int((addr + align - 1) / align) * align)
+ if (length(buf) > 0) {
+ print buf;
+ }
+}
diff --git a/bootrom/demo/Makefile b/bootrom/demo/Makefile
new file mode 100644
index 0000000..dfe3663
--- /dev/null
+++ b/bootrom/demo/Makefile
@@ -0,0 +1,5 @@
+PROG := demo
+SRCS := demo.S
+EXTRAS := hello_msg.txt
+
+include ../bram.mk
diff --git a/bootrom/demo/demo.S b/bootrom/demo/demo.S
new file mode 100644
index 0000000..c6f2618
--- /dev/null
+++ b/bootrom/demo/demo.S
@@ -0,0 +1,71 @@
+#define UART_BASE 0x48000000
+#define SPI_BASE 0x48001000
+#define GPIO_BASE 0x48002000
+
+#ifndef CFG_STRING
+#error Must define CFG_STRING
+#endif
+
+ .globl _start
+_start:
+ j uart_init
+ nop
+ nop
+ .word cfgstr
+
+uart_init:
+ // a1 = UART_TX
+ // a2 = hello_msg_end
+ // for (a0 = hello_msg_start; a0 != a2; ++ a0){
+ // while (a3 = TX_READY == 0);
+ // a3 = *a0
+ // *a1 = a3
+ // }
+
+ la a0, hello_msg_start
+ la a2, hello_msg_end
+ li a1, UART_BASE
+
+uart_loop:
+ lw a3, 4(a1) // Wait until non-zero (uart can send data).
+ beqz a3, uart_loop
+
+ lb a3, 0(a0) // read the next character in hello_msg
+ sw a3, 0(a1) // Write the current character.
+ addi a0, a0, 1 // increment the pointer.
+ bne a0, a2, uart_loop
+
+gpio_init:
+ li a0, GPIO_BASE
+ li t0, 0xFFFF0000
+ sw t0, 4(a0)
+
+gpio_loop:
+ // For Red LEDs, increment manually.
+ li t0, 0x1
+ sw t0, (a0)
+ li t0, 0x2
+ sw t0, (a0)
+ li t0, 0x4
+ sw t0, (a0)
+ li t0, 0x8
+ sw t0, (a0)
+
+ // For Blue and Green LEDs, sample the switches & buttons
+
+ lw t0, (a0)
+ srli t0, t0, 16
+ andi t0, t0, 0xFF
+ slli t0, t0, 4
+ sw t0, (a0)
+
+ j gpio_loop
+
+ .section .rodata
+
+hello_msg_start:
+ .incbin "hello_msg.txt"
+hello_msg_end:
+
+cfgstr:
+ .incbin CFG_STRING
diff --git a/bootrom/demo/hello_msg.txt b/bootrom/demo/hello_msg.txt
new file mode 100644
index 0000000..c3cb3f2
--- /dev/null
+++ b/bootrom/demo/hello_msg.txt
@@ -0,0 +1,37 @@
+
+ SIFIVE, INC.
+
+ 5555555555555555555555555
+ 5555 5555
+ 5555 5555
+ 5555 5555
+ 5555 5555555555555555555555
+ 5555 555555555555555555555555
+ 5555 5555
+ 5555 5555
+ 5555 5555
+5555555555555555555555555555 55555
+ 55555 555555555 55555
+ 55555 55555 55555
+ 55555 5 55555
+ 55555 55555
+ 55555 55555
+ 55555 55555
+ 55555 55555
+ 55555 55555
+ 555555555
+ 55555
+ 5
+
+ SiFive RISC-V Coreplex
+
+Welcome to the Arty FPGA Freedom E Dev Kit.
+The red LEDs are blinking very fast and appear
+dim. Try pressing the buttons and switches to control
+the blue and green LEDs. You can try using the
+debugger to step through the boot code.
+
+
+
+
+
diff --git a/openocd b/openocd
-Subproject 47ef2c144b298d820c6daf5d38e5d4c110cf9f3
+Subproject ebb090c01e7d8a0c29bcf86333cd30da28be28b
diff --git a/riscv-gnu-toolchain b/riscv-gnu-toolchain
-Subproject 11fb8bbdb07e80a5b02c9e8753482fb739152be
+Subproject 83665a769ab27547192c86045bd17b14f4f6446
diff --git a/riscv-tests b/riscv-tests
-Subproject c3b7d479afd8e5c2bcb7e0632f03b80386196f1
+Subproject 97cffefa6ebeb5fdc174fc51c7d642f714daa55
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