diff options
author | Palmer Dabbelt <palmer@dabbelt.com> | 2018-06-29 18:42:26 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-06-29 18:42:26 -0700 |
commit | b091d1cabe70c84825a7f304d725010d2cf163d9 (patch) | |
tree | 2605f4e81388a0513e742829ad932a93be1935c2 | |
parent | 20541dcc0b415199bd87410aa05b8302f18edaf5 (diff) | |
parent | 66ba2aac4875e9131a630c29cea989551ac4cabd (diff) |
Merge pull request #94 from sifive/clic
Add a CLIC interrupt example
l--------- | bsp/env/coreplexip-e21-arty/dhrystone.lds | 1 | ||||
l--------- | bsp/env/coreplexip-e21-arty/flash.lds | 1 | ||||
l--------- | bsp/env/coreplexip-e21-arty/init.c | 1 | ||||
l--------- | bsp/env/coreplexip-e21-arty/openocd.cfg | 1 | ||||
l--------- | bsp/env/coreplexip-e21-arty/platform.h | 1 | ||||
l--------- | bsp/env/coreplexip-e21-arty/scratchpad.lds | 1 | ||||
l--------- | bsp/env/coreplexip-e21-arty/settings.mk | 1 | ||||
-rw-r--r-- | bsp/env/coreplexip-e31-arty/init.c | 15 | ||||
-rw-r--r-- | bsp/env/coreplexip-e31-arty/platform.h | 5 | ||||
-rw-r--r-- | bsp/env/entry.S | 1 | ||||
-rw-r--r-- | bsp/include/sifive/devices/clic.h | 49 | ||||
-rw-r--r-- | software/clic_interrupts/Makefile | 8 | ||||
-rw-r--r-- | software/clic_interrupts/clic.c | 231 |
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; + +} |