#include "exception.h" #include "vriscv.h" #include __attribute__((noreturn)) void exception_trigger(rv32_cpu_t* cpu, uint32_t scause, uint32_t tval) { // An exception can only be triggered by the CPU itself, // so we know we already own the mutex // We are in the CPU thread itself, but we need // the return of this function to be the beginning of // the cpu loop // To achieve that, we can just call cpu_loop (noreturn) // at the end of this function // Exceptions cannot be disabled // TODO : Check medeleg to see if we should handle exception in S mode or M mode // Unset SIE (interrupt enable) bit csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) & (~STATUS_SIE)); // Set xCAUSE : exception cause, with interrupt bit set to null csr_write(cpu, CSR_SCAUSE, scause); if(gdbstub && scause == SCAUSE_BREAKPOINT) { cpu->sim_ticks_left = 0; // No simulation ticks left : wakeup people waiting on sim end pthread_cond_signal(&cpu->sim_condition); // Then, wait for simulation state to change until we get more ticks to simulate while(!cpu->sim_ticks_left) pthread_cond_wait(&cpu->sim_condition, &cpu->mutex); } // Save previous interrupt enable in xSTATUS.xPIE if(csr_read(cpu, CSR_SSTATUS) & STATUS_SIE) csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) | STATUS_SPIE); else csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) & (~STATUS_SPIE)); // Set previous privilege mode in xSTATUS.xPP if(cpu->privilege_mode == SUPERVISOR) csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) | STATUS_SPP); else if(cpu->privilege_mode == USER) csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) & (~STATUS_SPP)); // Set privilege mode for exception handling, checking for delegation // TODO // Set xTVAL, exception-specific information related to xCAUSE csr_write(cpu, CSR_STVAL, tval); // Set SEPC to instruction that caused exception csr_write(cpu, CSR_SEPC, cpu->pc); // Set PC to xTVEC : exception handling code // xTVEC: [Base(30bits) Mode(2 bits)], address 4-byte aligned in base // Exceptions are not vectored (we can safely ignore mode) cpu->pc = csr_read(cpu, CSR_STVEC) & 0xFFFFFFFC; // Unlock cpu mutex, cpu_loop will lock it just after pthread_mutex_unlock(&cpu->mutex); // TODO : Hard reset the stack pointer // cpu loop cpu_loop(cpu); __builtin_unreachable(); }