summaryrefslogtreecommitdiff
path: root/software
diff options
context:
space:
mode:
Diffstat (limited to 'software')
-rw-r--r--software/vectored_interrupts/Makefile10
-rw-r--r--software/vectored_interrupts/vectored_interrupts.c270
-rw-r--r--software/watchdog/.gitignore1
-rw-r--r--software/watchdog/.unsupported-boards1
-rw-r--r--software/watchdog/Makefile9
-rw-r--r--software/watchdog/watchdog.c221
6 files changed, 512 insertions, 0 deletions
diff --git a/software/vectored_interrupts/Makefile b/software/vectored_interrupts/Makefile
new file mode 100644
index 0000000..4365038
--- /dev/null
+++ b/software/vectored_interrupts/Makefile
@@ -0,0 +1,10 @@
+TARGET = vectored_interrupts
+CFLAGS += -O2 -fno-builtin-printf -DVECT_IRQ
+
+BSP_BASE = ../../bsp
+
+ASM_SRCS += $(ENV_DIR)/ventry.S
+C_SRCS += vectored_interrupts.c
+C_SRCS += $(BSP_BASE)/drivers/plic/plic_driver.c
+
+include $(BSP_BASE)/env/common.mk
diff --git a/software/vectored_interrupts/vectored_interrupts.c b/software/vectored_interrupts/vectored_interrupts.c
new file mode 100644
index 0000000..cb6a864
--- /dev/null
+++ b/software/vectored_interrupts/vectored_interrupts.c
@@ -0,0 +1,270 @@
+// 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;
+
+// Structures for registering different interrupt handlers
+// for different parts of the application.
+typedef void (*interrupt_function_ptr_t) (void);
+//array of function pointers which contains the PLIC
+//interrupt handlers
+interrupt_function_ptr_t g_ext_interrupt_handlers[PLIC_NUM_INTERRUPTS];
+
+//ecall countdown
+uint32_t ecall_countdown;
+//ecall macro used to store argument in a0
+#define ECALL(arg) ({ \
+ register uintptr_t a0 asm ("a0") = (uintptr_t)(arg); \
+ asm volatile ("ecall" \
+ : "+r" (a0) \
+ : \
+ : "memory"); \
+ a0; \
+})
+
+
+const char * instructions_msg = " \
+\n\
+ SIFIVE, INC.\n\
+E31/E51 Coreplex IP Eval Kit 'vectored_interrupts' demo. \n\
+\n\
+This demo demonstrates Vectored Interrupts capabilities of\n\
+the E31/E51 Coreplex. The vector table is defined in \n\
+bsp/env/ventry.S \n\
+Button 0 is a global external interrupt routed to the PLIC.\n\
+Button 1 is a local interrupt.\n\
+Every 10 seconds, an ECALL is made. \n\
+\n";
+
+void print_instructions() {
+
+ write (STDOUT_FILENO, instructions_msg, strlen(instructions_msg));
+
+}
+
+void set_timer() {
+ static uint64_t then = 0;
+
+ volatile uint64_t * mtime = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME);
+ volatile uint64_t * mtimecmp = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+ if(then != 0) {
+ //next timer irq is 1 second from previous
+ then += 1*RTC_FREQ;
+ } else{ //first time setting the timer
+ uint64_t now = *mtime;
+ then = now + 1*RTC_FREQ;
+ }
+ *mtimecmp = then;
+
+ set_csr(mie, MIP_MTIP);
+}
+
+/*Entry Point for Machine Timer Interrupt Handler*/
+/*called from bsp/env/ventry.s */
+void handle_m_time_interrupt(){
+ static uint32_t onoff=1;
+
+ clear_csr(mie, MIP_MTIP);
+
+ //increment ecall_countdown
+ ecall_countdown++;
+
+ // Set Green LED
+ if(onoff) {
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << GREEN_LED_OFFSET) ;
+ onoff=0;
+ }else {
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~((0x1 << GREEN_LED_OFFSET)) ;
+ onoff=1;
+ }
+
+ set_timer();
+ //re-enable button1 irq
+ set_csr(mie, MIP_MLIP(LOCAL_INT_BTN_1));
+
+}
+
+/*Synchronous Trap Handler*/
+/*called from bsp/env/ventry.s */
+void handle_sync_trap(uint32_t arg0) {
+ uint32_t exception_code = read_csr(mcause);
+
+ //check for machine mode ecall
+ if(exception_code == CAUSE_MACHINE_ECALL) {
+ //reset ecall_countdown
+ ecall_countdown = 0;
+
+ //ecall argument is stored in a0 prior to
+ //ECALL instruction.
+ printf("ecall from M-mode: %d\n",arg0);
+
+ //on exceptions, mepc points to the instruction
+ //which triggered the exception, in order to
+ //return to the next instruction, increment
+ //mepc
+ unsigned long epc = read_csr(mepc);
+ epc += 4; //return to next instruction
+ write_csr(mepc, epc);
+
+ } else{
+ printf("vUnhandled Trap:\n");
+ _exit(1 + read_csr(mcause));
+ }
+}
+
+/*Entry Point for PLIC Interrupt Handler*/
+/*called from bsp/env/ventry.s */
+void handle_m_external_interrupt(){
+ printf("In PLIC handler\n");
+ 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);
+}
+
+//default empty PLIC handler
+void invalid_global_isr() {
+ printf("Unexpected global interrupt!\n");
+}
+
+/* b0 global interrupt isr */
+/*called from handle_m_external_interrupt */
+void button_0_handler() {
+ static uint32_t onoff=1;
+ // Set Green LED
+
+ printf("In Button 0 handler\n");
+
+ if(onoff) {
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << BLUE_LED_OFFSET) ;
+ onoff=0;
+ }else {
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~((0x1 << BLUE_LED_OFFSET)) ;
+ onoff=1;
+ }
+
+ //clear irq - interrupt pending register is write 1 to clear
+ GPIO_REG(GPIO_FALL_IP) |= (1<<BUTTON_0_OFFSET);
+}
+
+/*b1 local vectored irq handler */
+/*called from bsp/env/ventry.s */
+void handle_local_interrupt5() {
+ static uint32_t onoff=1;
+ // Set Green LED
+
+ printf("In Button 1 handler\n");
+
+ if(onoff) {
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << RED_LED_OFFSET) ;
+ onoff=0;
+ }else {
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~((0x1 << RED_LED_OFFSET)) ;
+ onoff=1;
+ }
+
+ //debounce by turning off until next timer tick
+ clear_csr(mie, MIP_MLIP(LOCAL_INT_BTN_1));
+}
+
+/*configures Button0 as a global gpio irq*/
+void b0_irq_init() {
+
+ //dissable hw io function
+ GPIO_REG(GPIO_IOF_EN ) &= ~(1 << BUTTON_0_OFFSET);
+
+ //set to input
+ GPIO_REG(GPIO_INPUT_EN) |= (1<<BUTTON_0_OFFSET);
+ GPIO_REG(GPIO_PULLUP_EN) |= (1<<BUTTON_0_OFFSET);
+
+ //set to interrupt on falling edge
+ GPIO_REG(GPIO_FALL_IE) |= (1<<BUTTON_0_OFFSET);
+
+ PLIC_init(&g_plic,
+ PLIC_CTRL_ADDR,
+ PLIC_NUM_INTERRUPTS,
+ PLIC_NUM_PRIORITIES);
+
+ PLIC_enable_interrupt (&g_plic, INT_DEVICE_BUTTON_0);
+ PLIC_set_priority(&g_plic, INT_DEVICE_BUTTON_0, 2);
+ g_ext_interrupt_handlers[INT_DEVICE_BUTTON_0] = button_0_handler;
+}
+
+/*configures Button1 as a local interrupt*/
+void b1_irq_init() {
+
+ //enable the interrupt
+ set_csr(mie, MIP_MLIP(LOCAL_INT_BTN_1));
+
+}
+
+/*turn down the brightness, and configure GPIO */
+void led_init() {
+ // 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;
+ // Set up RGB LEDs for a visual.
+ 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)
+{
+ uint32_t ecall_count = 0;
+
+ //setup default global interrupt handler
+ for (int gisr = 0; gisr < PLIC_NUM_INTERRUPTS; gisr++){
+ g_ext_interrupt_handlers[PLIC_NUM_INTERRUPTS] = invalid_global_isr;
+ }
+
+ print_instructions();
+
+ led_init();
+ b0_irq_init();
+ b1_irq_init();
+
+ //initialize ecall_countdown
+ ecall_countdown = 0;
+
+ // Set up machine timer interrupt.
+ set_timer();
+
+ // Enable Global (PLIC) interrupts.
+ set_csr(mie, MIP_MEIP);
+
+ // Enable all interrupts
+ set_csr(mstatus, MSTATUS_MIE);
+
+
+ while(1){
+ asm volatile ("wfi");
+ //check if ecall_countdown is 10
+ if(ecall_countdown == 10) {
+ ECALL(ecall_count++);
+ }
+ //otherwise wfi
+ }
+
+ return 0;
+
+}
diff --git a/software/watchdog/.gitignore b/software/watchdog/.gitignore
new file mode 100644
index 0000000..35566c7
--- /dev/null
+++ b/software/watchdog/.gitignore
@@ -0,0 +1 @@
+demo_gpio
diff --git a/software/watchdog/.unsupported-boards b/software/watchdog/.unsupported-boards
new file mode 100644
index 0000000..1e65df5
--- /dev/null
+++ b/software/watchdog/.unsupported-boards
@@ -0,0 +1 @@
+coreplexip-e51-arty
diff --git a/software/watchdog/Makefile b/software/watchdog/Makefile
new file mode 100644
index 0000000..f614a4e
--- /dev/null
+++ b/software/watchdog/Makefile
@@ -0,0 +1,9 @@
+TARGET = watchdog
+CFLAGS += -O2 -fno-builtin-printf -DUSE_PLIC -DUSE_M_TIME
+
+BSP_BASE = ../../bsp
+
+C_SRCS += watchdog.c
+C_SRCS += $(BSP_BASE)/drivers/plic/plic_driver.c
+
+include $(BSP_BASE)/env/common.mk
diff --git a/software/watchdog/watchdog.c b/software/watchdog/watchdog.c
new file mode 100644
index 0000000..672ed68
--- /dev/null
+++ b/software/watchdog/watchdog.c
@@ -0,0 +1,221 @@
+// 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>
+#include "stdatomic.h"
+
+void reset_demo (void);
+
+// Structures for registering different interrupt handlers
+// for different parts of the application.
+typedef void (*function_ptr_t) (void);
+void no_interrupt_handler (void) {};
+function_ptr_t g_ext_interrupt_handlers[PLIC_NUM_INTERRUPTS];
+
+
+// Instance data for the PLIC.
+plic_instance_t g_plic;
+
+
+/**
+* use mtime to wait for a specified number of ticks.
+* async determins if this is a busy wait, or if
+* an irq is scheduled
+*/
+void mtime_wait( uint64_t ticks, uint32_t async)
+{
+
+ volatile uint64_t * mtime = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME);
+ uint64_t now = *mtime;
+
+ //if async, schedule irq
+ if(async) {
+ volatile uint64_t * mtimecmp = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+ uint64_t then = now + ticks;
+ *mtimecmp = then;
+ set_csr(mie, MIP_MTIP);
+
+ } else {
+ //else busy wait
+ uint64_t then = now + ticks;
+ while(*mtime<then) {}
+
+ }
+
+}
+
+/*Entry Point for PLIC Interrupt Handler*/
+void handle_m_ext_interrupt(){
+ 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);
+}
+
+//global countdown timer
+static uint32_t countdown = 10;
+/*Entry Point for Machine Timer Interrupt Handler*/
+void handle_m_time_interrupt(){
+
+ //cleare the timer irq
+ clear_csr(mie, MIP_MTIP);
+
+ //schedule next timer irq for 1 second
+ mtime_wait(1*RTC_FREQ, 1);
+
+ //flash a led
+ GPIO_REG(GPIO_OUTPUT_VAL) ^= (0x1 << BLUE_LED_OFFSET);
+
+ //print the count
+ printf("watchdog reset in %d\n", countdown--);
+}
+
+
+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\
+This application demonstrates the functionality of\n\
+the watchdog timer present in the HiFive1 AON peripheral.\n\
+\n\
+The Watchdog timer will expire in 10 seconds resulting in\n\
+a software reset.\n\
+\n\
+Press a key to prevent a reset\n\
+";
+
+void print_instructions() {
+
+ write (STDOUT_FILENO, instructions_msg, strlen(instructions_msg));
+
+}
+
+
+/**
+* Flash the red led for a second, then set up
+* blue for blinking during mtime irq
+*/
+void led_init() {
+
+
+ // Set up the GPIOs such that the LED GPIO
+ // can be used as both Inputs and 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));
+
+ //flash red led to indicate reset
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~(0x1 << RED_LED_OFFSET) ;
+ mtime_wait(1*RTC_FREQ,0);
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << RED_LED_OFFSET) ;
+}
+
+/**
+* initialize the watchdog to reset in
+* 5 seconds
+**/
+void watchdog_init() {
+
+
+//reset in 10 seconds
+AON_REG(AON_WDOGKEY) = AON_WDOGKEY_VALUE;
+AON_REG(AON_WDOGCMP) = 11;
+//wdogconfig: : wdogrsten | enablealways | reset to 0 | max scale
+AON_REG(AON_WDOGKEY) = AON_WDOGKEY_VALUE;
+AON_REG(AON_WDOGCFG) |= (AON_WDOGCFG_RSTEN | AON_WDOGCFG_ENALWAYS |\
+ AON_WDOGCFG_ZEROCMP | AON_WDOGCFG_SCALE) ;
+
+}
+
+void reset_demo () {
+
+ // Disable the machine & timer interrupts until setup is done.
+ clear_csr(mie, MIP_MEIP);
+ clear_csr(mie, MIP_MTIP);
+
+ //enable uart input
+ UART0_REG(UART_REG_RXCTRL) = UART_RXEN;
+
+ /**************************************************************************
+ * Set up the PLIC
+ *************************************************************************/
+ PLIC_init(&g_plic,
+ PLIC_CTRL_ADDR,
+ PLIC_NUM_INTERRUPTS,
+ PLIC_NUM_PRIORITIES);
+
+ for (int ii = 0; ii < PLIC_NUM_INTERRUPTS; ii ++){
+ g_ext_interrupt_handlers[ii] = no_interrupt_handler;
+ }
+
+
+ led_init();
+ print_instructions();
+ watchdog_init();
+
+ // Enable the Machine-External bit in MIE
+ set_csr(mie, MIP_MEIP);
+ // Enable interrupts in general.
+ set_csr(mstatus, MSTATUS_MIE);
+}
+
+int main(int argc, char **argv)
+{
+
+ reset_demo();
+ //schedule a 1 second timer
+ mtime_wait(1*RTC_FREQ,1);
+
+
+ while (1){
+ char c;
+ if(((int32_t) UART0_REG(UART_REG_RXFIFO)) > 0){
+ //flash green led to indicate Kick
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~(0x1 << GREEN_LED_OFFSET) ;
+
+ printf("Feeding Watchdog.\nHiFive1 will reset in 10 seconds.\n");
+ countdown = 10;
+ AON_REG(AON_WDOGKEY) = AON_WDOGKEY_VALUE;
+ AON_REG(AON_WDOGFEED) = AON_WDOGFEED_VALUE;
+
+ //busy wait a bit so the user sees the led blink
+ mtime_wait(5000, 0);
+ //turn off led
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << GREEN_LED_OFFSET) ;
+ }
+ }
+
+ return 0;
+
+}