summaryrefslogtreecommitdiff
path: root/software
diff options
context:
space:
mode:
Diffstat (limited to 'software')
-rw-r--r--software/coreplexip_welcome/Makefile8
-rw-r--r--software/coreplexip_welcome/coreplexip_welcome.c124
-rw-r--r--software/demo_gpio/demo_gpio.c40
-rw-r--r--software/dhrystone/Makefile6
-rw-r--r--software/double_tap_dontboot/double_tap_dontboot.c13
-rw-r--r--software/global_interrupts/Makefile9
-rw-r--r--software/global_interrupts/global_interrupts.c250
-rw-r--r--software/led_fade/led_fade.c6
-rw-r--r--software/local_interrupts/Makefile8
-rw-r--r--software/local_interrupts/local_interrupts.c216
10 files changed, 657 insertions, 23 deletions
diff --git a/software/coreplexip_welcome/Makefile b/software/coreplexip_welcome/Makefile
new file mode 100644
index 0000000..e56ed12
--- /dev/null
+++ b/software/coreplexip_welcome/Makefile
@@ -0,0 +1,8 @@
+TARGET = coreplexip_welcome
+CFLAGS += -O2 -fno-builtin-printf -DNO_INIT
+
+BSP_BASE = ../../bsp
+
+C_SRCS += coreplexip_welcome.c
+
+include $(BSP_BASE)/env/common.mk
diff --git a/software/coreplexip_welcome/coreplexip_welcome.c b/software/coreplexip_welcome/coreplexip_welcome.c
new file mode 100644
index 0000000..c090b37
--- /dev/null
+++ b/software/coreplexip_welcome/coreplexip_welcome.c
@@ -0,0 +1,124 @@
+// See LICENSE for license details.
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdatomic.h>
+#include "encoding.h"
+#include <platform.h>
+
+#ifndef _SIFIVE_COREPLEXIP_ARTY_H
+#error 'coreplexip_welcome' demo only supported for Coreplex IP Eval Kits
+#endif
+
+static const char sifive_msg[] = "\n\r\
+\n\r\
+ SIFIVE, INC.\n\r\
+\n\r\
+ 5555555555555555555555555\n\r\
+ 5555 5555\n\r\
+ 5555 5555\n\r\
+ 5555 5555\n\r\
+ 5555 5555555555555555555555\n\r\
+ 5555 555555555555555555555555\n\r\
+ 5555 5555\n\r\
+ 5555 5555\n\r\
+ 5555 5555\n\r\
+5555555555555555555555555555 55555\n\r\
+ 55555 555555555 55555\n\r\
+ 55555 55555 55555\n\r\
+ 55555 5 55555\n\r\
+ 55555 55555\n\r\
+ 55555 55555\n\r\
+ 55555 55555\n\r\
+ 55555 55555\n\r\
+ 55555 55555\n\r\
+ 555555555\n\r\
+ 55555\n\r\
+ 5\n\r\
+\n\r\
+";
+
+#if __riscv_xlen == 32
+ static const char welcome_msg[] = "\n\r\
+\n\r\
+Welcome to the E31 Coreplex IP FPGA Evaluation Kit!\n\r\
+\n\r";
+#else
+static const char welcome_msg[] = "\n\r\
+\n\r\
+Welcome to the E51 Coreplex IP FPGA Evaluation Kit!\n\r\
+\n\r";
+#endif
+
+static void _putc(char c) {
+ while ((int32_t) UART0_REG(UART_REG_TXFIFO) < 0);
+ UART0_REG(UART_REG_TXFIFO) = c;
+}
+
+int _getc(char * c){
+ int32_t val = (int32_t) UART0_REG(UART_REG_RXFIFO);
+ if (val > 0) {
+ *c = val & 0xFF;
+ return 1;
+ }
+ return 0;
+}
+
+static void _puts(const char * s) {
+ while (*s != '\0'){
+ _putc(*s++);
+ }
+}
+
+int main (void){
+
+ // 115200 Baud Rate at (65 / 2) MHz
+ UART0_REG(UART_REG_DIV) = 282;
+ UART0_REG(UART_REG_TXCTRL) = UART_TXEN;
+ UART0_REG(UART_REG_RXCTRL) = UART_RXEN;
+
+ // Wait a bit because we were changing the GPIOs
+ volatile int i=0;
+ while(i < 10000){i++;}
+
+ _puts(sifive_msg);
+
+ _puts(welcome_msg);
+
+ uint16_t r=0x3F;
+ uint16_t g=0;
+ uint16_t b=0;
+ // Set up RGB PWM
+
+ PWM0_REG(PWM_CFG) = 0;
+ PWM0_REG(PWM_CFG) = (PWM_CFG_ENALWAYS) | (PWM_CFG_ZEROCMP) | (PWM_CFG_DEGLITCH);
+ PWM0_REG(PWM_COUNT) = 0;
+
+ // The LEDs are intentionally left somewhat dim.
+ PWM0_REG(PWM_CMP0) = 0xFE;
+
+ while(1){
+ volatile uint64_t * now = (volatile uint64_t*)(CLINT_CTRL_ADDR + CLINT_MTIME);
+ volatile uint64_t then = *now + 400;
+ while (*now < then) { }
+
+ if(r > 0 && b == 0){
+ r--;
+ g++;
+ }
+ if(g > 0 && r == 0){
+ g--;
+ b++;
+ }
+ if(b > 0 && g == 0){
+ r++;
+ b--;
+ }
+
+ PWM0_REG(PWM_CMP1) = 0xFF - (r >> 2);
+ PWM0_REG(PWM_CMP2) = 0xFF - (g >> 2);
+ PWM0_REG(PWM_CMP3) = 0xFF - (b >> 2);
+
+ }// While (1)
+}
+
diff --git a/software/demo_gpio/demo_gpio.c b/software/demo_gpio/demo_gpio.c
index bfa388e..8fe03e1 100644
--- a/software/demo_gpio/demo_gpio.c
+++ b/software/demo_gpio/demo_gpio.c
@@ -9,8 +9,6 @@
#include <unistd.h>
#include "stdatomic.h"
-#define RTC_FREQUENCY 32768
-
void reset_demo (void);
// Structures for registering different interrupt handlers
@@ -48,10 +46,10 @@ void handle_m_time_interrupt(){
// Reset the timer for 3s in the future.
// This also clears the existing timer interrupt.
- volatile uint64_t * mtime = (uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME);
- volatile uint64_t * mtimecmp = (uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIMECMP);
+ volatile uint64_t * mtime = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME);
+ volatile uint64_t * mtimecmp = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
uint64_t now = *mtime;
- uint64_t then = now + 1.5 * RTC_FREQUENCY;
+ uint64_t then = now + 2 * RTC_FREQ;
*mtimecmp = then;
// read the current value of the LEDS and invert them.
@@ -94,7 +92,7 @@ const char * instructions_msg = " \
5\n\
\n\
SiFive E-Series Software Development Kit 'demo_gpio' program.\n\
-Every 1.5 second, the Timer Interrupt will invert the LEDs.\n\
+Every 2 second, the Timer Interrupt will invert the LEDs.\n\
(Arty Dev Kit Only): Press Buttons 0, 1, 2 to Set the LEDs.\n\
Pin 19 (HiFive1) or A5 (Arty Dev Kit) is being bit-banged\n\
for GPIO speed demonstration.\n\
@@ -179,10 +177,10 @@ void reset_demo (){
// Set the machine timer to go off in 3 seconds.
// The
- volatile uint64_t * mtime = (uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME);
- volatile uint64_t * mtimecmp = (uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIMECMP);
+ volatile uint64_t * mtime = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME);
+ volatile uint64_t * mtimecmp = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
uint64_t now = *mtime;
- uint64_t then = now + 1.5*RTC_FREQUENCY;
+ uint64_t then = now + 2*RTC_FREQ;
*mtimecmp = then;
// Enable the Machine-External bit in MIE
@@ -199,6 +197,7 @@ int main(int argc, char **argv)
{
// Set up the GPIOs such that the LED GPIO
// can be used as both Inputs and Outputs.
+
#ifdef HAS_BOARD_BUTTONS
GPIO_REG(GPIO_OUTPUT_EN) &= ~((0x1 << BUTTON_0_OFFSET) | (0x1 << BUTTON_1_OFFSET) | (0x1 << BUTTON_2_OFFSET));
@@ -211,15 +210,26 @@ int main(int argc, char **argv)
GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << BLUE_LED_OFFSET) ;
GPIO_REG(GPIO_OUTPUT_VAL) &= ~((0x1<< RED_LED_OFFSET) | (0x1<< GREEN_LED_OFFSET)) ;
+
// For Bit-banging with Atomics demo.
- GPIO_REG(GPIO_OUTPUT_EN) |= (0x1 << PIN_19_OFFSET);
-
+
+ uint32_t bitbang_mask = 0;
+#ifdef _SIFIVE_HIFIVE1_H
+ bitbang_mask = (1 << PIN_19_OFFSET);
+#else
+#ifdef _SIFIVE_COREPLEXIP_ARTY_H
+ bitbang_mask = (0x1 << JA_0_OFFSET);
+#endif
+#endif
+
+ GPIO_REG(GPIO_OUTPUT_EN) |= bitbang_mask;
+
/**************************************************************************
* Set up the PLIC
*
*************************************************************************/
PLIC_init(&g_plic,
- PLIC_BASE_ADDR,
+ PLIC_CTRL_ADDR,
PLIC_NUM_INTERRUPTS,
PLIC_NUM_PRIORITIES);
@@ -231,10 +241,10 @@ int main(int argc, char **argv)
* the entire OUTPUT_VAL that you want to write, but
* Atomics give a quick way to control a single bit.
*************************************************************************/
- uint32_t mask = (1 << PIN_19_OFFSET);
-
+ // For Bit-banging with Atomics demo.
+
while (1){
- atomic_fetch_xor_explicit(&GPIO_REG(GPIO_OUTPUT_VAL), mask, memory_order_relaxed);
+ atomic_fetch_xor_explicit(&GPIO_REG(GPIO_OUTPUT_VAL), bitbang_mask, memory_order_relaxed);
}
return 0;
diff --git a/software/dhrystone/Makefile b/software/dhrystone/Makefile
index 78a7b23..d401720 100644
--- a/software/dhrystone/Makefile
+++ b/software/dhrystone/Makefile
@@ -5,11 +5,11 @@ C_SRCS := dhry_stubs.c dhry_printf.c
HEADERS := dhry.h
DHRY_SRCS := dhry_1.c dhry_2.c
-DHRY_CFLAGS := -O2 -DTIME -fno-inline -fno-builtin-printf -Wno-implicit -march=rv32ima
+DHRY_CFLAGS := -O2 -DTIME -fno-inline -fno-builtin-printf -Wno-implicit -mcmodel=medany -march=$(RISCV_ARCH) -mabi=$(RISCV_ABI)
XLEN ?= 32
-CFLAGS := -Os -fno-common
-LDFLAGS := -Wl,--wrap=scanf -Wl,--wrap=printf
+CFLAGS := -Os -fno-common -mcmodel=medany -march=$(RISCV_ARCH) -mabi=$(RISCV_ABI)
+LDFLAGS := -Wl,--wrap=scanf -Wl,--wrap=printf -march=$(RISCV_ARCH) -mabi=$(RISCV_ABI) -mcmodel=medany
DHRY_OBJS := $(patsubst %.c,%.o,$(DHRY_SRCS))
LINK_OBJS := $(DHRY_OBJS)
diff --git a/software/double_tap_dontboot/double_tap_dontboot.c b/software/double_tap_dontboot/double_tap_dontboot.c
index 0cae5b5..53c2c64 100644
--- a/software/double_tap_dontboot/double_tap_dontboot.c
+++ b/software/double_tap_dontboot/double_tap_dontboot.c
@@ -42,6 +42,11 @@
#include "platform.h"
#include "encoding.h"
+#ifndef _SIFIVE_HIFIVE1_H
+#error "double_tap_dontboot is designed to run on HiFive1 and/or E300 Arty Dev Kit."
+#endif
+
+
#define BACKUP15_MAGIC 0xD027B007
#define FINAL_ADDRESS 0x20400000
@@ -97,9 +102,9 @@ int main(void)
// because it makes it clear that the processor is actually
// running this code, not just the PWM hardware.
- now = *((volatile uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME));
+ now = *((volatile uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME));
then = now + 32768/500;
- while (*((volatile uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME)) < then) {
+ while (*((volatile uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME)) < then) {
asm volatile ("");
}
pwm_val = (pwm_val == 0) ? 255 : (pwm_val -1);
@@ -121,9 +126,9 @@ int main(void)
// Wait 500 ms. If reset is tapped at this point,
// we will execute the "magic" loop above.
- now = *((volatile uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME));
+ now = *((volatile uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME));
then = now + 32768/2;
- while (*((volatile uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME)) < then) {
+ while (*((volatile uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME)) < then) {
asm volatile ("");
}
diff --git a/software/global_interrupts/Makefile b/software/global_interrupts/Makefile
new file mode 100644
index 0000000..6a09f97
--- /dev/null
+++ b/software/global_interrupts/Makefile
@@ -0,0 +1,9 @@
+TARGET = global_interrupts
+CFLAGS += -O2 -fno-builtin-printf -DUSE_LOCAL_ISR
+
+BSP_BASE = ../../bsp
+
+C_SRCS += global_interrupts.c
+C_SRCS += $(BSP_BASE)/drivers/plic/plic_driver.c
+
+include $(BSP_BASE)/env/common.mk
diff --git a/software/global_interrupts/global_interrupts.c b/software/global_interrupts/global_interrupts.c
new file mode 100644
index 0000000..4d3a554
--- /dev/null
+++ b/software/global_interrupts/global_interrupts.c
@@ -0,0 +1,250 @@
+// See LICENSE for license details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "platform.h"
+#include <string.h>
+#include "plic/plic_driver.h"
+#include "encoding.h"
+#include <unistd.h>
+
+#ifndef _SIFIVE_COREPLEXIP_ARTY_H
+#error 'global_interrupts' demo only supported for Coreplex IP Eval Kits
+#endif
+
+// Global Instance data for the PLIC
+// for use by the PLIC Driver.
+plic_instance_t g_plic;
+
+// Flag for state
+int g_switch1Wins;
+
+// Debounce counter (PWM can't go slow enough)
+int g_debounce;
+
+void debounce();
+
+// Structures for registering different interrupt handlers
+// for different parts of the application.
+typedef void (*interrupt_function_ptr_t) (void);
+
+// See bsp/env/<BOARD>/init.c for how this
+// interrupt vector is used.
+interrupt_function_ptr_t localISR[32];
+
+interrupt_function_ptr_t g_ext_interrupt_handlers[PLIC_NUM_INTERRUPTS];
+
+void set_timer() {
+
+ volatile uint64_t * mtime = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME);
+ volatile uint64_t * mtimecmp = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+ uint64_t now = *mtime;
+ uint64_t then = now + 10*RTC_FREQ;
+ *mtimecmp = then;
+
+}
+
+/*Entry Point for Machine Timer Interrupt Handler*/
+void mti_isr(){
+
+ if (g_switch1Wins) {
+ printf("#### Giving Switch 1 Priority for 10 seconds ####\n");
+ // All other things being equal, lower IDs have
+ // higher priority. We have already set
+ // Switch 1 to priority 2
+ // in the setup, so by giving these equal priority Switch 1 will win.
+ PLIC_set_priority(&g_plic, INT_EXT_DEVICE_SW_2, 2);
+ } else {
+ printf("**** Giving Switch 2 Priority for 10 seconds ****\n");
+ // By setting Switch 2 a higher integer priority, it will win over switch 1.
+ PLIC_set_priority(&g_plic, INT_EXT_DEVICE_SW_2, 3);
+ }
+ g_switch1Wins ^= 0x1;
+
+ set_timer();
+
+}
+
+/*Entry Point for PLIC Interrupt Handler*/
+void mei_isr(){
+ plic_source int_num = PLIC_claim_interrupt(&g_plic);
+ if ((int_num >=1 ) && (int_num < PLIC_NUM_INTERRUPTS)) {
+ g_ext_interrupt_handlers[int_num]();
+ }
+ else {
+ exit(1 + (uintptr_t) int_num);
+ }
+ PLIC_complete_interrupt(&g_plic, int_num);
+}
+
+const char * instructions_msg = " \
+\n\
+ SIFIVE, INC.\n\
+E31/E51 Coreplex IP Eval Kit 'global_interrupts' demo.\n\
+\n\
+Switches 1 and 2 are enabled as External Global Interrupts \n\
+(they don't go through the PLIC). You an observe priorities.\n\
+Priorities invert every few seconds, which is driven by the \n\
+PWM0 global interrupt. \n\
+\n";
+
+void print_instructions() {
+
+ write (STDOUT_FILENO, instructions_msg, strlen(instructions_msg));
+
+}
+
+void invalid_global_isr() {
+ printf("Unexpected global interrupt!\n");
+}
+
+void invalid_local_isr() {
+ printf ("Unexpected local interrupt!\n");
+}
+
+void switch_1_handler() {
+
+ printf("Switch 1 is on! Even if Switch 2 is on, Switch 1 must have higher priority right now.\n");
+
+ // Set Green LED
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << GREEN_LED_OFFSET) ;
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~((0x1<< RED_LED_OFFSET));
+
+ debounce();
+
+}
+
+void switch_2_handler() {
+ printf("Switch 2 is on! Even if Switch 1 is on, Switch 2 must have higher priority right now.\n");
+
+ // Set RED LED
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~(0x1 << GREEN_LED_OFFSET) ;
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1<< RED_LED_OFFSET);
+
+ debounce();
+}
+
+// We use PWM 0 as a
+// timer interrupt for debouncing.
+
+void pwm_0_handler() {
+
+
+ if (g_debounce == 0) {
+ printf(" Done debouncing.\n");
+
+ //Lower the threshold s.t. the switches can hit.
+ PLIC_set_threshold(&g_plic, 1);
+
+ // Clear the PWM interrupt
+ PWM0_REG(PWM_CFG) = 0;
+
+ } else {
+ // Keep waiting
+ g_debounce --;
+ // This clears out the interrupt and re-arms the timer.
+ PWM0_REG(PWM_CFG) = ((PWM_CFG_ONESHOT) | (PWM_CFG_ZEROCMP)| 0x7 | (PWM_CFG_STICKY));
+
+ }
+
+}
+
+void debounce(int local_interrupt_num) {
+
+ printf(" Starting a debounce.\n");
+
+ g_debounce = 600;
+
+ // This clears out the interrupt and re-arms the timer.
+ PWM0_REG(PWM_CFG) = ((PWM_CFG_ONESHOT) | (PWM_CFG_ZEROCMP)| 0x7 | (PWM_CFG_STICKY));
+
+ // Set the threshold high enough that the
+ // switches won't cause the interrupt to fire,
+ // only the PWM or timer interrupts.
+ PLIC_set_threshold(&g_plic, 4);
+
+}
+
+int main(int argc, char **argv)
+{
+
+ for (int gisr = 0; gisr < PLIC_NUM_INTERRUPTS; gisr++){
+ g_ext_interrupt_handlers[PLIC_NUM_INTERRUPTS] = invalid_global_isr;
+ }
+ g_ext_interrupt_handlers[PWM0_INT_BASE + 0] = pwm_0_handler;
+ g_ext_interrupt_handlers[INT_EXT_DEVICE_SW_1] = switch_1_handler;
+ g_ext_interrupt_handlers[INT_EXT_DEVICE_SW_2] = switch_2_handler;
+
+ for (int lisr = 0; lisr < 32; lisr++){
+ localISR[lisr] = invalid_local_isr;
+ }
+
+ localISR[IRQ_M_TIMER] = mti_isr;
+ localISR[IRQ_M_EXT] = mei_isr;
+
+ print_instructions();
+
+ // Set up RGB LEDs for a visual.
+
+ GPIO_REG(GPIO_OUTPUT_EN) |= ((0x1<< RED_LED_OFFSET)| (0x1<< GREEN_LED_OFFSET));
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << GREEN_LED_OFFSET) ;
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~(0x1<< RED_LED_OFFSET);
+
+ /**************************************************************************
+ * Set up the PLIC
+ *
+ *************************************************************************/
+ PLIC_init(&g_plic,
+ PLIC_CTRL_ADDR,
+ PLIC_NUM_INTERRUPTS,
+ PLIC_NUM_PRIORITIES);
+
+ /**************************************************************************
+ * Give Switch 1 and Switch 2 Equal priority of 2.
+ *
+ *************************************************************************/
+
+ PLIC_enable_interrupt (&g_plic, PWM0_INT_BASE + 0);
+ PLIC_enable_interrupt (&g_plic, INT_EXT_DEVICE_SW_1);
+ PLIC_enable_interrupt (&g_plic, INT_EXT_DEVICE_SW_2);
+
+ // PWM always beats the switches, because we use it
+ // as a debouncer, and we lower the threshold
+ // to do so.
+
+ PWM0_REG(PWM_CFG) = 0;
+
+ // Make sure people aren't blinded by LEDs connected here.
+ PWM0_REG(PWM_CMP0) = 0xFE;
+ PWM0_REG(PWM_CMP1) = 0xFF;
+ PWM0_REG(PWM_CMP2) = 0xFF;
+ PWM0_REG(PWM_CMP3) = 0xFF;
+ PLIC_set_priority(&g_plic, PWM0_INT_BASE + 0 , 5);
+
+ // Start the switches out at the same priority. Switch1
+ // would win.
+ PLIC_set_priority(&g_plic, INT_EXT_DEVICE_SW_1, 2);
+ PLIC_set_priority(&g_plic, INT_EXT_DEVICE_SW_2, 2);
+
+ // Set up machine timer interrupt. Every few seconds it
+ // will invert the switch priorities.
+ set_timer();
+
+ // Enable timer interrupts.
+ set_csr(mie, MIP_MTIP);
+
+ // Enable Global (PLIC) interrupts.
+ set_csr(mie, MIP_MEIP);
+
+ g_switch1Wins = 1;
+
+ // Enable all interrupts
+ set_csr(mstatus, MSTATUS_MIE);
+
+ while(1){
+ asm volatile ("wfi");
+ }
+
+ return 0;
+
+}
diff --git a/software/led_fade/led_fade.c b/software/led_fade/led_fade.c
index 775647a..3c7b8c8 100644
--- a/software/led_fade/led_fade.c
+++ b/software/led_fade/led_fade.c
@@ -6,6 +6,10 @@
#include <stdint.h>
#include "platform.h"
+#ifndef _SIFIVE_HIFIVE1_H
+#error "'led_fade' is designed to run on HiFive1 and/or E300 Arty Dev Kit."
+#endif
+
static const char led_msg[] = "\a\n\r\n\r\
55555555555555555555555555555555555555555555555\n\r\
5555555 Are the LEDs Changing? [y/n] 555555555\n\r\
@@ -118,7 +122,7 @@ int main (void){
GPIO_REG(GPIO_OUTPUT_XOR) |= (1 << RED_LED_OFFSET);
while(1){
- volatile uint64_t * now = (volatile uint64_t*)(CLINT_BASE_ADDR + CLINT_MTIME);
+ volatile uint64_t * now = (volatile uint64_t*)(CLINT_CTRL_ADDR + CLINT_MTIME);
volatile uint64_t then = *now + 100;
while (*now < then) { }
diff --git a/software/local_interrupts/Makefile b/software/local_interrupts/Makefile
new file mode 100644
index 0000000..4605ee9
--- /dev/null
+++ b/software/local_interrupts/Makefile
@@ -0,0 +1,8 @@
+TARGET = local_interrupts
+CFLAGS += -O2 -fno-builtin-printf -DUSE_LOCAL_ISR
+
+BSP_BASE = ../../bsp
+
+C_SRCS += local_interrupts.c
+
+include $(BSP_BASE)/env/common.mk
diff --git a/software/local_interrupts/local_interrupts.c b/software/local_interrupts/local_interrupts.c
new file mode 100644
index 0000000..cb2aca3
--- /dev/null
+++ b/software/local_interrupts/local_interrupts.c
@@ -0,0 +1,216 @@
+// See LICENSE for license details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "platform.h"
+#include <string.h>
+#include "encoding.h"
+#include <unistd.h>
+
+#ifndef _SIFIVE_COREPLEXIP_ARTY_H
+#error 'local_interrupts' demo only supported for Coreplex IP Eval Kits
+#endif
+
+// Global Variable used to show
+// software interrupts.
+volatile uint32_t g_debouncing;
+
+void debounce();
+
+// Structures for registering different interrupt handlers
+// for different parts of the application.
+typedef void (*interrupt_function_ptr_t) (void);
+
+// This function enables some of the local interrupts sources
+// used in this demo -- just those for the buttons and
+// Switch 3.
+
+void enable_local_interrupts(){
+
+ // lowest priority
+ set_csr(mie, MIP_MLIP(LOCAL_INT_SW_3 ));
+ set_csr(mie, MIP_MLIP(LOCAL_INT_BTN_0));
+ set_csr(mie, MIP_MLIP(LOCAL_INT_BTN_1));
+ set_csr(mie, MIP_MLIP(LOCAL_INT_BTN_2));
+ set_csr(mie, MIP_MLIP(LOCAL_INT_BTN_3));
+ // highest priority
+
+}
+
+void disable_local_interrupts() {
+
+ // lowest priority
+ clear_csr(mie, MIP_MLIP(LOCAL_INT_SW_3 ));
+ clear_csr(mie, MIP_MLIP(LOCAL_INT_BTN_0));
+ clear_csr(mie, MIP_MLIP(LOCAL_INT_BTN_1));
+ clear_csr(mie, MIP_MLIP(LOCAL_INT_BTN_2));
+ clear_csr(mie, MIP_MLIP(LOCAL_INT_BTN_3));
+ // highest priority
+
+}
+
+/*Entry Point for Machine Software Interrupt Handler*/
+void msi_isr() {
+
+ const char msi_msg[] = " Debouncing: (this message due to Software Interrupt))\n\n";
+ write (STDOUT_FILENO, msi_msg, strlen(msi_msg));
+
+ //clear the SW interrupt
+ CLINT_REG(CLINT_MSIP) = 0;
+
+}
+
+/*Entry Point for Machine Timer Interrupt Handler*/
+void mti_isr(){
+
+ // Disable the timer interrupt. The Debounce logic sets it.
+ clear_csr(mie, MIP_MTIP);
+
+ // Enable all the local interrupts
+ enable_local_interrupts();
+}
+
+
+const char * instructions_msg = " \
+\n\
+ SiFive, Inc\n\
+ E31/E51 Coreplex IP Eval Kit 'local_interrupts' demo.\n\
+\n\
+The Buttons 0-3 and Switch 3 are enabled as local\n\
+interrupts sources. A .5 s 'debounce' timer is used \n\
+between these interrupts. Software interrupts are
+used to print a message while debouncing.\n\
+Note the priority of the interrupts sources.\n\
+\n";
+
+void print_instructions() {
+
+ write (STDERR_FILENO, instructions_msg, strlen(instructions_msg));
+
+}
+
+void button_0_isr(void) {
+
+ // Toggle Red LED
+ const char button_0_msg[] = "Button 0 was pressed. Toggle Red.\n";
+ write (STDOUT_FILENO, button_0_msg, strlen(button_0_msg));
+ GPIO_REG(GPIO_OUTPUT_VAL) = GPIO_REG(GPIO_OUTPUT_VAL) ^ (0x1 << RED_LED_OFFSET);
+ debounce();
+};
+
+void button_1_isr(void) {
+
+ // Toggle Green LED
+ const char button_1_msg[] = "Button 1 was pressed. Toggle Green.\n";
+ write (STDOUT_FILENO, button_1_msg, strlen(button_1_msg));
+ GPIO_REG(GPIO_OUTPUT_VAL) = GPIO_REG(GPIO_OUTPUT_VAL) ^ (0x1 << GREEN_LED_OFFSET);
+ debounce();
+};
+
+
+void button_2_isr(void) {
+
+ // Toggle Blue LED
+ const char button_2_msg[] = "Button 2 was pressed. Toggle Blue.\n";
+ write (STDOUT_FILENO, button_2_msg, strlen(button_2_msg));
+ GPIO_REG(GPIO_OUTPUT_VAL) = GPIO_REG(GPIO_OUTPUT_VAL) ^ (0x1 << BLUE_LED_OFFSET);
+ debounce();
+
+};
+
+void button_3_isr(void) {
+ const char button_3_msg[] = "Button 3 was pressed! (No LEDs change).\n";
+ write (STDOUT_FILENO, button_3_msg, strlen(button_3_msg));
+ debounce();
+}
+
+void switch_3_isr(void) {
+ const char sw_3_msg[] = "Switch 3 is on! But buttons have higher priority.\n";
+ write (STDOUT_FILENO, sw_3_msg, strlen(sw_3_msg));
+ debounce();
+}
+
+void debounce(int local_interrupt_num) {
+
+ // Disable the most recent interrupt.
+ // Don't enable it again until the timer goes off,
+ // in .5 second.
+
+ // Set the machine timer to go off in .5 seconds.
+ // If the timer was already set to go off, this "cancels"
+ // the current one.
+
+ volatile uint64_t * mtime = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME);
+ volatile uint64_t * mtimecmp = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+ uint64_t now = *mtime;
+ uint64_t then = now + .5*RTC_FREQ;
+ *mtimecmp = then;
+
+ disable_local_interrupts();
+ g_debouncing = 1;
+
+ // Enable the Machine-Timer bit in MIE
+ set_csr(mie, MIP_MTIP);
+
+}
+
+// See bsp/env/<BOARD>/init.c for how this
+// interrupt vector is used.
+
+interrupt_function_ptr_t localISR[32];
+
+int main(int argc, char **argv)
+{
+
+ // Configure LEDs as outputs.
+ GPIO_REG(GPIO_INPUT_EN) &= ~((0x1<< RED_LED_OFFSET) | (0x1<< GREEN_LED_OFFSET) | (0x1 << BLUE_LED_OFFSET)) ;
+ GPIO_REG(GPIO_OUTPUT_EN) |= ((0x1<< RED_LED_OFFSET)| (0x1<< GREEN_LED_OFFSET) | (0x1 << BLUE_LED_OFFSET)) ;
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << BLUE_LED_OFFSET) ;
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~((0x1<< RED_LED_OFFSET) | (0x1<< GREEN_LED_OFFSET)) ;
+
+ // The Buttons and Switches which are used as local interrupt sources
+ // do not go through the GPIO peripheral, so they do not need to
+ // be configured as inputs.
+
+ // Disable the timer & local interrupts until setup is done (they're
+ // not reset by default)
+
+ // Disable all interrupts. MIE is not reset.
+ write_csr(mie, 0);
+
+ for (int isr = 0; isr < 32; isr++){
+ localISR[isr] = 0;
+ }
+
+ localISR[IRQ_M_SOFT] = msi_isr;
+ localISR[IRQ_M_TIMER] = mti_isr;
+ localISR[IRQ_M_LOCAL + LOCAL_INT_SW_3] = switch_3_isr;
+ localISR[IRQ_M_LOCAL + LOCAL_INT_BTN_0] = button_0_isr;
+ localISR[IRQ_M_LOCAL + LOCAL_INT_BTN_1] = button_1_isr;
+ localISR[IRQ_M_LOCAL + LOCAL_INT_BTN_2] = button_2_isr;
+ localISR[IRQ_M_LOCAL + LOCAL_INT_BTN_3] = button_3_isr;
+
+ print_instructions();
+
+ enable_local_interrupts();
+
+ g_debouncing = 0;
+
+ // Enable SW interrupts as well in this demo.
+ set_csr(mie, MIP_MSIP);
+
+ // Enable all global interrupts
+ set_csr(mstatus, MSTATUS_MIE);
+
+ volatile int foo = 1;
+ while(foo){
+ if (g_debouncing){
+ //Trigger a SW interrupt
+ CLINT_REG(CLINT_MSIP) = 1;
+ g_debouncing = 0;
+ }
+ }
+
+ return 0;
+
+}