- Cleanup exception trigger code - Cleanup division to divide by 0 - Cleanup SRET code - Cleanup CSR code - Added interrupts - Added TIMER interruptmaster
parent
a0935f0aad
commit
02114ea7d8
@ -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); |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
#ifndef INTERRUPT_H |
||||||
|
#define INTERRUPT_H |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
#include "rv32cpu.h" |
||||||
|
|
||||||
|
#define SCAUSE_SUPERVISOR_SOFTWARE_INTERRUPT 0x1 |
||||||
|
#define SCAUSE_SUPERVISOR_TIMER_INTERRUPT 0x5 |
||||||
|
#define SCAUSE_SUPERVISOR_EXTERNAL_INTERRUPT 0x9 |
||||||
|
|
||||||
|
void interrupt_trigger(rv32_cpu_t* cpu, uint32_t scause); |
||||||
|
void interrupt_timer_setup(); |
||||||
|
|
||||||
|
#endif |
Loading…
Reference in new issue