OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [or1ksim/] [cpu/] [or1k/] [except.c] - Blame information for rev 1525

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 33 lampret
/* except.c -- Simulation of OR1K exceptions
2
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
3
 
4
This file is part of OpenRISC 1000 Architectural Simulator.
5
 
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
10
 
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
GNU General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
 
20
#include <stdlib.h>
21
#include <stdio.h>
22
#include <string.h>
23
 
24 1350 nogj
#include "config.h"
25
 
26
#ifdef HAVE_INTTYPES_H
27
#include <inttypes.h>
28
#endif
29
 
30
#include "port.h"
31
#include "arch.h"
32 33 lampret
#include "abstract.h"
33
#include "except.h"
34 344 markom
#include "sim-config.h"
35 1308 phoenix
#include "debug_unit.h"
36 1432 nogj
#include "opcode/or32.h"
37
#include "spr_defs.h"
38 1350 nogj
#include "execute.h"
39 1432 nogj
#include "sprs.h"
40 1510 nogj
#include "debug.h"
41 33 lampret
 
42 1452 nogj
#if DYNAMIC_EXECUTION
43
#include "sched.h"
44
#include "rec_i386.h"
45
#include "op_support.h"
46
#endif
47
 
48 1510 nogj
DEFAULT_DEBUG_CHANNEL(except);
49 82 lampret
 
50 1386 nogj
int except_pending = 0;
51 139 chris
 
52 1386 nogj
static const char *except_names[] = {
53
 NULL,
54
 "Reset",
55
 "Bus Error",
56
 "Data Page Fault",
57
 "Insn Page Fault",
58
 "Tick timer",
59
 "Alignment",
60
 "Illegal instruction",
61
 "Interrupt",
62
 "Data TLB Miss",
63
 "Insn TLB Miss",
64
 "Range",
65
 "System Call",
66
 "Trap" };
67
 
68 1452 nogj
const char *except_name(oraddr_t except)
69 139 chris
{
70 1386 nogj
  return except_names[except >> 8];
71 139 chris
}
72
 
73 1452 nogj
#if DYNAMIC_EXECUTION
74
/* FIXME: Remove the need for this */
75
/* This is needed because immu_translate can be called from do_rfe and do_jump
76
 * in which case the scheduler does not need to get run. immu_translate can also
77
 * be called from mtspr in which case the exceptions that it generates happen
78
 * during an instruction and the scheduler needs to get run. */
79
int immu_ex_from_insn = 0;
80
#endif
81
 
82 479 markom
/* Asserts OR1K exception. */
83 1473 nogj
/* WARNING: Don't excpect except_handle to return.  Sometimes it _may_ return at
84
 * other times it may not. */
