|
Message
From: =?unknown-8bit?Q?Gy=F6rgy?= 'nog' Jeney<nog@s...>
Date: Sun Jan 30 11:24:47 CET 2005
Subject: [openrisc] [or1ksim #9] Rework exception handling
Hi,I have reworked how we handle exceptions. Checking pending.valid is now not needed on every cycle. This took a rather long time to get working, but I believe I got it right.
I know I introduced some extra checks in cpu_clock that weren't there before but with this new exception scheme a dynamic recompiler shall be able to just jump to an exception handler without haveing to check pending.valid on each instruction.
I have also moved the debugger checks to eval_insn, just to be conformant with the eval_mem* set of functions.
I never understood the hughe comment in except_handle_backend, so I just blatently disregarded it and implemented the new exception handling based only on my interpretation of the architechture manual. Ofcourse if I screwed up don't hesitate to speek up.
ChangeLog: * Rework exception handling, voiding the need to check pending.valid on each simulated cycle.
nog. -------------- next part -------------- --- cpu/or32/execute.c 2005-01-29 09:44:21.000000000 +0100 +++ ../or1ksim-ac/cpu/or32/execute.c 2005-01-30 10:13:34.000000000 +0100 @@ -64,15 +64,11 @@ int multissue[20]; int issued_per_cycle = 4; -/* Whether break was hit - so we can step over a break */ -static int break_just_hit = 0; - /* Completition queue */ struct iqueue_entry icomplet[20]; /* Program counter (and translated PC) */ oraddr_t pc; -oraddr_t pc_phy; /* Previous program counter */ oraddr_t pcprev = 0; @@ -86,9 +82,6 @@ /* CCR */ int flag; -/* CCR (for dependency calculation) */ -char ccr_flag[10] = "flag"; - /* Store buffer analysis - stores are accumulated and commited when IO is idle */ static int sbuf_head = 0, sbuf_tail = 0, sbuf_count = 0; static int sbuf_buf[MAX_SBUF_LEN] = {0}; @@ -284,31 +277,27 @@ /* Fetch returns nonzero if instruction should NOT be executed. */ static inline int fetch() { - /* Update the pc for pending exceptions, or get physical pc */ - if (!pending.valid) - pc_phy = immu_translate(pc); - - if(pending.valid) - except_handle_backend(pending.type, pending.address, pending.saved); + static int break_just_hit = 0; if (CHECK_BREAKPOINTS) { /* MM: Check for breakpoint. This has to be done in fetch cycle, because of peripheria. MM1709: if we cannot access the memory entry, we could not set the - breakpoint earlier, so just chech the breakpoint list. */ - if (has_breakpoint (pc_phy) && !break_just_hit) { + breakpoint earlier, so just check the breakpoint list. */ + if (has_breakpoint (peek_into_itlb (pc)) && !break_just_hit) { break_just_hit = 1; return 1; /* Breakpoint set. */ } break_just_hit = 0; } - pc_phy &= ~ADDR_C(0x3); - - runtime.cpu.instructions++; + breakpoint = 0; /* Fetch instruction. */ iqueue[0].insn_addr = pc; - iqueue[0].insn = eval_insn (pc_phy, &breakpoint); + iqueue[0].insn = eval_insn (pc, &breakpoint); + + if (!except_pending) + runtime.cpu.instructions++; /* update_pc will be called after execution */ @@ -593,15 +582,11 @@ static inline void decode_execute_wrapper (struct iqueue_entry *current) { breakpoint = 0; - next_delay_insn = 0; #ifndef HAS_EXECUTION #error HAS_EXECUTION has to be defined in order to execute programs. #endif
- if(config.debug.enabled && CheckDebugUnit(DebugInstructionFetch, pc_phy))
- breakpoint = 1;
-
decode_execute (current);
#if SET_OV_FLAG
@@ -643,22 +628,39 @@
pcnext = 0x0; /* MM1409: All programs should start at reset vector entry! */
if (config.sim.verbose) PRINTF ("Starting at 0x%"PRIxADDR"\n", pcnext);
pc = pcnext;
- pc_phy = pc;
pcnext += 4;
debug(1, "reset ...\n");
/* MM1409: All programs should set their stack pointer! */
except_handle(EXCEPT_RESET, 0);
+ update_pc();
+ except_pending = 0;
}
/* Simulates one CPU clock cycle */
inline int cpu_clock ()
{
+ except_pending = 0;
+ next_delay_insn = 0;
if(fetch()) {
PRINTF ("Breakpoint hit.\n");
runtime.sim.cont_run = 0; /* memory breakpoint encountered */
return 1;
}
+
+ if(except_pending) {
+ update_pc();
+ except_pending = 0;
+ return 0;
+ }
+
+ if(breakpoint) {
+ except_handle(EXCEPT_TRAP, mfspr(SPR_EEAR_BASE));
+ update_pc();
+ except_pending = 0;
+ return 0;
+ }
+
decode_execute_wrapper (&iqueue[0]);
update_pc();
return 0;
--- cpu/or1k/except.h 2005-01-28 21:37:24.000000000 +0100
+++ ../or1ksim-ac/cpu/or1k/except.h 2005-01-28 16:22:38.000000000 +0100
@@ -42,34 +42,10 @@
/* Non maskable exceptions */
#define IS_NME(E) ((E) == EXCEPT_RESET)
-#define EXCEPT_NAME(E) E == EXCEPT_RESET ? "Reset" : \
- E == EXCEPT_BUSERR ? "Bus Error" : \
- E == EXCEPT_DPF ? "Data Page Fault" : \
- E == EXCEPT_IPF ? "Insn Page Fault" : \
- E == EXCEPT_TICK ? "Tick timer" : \
- E == EXCEPT_ALIGN ? "Alignment" : \
- E == EXCEPT_ILLEGAL ? "Illegal instruction" : \
- E == EXCEPT_INT ? "Interrupt" : \
- E == EXCEPT_DTLBMISS ? "Data TLB Miss" : \
- E == EXCEPT_ITLBMISS ? "Insn TLB Miss" : \
- E == EXCEPT_RANGE ? "Range" : \
- E == EXCEPT_SYSCALL ? "System Call" : \
- E == EXCEPT_TRAP ? "Trap" : "Unknown"
-
-extern struct _pending {
- int valid;
- oraddr_t type;
- oraddr_t address;
- oraddr_t saved;
-} pending;
-
/* Prototypes */
void except_handle(oraddr_t except, oraddr_t ea);
-/* Actually handles exception */
-void except_handle_backend (oraddr_t except, oraddr_t ea, oraddr_t pc_saved);
-
-/* Discards all pending exceptions */
-void clear_pending_exception();
+/* Has an exception been raised in this cycle ? */
+extern int except_pending;
#endif
--- cpu/or1k/except.c 2005-01-28 21:37:24.000000000 +0100
+++ ../or1ksim-ac/cpu/or1k/except.c 2005-01-30 10:46:20.000000000 +0100
@@ -36,79 +36,83 @@
#include "debug_unit.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 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 */
-void clear_pending_exception()
+static const char *except_name(oraddr_t except)
{
- pending.valid = 0;
- pending.type = 0;
- pending.address = 0;
- pending.saved = 0;
+ return except_names[except >> 8];
}
/* Asserts OR1K exception. */
void except_handle(oraddr_t except, oraddr_t ea)
{
- if(debug_ignore_exception (except)) {
- clear_pending_exception ();
- } else {
- pending.valid = 1;
- pending.type = except;
- pending.address = ea;
- if (delay_insn)
- pending.saved = pc - 4;
- else
- pending.saved = pc;
- if (config.sim.verbose)
- PRINTF("Exception 0x%"PRIxADDR" (%s) at 0x%"PRIxADDR", EA: 0x%"PRIxADDR
- ", ppc: 0x%"PRIxADDR", npc: 0x%"PRIxADDR", cycles %lld, #%lld\n",
- except, EXCEPT_NAME(except), iqueue[0].insn_addr, ea, pc, pcnext,
- runtime.sim.cycles, runtime.cpu.instructions);
- }
-}
+ if(debug_ignore_exception (except))
+ return;
-/* Actually handles exception */
-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;
- }
+ except_pending = 1;
- pc_saved = pc & ~ADDR_C(0x3);
- if (except == EXCEPT_ILLEGAL)
- mtspr(SPR_EPCR_BASE, pending.saved);
- else if (except == EXCEPT_ALIGN)
- mtspr(SPR_EPCR_BASE, pending.saved);
- else if (except == EXCEPT_DTLBMISS)
- mtspr(SPR_EPCR_BASE, pending.saved);
- else if (except == EXCEPT_DPF)
- mtspr(SPR_EPCR_BASE, pending.saved);
- else if (except == EXCEPT_BUSERR)
- mtspr(SPR_EPCR_BASE, pending.saved);
- else if (except == EXCEPT_TRAP)
- mtspr(SPR_EPCR_BASE, pending.saved);
- else if (except == EXCEPT_RANGE)
- mtspr(SPR_EPCR_BASE, pending.saved);
- else if (except == EXCEPT_ITLBMISS)
- mtspr(SPR_EPCR_BASE, pending.saved);
- else if (except == EXCEPT_IPF)
- mtspr(SPR_EPCR_BASE, pending.saved);
- else
- mtspr(SPR_EPCR_BASE, pc_saved);
+ if (config.sim.verbose)
+ PRINTF("Exception 0x%"PRIxADDR" (%s) at 0x%"PRIxADDR", EA: 0x%"PRIxADDR
+ ", ppc: 0x%"PRIxADDR", npc: 0x%"PRIxADDR", dpc: 0x%"PRIxADDR
+ ", cycles %lld, #%lld\n",
+ except, except_name(except), pcprev, ea, pc, pcnext, pcdelay,
+ runtime.sim.cycles, runtime.cpu.instructions);
+
+ pcnext = except + (testsprbits (SPR_SR, SPR_SR_EPH) ? 0xf0000000 : 0x00000000);
+
+ switch(except) {
+ /* EPCR is irrelevent */
+ case EXCEPT_RESET:
+ break;
+ /* EPCR is loaded with address of instruction that caused the exception */
+ /* All these exceptions happen during a simulated instruction */
+ case EXCEPT_BUSERR:
+ case EXCEPT_DPF:
+ case EXCEPT_IPF:
+ case EXCEPT_ALIGN:
+ case EXCEPT_ILLEGAL:
+ case EXCEPT_DTLBMISS:
+ case EXCEPT_ITLBMISS:
+ case EXCEPT_RANGE:
+ case EXCEPT_TRAP:
+ mtspr(SPR_EPCR_BASE, pc - (delay_insn ? 4 : 0));
+ break;
+ /* EPCR is loaded with address of next not-yet-executed instruction */
+ case EXCEPT_SYSCALL:
+ mtspr(SPR_EPCR_BASE, (pc + 4) - (delay_insn ? 4 : 0));
+ 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_ESR_BASE, mfspr(SPR_SR));
@@ -122,30 +126,5 @@
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. */
- clear_pending_exception ();
-
- 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 */
+ delay_insn = 0;
}
--- cpu/common/abstract.c 2005-01-29 09:44:21.000000000 +0100
+++ ../or1ksim-ac/cpu/common/abstract.c 2005-01-29 09:44:56.000000000 +0100
@@ -357,10 +357,9 @@
memaddr);
except_handle(EXCEPT_BUSERR, cur_vadd);
temp = 0;
- }
-
- if (!pending.valid && cur_area->log)
+ } else if (cur_area->log)
fprintf (cur_area->log, "[%"PRIxADDR"] -> read %08"PRIx32"\n", memaddr, temp);
+
if (config.debug.enabled)
*breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */
return temp;
@@ -388,7 +387,7 @@
cur_vadd = memaddr;
memaddr = dmmu_translate(memaddr, 0);
- if (pending.valid)
+ if (except_pending)
return 0;
if (config.dc.enabled)
@@ -447,22 +446,24 @@
*
* STATISTICS OK (only used for cpu_access, that is architectural access)
*/
-uint32_t eval_insn(oraddr_t memaddr,int* breakpoint)
+uint32_t eval_insn(oraddr_t memaddr, int* breakpoint)
{
uint32_t temp;
if (config.sim.mprofile)
mprofile (memaddr, MPROF_32 | MPROF_FETCH);
// memaddr = simulate_ic_mmu_fetch(memaddr);
- cur_vadd = pc;
- // I think this does not belong into eval_insn() 2004-01-30 HP
-// if (config.debug.enabled)
-// *breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */
+ cur_vadd = memaddr;
+
+ memaddr = immu_translate(memaddr);
+
+ if (except_pending)
+ return 0;
+
+ if (config.debug.enabled)
+ *breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr);
- // We could place the CheckDebugUnit(DebugInstructionFetch) here, but it is currently done
- // in decode_execute_wrapper, so I leave it like this. 2004-01-30 HP
-
if (config.ic.enabled)
temp = ic_simulate_fetch(memaddr);
else {
@@ -475,9 +476,8 @@
}
}
- // I think this does not belong into eval_insn() 2004-01-30 HP
-// if (config.debug.enabled)
-// *breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */
+ if (config.debug.enabled)
+ *breakpoint += CheckDebugUnit(DebugLoadData,temp);
return temp;
}
@@ -503,11 +503,11 @@
cur_vadd = memaddr;
memaddr = dmmu_translate(memaddr, 0);
- if (pending.valid)
+ if (except_pending)
return 0;
if (config.dc.enabled)
- temp = (unsigned short)dc_simulate_read(memaddr, 2);
+ temp = (uint16_t)dc_simulate_read(memaddr, 2);
else {
temp = evalsim_mem16(memaddr);
if (!cur_area) {
@@ -575,11 +575,11 @@
cur_vadd = memaddr;
memaddr = dmmu_translate(memaddr, 0);
- if (pending.valid)
+ if (except_pending)
return 0;
if (config.dc.enabled)
- temp = (unsigned char)dc_simulate_read(memaddr, 1);
+ temp = (uint8_t)dc_simulate_read(memaddr, 1);
else {
temp = evalsim_mem8(memaddr);
if (!cur_area) {
@@ -782,7 +782,7 @@
cur_vadd = memaddr;
memaddr = dmmu_translate(memaddr, 1);;
/* If we produced exception don't set anything */
- if (pending.valid)
+ if (except_pending)
return;
if (config.debug.enabled) {
@@ -846,7 +846,7 @@
cur_vadd = memaddr;
memaddr = dmmu_translate(memaddr, 1);;
/* If we produced exception don't set anything */
- if (pending.valid)
+ if (except_pending)
return;
if (config.debug.enabled) {
@@ -854,7 +854,7 @@
*breakpoint += CheckDebugUnit(DebugStoreData,value);
}
- dc_simulate_write(memaddr, (unsigned long)value, 2);
+ dc_simulate_write(memaddr, value, 2);
if (cur_area && cur_area->log)
fprintf (cur_area->log, "[%"PRIxADDR"] -> write %04"PRIx16"\n", memaddr,
@@ -903,14 +903,14 @@
cur_vadd = memaddr;
memaddr = dmmu_translate(memaddr, 1);;
/* If we produced exception don't set anything */
- if (pending.valid) return;
+ if (except_pending) return;
if (config.debug.enabled) {
*breakpoint += CheckDebugUnit(DebugStoreAddress,memaddr); /* 28/05/01 CZ */
*breakpoint += CheckDebugUnit(DebugStoreData,value);
}
- dc_simulate_write(memaddr, (unsigned long)value, 1);
+ dc_simulate_write(memaddr, value, 1);
if (cur_area && cur_area->log)
fprintf (cur_area->log, "[%"PRIxADDR"] -> write %02"PRIx8"\n", memaddr,
--- tick/tick.c 2005-01-28 21:37:24.000000000 +0100
+++ ../or1ksim-ac/tick/tick.c 2005-01-28 16:31:21.000000000 +0100
@@ -76,7 +76,7 @@
if (ttmr & SPR_TTMR_IE) {
setsprbits(SPR_TTMR, SPR_TTMR_IP, 1);
/* be sure not to issue timer exception if an exception occured before it */
- if (((mfspr(SPR_SR) & SPR_SR_TEE) == SPR_SR_TEE) && (!pending.valid))
+ if ((mfspr(SPR_SR) & SPR_SR_TEE) == SPR_SR_TEE)
except_handle(EXCEPT_TICK, mfspr(SPR_EEAR_BASE));
else
/* If TEE is currently not set we have to pend tick exception
--- pic/pic.c 2005-01-28 21:37:24.000000000 +0100
+++ ../or1ksim-ac/pic/pic.c 2005-01-28 16:30:09.000000000 +0100
@@ -40,8 +40,6 @@
#include "sprs.h"
#include "debug.h"
-extern int cont_run;
-
/* Reset. It initializes PIC registers. */
void pic_reset()
{
@@ -57,7 +55,7 @@
{
/* Don't do anything if interrupts not currently enabled or
higher priority exception was allready reported */
- if(mfspr(SPR_PICSR) && testsprbits (SPR_SR, SPR_SR_IEE) && !pending.valid)
+ if(mfspr(SPR_PICSR) && testsprbits (SPR_SR, SPR_SR_IEE))
except_handle(EXCEPT_INT, mfspr(SPR_EEAR_BASE));
}
--- cpu/or1k/sprs.c 2005-01-29 09:44:21.000000000 +0100
+++ ../or1ksim-ac/cpu/or1k/sprs.c 2005-01-29 09:44:56.000000000 +0100
@@ -68,8 +68,6 @@
{
extern int delay_insn;
- clear_pending_exception ();
-
/* The debugger has redirected us to a new address */
/* This is usually done to reissue an instruction
which just caused a breakpoint exception. */
--- cpu/or32/insnset.c 2005-01-29 09:44:21.000000000 +0100
+++ ../or1ksim-ac/cpu/or32/insnset.c 2005-01-29 17:11:02.000000000 +0100
@@ -97,7 +97,7 @@
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem32(PARAM1, &breakpoint);
/* If eval operand produced exception don't set anything */
- if (!pending.valid)
+ if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_lbs) {
@@ -105,7 +105,7 @@
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem8(PARAM1, &breakpoint);
/* If eval opreand produced exception don't set anything */
- if (!pending.valid)
+ if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_lbz) {
@@ -113,7 +113,7 @@
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem8(PARAM1, &breakpoint);
/* If eval opreand produced exception don't set anything */
- if (!pending.valid)
+ if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_lhs) {
@@ -121,7 +121,7 @@
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem16(PARAM1, &breakpoint);
/* If eval opreand produced exception don't set anything */
- if (!pending.valid)
+ if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_lhz) {
@@ -129,7 +129,7 @@
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem16(PARAM1, &breakpoint);
/* If eval opreand produced exception don't set anything */
- if (!pending.valid)
+ if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_movhi) {
--- cache/dcache_model.c 2005-01-28 21:37:25.000000000 +0100
+++ ../or1ksim-ac/cache/dcache_model.c 2005-01-28 16:32:44.000000000 +0100
@@ -107,9 +107,7 @@
dataaddr);
except_handle(EXCEPT_BUSERR, cur_vadd);
return 0;
- }
-
- if (!pending.valid && cur_area->log)
+ } else if (cur_area->log)
fprintf (cur_area->log, "[%"PRIxADDR"] -> read %08"PRIx32"\n", dataaddr,
tmp);
@@ -169,8 +167,7 @@
dataaddr);
except_handle(EXCEPT_BUSERR, cur_vadd);
return 0;
- }
- if (!pending.valid && cur_area->log)
+ } else if (cur_area->log)
fprintf (cur_area->log, "[%"PRIxADDR"] -> read %08"PRIx32"\n", dataaddr,
tmp);
}
--- cache/icache_model.c 2005-01-28 21:37:25.000000000 +0100
+++ ../or1ksim-ac/cache/icache_model.c 2005-01-28 16:32:13.000000000 +0100
@@ -94,8 +94,7 @@
fetchaddr);
except_handle(EXCEPT_BUSERR, cur_vadd);
return 0;
- }
- if (!pending.valid && cur_area->log)
+ } else if (cur_area->log)
fprintf (cur_area->log, "[%"PRIxADDR"] -> read %08"PRIx32"\n", fetchaddr,
tmp);
return tmp;
@@ -144,8 +143,7 @@
fetchaddr);
except_handle(EXCEPT_BUSERR, cur_vadd);
return 0;
- }
- if (!pending.valid && cur_area->log)
+ } else if (cur_area->log)
fprintf (cur_area->log, "[%"PRIxADDR"] -> read %08"PRIx32"\n",
fetchaddr, tmp);
}
|
 |