// See LICENSE for license details. #include #include #include "platform.h" #include #include "plic/plic_driver.h" #include "encoding.h" #include #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<