85 1350 nogj
void except_handle(oraddr_t except, oraddr_t ea)
86 33 lampret
{
87 1452 nogj
  oraddr_t except_vector;
88
 
89 1386 nogj
  if(debug_ignore_exception (except))
90
    return;
91 139 chris
 
92 1452 nogj
#if !(DYNAMIC_EXECUTION)
93
  /* In the dynamic recompiler, this function never returns, so this is not
94
   * needed.  Ofcourse we could set it anyway, but then all code that checks
95
   * this variable would break, since it is never reset */
96 1386 nogj
  except_pending = 1;
97 1452 nogj
#endif
98 51 lampret
 
99 1510 nogj
  TRACE("Exception 0x%"PRIxADDR" (%s) at 0x%"PRIxADDR", EA: 0x%"PRIxADDR
100
        ", cycles %lld, #%lld\n",
101
        except, except_name(except), cpu_state.pc, ea, runtime.sim.cycles,
102
        runtime.cpu.instructions);
103 1386 nogj
 
104 1506 nogj
  except_vector = except + (cpu_state.sprs[SPR_SR] & SPR_SR_EPH ? 0xf0000000 : 0x00000000);
105 1386 nogj
 
106 1452 nogj
#if !(DYNAMIC_EXECUTION)
107
  pcnext = except_vector;
108
#endif
109
 
110 1442 nogj
  cpu_state.sprs[SPR_EEAR_BASE] =  ea;
111
  cpu_state.sprs[SPR_ESR_BASE] = cpu_state.sprs[SPR_SR];
112
 
113
  cpu_state.sprs[SPR_SR] &= ~SPR_SR_OVE;   /* Disable overflow flag exception. */
114
 
115
  cpu_state.sprs[SPR_SR] |= SPR_SR_SM;    /* SUPV mode */
116
  cpu_state.sprs[SPR_SR] &= ~(SPR_SR_IEE | SPR_SR_TEE);   /* Disable interrupts. */
117
 
118
  /* Address translation is always disabled when starting exception. */
119
  cpu_state.sprs[SPR_SR] &= ~SPR_SR_DME;
120
 
121 1452 nogj
#if DYNAMIC_EXECUTION
122
  /* If we were called from do_scheduler and there were more jobs scheduled to
123
   * run after this, they won't run unless the following call is made since this
124
   * function never returns.  (If we weren't called from do_scheduler, then the
125
   * job at the head of the queue will still have some time remaining) */
126
  if(scheduler.job_queue->time <= 0)
127
    do_scheduler();
128
#endif
129
 
130 1386 nogj
  switch(except) {
131
  /* EPCR is irrelevent */
132
  case EXCEPT_RESET:
133
    break;
134
  /* EPCR is loaded with address of instruction that caused the exception */
135 1452 nogj
  case EXCEPT_ITLBMISS:
136
  case EXCEPT_IPF:
137
#if DYNAMIC_EXECUTION
138
    /* In immu_translate except_handle is called with except_handle(..., virtaddr) */
139
    /* Add the immu miss delay to the cycle counter */
140 1481 nogj
    if(!immu_ex_from_insn) {
141 1508 nogj
      cpu_state.sprs[SPR_EPCR_BASE] = get_pc() - (cpu_state.delay_insn ? 4 : 0);
142 1481 nogj
    } else
143 1452 nogj
      /* This exception came from an l.mtspr instruction in which case the pc
144
       * points to the l.mtspr instruction when in acutal fact, it is the next
145
       * instruction that would have faulted/missed.  ea is used instead of
146
       * cpu_state.pc + 4 because in the event that the l.mtspr instruction is
147
       * in the delay slot of a page local jump the fault must happen on the
148
       * instruction that was jumped to.  This is handled in recheck_immu. */
149 1508 nogj
      cpu_state.sprs[SPR_EPCR_BASE] = ea;
150 1481 nogj
    run_sched_out_of_line(immu_ex_from_insn);
151
    /* Save the registers that are in the temporaries */
152
    if(!cpu_state.ts_current)
153
      upd_reg_from_t(cpu_state.pc, !immu_ex_from_insn);
154
    immu_ex_from_insn = 0;
155
    break;
156 1452 nogj
#endif
157 1386 nogj
  /* All these exceptions happen during a simulated instruction */
158
  case EXCEPT_BUSERR:
159
  case EXCEPT_DPF:
160
  case EXCEPT_ALIGN:
161
  case EXCEPT_ILLEGAL:
162
  case EXCEPT_DTLBMISS:
163
  case EXCEPT_RANGE:
164
  case EXCEPT_TRAP:
165 1452 nogj
#if DYNAMIC_EXECUTION
166
    /* Since these exceptions happen during a simulated instruction and this
167
     * function jumps out to the exception vector the scheduler would never have
168
     * a chance to run, therefore run it now */
169
    run_sched_out_of_line(1);
170 1481 nogj
    /* Save the registers that are in the temporaries */
171
    if(!cpu_state.ts_current) {
172
      if(cpu_state.delay_insn &&
173 1525 nogj
         (IADDR_PAGE(cpu_state.pc) == IADDR_PAGE(cpu_state.pc - 4)))
174 1481 nogj
        upd_reg_from_t(cpu_state.pc - 4, 0);
175
      else
176
        upd_reg_from_t(cpu_state.pc, 0);
177
    }
178 1452 nogj
#endif
179 1508 nogj
    cpu_state.sprs[SPR_EPCR_BASE] = cpu_state.pc - (cpu_state.delay_insn ? 4 : 0);
180 1386 nogj
    break;
181
  /* EPCR is loaded with address of next not-yet-executed instruction */
182
  case EXCEPT_SYSCALL:
183 1508 nogj
    cpu_state.sprs[SPR_EPCR_BASE] = (cpu_state.pc + 4) - (cpu_state.delay_insn ? 4 : 0);
184 1386 nogj
    break;
185
  /* These exceptions happen AFTER (or before) an instruction has been
186
   * simulated, therefore the pc already points to the *next* instruction */
187
  case EXCEPT_TICK:
188
  case EXCEPT_INT:
189 1508 nogj
    cpu_state.sprs[SPR_EPCR_BASE] = cpu_state.pc - (cpu_state.delay_insn ? 4 : 0);
190 1452 nogj
#if !(DYNAMIC_EXECUTION)
191 1386 nogj
    /* If we don't update the pc now, then it will only happen *after* the next
192
     * instruction (There would be serious problems if the next instruction just
193
     * happens to be a branch), when it should happen NOW. */
194 1432 nogj
    cpu_state.pc = pcnext;
195 1386 nogj
    pcnext += 4;
196 1452 nogj
#else
197
    /* except_handle() mucks around with the temporaries, which are in the state
198
     * of the last instruction executed and not the next one, to which the pc
199
     * now points to */
200
    cpu_state.pc -= 4;
201 1481 nogj
 
202
    /* Save the registers that are in the temporaries */
203
    if(!cpu_state.ts_current)
204
      upd_reg_from_t(cpu_state.pc, 1);
205 1452 nogj
#endif
206 1386 nogj
    break;
207 479 markom
  }
208 693 markom
 
209 1452 nogj
  /* Address trnaslation is here because run_sched_out_of_line calls
210
   * eval_insn_direct which checks out the immu for the address translation but
211
   * if it would be disabled above then there would be not much point... */
212
  cpu_state.sprs[SPR_SR] &= ~SPR_SR_IME;
213
 
214
  /* Complex/simple execution strictly don't need this because of the
215
   * next_delay_insn thingy but in the dynamic execution modell that doesn't
216 1481 nogj
   * exist and thus cpu_state.delay_insn would stick in the exception handler
217 1452 nogj
   * causeing grief if the first instruction of the exception handler is also in
218
   * the delay slot of the previous instruction */
219 1432 nogj
  cpu_state.delay_insn = 0;
220 1452 nogj
 
221
#if DYNAMIC_EXECUTION
222
  cpu_state.pc = except_vector;
223
  cpu_state.ts_current = 0;
224
  jump_dyn_code(except_vector);
225
#endif
226 33 lampret
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.