Files
vriscv/src/cpu/exception.c

70 lines
2.3 KiB
C

#include "exception.h"
#include "vriscv.h"
#include <stdio.h>
__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();
}