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:
		@@ -3,19 +3,19 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
uint32_t csr_read(struct RV32_CPU* cpu, uint32_t csr)
 | 
					uint32_t csr_read(struct RV32_CPU* cpu, uint32_t csr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    switch(csr)
 | 
						switch(csr)
 | 
				
			||||||
    {
 | 
						{
 | 
				
			||||||
        case CSR_TIME:
 | 
							case CSR_CYCLE:
 | 
				
			||||||
            return cpu->sim_ticks_done;
 | 
								return cpu->sim_ticks_done;
 | 
				
			||||||
            break;
 | 
								break;
 | 
				
			||||||
        default:
 | 
							default:
 | 
				
			||||||
            break;
 | 
								break;
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return cpu->csr[csr];
 | 
						return cpu->csr[csr];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void csr_write(struct RV32_CPU* cpu, uint32_t csr, uint32_t value)
 | 
					void csr_write(struct RV32_CPU* cpu, uint32_t csr, uint32_t value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    cpu->csr[csr] = value;
 | 
						cpu->csr[csr] = value;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,24 +2,48 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void exception_trigger(rv32_cpu_t* cpu, uint32_t scause)
 | 
					void exception_trigger(rv32_cpu_t* cpu, uint32_t scause, uint32_t tval)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // An exception can only be triggered by the CPU itself,
 | 
						// An exception can only be triggered by the CPU itself,
 | 
				
			||||||
    // so we know we already own the mutex
 | 
						// so we know we already own the mutex
 | 
				
			||||||
    // We are in the CPU thread itself, but we need
 | 
						// We are in the CPU thread itself, but we need
 | 
				
			||||||
    // the return of this function to be the beginning of
 | 
						// the return of this function to be the beginning of
 | 
				
			||||||
    // the cpu loop
 | 
						// the cpu loop
 | 
				
			||||||
    // To achieve that, we can just call cpu_loop (noreturn)
 | 
						// To achieve that, we can just call cpu_loop (noreturn)
 | 
				
			||||||
    // at the end of this function
 | 
						// at the end of this function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Save execution context, so that 'mret/sret/..' can restore it
 | 
						// Exceptions cannot be disabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Set xCAUSE : exception cause, with interrupt bit set to null
 | 
				
			||||||
 | 
						cpu->csr[CSR_SCAUSE] = scause;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Save previous interrupt enable in xSTATUS.xPIE
 | 
				
			||||||
 | 
						if(cpu->csr[CSR_SSTATUS] & 0b10U)
 | 
				
			||||||
 | 
							cpu->csr[CSR_SSTATUS] |= 0x80;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Set previous privilege mode in xSTATUS.xPP
 | 
				
			||||||
    // TODO
 | 
					    // TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Set PC to STVEC, and set SCAUSE
 | 
						// Unset SIE (interrupt enable) bit
 | 
				
			||||||
    // TODO: If PC cannot be mmu_resolved, throw a 'double fault' ?
 | 
						cpu->csr[CSR_SSTATUS] &= ~0b10U;
 | 
				
			||||||
    cpu->pc = cpu->csr[CSR_STVEC];
 | 
					 | 
				
			||||||
    cpu->csr[CSR_SCAUSE] = scause;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pthread_mutex_unlock(&cpu0_mutex);
 | 
						// Set privilege mode for exception handling, checking for delegation
 | 
				
			||||||
    cpu_loop(cpu);
 | 
					    // TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Set xTVAL, exception-specific information related to xCAUSE
 | 
				
			||||||
 | 
						cpu->csr[CSR_STVAL] = tval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Set SEPC to instruction that caused exception
 | 
				
			||||||
 | 
						cpu->csr[CSR_SEPC] = cpu->pc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Set PC to xTVEC : exception handling code
 | 
				
			||||||
 | 
						// xTVEC: [Base(30bits) Mode(2 bits)], address 4-byte aligned in base
 | 
				
			||||||
 | 
						// Exceptions are not vectored (we can safely ignore mode)
 | 
				
			||||||
 | 
						cpu->pc = cpu->csr[CSR_STVEC] & 0xFFFFFFFC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Unlock cpu mutex, cpu_loop will lock it just after
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&cpu0_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // cpu loop (attribute noreturn should erase previous stack)
 | 
				
			||||||
 | 
						cpu_loop(cpu);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "rv32cpu.h"
 | 
					#include "rv32cpu.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void exception_trigger(rv32_cpu_t* cpu, uint32_t scause);
 | 
					void exception_trigger(rv32_cpu_t* cpu, uint32_t scause, uint32_t tval);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SCAUSE_INSTRUCTION_MISSALIGNED 0x0
 | 
					#define SCAUSE_INSTRUCTION_MISSALIGNED 0x0
 | 
				
			||||||
#define SCAUSE_INSTRUCTION_ACCESS_FAULT 0x1
 | 
					#define SCAUSE_INSTRUCTION_ACCESS_FAULT 0x1
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										87
									
								
								src/cpu/interrupt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/cpu/interrupt.c
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										15
									
								
								src/cpu/interrupt.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/cpu/interrupt.h
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
				
			||||||
@@ -49,7 +49,7 @@ void cpu_init()
 | 
				
			|||||||
	cpu0->privilege_mode = MACHINE;
 | 
						cpu0->privilege_mode = MACHINE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void cpu_decode(raw_instruction_t raw_instruction, instruction_t* output)
 | 
					static void cpu_decode(rv32_cpu_t* cpu, raw_instruction_t raw_instruction, instruction_t* output)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	output->opcode = raw_instruction.opcode;
 | 
						output->opcode = raw_instruction.opcode;
 | 
				
			||||||
	output->immediate = 0;
 | 
						output->immediate = 0;
 | 
				
			||||||
@@ -112,8 +112,8 @@ static void cpu_decode(raw_instruction_t raw_instruction, instruction_t* output)
 | 
				
			|||||||
			// TODO : Decode NOP instructions
 | 
								// TODO : Decode NOP instructions
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			fprintf(stderr, "Error: Unknown instruction opcode 0x%x, could not decode\n", raw_instruction.opcode);
 | 
								// Throw an 'Invalid OPCODE' exception
 | 
				
			||||||
			exit(EXIT_FAILURE);
 | 
								exception_trigger(cpu, SCAUSE_ILLEGAL_INSTRUCTION, 0);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -433,6 +433,13 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction)
 | 
				
			|||||||
							cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] ^ cpu->regs.x[instruction->rs2];
 | 
												cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] ^ cpu->regs.x[instruction->rs2];
 | 
				
			||||||
							break;
 | 
												break;
 | 
				
			||||||
						case FUNC7_DIV:
 | 
											case FUNC7_DIV:
 | 
				
			||||||
 | 
												if(!cpu->regs.x[instruction->rs2])
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													// ISA dictates that we return FFFFFFFF and set a flag bit to signal the exception
 | 
				
			||||||
 | 
													cpu->regs.x[instruction->rd] = 0xFFFFFFFF;
 | 
				
			||||||
 | 
													// TODO flag ?
 | 
				
			||||||
 | 
													break;
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
							cpu->regs.x[instruction->rd] = ((int32_t) cpu->regs.x[instruction->rs1]) / ((int32_t) cpu->regs.x[instruction->rs2]);
 | 
												cpu->regs.x[instruction->rd] = ((int32_t) cpu->regs.x[instruction->rs1]) / ((int32_t) cpu->regs.x[instruction->rs2]);
 | 
				
			||||||
							break;
 | 
												break;
 | 
				
			||||||
						default:
 | 
											default:
 | 
				
			||||||
@@ -518,15 +525,30 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction)
 | 
				
			|||||||
							break;
 | 
												break;
 | 
				
			||||||
						case IMM_EBREAK:
 | 
											case IMM_EBREAK:
 | 
				
			||||||
							// EBREAK : generate a breakpoint exception
 | 
												// EBREAK : generate a breakpoint exception
 | 
				
			||||||
							exception_trigger(cpu, SCAUSE_BREAKPOINT);
 | 
												exception_trigger(cpu, SCAUSE_BREAKPOINT, 0);
 | 
				
			||||||
							break;
 | 
												break;
 | 
				
			||||||
						case IMM_SRET:
 | 
											case IMM_SRET:
 | 
				
			||||||
							fprintf(stderr, "SRET: We don't support that.\n");
 | 
												// SRET: Return from supervisor interrupt
 | 
				
			||||||
 | 
												// Restore Interrupt Enable from Previous Interrupt Enable
 | 
				
			||||||
 | 
												uint32_t sstatus = csr_read(cpu, CSR_SSTATUS);
 | 
				
			||||||
 | 
												if(sstatus & 0x80)
 | 
				
			||||||
 | 
													csr_write(cpu, CSR_SSTATUS, sstatus | 0b10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												// Restore privilege mode from Previous Privilege
 | 
				
			||||||
 | 
												// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												// Set Previous Interrupt Enable to 1
 | 
				
			||||||
 | 
												csr_write(cpu, CSR_SSTATUS, csr_read(cpu, CSR_SSTATUS) | 0x80);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												// Set Previous Privilege to 0
 | 
				
			||||||
 | 
												// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												// Saved PC before interrupt is in CSR SEPC, jump back
 | 
				
			||||||
 | 
												cpu->pc = csr_read(cpu, CSR_SEPC) - 4;
 | 
				
			||||||
							break;
 | 
												break;
 | 
				
			||||||
						case IMM_MRET:
 | 
											case IMM_MRET:
 | 
				
			||||||
							// Ret to destination address : CSR_MEPC content
 | 
												// Ret to destination address : CSR_MEPC content
 | 
				
			||||||
							// Change privilege mode to SUPERVISOR
 | 
												// TODO fix it to act like sret
 | 
				
			||||||
							// TODO : Pop lower-privilege interrupt enable and privilege mode stack
 | 
					 | 
				
			||||||
							cpu->privilege_mode = SUPERVISOR;
 | 
												cpu->privilege_mode = SUPERVISOR;
 | 
				
			||||||
							cpu->pc = cpu->csr[CSR_MEPC] - 4;
 | 
												cpu->pc = cpu->csr[CSR_MEPC] - 4;
 | 
				
			||||||
							break;
 | 
												break;
 | 
				
			||||||
@@ -537,7 +559,9 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction)
 | 
				
			|||||||
									// TODO : Check if we really need to do something on SFENCE.VMA ?
 | 
														// TODO : Check if we really need to do something on SFENCE.VMA ?
 | 
				
			||||||
									break;
 | 
														break;
 | 
				
			||||||
								case FUNC7_WFI:
 | 
													case FUNC7_WFI:
 | 
				
			||||||
									fprintf(stderr, "WFI: Guest kernel must think we have interrupts. We have none. Halting simulation.\n");
 | 
														// Wait For Interrupt : halt the simulation
 | 
				
			||||||
 | 
														// It will be woken up by an interruption
 | 
				
			||||||
 | 
														fprintf(stderr, "WFI: Halting simulation.\n");
 | 
				
			||||||
									cpu->sim_ticks_left = 1;
 | 
														cpu->sim_ticks_left = 1;
 | 
				
			||||||
									break;
 | 
														break;
 | 
				
			||||||
								default:
 | 
													default:
 | 
				
			||||||
