diff options
Diffstat (limited to 'software')
-rw-r--r-- | software/clic_interrupts/Makefile | 8 | ||||
-rw-r--r-- | software/clic_interrupts/clic.c | 231 | ||||
-rw-r--r-- | software/clic_vectored/Makefile | 10 | ||||
-rw-r--r-- | software/clic_vectored/clic_vectored.c | 197 |
4 files changed, 207 insertions, 239 deletions
diff --git a/software/clic_interrupts/Makefile b/software/clic_interrupts/Makefile deleted file mode 100644 index 502534d..0000000 --- a/software/clic_interrupts/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index ccf98b2..0000000 --- a/software/clic_interrupts/clic.c +++ /dev/null @@ -1,231 +0,0 @@ -// 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; - -} diff --git a/software/clic_vectored/Makefile b/software/clic_vectored/Makefile new file mode 100644 index 0000000..d6e2342 --- /dev/null +++ b/software/clic_vectored/Makefile @@ -0,0 +1,10 @@ +TARGET = clic_vectored +CFLAGS += -Og -fno-builtin-printf + +BSP_BASE = ../../bsp + +C_SRCS += clic_vectored.c + +C_SRCS += $(BSP_BASE)/drivers/clic/clic_driver.c + +include $(BSP_BASE)/env/common.mk diff --git a/software/clic_vectored/clic_vectored.c b/software/clic_vectored/clic_vectored.c new file mode 100644 index 0000000..37ea723 --- /dev/null +++ b/software/clic_vectored/clic_vectored.c @@ -0,0 +1,197 @@ +// 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" +#include "clic/clic_driver.h" +#include "sifive/devices/clint.h" + +#ifndef _SIFIVE_COREPLEXIP_ARTY_H +#error 'local_interrupts' demo only supported for Core IP Eval Kits +#endif + +// Global Variable used to show +// software interrupts. +volatile uint32_t g_debouncing; + +// vector table defined in init.c +typedef void (*interrupt_function_ptr_t) (void); +extern interrupt_function_ptr_t localISR[CLIC_NUM_INTERRUPTS]; +extern void default_handler(void); + +//clic data structure +clic_instance_t clic; + +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\ +E2 Core IP Eval Kit 'clic_vectored' demo.\n\ +This demo uses buttons 0, 1, and 2 on the\n\ +Arty board to trigger vectored clic interrupts.\n\ +The higher the button number, the higher the\n\ +interupt priority. Button 0's handler runs for\n\ +10 seconds, button 1's for 5, and button 2's for 1.\n\ +Preemption is enabled so that higher priority\n\ +interrupts can be triggered while in low priority\n\ +handlers. The demo also uses the CLIC's software\n\ +interrupt to pend a lower priority interrupt from\n\ +button 2's handler.\n\ +\n\ +Note the buttons are wired directly into the local\n\ +interrupts, so a given interrupt will stay asserted\n\ +as long as the button is being pushed.\n\ +\n\ +This demo works for both the E20 and E21 FPGA\n\ +as long as CLIC_CONFIG_BITS matches the desired\n\ +core.\n\ +\n"; + +void print_instructions() { + write (STDERR_FILENO, instructions_msg, strlen(instructions_msg)); +} + + +//busy wait for the specified time +void wait_ms(uint64_t ms) { + static const uint64_t ms_tick = RTC_FREQ/1000; + volatile uint64_t * mtime = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME); + uint64_t then = (ms_tick * ms) + *mtime; + while(*mtime<then); +} + +void button_0_isr(void) __attribute__((interrupt("SiFive-CLIC-preemptible"))); +void button_0_isr(void) { + // Toggle Red LED + uint8_t level = clic_get_int_level(&clic, (LOCALINTIDBASE + LOCAL_INT_BTN_0)); + printf("Button 0 was pressed, interrupt level %d. Toggle Red.\n", level); + GPIO_REG(GPIO_OUTPUT_VAL) = GPIO_REG(GPIO_OUTPUT_VAL) ^ (0x1 << RED_LED_OFFSET); + wait_ms(10000); + GPIO_REG(GPIO_OUTPUT_VAL) = GPIO_REG(GPIO_OUTPUT_VAL) ^ (0x1 << RED_LED_OFFSET); +} + +void button_0_setup(void) { + clic_install_handler(&clic, (LOCALINTIDBASE + LOCAL_INT_BTN_0), button_0_isr); + clic_set_int_level(&clic, (LOCALINTIDBASE + LOCAL_INT_BTN_0), 1); + clic_enable_interrupt(&clic, (LOCALINTIDBASE + LOCAL_INT_BTN_0)); +} + +void button_1_isr(void) __attribute__((interrupt("SiFive-CLIC-preemptible"))); +void button_1_isr(void) { + // Toggle Red LED + uint8_t level = clic_get_int_level(&clic, (LOCALINTIDBASE + LOCAL_INT_BTN_1)); + printf("Button 1 was pressed, interrupt level %d. Toggle Blue.\n", level); + GPIO_REG(GPIO_OUTPUT_VAL) = GPIO_REG(GPIO_OUTPUT_VAL) ^ (0x1 << BLUE_LED_OFFSET); + wait_ms(5000); + GPIO_REG(GPIO_OUTPUT_VAL) = GPIO_REG(GPIO_OUTPUT_VAL) ^ (0x1 << BLUE_LED_OFFSET); +} + +void button_1_setup(void) { + clic_install_handler(&clic, (LOCALINTIDBASE + LOCAL_INT_BTN_1), button_1_isr); + clic_set_int_level(&clic, (LOCALINTIDBASE + LOCAL_INT_BTN_1), 2); + clic_enable_interrupt(&clic, (LOCALINTIDBASE + LOCAL_INT_BTN_1)); +} + +void button_2_isr(void) __attribute__((interrupt("SiFive-CLIC-preemptible"))); +void button_2_isr(void) { + // Toggle Red LED + uint8_t level = clic_get_int_level(&clic, (LOCALINTIDBASE + LOCAL_INT_BTN_2)); + printf("Button 2 was pressed, interrupt level %d. Pending CSIPID and toggle Green.\n", level); + GPIO_REG(GPIO_OUTPUT_VAL) = GPIO_REG(GPIO_OUTPUT_VAL) ^ (0x1 << GREEN_LED_OFFSET); + //pend a software interrupt + clic_set_pending(&clic, CSIPID); + wait_ms(1000); + GPIO_REG(GPIO_OUTPUT_VAL) = GPIO_REG(GPIO_OUTPUT_VAL) ^ (0x1 << GREEN_LED_OFFSET); +} + +void button_2_setup(void) { + clic_install_handler(&clic, (LOCALINTIDBASE + LOCAL_INT_BTN_2), button_2_isr); + clic_set_int_level(&clic, (LOCALINTIDBASE + LOCAL_INT_BTN_2), 3); + clic_enable_interrupt(&clic, (LOCALINTIDBASE + LOCAL_INT_BTN_2)); +} + +/*Entry Point for Machine Software Interrupt Handler*/ +uint32_t COUNT; +void csip_isr()__attribute((interrupt)); +void csip_isr() { + //clear the SW interrupt + CLIC0_REG8(CLIC_INTIP + CSIPID) = 0; + COUNT++; +} + +void csip_setup(void) { + clic_install_handler(&clic, CSIPID, csip_isr); + clic_set_int_level(&clic, CSIPID, 1); + clic_enable_interrupt(&clic, CSIPID); +} + +void config_gpio() { + // 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<< RED_LED_OFFSET) | (0x1<< GREEN_LED_OFFSET)| (0x1 << BLUE_LED_OFFSET)) ; +} + +int main(int argc, char **argv) +{ + clear_csr(mstatus, MSTATUS_MIE); + clear_csr(mie, IRQ_M_SOFT); + clear_csr(mie, IRQ_M_TIMER); + + //initialize clic registers and vector table + clic_init(&clic, CLIC_HART0_ADDR, + (interrupt_function_ptr_t*)localISR, + default_handler, + CLIC_NUM_INTERRUPTS, + CLIC_CONFIG_BITS); + + //use all 4 config bits for levels, no shv + clic_set_cliccfg(&clic, (CLIC_CONFIG_BITS<<1)); + + //initialize gpio and buttons. + //each button registers an interrupt handler + config_gpio(); + button_0_setup(); + button_1_setup(); + button_2_setup(); + csip_setup(); + + // Enable all global interrupts + set_csr(mstatus, MSTATUS_MIE); + print_instructions(); + + while(1) { + wait_ms(10000); + printf("Count=%d\n", COUNT); + //Trigger a SW interrupt + clic_set_pending(&clic, CSIPID); + } + + return 0; + +} |