LOGIN   :::   RECOVER PASS   :::   GET ACCOUNT    
Browse
  • Projects
  • Code (CVS)
  • Forums
  • News
  • Articles
  • Polls
  •  
    OpenCores
  • FAQ
  • CVS HowTo
  • Mission
  • Media
  • Tools
  • Advertise
  • Mirrors
  • Logos
  • Contact us
  • Find Resources
  • Job Opportunity
  •  
    Tools
  • Search
      
  • Download Cores (CVSGet)
  •  
    More
  • Wishbone
  • Perlilog
  • EDA tools
  • OpenTech CD
  •  
    Navigation: All forums > Openrisc > Message List > Message Post

    Message

    Reply | Reply all
    Date Prev | Date Next | Thread Prev | Thread Next Date Index | Thread Index

    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
    Top
    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); }

     
    Copyright (c) 1999 OPENCORES.ORG. All rights reserved.