@@ -712,7 +736,7 @@ __attribute__((noreturn)) void cpu_loop(rv32_cpu_t* cpu)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Decode
 | 
							// Decode
 | 
				
			||||||
		instruction_t instruction;
 | 
							instruction_t instruction;
 | 
				
			||||||
		cpu_decode(raw_instruction, &instruction);
 | 
							cpu_decode(cpu, raw_instruction, &instruction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if(trace)
 | 
							if(trace)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								src/main.c
									
									
									
									
									
								
							@@ -2,6 +2,7 @@
 | 
				
			|||||||
#include "memory/memory.h"
 | 
					#include "memory/memory.h"
 | 
				
			||||||
#include "bootloader/bootloader.h"
 | 
					#include "bootloader/bootloader.h"
 | 
				
			||||||
#include "cpu/rv32cpu.h"
 | 
					#include "cpu/rv32cpu.h"
 | 
				
			||||||
 | 
					#include "cpu/interrupt.h"
 | 
				
			||||||
#include "gdbstub/gdbstub.h"
 | 
					#include "gdbstub/gdbstub.h"
 | 
				
			||||||
#include "devices/uart/uart.h"
 | 
					#include "devices/uart/uart.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,34 +32,20 @@ int main(int argc, char** argv)
 | 
				
			|||||||
		gdbstub_wait_for_connection();
 | 
							gdbstub_wait_for_connection();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Initialize timer for timer interrupt
 | 
				
			||||||
 | 
						interrupt_timer_setup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// CPU simulation : create cpu0 thread
 | 
						// CPU simulation : create cpu0 thread
 | 
				
			||||||
	if(!gdbstub) cpu0->sim_ticks_left = -1; // Simulate forever
 | 
						if(!gdbstub) cpu0->sim_ticks_left = -1; // Simulate forever
 | 
				
			||||||
	pthread_t cpu0_thread;
 | 
						pthread_t cpu0_thread;
 | 
				
			||||||
	pthread_create(&cpu0_thread, 0, (void*) cpu_loop, cpu0);
 | 
						pthread_create(&cpu0_thread, 0, (void*) cpu_loop, cpu0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Wait for the simulation to end
 | 
						// Wait forever, until simulation end (which should be an ecall shutdown)
 | 
				
			||||||
 | 
						pthread_join(cpu0_thread, 0);
 | 
				
			||||||
	if(gdbstub)
 | 
						if(gdbstub)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		pthread_join(cpu0_thread, 0);
 | 
					 | 
				
			||||||
		gdbstub_stop();
 | 
							gdbstub_stop();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		while(1)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			pthread_mutex_lock(&cpu0_mutex);
 | 
					 | 
				
			||||||
			pthread_cond_wait(&cpu0->sim_condition, &cpu0_mutex);
 | 
					 | 
				
			||||||
			if(!cpu0->sim_ticks_left && cpu0->sim_ticks_done > 0)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				// Simulation ended
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			pthread_mutex_unlock(&cpu0_mutex);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        fprintf(stderr, "Simulation ended (in a non-debug environment)\n");
 | 
					 | 
				
			||||||
        return cpu0->regs.a0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -81,7 +81,7 @@ uint32_t mmu_resolve(rv32_cpu_t* cpu, memory_access_type_t access_type, uint32_t
 | 
				
			|||||||
	if(!(pte & PTE_V))
 | 
						if(!(pte & PTE_V))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// Invalid PTE
 | 
							// Invalid PTE
 | 
				
			||||||
		exception_trigger(cpu, mmu_scause_from_access(access_type));
 | 
							exception_trigger(cpu, mmu_scause_from_access(access_type), vaddr);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if((pte & PTE_R) || (pte & PTE_W) || (pte & PTE_X))
 | 
						if((pte & PTE_R) || (pte & PTE_W) || (pte & PTE_X))
 | 
				
			||||||
@@ -109,7 +109,7 @@ uint32_t mmu_resolve(rv32_cpu_t* cpu, memory_access_type_t access_type, uint32_t
 | 
				
			|||||||
	if(!(pte & PTE_V))
 | 
						if(!(pte & PTE_V))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// Invalid PTE
 | 
							// Invalid PTE
 | 
				
			||||||
		exception_trigger(cpu, mmu_scause_from_access(access_type));
 | 
							exception_trigger(cpu, mmu_scause_from_access(access_type), vaddr);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// This must be a leaf PTE, as Sv32 only supports 2-level mappings
 | 
						// This must be a leaf PTE, as Sv32 only supports 2-level mappings
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user