Line 34... |
Line 34... |
#include "sprs.h"
|
#include "sprs.h"
|
#include "sim-config.h"
|
#include "sim-config.h"
|
#include "debug_unit.h"
|
#include "debug_unit.h"
|
#include "execute.h"
|
#include "execute.h"
|
|
|
extern int cont_run;
|
|
extern struct iqueue_entry iqueue[20];
|
|
extern unsigned long pc_phy;
|
|
extern struct iqueue_entry iqueue[];
|
|
|
|
extern int delay_insn;
|
extern int delay_insn;
|
|
extern oraddr_t pcprev;
|
|
extern oraddr_t pcdelay;
|
|
|
|
int except_pending = 0;
|
|
|
struct _pending pending;
|
static const char *except_names[] = {
|
|
NULL,
|
|
"Reset",
|
|
"Bus Error",
|
|
"Data Page Fault",
|
|
"Insn Page Fault",
|
|
"Tick timer",
|
|
"Alignment",
|
|
"Illegal instruction",
|
|
"Interrupt",
|
|
"Data TLB Miss",
|
|
"Insn TLB Miss",
|
|
"Range",
|
|
"System Call",
|
|
"Trap" };
|
|
|
/* Discards all pending exceptions */
|
static const char *except_name(oraddr_t except)
|
void clear_pending_exception()
|
|
{
|
{
|
pending.valid = 0;
|
return except_names[except >> 8];
|
pending.type = 0;
|
|
pending.address = 0;
|
|
pending.saved = 0;
|
|
}
|
}
|
|
|
/* Asserts OR1K exception. */
|
/* Asserts OR1K exception. */
|
void except_handle(oraddr_t except, oraddr_t ea)
|
void except_handle(oraddr_t except, oraddr_t ea)
|
{
|
{
|
if(debug_ignore_exception (except)) {
|
if(debug_ignore_exception (except))
|
clear_pending_exception ();
|
return;
|
} else {
|
|
pending.valid = 1;
|
except_pending = 1;
|
pending.type = except;
|
|
pending.address = ea;
|
|
if (delay_insn)
|
|
pending.saved = pc - 4;
|
|
else
|
|
pending.saved = pc;
|
|
if (config.sim.verbose)
|
if (config.sim.verbose)
|
PRINTF("Exception 0x%"PRIxADDR" (%s) at 0x%"PRIxADDR", EA: 0x%"PRIxADDR
|
PRINTF("Exception 0x%"PRIxADDR" (%s) at 0x%"PRIxADDR", EA: 0x%"PRIxADDR
|
", ppc: 0x%"PRIxADDR", npc: 0x%"PRIxADDR", cycles %lld, #%lld\n",
|
", ppc: 0x%"PRIxADDR", npc: 0x%"PRIxADDR", dpc: 0x%"PRIxADDR
|
except, EXCEPT_NAME(except), iqueue[0].insn_addr, ea, pc, pcnext,
|
", cycles %lld, #%lld\n",
|
|
except, except_name(except), pcprev, ea, pc, pcnext, pcdelay,
|
runtime.sim.cycles, runtime.cpu.instructions);
|
runtime.sim.cycles, runtime.cpu.instructions);
|
}
|
|
}
|
|
|
|
/* Actually handles exception */
|
pcnext = except + (testsprbits (SPR_SR, SPR_SR_EPH) ? 0xf0000000 : 0x00000000);
|
void except_handle_backend (oraddr_t except, oraddr_t ea, oraddr_t pc_saved)
|
|
{
|
|
#if ONLY_VIRTUAL_MACHINE
|
|
fprintf(stderr, "WARNING: No exception processing while ONLY_VIRTUAL_MACHINE is defined.\n");
|
|
cont_run = 0;
|
|
#else
|
|
|
|
if (delay_insn) {
|
|
if (config.sim.verbose) PRINTF("INFO: Exception during execution of delay slot insn.\n");
|
|
pc -= 4;
|
|
}
|
|
|
|
pc_saved = pc & ~ADDR_C(0x3);
|
switch(except) {
|
if (except == EXCEPT_ILLEGAL)
|
/* EPCR is irrelevent */
|
mtspr(SPR_EPCR_BASE, pending.saved);
|
case EXCEPT_RESET:
|
else if (except == EXCEPT_ALIGN)
|
break;
|
mtspr(SPR_EPCR_BASE, pending.saved);
|
/* EPCR is loaded with address of instruction that caused the exception */
|
else if (except == EXCEPT_DTLBMISS)
|
/* All these exceptions happen during a simulated instruction */
|
mtspr(SPR_EPCR_BASE, pending.saved);
|
case EXCEPT_BUSERR:
|
else if (except == EXCEPT_DPF)
|
case EXCEPT_DPF:
|
mtspr(SPR_EPCR_BASE, pending.saved);
|
case EXCEPT_IPF:
|
else if (except == EXCEPT_BUSERR)
|
case EXCEPT_ALIGN:
|
mtspr(SPR_EPCR_BASE, pending.saved);
|
case EXCEPT_ILLEGAL:
|
else if (except == EXCEPT_TRAP)
|
case EXCEPT_DTLBMISS:
|
mtspr(SPR_EPCR_BASE, pending.saved);
|
case EXCEPT_ITLBMISS:
|
else if (except == EXCEPT_RANGE)
|
case EXCEPT_RANGE:
|
mtspr(SPR_EPCR_BASE, pending.saved);
|
case EXCEPT_TRAP:
|
else if (except == EXCEPT_ITLBMISS)
|
mtspr(SPR_EPCR_BASE, pc - (delay_insn ? 4 : 0));
|
mtspr(SPR_EPCR_BASE, pending.saved);
|
break;
|
else if (except == EXCEPT_IPF)
|
/* EPCR is loaded with address of next not-yet-executed instruction */
|
mtspr(SPR_EPCR_BASE, pending.saved);
|
case EXCEPT_SYSCALL:
|
else
|
mtspr(SPR_EPCR_BASE, (pc + 4) - (delay_insn ? 4 : 0));
|
mtspr(SPR_EPCR_BASE, pc_saved);
|
break;
|
|
/* These exceptions happen AFTER (or before) an instruction has been
|
|
* simulated, therefore the pc already points to the *next* instruction */
|
|
case EXCEPT_TICK:
|
|
case EXCEPT_INT:
|
|
mtspr(SPR_EPCR_BASE, pc - (delay_insn ? 4 : 0));
|
|
/* If we don't update the pc now, then it will only happen *after* the next
|
|
* instruction (There would be serious problems if the next instruction just
|
|
* happens to be a branch), when it should happen NOW. */
|
|
pc = pcnext;
|
|
pcnext += 4;
|
|
break;
|
|
}
|
|
|
mtspr(SPR_EEAR_BASE, ea);
|
mtspr(SPR_EEAR_BASE, ea);
|
mtspr(SPR_ESR_BASE, mfspr(SPR_SR));
|
mtspr(SPR_ESR_BASE, mfspr(SPR_SR));
|
|
|
/* Address translation is always disabled when starting exception. */
|
/* Address translation is always disabled when starting exception. */
|
Line 120... |
Line 124... |
mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_OVE); /* Disable overflow flag exception. */
|
mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_OVE); /* Disable overflow flag exception. */
|
|
|
mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_SM); /* SUPV mode */
|
mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_SM); /* SUPV mode */
|
mtspr(SPR_SR, mfspr(SPR_SR) & ~(SPR_SR_IEE | SPR_SR_TEE)); /* Disable interrupts. */
|
mtspr(SPR_SR, mfspr(SPR_SR) & ~(SPR_SR_IEE | SPR_SR_TEE)); /* Disable interrupts. */
|
|
|
clear_pending_exception ();
|
delay_insn = 0;
|
|
|
pc = (unsigned long)except + (testsprbits (SPR_SR, SPR_SR_EPH) ? 0xf0000000 : 0x00000000);
|
|
|
|
/* This has been removed. All exceptions (not just SYSCALL) suffer
|
|
from the same problem. The solution is to continue just like
|
|
the pipeline would, and issue the exception on the next
|
|
clock cycle. We assume now that this function is being called
|
|
->BEFORE<- the instruction fetch and after the previous update
|
|
which always yields the correct behavior. This has the added
|
|
advantage that a debugger can prevent an exception from
|
|
taking place by resetting the pc. */
|
|
#if 0
|
|
/* MM: We do pc update after the execute (in the simulator), so we
|
|
decrease it by 4 so that next instruction points to first exception
|
|
instruction. Do NOT comment this out. */
|
|
if (except == EXCEPT_SYSCALL)
|
|
pc -= 4;
|
|
#endif
|
|
pcnext = pc + 4;
|
|
|
|
/* Added by CZ 27/05/01 */
|
|
pc_phy = pc; /* An exception always turns off the MMU, so
|
|
pc is always pc_phy */
|
|
|
|
#endif /* !ONLY_VIRUAL_MACHINE */
|
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|