Multiple cleanups and improvements
- Cleanup exception trigger code - Cleanup division to divide by 0 - Cleanup SRET code - Cleanup CSR code - Added interrupts - Added TIMER interrupt
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
#include "interrupt.h"
|
||||
#include "rv32cpu.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void interrupt_trigger(rv32_cpu_t* cpu, uint32_t scause)
|
||||
{
|
||||
// Make sure that interrupts are enabled
|
||||
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)
|
||||
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);
|
||||
}
|
||||
|
||||
// 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
|
||||
// We obtain in this thread the control of the CPU,
|
||||
// but we know it is not in the middle of an instruction
|
||||
// (we got the mutex) ; this way we can just change
|
||||
// registers to set interrupt handler execution
|
||||
pthread_mutex_lock(&cpu0_mutex);
|
||||
|
||||
// Set xCAUSE with interrupt bit set
|
||||
cpu->csr[CSR_SCAUSE] = 0x80000000 | scause;
|
||||
|
||||
// Set xSTATUS.xPIE (previous interrupt enable) bit
|
||||
cpu->csr[CSR_SSTATUS] |= 0x80;
|
||||
|
||||
// Set xSTATUS.xPP (Previous Privilege) bit
|
||||
|
||||
// Unset xSTATUS.xIE (interrupt enable) bit
|
||||
cpu->csr[CSR_SSTATUS] &= ~0b10U;
|
||||
|
||||
// Set xEPC : PC at interruption
|
||||
cpu->csr[CSR_SEPC] = cpu->pc;
|
||||
|
||||
// Set PC to xTVEC : exception handler code
|
||||
// xTVEC: [Base(30bits) Mode(2 bits)], address 4-byte aligned in base
|
||||
// Interrupts can be vectored, if mode == 1, then pc = xTVEC + scause * 4
|
||||
int mode = cpu->csr[CSR_STVEC] & 0b11;
|
||||
switch(mode)
|
||||
{
|
||||
case 0:
|
||||
cpu->pc = cpu->csr[CSR_STVEC] & 0xFFFFFFFC;
|
||||
break;
|
||||
case 1:
|
||||
cpu->pc = (cpu->csr[CSR_STVEC] & 0xFFFFFFFC) + scause * 4;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "interrupt_trigger: invalid mode encountered in sTVEC register\n");
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&cpu0_mutex);
|
||||
}
|
||||
|
||||
void interrupt_timer_thread()
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
cpu0->csr[CSR_TIME]++;
|
||||
interrupt_trigger(cpu0, SCAUSE_SUPERVISOR_TIMER_INTERRUPT);
|
||||
usleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
void interrupt_timer_setup()
|
||||
{
|
||||
pthread_t timer_thread;
|
||||
pthread_create(&timer_thread, 0, (void*) interrupt_timer_thread, 0);
|
||||
}
|
||||
Reference in New Issue
Block a user