Better exception/interrupt handle
This commit is contained in:
parent
0983be511c
commit
923e9d39a0
@ -15,6 +15,8 @@ __attribute__((noreturn)) void exception_trigger(rv32_cpu_t* cpu, uint32_t scaus
|
||||
|
||||
// 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));
|
||||
|
||||
@ -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));
|
||||
|
||||
// Set previous privilege mode in xSTATUS.xPP
|
||||
// TODO : Allow user mode exceptions (by not setting this)
|
||||
csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) | STATUS_SPP);
|
||||
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
|
||||
|
@ -4,28 +4,38 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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
|
||||
if(cpu->privilege_mode == MACHINE)
|
||||
// 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)))
|
||||
{
|
||||
// In machine mode, we check mstatus.sie (bit 1)
|
||||
if(!(cpu->csr[CSR_MSTATUS] & 0b10))
|
||||
return;
|
||||
}
|
||||
else if(cpu->privilege_mode == SUPERVISOR)
|
||||
{
|
||||
// In supervisor mode, we check sstatus.sie (bit 1)
|
||||
if(!(cpu->csr[CSR_SSTATUS] & 0b10))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
fprintf(stderr, "interrupt_trigger in non M/S-mode not implemented yet\n");
|
||||
exit(EXIT_FAILURE);
|
||||
// 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
|
||||
@ -39,14 +49,14 @@ void interrupt_trigger(rv32_cpu_t* cpu, uint32_t scause)
|
||||
cpu->csr[CSR_SCAUSE] = 0x80000000 | scause;
|
||||
|
||||
// Set xSTATUS.xPIE (previous interrupt enable) bit
|
||||
cpu->csr[CSR_SSTATUS] |= 0x80;
|
||||
cpu->csr[CSR_MSTATUS] |= STATUS_SPIE;
|
||||
|
||||
// Set xSTATUS.xPP (Previous Privilege) bit
|
||||
// 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
|
||||
cpu->csr[CSR_SSTATUS] &= ~0b10U;
|
||||
cpu->csr[CSR_MSTATUS] &= (~STATUS_SIE);
|
||||
|
||||
// Set xEPC : PC at interruption
|
||||
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);
|
||||
|
||||
// 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
|
||||
csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) | STATUS_SPIE);
|
||||
|
||||
// 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
|
||||
cpu->pc = csr_read(cpu, CSR_SEPC) - 4;
|
||||
|
Loading…
Reference in New Issue
Block a user