Better exception/interrupt handle

master
vhaudiquet 1 year ago
parent 0983be511c
commit 923e9d39a0
  1. 6
      src/cpu/exception.c
  2. 46
      src/cpu/interrupt.c
  3. 9
      src/cpu/rv32cpu.c

@ -15,6 +15,8 @@ __attribute__((noreturn)) void exception_trigger(rv32_cpu_t* cpu, uint32_t scaus
// Exceptions cannot be disabled // 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 // Unset SIE (interrupt enable) bit
csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) & (~STATUS_SIE)); csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) & (~STATUS_SIE));
@ -37,8 +39,10 @@ __attribute__((noreturn)) void exception_trigger(rv32_cpu_t* cpu, uint32_t scaus
csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) & (~STATUS_SPIE)); csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) & (~STATUS_SPIE));
// Set previous privilege mode in xSTATUS.xPP // Set previous privilege mode in xSTATUS.xPP
// TODO : Allow user mode exceptions (by not setting this) if(cpu->privilege_mode == SUPERVISOR)
csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) | STATUS_SPP); 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 // Set privilege mode for exception handling, checking for delegation
// TODO // TODO

@ -4,28 +4,38 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
void interrupt_trigger(rv32_cpu_t* cpu, uint32_t scause) uint32_t interrupt_mi_from_scause(uint32_t scause)
{ {
// Make sure that interrupts are enabled switch(scause)
if(cpu->privilege_mode == MACHINE)
{ {
// In machine mode, we check mstatus.sie (bit 1) case SCAUSE_SUPERVISOR_TIMER_INTERRUPT:
if(!(cpu->csr[CSR_MSTATUS] & 0b10)) return 0x20;
return; default:
fprintf(stderr, "interrupt_mie_bit_from_scause: wrong scause 0x%x\n", scause);
exit(EXIT_FAILURE);
} }
else if(cpu->privilege_mode == SUPERVISOR)
{ return 0;
// In supervisor mode, we check sstatus.sie (bit 1) }
if(!(cpu->csr[CSR_SSTATUS] & 0b10))
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; return;
}
else // Make sure that current interrupt is enabled
if(!(csr_read(cpu, CSR_MIE) & interrupt_mi_from_scause(scause)))
{ {
// TODO // Mark interrupt as pending
fprintf(stderr, "interrupt_trigger in non M/S-mode not implemented yet\n"); csr_write(cpu, CSR_MIP, csr_read(cpu, CSR_MIP) | interrupt_mi_from_scause(scause));
exit(EXIT_FAILURE);
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 // An interrupt can only be triggered from outside
// of the cpu, so we are on a different thread // of the cpu, so we are on a different thread
// and we don't already own the CPU mutex // and we don't already own the CPU mutex
@ -39,14 +49,14 @@ void interrupt_trigger(rv32_cpu_t* cpu, uint32_t scause)
cpu->csr[CSR_SCAUSE] = 0x80000000 | scause; cpu->csr[CSR_SCAUSE] = 0x80000000 | scause;
// Set xSTATUS.xPIE (previous interrupt enable) bit // Set xSTATUS.xPIE (previous interrupt enable) bit
cpu->csr[CSR_SSTATUS] |= 0x80; cpu->csr[CSR_MSTATUS] |= STATUS_SPIE;
// Set xSTATUS.xPP (Previous Privilege) bit // Set xSTATUS.xPP (Previous Privilege) bit
// TODO : Allow user mode interrupts (by not setting this) // TODO : Allow user mode interrupts (by not setting this)
cpu->csr[CSR_SSTATUS] |= 0x100; cpu->csr[CSR_MSTATUS] |= 0x100;
// Unset xSTATUS.xIE (interrupt enable) bit // Unset xSTATUS.xIE (interrupt enable) bit
cpu->csr[CSR_SSTATUS] &= ~0b10U; cpu->csr[CSR_MSTATUS] &= (~STATUS_SIE);
// Set xEPC : PC at interruption // Set xEPC : PC at interruption
cpu->csr[CSR_SEPC] = cpu->pc; cpu->csr[CSR_SEPC] = cpu->pc;

@ -533,13 +533,18 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction)
csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) | STATUS_SIE); csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) | STATUS_SIE);
// Restore privilege mode from Previous Privilege // Restore privilege mode from Previous Privilege
// TODO if(!(csr_read(cpu, CSR_SSTATUS) & STATUS_SPP))
{
// Previous Privilege was 0, return to user mode
fprintf(stderr, "SRET to user mode : not implemented yet\n");
exit(EXIT_FAILURE);
}
// Set Previous Interrupt Enable to 1 // Set Previous Interrupt Enable to 1
csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) | STATUS_SPIE); csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) | STATUS_SPIE);
// Set Previous Privilege to 0 // Set Previous Privilege to 0
// TODO csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) & (~STATUS_SPP));
// Saved PC before interrupt is in CSR SEPC, jump back // Saved PC before interrupt is in CSR SEPC, jump back
cpu->pc = csr_read(cpu, CSR_SEPC) - 4; cpu->pc = csr_read(cpu, CSR_SEPC) - 4;

Loading…
Cancel
Save