Better exception/interrupt handle
This commit is contained in:
		@@ -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);
 | 
				
			||||||
	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);
 | 
								exit(EXIT_FAILURE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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)))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// 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
 | 
						// 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;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user