|
|
@ -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)
|
|
|
|
|
|
|
|
if(!(cpu->csr[CSR_MSTATUS] & 0b10)) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if(cpu->privilege_mode == SUPERVISOR) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
// In supervisor mode, we check sstatus.sie (bit 1)
|
|
|
|
case SCAUSE_SUPERVISOR_TIMER_INTERRUPT: |
|
|
|
if(!(cpu->csr[CSR_SSTATUS] & 0b10)) |
|
|
|
return 0x20; |
|
|
|
return; |
|
|
|
default: |
|
|
|
|
|
|
|
fprintf(stderr, "interrupt_mie_bit_from_scause: wrong scause 0x%x\n", scause); |
|
|
|
|
|
|
|
exit(EXIT_FAILURE); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
|
|
|
|
|
|
|
|
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))) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// 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; |
|
|
|