summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
l---------bsp/env/coreplexip-e21-arty/dhrystone.lds1
l---------bsp/env/coreplexip-e21-arty/flash.lds1
l---------bsp/env/coreplexip-e21-arty/init.c1
l---------bsp/env/coreplexip-e21-arty/openocd.cfg1
l---------bsp/env/coreplexip-e21-arty/platform.h1
l---------bsp/env/coreplexip-e21-arty/scratchpad.lds1
l---------bsp/env/coreplexip-e21-arty/settings.mk1
-rw-r--r--bsp/env/coreplexip-e31-arty/init.c15
-rw-r--r--bsp/env/coreplexip-e31-arty/platform.h5
-rw-r--r--bsp/env/entry.S1
-rw-r--r--bsp/include/sifive/devices/clic.h49
-rw-r--r--software/clic_interrupts/Makefile8
-rw-r--r--software/clic_interrupts/clic.c231
13 files changed, 314 insertions, 2 deletions
diff --git a/bsp/env/coreplexip-e21-arty/dhrystone.lds b/bsp/env/coreplexip-e21-arty/dhrystone.lds
new file mode 120000
index 0000000..8459e13
--- /dev/null
+++ b/bsp/env/coreplexip-e21-arty/dhrystone.lds
@@ -0,0 +1 @@
+../coreplexip-e31-arty/dhrystone.lds \ No newline at end of file
diff --git a/bsp/env/coreplexip-e21-arty/flash.lds b/bsp/env/coreplexip-e21-arty/flash.lds
new file mode 120000
index 0000000..54c1026
--- /dev/null
+++ b/bsp/env/coreplexip-e21-arty/flash.lds
@@ -0,0 +1 @@
+../coreplexip-e31-arty/flash.lds \ No newline at end of file
diff --git a/bsp/env/coreplexip-e21-arty/init.c b/bsp/env/coreplexip-e21-arty/init.c
new file mode 120000
index 0000000..de048a9
--- /dev/null
+++ b/bsp/env/coreplexip-e21-arty/init.c
@@ -0,0 +1 @@
+../coreplexip-e31-arty/init.c \ No newline at end of file
diff --git a/bsp/env/coreplexip-e21-arty/openocd.cfg b/bsp/env/coreplexip-e21-arty/openocd.cfg
new file mode 120000
index 0000000..2f4de8d
--- /dev/null
+++ b/bsp/env/coreplexip-e21-arty/openocd.cfg
@@ -0,0 +1 @@
+../coreplexip-e31-arty/openocd.cfg \ No newline at end of file
diff --git a/bsp/env/coreplexip-e21-arty/platform.h b/bsp/env/coreplexip-e21-arty/platform.h
new file mode 120000
index 0000000..311ca36
--- /dev/null
+++ b/bsp/env/coreplexip-e21-arty/platform.h
@@ -0,0 +1 @@
+../coreplexip-e31-arty/platform.h \ No newline at end of file
diff --git a/bsp/env/coreplexip-e21-arty/scratchpad.lds b/bsp/env/coreplexip-e21-arty/scratchpad.lds
new file mode 120000
index 0000000..7fbe10a
--- /dev/null
+++ b/bsp/env/coreplexip-e21-arty/scratchpad.lds
@@ -0,0 +1 @@
+../coreplexip-e31-arty/scratchpad.lds \ No newline at end of file
diff --git a/bsp/env/coreplexip-e21-arty/settings.mk b/bsp/env/coreplexip-e21-arty/settings.mk
new file mode 120000
index 0000000..2b2a962
--- /dev/null
+++ b/bsp/env/coreplexip-e21-arty/settings.mk
@@ -0,0 +1 @@
+../coreplexip-e31-arty/settings.mk \ No newline at end of file
diff --git a/bsp/env/coreplexip-e31-arty/init.c b/bsp/env/coreplexip-e31-arty/init.c
index 409eeb4..1f8b679 100644
--- a/bsp/env/coreplexip-e31-arty/init.c
+++ b/bsp/env/coreplexip-e31-arty/init.c
@@ -64,6 +64,7 @@ extern my_interrupt_function_ptr_t localISR[];
#endif
#ifndef VECT_IRQ
+uintptr_t handle_trap(uintptr_t mcause, uintptr_t epc) __attribute__((noinline));
uintptr_t handle_trap(uintptr_t mcause, uintptr_t epc)
{
if (0){
@@ -90,6 +91,16 @@ uintptr_t handle_trap(uintptr_t mcause, uintptr_t epc)
}
#endif
+#ifdef USE_CLIC
+void trap_entry(void) __attribute__((interrupt("SiFive-CLIC-preemptible"), aligned(64)));
+void trap_entry(void)
+{
+ unsigned long mcause = read_csr(mcause);
+ unsigned long mepc = read_csr(mepc);
+ handle_trap(mcause, mepc);
+}
+#endif
+
void _init()
{
#ifndef NO_INIT
@@ -97,7 +108,11 @@ void _init()
puts("core freq at " STR(CPU_FREQ) " Hz\n");
+#ifdef USE_CLIC
+ write_csr(mtvec, ((unsigned long)&trap_entry | MTVEC_CLIC));
+#else
write_csr(mtvec, ((unsigned long)&TRAP_ENTRY | MTVEC_VECTORED));
+#endif
#endif
}
diff --git a/bsp/env/coreplexip-e31-arty/platform.h b/bsp/env/coreplexip-e31-arty/platform.h
index 0ac341e..6fa79ea 100644
--- a/bsp/env/coreplexip-e31-arty/platform.h
+++ b/bsp/env/coreplexip-e31-arty/platform.h
@@ -7,10 +7,10 @@
#if __riscv_xlen == 32
#define MCAUSE_INT 0x80000000UL
-#define MCAUSE_CAUSE 0x7FFFFFFFUL
+#define MCAUSE_CAUSE 0x000003FFUL
#else
#define MCAUSE_INT 0x8000000000000000UL
-#define MCAUSE_CAUSE 0x7FFFFFFFFFFFFFFFUL
+#define MCAUSE_CAUSE 0x00000000000003FFUL
#endif
#ifdef VECT_IRQ
@@ -18,6 +18,7 @@
#else
#define MTVEC_VECTORED 0x00
#endif
+#define MTVEC_CLIC 0x02
#define IRQ_M_LOCAL 16
#define MIP_MLIP(x) (1 << (IRQ_M_LOCAL + x))
diff --git a/bsp/env/entry.S b/bsp/env/entry.S
index 1f5de24..261b2a4 100644
--- a/bsp/env/entry.S
+++ b/bsp/env/entry.S
@@ -8,6 +8,7 @@
.section .text.entry
.align 2
+ .weak trap_entry
.global trap_entry
trap_entry:
addi sp, sp, -32*REGBYTES
diff --git a/bsp/include/sifive/devices/clic.h b/bsp/include/sifive/devices/clic.h
new file mode 100644
index 0000000..b31e1ce
--- /dev/null
+++ b/bsp/include/sifive/devices/clic.h
@@ -0,0 +1,49 @@
+// See LICENSE for license details.
+
+#ifndef _SIFIVE_CLIC_H
+#define _SIFIVE_CLIC_H
+
+#define CLIC_CTRL_ADDR _AC(0x2000000,UL)
+
+#define CLIC_MSIP 0x0000
+#define CLIC_MSIP_size 0x4
+#define CLIC_MTIMECMP 0x4000
+#define CLIC_MTIMECMP_size 0x8
+#define CLIC_MTIME 0xBFF8
+#define CLIC_MTIME_size 0x8
+
+#define CLIC_INTIP 0x0800000
+#define CLIC_INTIE 0x0800400
+#define CLIC_INTCFG 0x0800800
+#define CLIC_CFG 0x0800c00
+
+// These interrupt IDs are consistent across old and new mtvec modes
+#define SSIPID 1
+#define MSIPID 3
+#define STIPID 5
+#define MTIPID 7
+#define SEIPID 9
+#define MEIPID 11
+#define CSIPID 12
+#define LOCALINTIDBASE 16
+
+#define CLIC_REG(offset) _REG32(CLIC_CTRL_ADDR, offset)
+#define CLIC_REG8(offset) (*(volatile uint8_t *)((CLIC_CTRL_ADDR) + (offset)))
+
+#ifndef CLINT_CTRL_ADDR
+#define CLINT_CTRL_ADDR CLIC_CTRL_ADDR
+#endif
+#ifndef CLINT_REG
+#define CLINT_REG CLIC_REG
+#endif
+#ifndef CLINT_MSIP
+#define CLINT_MSIP CLIC_MSIP
+#endif
+#ifndef CLINT_MTIME
+#define CLINT_MTIME CLIC_MTIME
+#endif
+#ifndef CLINT_MTIMECMP
+#define CLINT_MTIMECMP CLIC_MTIMECMP
+#endif
+
+#endif /* _SIFIVE_CLIC_H */
diff --git a/software/clic_interrupts/Makefile b/software/clic_interrupts/Makefile
new file mode 100644
index 0000000..502534d
--- /dev/null
+++ b/software/clic_interrupts/Makefile
@@ -0,0 +1,8 @@
+TARGET = clic_interrupts
+CFLAGS += -O2 -fno-builtin-printf -DUSE_CLIC -DUSE_LOCAL_ISR
+
+BSP_BASE = ../../bsp
+
+C_SRCS += clic.c
+
+include $(BSP_BASE)/env/common.mk
diff --git a/software/clic_interrupts/clic.c b/software/clic_interrupts/clic.c
new file mode 100644
index 0000000..ccf98b2
--- /dev/null
+++ b/software/clic_interrupts/clic.c
@@ -0,0 +1,231 @@
+// See LICENSE for license details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "platform.h"
+#include <string.h>
+#include "encoding.h"
+#include <unistd.h>
+#include "sifive/devices/clic.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();
+
+static void clic_enable(int offset) __attribute__((noinline));
+static void clic_enable(int offset)
+{
+ CLIC_REG8(CLIC_INTCFG + offset) = 0xff;
+ CLIC_REG8(CLIC_INTIE + offset) = 1;
+}
+
+static void clic_disable(int offset) __attribute__((noinline));
+static void clic_disable(int offset)
+{
+ CLIC_REG8(CLIC_INTCFG + offset) = 0xff;
+ CLIC_REG8(CLIC_INTIE + offset) = 0;
+}
+
+// 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(){
+ clic_enable(IRQ_M_LOCAL + LOCAL_INT_SW_3);
+ clic_enable(IRQ_M_LOCAL + LOCAL_INT_BTN_0);
+ clic_enable(IRQ_M_LOCAL + LOCAL_INT_BTN_1);
+ clic_enable(IRQ_M_LOCAL + LOCAL_INT_BTN_2);
+ clic_enable(IRQ_M_LOCAL + LOCAL_INT_BTN_3);
+}
+
+void disable_local_interrupts() {
+ clic_disable(IRQ_M_LOCAL + LOCAL_INT_SW_3);
+ clic_disable(IRQ_M_LOCAL + LOCAL_INT_BTN_0);
+ clic_disable(IRQ_M_LOCAL + LOCAL_INT_BTN_1);
+ clic_disable(IRQ_M_LOCAL + LOCAL_INT_BTN_2);
+ clic_disable(IRQ_M_LOCAL + LOCAL_INT_BTN_3);
+}
+
+/*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
+ CLIC_REG(CLIC_MSIP) = 0;
+}
+
+/*Entry Point for Machine Timer Interrupt Handler*/
+void mti_isr(){
+ const char mti_msg[] = " Timer interrupt, done debouncing.\n\n";
+ write (STDOUT_FILENO, mti_msg, strlen(mti_msg));
+
+ // Disable the timer interrupt. The Debounce logic sets it.
+ clic_disable(IRQ_M_TIMER);
+
+ // Enable all the local interrupts
+ enable_local_interrupts();
+}
+
+const char * instructions_msg = " \
+\n\
+ SiFive, Inc\n\
+ E21 Core IP Eval Kit 'clic_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\n\
+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
+ clic_enable(IRQ_M_TIMER);
+}
+
+// See bsp/env/<BOARD>/init.c for how this
+// interrupt vector is used.
+
+interrupt_function_ptr_t localISR[32];
+
+static void unmapped_interrupt(void) {
+ printf("unmapped interrupt");
+ asm volatile ("1: j 1b" ::: "memory");
+}
+
+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)
+
+ // Unconfigure the CLIC before doing anything
+ for (int i = 0; i < 1024; ++i)
+ CLIC_REG8(CLIC_INTIE + i) = 0;
+
+ // Write down the software interrupt pending bit, as we shouldn't start out
+ // by debouncing anything at all.
+ CLIC_REG(CLIC_MSIP) = 0;
+
+ for (int isr = 0; isr < 32; isr++)
+ localISR[isr] = &unmapped_interrupt;
+
+ 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;
+
+ // Set up the CLIC interrupt mechanism
+ CLIC_REG(CLIC_CFG) = 4<<1; // nmBits=0; nlBits=4; nvBits=0
+
+ print_instructions();
+
+ enable_local_interrupts();
+
+ g_debouncing = 0;
+
+ // Enable SW interrupts as well in this demo.
+ clic_enable(IRQ_M_SOFT);
+
+ // Enable all global interrupts
+ set_csr(mstatus, MSTATUS_MIE);
+
+ volatile int foo = 1;
+ while(foo){
+ if (g_debouncing){
+ //Trigger a SW interrupt
+ CLIC_REG(CLIC_MSIP) = 1;
+ g_debouncing = 0;
+ }
+ }
+
+ return 0;
+
+}