#include "interrupt.h" #include "rv32cpu.h" #include #include uint32_t interrupt_mi_from_scause(uint32_t scause) { switch(scause) { case SCAUSE_SUPERVISOR_TIMER_INTERRUPT: return 0x20; default: fprintf(stderr, "interrupt_mie_bit_from_scause: wrong scause 0x%x\n", scause); exit(EXIT_FAILURE); } return 0; } void interrupt_trigger(rv32_cpu_t* cpu, uint32_t scause) { // Make sure that interrupts are enabled globally if(!(csr_read(cpu, CSR_MSTATUS) & STATUS_SIE)) return; // Make sure that current interrupt is enabled if(!(csr_read(cpu, CSR_MIE) & interrupt_mi_from_scause(scause))) { // Mark interrupt as pending csr_write(cpu, CSR_MIP, csr_read(cpu, CSR_MIP) | interrupt_mi_from_scause(scause)); return; } // TODO : CHECK mideleg to see wether we should handle interrupt is S mode or M mode // An interrupt can only be triggered from outside // of the cpu, so we are on a different thread // and we don't already own the CPU mutex // We obtain in this thread the control of the CPU, // but we know it is not in the middle of an instruction // (we got the mutex) ; this way we can just change // registers to set interrupt handler execution pthread_mutex_lock(&cpu->mutex); // Set xCAUSE with interrupt bit set cpu->csr[CSR_SCAUSE] = 0x80000000 | scause; // Set xSTATUS.xPIE (previous interrupt enable) bit cpu->csr[CSR_MSTATUS] |= STATUS_SPIE; // Set xSTATUS.xPP (Previous Privilege) bit // TODO : Allow user mode interrupts (by not setting this) cpu->csr[CSR_MSTATUS] |= 0x100; // Unset xSTATUS.xIE (interrupt enable) bit cpu->csr[CSR_MSTATUS] &= (~STATUS_SIE); // Set xEPC : PC at interruption cpu->csr[CSR_SEPC] = cpu->pc; // Set PC to xTVEC : exception handler code // xTVEC: [Base(30bits) Mode(2 bits)], address 4-byte aligned in base // Interrupts can be vectored, if mode == 1, then pc = xTVEC + scause * 4 int mode = cpu->csr[CSR_STVEC] & 0b11; switch(mode) { case 0: cpu->pc = cpu->csr[CSR_STVEC] & 0xFFFFFFFC; break; case 1: cpu->pc = (cpu->csr[CSR_STVEC] & 0xFFFFFFFC) + scause * 4; break; default: fprintf(stderr, "interrupt_trigger: invalid mode encountered in sTVEC register\n"); exit(EXIT_FAILURE); break; } pthread_mutex_unlock(&cpu->mutex); } void interrupt_timer_thread() { while(1) { cpu0->csr[CSR_TIME]++; interrupt_trigger(cpu0, SCAUSE_SUPERVISOR_TIMER_INTERRUPT); usleep(1); } } void interrupt_timer_setup() { pthread_t timer_thread; pthread_create(&timer_thread, 0, (void*) interrupt_timer_thread, 0); }