summaryrefslogtreecommitdiff
path: root/software/shared
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/shared
parenta2d28c8318ab3ed40b3674aeee8b9487a3129f15 (diff)
Initial Checkin
Diffstat (limited to 'software/shared')
-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
11 files changed, 599 insertions, 0 deletions
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