cpu/
[deliverable/binutils-gdb.git] / sim / frv / interrupts.c
1 /* frv exception and interrupt support
2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3 Contributed by Red Hat.
4
5 This file is part of the GNU simulators.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 #define WANT_CPU frvbf
22 #define WANT_CPU_FRVBF
23
24 #include "sim-main.h"
25 #include "bfd.h"
26
27 /* FR-V Interrupt table.
28 Describes the interrupts supported by the FR-V.
29 This table *must* be maintained in order of interrupt priority as defined by
30 frv_interrupt_kind. */
31 #define DEFERRED 1
32 #define PRECISE 1
33 #define ITABLE_ENTRY(name, class, deferral, precision, offset) \
34 {FRV_##name, FRV_EC_##name, class, deferral, precision, offset}
35
36 struct frv_interrupt frv_interrupt_table[NUM_FRV_INTERRUPT_KINDS] =
37 {
38 /* External interrupts */
39 ITABLE_ENTRY(INTERRUPT_LEVEL_1, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x21),
40 ITABLE_ENTRY(INTERRUPT_LEVEL_2, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x22),
41 ITABLE_ENTRY(INTERRUPT_LEVEL_3, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x23),
42 ITABLE_ENTRY(INTERRUPT_LEVEL_4, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x24),
43 ITABLE_ENTRY(INTERRUPT_LEVEL_5, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x25),
44 ITABLE_ENTRY(INTERRUPT_LEVEL_6, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x26),
45 ITABLE_ENTRY(INTERRUPT_LEVEL_7, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x27),
46 ITABLE_ENTRY(INTERRUPT_LEVEL_8, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x28),
47 ITABLE_ENTRY(INTERRUPT_LEVEL_9, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x29),
48 ITABLE_ENTRY(INTERRUPT_LEVEL_10, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2a),
49 ITABLE_ENTRY(INTERRUPT_LEVEL_11, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2b),
50 ITABLE_ENTRY(INTERRUPT_LEVEL_12, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2c),
51 ITABLE_ENTRY(INTERRUPT_LEVEL_13, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2d),
52 ITABLE_ENTRY(INTERRUPT_LEVEL_14, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2e),
53 ITABLE_ENTRY(INTERRUPT_LEVEL_15, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2f),
54 /* Software interrupt */
55 ITABLE_ENTRY(TRAP_INSTRUCTION, FRV_SOFTWARE_INTERRUPT, !DEFERRED, !PRECISE, 0x80),
56 /* Program interrupts */
57 ITABLE_ENTRY(COMMIT_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x19),
58 ITABLE_ENTRY(DIVISION_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x17),
59 ITABLE_ENTRY(DATA_STORE_ERROR, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x14),
60 ITABLE_ENTRY(DATA_ACCESS_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x13),
61 ITABLE_ENTRY(DATA_ACCESS_MMU_MISS, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x12),
62 ITABLE_ENTRY(DATA_ACCESS_ERROR, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x11),
63 ITABLE_ENTRY(MP_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x0e),
64 ITABLE_ENTRY(FP_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x0d),
65 ITABLE_ENTRY(MEM_ADDRESS_NOT_ALIGNED, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x10),
66 ITABLE_ENTRY(REGISTER_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x08),
67 ITABLE_ENTRY(MP_DISABLED, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x0b),
68 ITABLE_ENTRY(FP_DISABLED, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x0a),
69 ITABLE_ENTRY(PRIVILEGED_INSTRUCTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x06),
70 ITABLE_ENTRY(ILLEGAL_INSTRUCTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x07),
71 ITABLE_ENTRY(INSTRUCTION_ACCESS_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x03),
72 ITABLE_ENTRY(INSTRUCTION_ACCESS_ERROR, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x02),
73 ITABLE_ENTRY(INSTRUCTION_ACCESS_MMU_MISS, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x01),
74 ITABLE_ENTRY(COMPOUND_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x20),
75 /* Break interrupt */
76 ITABLE_ENTRY(BREAK_EXCEPTION, FRV_BREAK_INTERRUPT, !DEFERRED, !PRECISE, 0xff),
77 /* Reset interrupt */
78 ITABLE_ENTRY(RESET, FRV_RESET_INTERRUPT, !DEFERRED, !PRECISE, 0x00)
79 };
80
81 /* The current interrupt state. */
82 struct frv_interrupt_state frv_interrupt_state;
83
84 /* maintain the address of the start of the previous VLIW insn sequence. */
85 IADDR previous_vliw_pc;
86
87 /* Add a break interrupt to the interrupt queue. */
88 struct frv_interrupt_queue_element *
89 frv_queue_break_interrupt (SIM_CPU *current_cpu)
90 {
91 return frv_queue_interrupt (current_cpu, FRV_BREAK_EXCEPTION);
92 }
93
94 /* Add a software interrupt to the interrupt queue. */
95 struct frv_interrupt_queue_element *
96 frv_queue_software_interrupt (SIM_CPU *current_cpu, SI offset)
97 {
98 struct frv_interrupt_queue_element *new_element
99 = frv_queue_interrupt (current_cpu, FRV_TRAP_INSTRUCTION);
100
101 struct frv_interrupt *interrupt = & frv_interrupt_table[new_element->kind];
102 interrupt->handler_offset = offset;
103
104 return new_element;
105 }
106
107 /* Add a program interrupt to the interrupt queue. */
108 struct frv_interrupt_queue_element *
109 frv_queue_program_interrupt (
110 SIM_CPU *current_cpu, enum frv_interrupt_kind kind
111 )
112 {
113 return frv_queue_interrupt (current_cpu, kind);
114 }
115
116 /* Add an external interrupt to the interrupt queue. */
117 struct frv_interrupt_queue_element *
118 frv_queue_external_interrupt (
119 SIM_CPU *current_cpu, enum frv_interrupt_kind kind
120 )
121 {
122 if (! GET_H_PSR_ET ()
123 || (kind != FRV_INTERRUPT_LEVEL_15 && kind < GET_H_PSR_PIL ()))
124 return NULL; /* Leave it for later. */
125
126 return frv_queue_interrupt (current_cpu, kind);
127 }
128
129 /* Add any interrupt to the interrupt queue. It will be added in reverse
130 priority order. This makes it easy to find the highest priority interrupt
131 at the end of the queue and to remove it after processing. */
132 struct frv_interrupt_queue_element *
133 frv_queue_interrupt (SIM_CPU *current_cpu, enum frv_interrupt_kind kind)
134 {
135 int i;
136 int j;
137 int limit = frv_interrupt_state.queue_index;
138 struct frv_interrupt_queue_element *new_element;
139 enum frv_interrupt_class iclass;
140
141 if (limit >= FRV_INTERRUPT_QUEUE_SIZE)
142 abort (); /* TODO: Make the queue dynamic */
143
144 /* Find the right place in the queue. */
145 for (i = 0; i < limit; ++i)
146 {
147 if (frv_interrupt_state.queue[i].kind >= kind)
148 break;
149 }
150
151 /* Don't queue two external interrupts of the same priority. */
152 iclass = frv_interrupt_table[kind].iclass;
153 if (i < limit && iclass == FRV_EXTERNAL_INTERRUPT)
154 {
155 if (frv_interrupt_state.queue[i].kind == kind)
156 return & frv_interrupt_state.queue[i];
157 }
158
159 /* Make room for the new interrupt in this spot. */
160 for (j = limit - 1; j >= i; --j)
161 frv_interrupt_state.queue[j + 1] = frv_interrupt_state.queue[j];
162
163 /* Add the new interrupt. */
164 frv_interrupt_state.queue_index++;
165 new_element = & frv_interrupt_state.queue[i];
166 new_element->kind = kind;
167 new_element->vpc = CPU_PC_GET (current_cpu);
168 new_element->u.data_written.length = 0;
169 frv_set_interrupt_queue_slot (current_cpu, new_element);
170
171 return new_element;
172 }
173
174 struct frv_interrupt_queue_element *
175 frv_queue_register_exception_interrupt (SIM_CPU *current_cpu, enum frv_rec rec)
176 {
177 struct frv_interrupt_queue_element *new_element =
178 frv_queue_program_interrupt (current_cpu, FRV_REGISTER_EXCEPTION);
179
180 new_element->u.rec = rec;
181
182 return new_element;
183 }
184
185 struct frv_interrupt_queue_element *
186 frv_queue_mem_address_not_aligned_interrupt (SIM_CPU *current_cpu, USI addr)
187 {
188 struct frv_interrupt_queue_element *new_element;
189 USI isr = GET_ISR ();
190
191 /* Make sure that this exception is not masked. */
192 if (GET_ISR_EMAM (isr))
193 return NULL;
194
195 /* Queue the interrupt. */
196 new_element = frv_queue_program_interrupt (current_cpu,
197 FRV_MEM_ADDRESS_NOT_ALIGNED);
198 new_element->eaddress = addr;
199 new_element->u.data_written = frv_interrupt_state.data_written;
200 frv_interrupt_state.data_written.length = 0;
201
202 return new_element;
203 }
204
205 struct frv_interrupt_queue_element *
206 frv_queue_data_access_error_interrupt (SIM_CPU *current_cpu, USI addr)
207 {
208 struct frv_interrupt_queue_element *new_element;
209 new_element = frv_queue_program_interrupt (current_cpu,
210 FRV_DATA_ACCESS_ERROR);
211 new_element->eaddress = addr;
212 return new_element;
213 }
214
215 struct frv_interrupt_queue_element *
216 frv_queue_data_access_exception_interrupt (SIM_CPU *current_cpu)
217 {
218 return frv_queue_program_interrupt (current_cpu, FRV_DATA_ACCESS_EXCEPTION);
219 }
220
221 struct frv_interrupt_queue_element *
222 frv_queue_instruction_access_error_interrupt (SIM_CPU *current_cpu)
223 {
224 return frv_queue_program_interrupt (current_cpu, FRV_INSTRUCTION_ACCESS_ERROR);
225 }
226
227 struct frv_interrupt_queue_element *
228 frv_queue_instruction_access_exception_interrupt (SIM_CPU *current_cpu)
229 {
230 return frv_queue_program_interrupt (current_cpu, FRV_INSTRUCTION_ACCESS_EXCEPTION);
231 }
232
233 struct frv_interrupt_queue_element *
234 frv_queue_illegal_instruction_interrupt (
235 SIM_CPU *current_cpu, const CGEN_INSN *insn
236 )
237 {
238 SIM_DESC sd = CPU_STATE (current_cpu);
239 switch (STATE_ARCHITECTURE (sd)->mach)
240 {
241 case bfd_mach_fr400:
242 case bfd_mach_fr550:
243 break;
244 default:
245 /* Some machines generate fp_exception for this case. */
246 if (frv_is_float_insn (insn) || frv_is_media_insn (insn))
247 {
248 struct frv_fp_exception_info fp_info = {
249 FSR_NO_EXCEPTION, FTT_SEQUENCE_ERROR
250 };
251 return frv_queue_fp_exception_interrupt (current_cpu, & fp_info);
252 }
253 break;
254 }
255
256 return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
257 }
258
259 struct frv_interrupt_queue_element *
260 frv_queue_privileged_instruction_interrupt (SIM_CPU *current_cpu, const CGEN_INSN *insn)
261 {
262 /* The fr550 has no privileged instruction interrupt. It uses
263 illegal_instruction. */
264 SIM_DESC sd = CPU_STATE (current_cpu);
265 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
266 return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
267
268 return frv_queue_program_interrupt (current_cpu, FRV_PRIVILEGED_INSTRUCTION);
269 }
270
271 struct frv_interrupt_queue_element *
272 frv_queue_float_disabled_interrupt (SIM_CPU *current_cpu)
273 {
274 /* The fr550 has no fp_disabled interrupt. It uses illegal_instruction. */
275 SIM_DESC sd = CPU_STATE (current_cpu);
276 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
277 return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
278
279 return frv_queue_program_interrupt (current_cpu, FRV_FP_DISABLED);
280 }
281
282 struct frv_interrupt_queue_element *
283 frv_queue_media_disabled_interrupt (SIM_CPU *current_cpu)
284 {
285 /* The fr550 has no mp_disabled interrupt. It uses illegal_instruction. */
286 SIM_DESC sd = CPU_STATE (current_cpu);
287 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
288 return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
289
290 return frv_queue_program_interrupt (current_cpu, FRV_MP_DISABLED);
291 }
292
293 struct frv_interrupt_queue_element *
294 frv_queue_non_implemented_instruction_interrupt (
295 SIM_CPU *current_cpu, const CGEN_INSN *insn
296 )
297 {
298 SIM_DESC sd = CPU_STATE (current_cpu);
299 switch (STATE_ARCHITECTURE (sd)->mach)
300 {
301 case bfd_mach_fr400:
302 case bfd_mach_fr550:
303 break;
304 default:
305 /* Some machines generate fp_exception or mp_exception for this case. */
306 if (frv_is_float_insn (insn))
307 {
308 struct frv_fp_exception_info fp_info = {
309 FSR_NO_EXCEPTION, FTT_UNIMPLEMENTED_FPOP
310 };
311 return frv_queue_fp_exception_interrupt (current_cpu, & fp_info);
312 }
313 if (frv_is_media_insn (insn))
314 {
315 frv_set_mp_exception_registers (current_cpu, MTT_UNIMPLEMENTED_MPOP,
316 0);
317 return NULL; /* no interrupt queued at this time. */
318 }
319 break;
320 }
321
322 return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
323 }
324
325 /* Queue the given fp_exception interrupt. Also update fp_info by removing
326 masked interrupts and updating the 'slot' flield. */
327 struct frv_interrupt_queue_element *
328 frv_queue_fp_exception_interrupt (
329 SIM_CPU *current_cpu, struct frv_fp_exception_info *fp_info
330 )
331 {
332 SI fsr0 = GET_FSR (0);
333 int tem = GET_FSR_TEM (fsr0);
334 int aexc = GET_FSR_AEXC (fsr0);
335 struct frv_interrupt_queue_element *new_element = NULL;
336
337 /* Update AEXC with the interrupts that are masked. */
338 aexc |= fp_info->fsr_mask & ~tem;
339 SET_FSR_AEXC (fsr0, aexc);
340 SET_FSR (0, fsr0);
341
342 /* update fsr_mask with the exceptions that are enabled. */
343 fp_info->fsr_mask &= tem;
344
345 /* If there is an unmasked interrupt then queue it, unless
346 this was a non-excepting insn, in which case simply set the NE
347 status registers. */
348 if (frv_interrupt_state.ne_index != NE_NOFLAG
349 && fp_info->fsr_mask != FSR_NO_EXCEPTION)
350 {
351 SET_NE_FLAG (frv_interrupt_state.f_ne_flags,
352 frv_interrupt_state.ne_index);
353 /* TODO -- Set NESR for chips which support it. */
354 new_element = NULL;
355 }
356 else if (fp_info->fsr_mask != FSR_NO_EXCEPTION
357 || fp_info->ftt == FTT_UNIMPLEMENTED_FPOP
358 || fp_info->ftt == FTT_SEQUENCE_ERROR
359 || fp_info->ftt == FTT_INVALID_FR)
360 {
361 new_element = frv_queue_program_interrupt (current_cpu, FRV_FP_EXCEPTION);
362 new_element->u.fp_info = *fp_info;
363 }
364
365 return new_element;
366 }
367
368 struct frv_interrupt_queue_element *
369 frv_queue_division_exception_interrupt (SIM_CPU *current_cpu, enum frv_dtt dtt)
370 {
371 struct frv_interrupt_queue_element *new_element =
372 frv_queue_program_interrupt (current_cpu, FRV_DIVISION_EXCEPTION);
373
374 new_element->u.dtt = dtt;
375
376 return new_element;
377 }
378
379 /* Check for interrupts caused by illegal insn access. These conditions are
380 checked in the order specified by the fr400 and fr500 LSI specs. */
381 void
382 frv_detect_insn_access_interrupts (SIM_CPU *current_cpu, SCACHE *sc)
383 {
384
385 const CGEN_INSN *insn = sc->argbuf.idesc->idata;
386 SIM_DESC sd = CPU_STATE (current_cpu);
387 FRV_VLIW *vliw = CPU_VLIW (current_cpu);
388
389 /* Check for vliw constraints. */
390 if (vliw->constraint_violation)
391 frv_queue_illegal_instruction_interrupt (current_cpu, insn);
392 /* Check for non-excepting insns. */
393 else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_NON_EXCEPTING)
394 && ! GET_H_PSR_NEM ())
395 frv_queue_non_implemented_instruction_interrupt (current_cpu, insn);
396 /* Check for conditional insns. */
397 else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONDITIONAL)
398 && ! GET_H_PSR_CM ())
399 frv_queue_non_implemented_instruction_interrupt (current_cpu, insn);
400 /* Make sure floating point support is enabled. */
401 else if (! GET_H_PSR_EF ())
402 {
403 /* Generate fp_disabled if it is a floating point insn or if PSR.EM is
404 off and the insns accesses a fp register. */
405 if (frv_is_float_insn (insn)
406 || (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR_ACCESS)
407 && ! GET_H_PSR_EM ()))
408 frv_queue_float_disabled_interrupt (current_cpu);
409 }
410 /* Make sure media support is enabled. */
411 else if (! GET_H_PSR_EM ())
412 {
413 /* Generate mp_disabled if it is a media insn. */
414 if (frv_is_media_insn (insn) || CGEN_INSN_NUM (insn) == FRV_INSN_MTRAP)
415 frv_queue_media_disabled_interrupt (current_cpu);
416 }
417 /* Check for privileged insns. */
418 else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_PRIVILEGED) &&
419 ! GET_H_PSR_S ())
420 frv_queue_privileged_instruction_interrupt (current_cpu, insn);
421 #if 0 /* disable for now until we find out how FSR0.QNE gets reset. */
422 else
423 {
424 /* Enter the halt state if FSR0.QNE is set and we are executing a
425 floating point insn, a media insn or an insn which access a FR
426 register. */
427 SI fsr0 = GET_FSR (0);
428 if (GET_FSR_QNE (fsr0)
429 && (frv_is_float_insn (insn) || frv_is_media_insn (insn)
430 || CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR_ACCESS)))
431 {
432 sim_engine_halt (sd, current_cpu, NULL, GET_H_PC (), sim_stopped,
433 SIM_SIGINT);
434 }
435 }
436 #endif
437 }
438
439 /* Record the current VLIW slot in the given interrupt queue element. */
440 void
441 frv_set_interrupt_queue_slot (
442 SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
443 )
444 {
445 FRV_VLIW *vliw = CPU_VLIW (current_cpu);
446 int slot = vliw->next_slot - 1;
447 item->slot = (*vliw->current_vliw)[slot];
448 }
449
450 /* Handle an individual interrupt. */
451 static void
452 handle_interrupt (SIM_CPU *current_cpu, IADDR pc)
453 {
454 struct frv_interrupt *interrupt;
455 int writeback_done = 0;
456 while (1)
457 {
458 /* Interrupts are queued in priority order with the highest priority
459 last. */
460 int index = frv_interrupt_state.queue_index - 1;
461 struct frv_interrupt_queue_element *item
462 = & frv_interrupt_state.queue[index];
463 interrupt = & frv_interrupt_table[item->kind];
464
465 switch (interrupt->iclass)
466 {
467 case FRV_EXTERNAL_INTERRUPT:
468 /* Perform writeback first. This may cause a higher priority
469 interrupt. */
470 if (! writeback_done)
471 {
472 frvbf_perform_writeback (current_cpu);
473 writeback_done = 1;
474 continue;
475 }
476 frv_external_interrupt (current_cpu, item, pc);
477 return;
478 case FRV_SOFTWARE_INTERRUPT:
479 frv_interrupt_state.queue_index = index;
480 frv_software_interrupt (current_cpu, item, pc);
481 return;
482 case FRV_PROGRAM_INTERRUPT:
483 /* If the program interrupt is not strict (imprecise), then perform
484 writeback first. This may, in turn, cause a higher priority
485 interrupt. */
486 if (! interrupt->precise && ! writeback_done)
487 {
488 frv_interrupt_state.imprecise_interrupt = item;
489 frvbf_perform_writeback (current_cpu);
490 writeback_done = 1;
491 continue;
492 }
493 frv_interrupt_state.queue_index = index;
494 frv_program_interrupt (current_cpu, item, pc);
495 return;
496 case FRV_BREAK_INTERRUPT:
497 frv_interrupt_state.queue_index = index;
498 frv_break_interrupt (current_cpu, interrupt, pc);
499 return;
500 case FRV_RESET_INTERRUPT:
501 break;
502 default:
503 break;
504 }
505 frv_interrupt_state.queue_index = index;
506 break; /* out of loop. */
507 }
508
509 /* We should never get here. */
510 {
511 SIM_DESC sd = CPU_STATE (current_cpu);
512 sim_engine_abort (sd, current_cpu, pc,
513 "interrupt class not supported %d\n",
514 interrupt->iclass);
515 }
516 }
517
518 /* Check to see the if the RSTR.HR or RSTR.SR bits have been set. If so, handle
519 the appropriate reset interrupt. */
520 static int
521 check_reset (SIM_CPU *current_cpu, IADDR pc)
522 {
523 int hsr0;
524 int hr;
525 int sr;
526 SI rstr;
527 FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
528 IADDR address = RSTR_ADDRESS;
529
530 /* We don't want this to show up in the cache statistics, so read the
531 cache passively. */
532 if (! frv_cache_read_passive_SI (cache, address, & rstr))
533 rstr = sim_core_read_unaligned_4 (current_cpu, pc, read_map, address);
534
535 hr = GET_RSTR_HR (rstr);
536 sr = GET_RSTR_SR (rstr);
537
538 if (! hr && ! sr)
539 return 0; /* no reset. */
540
541 /* Reinitialize the machine state. */
542 if (hr)
543 frv_hardware_reset (current_cpu);
544 else
545 frv_software_reset (current_cpu);
546
547 /* Branch to the reset address. */
548 hsr0 = GET_HSR0 ();
549 if (GET_HSR0_SA (hsr0))
550 SET_H_PC (0xff000000);
551 else
552 SET_H_PC (0);
553
554 return 1; /* reset */
555 }
556
557 /* Process any pending interrupt(s) after a group of parallel insns. */
558 void
559 frv_process_interrupts (SIM_CPU *current_cpu)
560 {
561 SI NE_flags[2];
562 /* Need to save the pc here because writeback may change it (due to a
563 branch). */
564 IADDR pc = CPU_PC_GET (current_cpu);
565
566 /* Check for a reset before anything else. */
567 if (check_reset (current_cpu, pc))
568 return;
569
570 /* First queue the writes for any accumulated NE flags. */
571 if (frv_interrupt_state.f_ne_flags[0] != 0
572 || frv_interrupt_state.f_ne_flags[1] != 0)
573 {
574 GET_NE_FLAGS (NE_flags, H_SPR_FNER0);
575 NE_flags[0] |= frv_interrupt_state.f_ne_flags[0];
576 NE_flags[1] |= frv_interrupt_state.f_ne_flags[1];
577 SET_NE_FLAGS (H_SPR_FNER0, NE_flags);
578 }
579
580 /* If there is no interrupt pending, then perform parallel writeback. This
581 may cause an interrupt. */
582 if (frv_interrupt_state.queue_index <= 0)
583 frvbf_perform_writeback (current_cpu);
584
585 /* If there is an interrupt pending, then process it. */
586 if (frv_interrupt_state.queue_index > 0)
587 handle_interrupt (current_cpu, pc);
588 }
589
590 /* Find the next available ESR and return its index */
591 static int
592 esr_for_data_access_exception (
593 SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
594 )
595 {
596 SIM_DESC sd = CPU_STATE (current_cpu);
597 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
598 return 8; /* Use ESR8, EPCR8. */
599
600 if (item->slot == UNIT_I0)
601 return 8; /* Use ESR8, EPCR8, EAR8, EDR8. */
602
603 return 9; /* Use ESR9, EPCR9, EAR9. */
604 }
605
606 /* Set the next available EDR register with the data which was to be stored
607 and return the index of the register. */
608 static int
609 set_edr_register (
610 SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, int edr_index
611 )
612 {
613 /* EDR0, EDR4 and EDR8 are available as blocks of 4.
614 SI data uses EDR3, EDR7 and EDR11
615 DI data uses EDR2, EDR6 and EDR10
616 XI data uses EDR0, EDR4 and EDR8. */
617 int i;
618 edr_index += 4 - item->u.data_written.length;
619 for (i = 0; i < item->u.data_written.length; ++i)
620 SET_EDR (edr_index + i, item->u.data_written.words[i]);
621
622 return edr_index;
623 };
624
625 /* Clear ESFR0, EPCRx, ESRx, EARx and EDRx. */
626 static void
627 clear_exception_status_registers (SIM_CPU *current_cpu)
628 {
629 int i;
630 /* It is only necessary to clear the flag bits indicating which registers
631 are valid. */
632 SET_ESFR (0, 0);
633 SET_ESFR (1, 0);
634
635 for (i = 0; i <= 2; ++i)
636 {
637 SI esr = GET_ESR (i);
638 CLEAR_ESR_VALID (esr);
639 SET_ESR (i, esr);
640 }
641 for (i = 8; i <= 15; ++i)
642 {
643 SI esr = GET_ESR (i);
644 CLEAR_ESR_VALID (esr);
645 SET_ESR (i, esr);
646 }
647 }
648
649 /* Record state for media exception. */
650 void
651 frv_set_mp_exception_registers (
652 SIM_CPU *current_cpu, enum frv_msr_mtt mtt, int sie
653 )
654 {
655 /* Record the interrupt factor in MSR0. */
656 SI msr0 = GET_MSR (0);
657 if (GET_MSR_MTT (msr0) == MTT_NONE)
658 SET_MSR_MTT (msr0, mtt);
659
660 /* Also set the OVF bit in the appropriate MSR as well as MSR0.AOVF. */
661 if (mtt == MTT_OVERFLOW)
662 {
663 FRV_VLIW *vliw = CPU_VLIW (current_cpu);
664 int slot = vliw->next_slot - 1;
665 SIM_DESC sd = CPU_STATE (current_cpu);
666
667 /* If this insn is in the M2 slot, then set MSR1.OVF and MSR1.SIE,
668 otherwise set MSR0.OVF and MSR0.SIE. */
669 if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550 && (*vliw->current_vliw)[slot] == UNIT_FM1)
670 {
671 SI msr = GET_MSR (1);
672 OR_MSR_SIE (msr, sie);
673 SET_MSR_OVF (msr);
674 SET_MSR (1, msr);
675 }
676 else
677 {
678 OR_MSR_SIE (msr0, sie);
679 SET_MSR_OVF (msr0);
680 }
681
682 /* Generate the interrupt now if MSR0.MPEM is set on fr550 */
683 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550 && GET_MSR_MPEM (msr0))
684 frv_queue_program_interrupt (current_cpu, FRV_MP_EXCEPTION);
685 else
686 {
687 /* Regardless of the slot, set MSR0.AOVF. */
688 SET_MSR_AOVF (msr0);
689 }
690 }
691
692 SET_MSR (0, msr0);
693 }
694
695 /* Determine the correct FQ register to use for the given exception.
696 Return -1 if a register is not available. */
697 static int
698 fq_for_exception (
699 SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
700 )
701 {
702 SI fq;
703 struct frv_fp_exception_info *fp_info = & item->u.fp_info;
704
705 /* For fp_exception overflow, underflow or inexact, use FQ0 or FQ1. */
706 if (fp_info->ftt == FTT_IEEE_754_EXCEPTION
707 && (fp_info->fsr_mask & (FSR_OVERFLOW | FSR_UNDERFLOW | FSR_INEXACT)))
708 {
709 fq = GET_FQ (0);
710 if (! GET_FQ_VALID (fq))
711 return 0; /* FQ0 is available. */
712 fq = GET_FQ (1);
713 if (! GET_FQ_VALID (fq))
714 return 1; /* FQ1 is available. */
715
716 /* No FQ register is available */
717 {
718 SIM_DESC sd = CPU_STATE (current_cpu);
719 IADDR pc = CPU_PC_GET (current_cpu);
720 sim_engine_abort (sd, current_cpu, pc, "No FQ register available\n");
721 }
722 return -1;
723 }
724 /* For other exceptions, use FQ2 if the insn was in slot F0/I0 and FQ3
725 otherwise. */
726 if (item->slot == UNIT_FM0 || item->slot == UNIT_I0)
727 return 2;
728
729 return 3;
730 }
731
732 /* Set FSR0, FQ0-FQ9, depending on the interrupt. */
733 static void
734 set_fp_exception_registers (
735 SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
736 )
737 {
738 int fq_index;
739 SI fq;
740 SI insn;
741 SI fsr0;
742 IADDR pc;
743 struct frv_fp_exception_info *fp_info;
744 SIM_DESC sd = CPU_STATE (current_cpu);
745
746 /* No FQ registers on fr550 */
747 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
748 {
749 /* Update the fsr. */
750 fp_info = & item->u.fp_info;
751 fsr0 = GET_FSR (0);
752 SET_FSR_FTT (fsr0, fp_info->ftt);
753 SET_FSR (0, fsr0);
754 return;
755 }
756
757 /* Select an FQ and update it with the exception information. */
758 fq_index = fq_for_exception (current_cpu, item);
759 if (fq_index == -1)
760 return;
761
762 fp_info = & item->u.fp_info;
763 fq = GET_FQ (fq_index);
764 SET_FQ_MIV (fq, MIV_FLOAT);
765 SET_FQ_SIE (fq, SIE_NIL);
766 SET_FQ_FTT (fq, fp_info->ftt);
767 SET_FQ_CEXC (fq, fp_info->fsr_mask);
768 SET_FQ_VALID (fq);
769 SET_FQ (fq_index, fq);
770
771 /* Write the failing insn into FQx.OPC. */
772 pc = item->vpc;
773 insn = GETMEMSI (current_cpu, pc, pc);
774 SET_FQ_OPC (fq_index, insn);
775
776 /* Update the fsr. */
777 fsr0 = GET_FSR (0);
778 SET_FSR_QNE (fsr0); /* FQ not empty */
779 SET_FSR_FTT (fsr0, fp_info->ftt);
780 SET_FSR (0, fsr0);
781 }
782
783 /* Record the state of a division exception in the ISR. */
784 static void
785 set_isr_exception_fields (
786 SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
787 )
788 {
789 USI isr = GET_ISR ();
790 int dtt = GET_ISR_DTT (isr);
791 dtt |= item->u.dtt;
792 SET_ISR_DTT (isr, dtt);
793 SET_ISR (isr);
794 }
795
796 /* Set ESFR0, EPCRx, ESRx, EARx and EDRx, according to the given program
797 interrupt. */
798 static void
799 set_exception_status_registers (
800 SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
801 )
802 {
803 struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind];
804 int slot = (item->vpc - previous_vliw_pc) / 4;
805 int reg_index = -1;
806 int set_ear = 0;
807 int set_edr = 0;
808 int set_daec = 0;
809 int set_epcr = 0;
810 SI esr = 0;
811 SIM_DESC sd = CPU_STATE (current_cpu);
812
813 /* If the interrupt is strict (precise) or the interrupt is on the insns
814 in the I0 pipe, then set the 0 registers. */
815 if (interrupt->precise)
816 {
817 reg_index = 0;
818 if (interrupt->kind == FRV_REGISTER_EXCEPTION)
819 SET_ESR_REC (esr, item->u.rec);
820 else if (interrupt->kind == FRV_INSTRUCTION_ACCESS_EXCEPTION)
821 SET_ESR_IAEC (esr, item->u.iaec);
822 /* For fr550, don't set epcr for precise interrupts. */
823 if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550)
824 set_epcr = 1;
825 }
826 else
827 {
828 switch (interrupt->kind)
829 {
830 case FRV_DIVISION_EXCEPTION:
831 set_isr_exception_fields (current_cpu, item);
832 /* fall thru to set reg_index. */
833 case FRV_COMMIT_EXCEPTION:
834 /* For fr550, always use ESR0. */
835 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
836 reg_index = 0;
837 else if (item->slot == UNIT_I0)
838 reg_index = 0;
839 else if (item->slot == UNIT_I1)
840 reg_index = 1;
841 set_epcr = 1;
842 break;
843 case FRV_DATA_STORE_ERROR:
844 reg_index = 14; /* Use ESR14. */
845 break;
846 case FRV_DATA_ACCESS_ERROR:
847 reg_index = 15; /* Use ESR15, EPCR15. */
848 set_ear = 1;
849 break;
850 case FRV_DATA_ACCESS_EXCEPTION:
851 set_daec = 1;
852 /* fall through */
853 case FRV_DATA_ACCESS_MMU_MISS:
854 case FRV_MEM_ADDRESS_NOT_ALIGNED:
855 /* Get the appropriate ESR, EPCR, EAR and EDR.
856 EAR will be set. EDR will not be set if this is a store insn. */
857 set_ear = 1;
858 /* For fr550, never use EDRx. */
859 if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550)
860 if (item->u.data_written.length != 0)
861 set_edr = 1;
862 reg_index = esr_for_data_access_exception (current_cpu, item);
863 set_epcr = 1;
864 break;
865 case FRV_MP_EXCEPTION:
866 /* For fr550, use EPCR2 and ESR2. */
867 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
868 {
869 reg_index = 2;
870 set_epcr = 1;
871 }
872 break; /* MSR0-1, FQ0-9 are already set. */
873 case FRV_FP_EXCEPTION:
874 set_fp_exception_registers (current_cpu, item);
875 /* For fr550, use EPCR2 and ESR2. */
876 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
877 {
878 reg_index = 2;
879 set_epcr = 1;
880 }
881 break;
882 default:
883 {
884 SIM_DESC sd = CPU_STATE (current_cpu);
885 IADDR pc = CPU_PC_GET (current_cpu);
886 sim_engine_abort (sd, current_cpu, pc,
887 "invalid non-strict program interrupt kind: %d\n",
888 interrupt->kind);
889 break;
890 }
891 }
892 } /* non-strict (imprecise) interrupt */
893
894 /* Now fill in the selected exception status registers. */
895 if (reg_index != -1)
896 {
897 /* Now set the exception status registers. */
898 SET_ESFR_FLAG (reg_index);
899 SET_ESR_EC (esr, interrupt->ec);
900
901 if (set_epcr)
902 {
903 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400)
904 SET_EPCR (reg_index, previous_vliw_pc);
905 else
906 SET_EPCR (reg_index, item->vpc);
907 }
908
909 if (set_ear)
910 {
911 SET_EAR (reg_index, item->eaddress);
912 SET_ESR_EAV (esr);
913 }
914 else
915 CLEAR_ESR_EAV (esr);
916
917 if (set_edr)
918 {
919 int edn = set_edr_register (current_cpu, item, 0/* EDR0-3 */);
920 SET_ESR_EDN (esr, edn);
921 SET_ESR_EDV (esr);
922 }
923 else
924 CLEAR_ESR_EDV (esr);
925
926 if (set_daec)
927 SET_ESR_DAEC (esr, item->u.daec);
928
929 SET_ESR_VALID (esr);
930 SET_ESR (reg_index, esr);
931 }
932 }
933
934 /* Check for compound interrupts.
935 Returns NULL if no interrupt is to be processed. */
936 static struct frv_interrupt *
937 check_for_compound_interrupt (
938 SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
939 )
940 {
941 struct frv_interrupt *interrupt;
942
943 /* Set the exception status registers for the original interrupt. */
944 set_exception_status_registers (current_cpu, item);
945 interrupt = & frv_interrupt_table[item->kind];
946
947 if (! interrupt->precise)
948 {
949 IADDR vpc = 0;
950 int mask = 0;
951
952 vpc = item->vpc;
953 mask = (1 << item->kind);
954
955 /* Look for more queued program interrupts which are non-deferred
956 (pending inhibit), imprecise (non-strict) different than an interrupt
957 already found and caused by a different insn. A bit mask is used
958 to keep track of interrupts which have already been detected. */
959 while (item != frv_interrupt_state.queue)
960 {
961 enum frv_interrupt_kind kind;
962 struct frv_interrupt *next_interrupt;
963 --item;
964 kind = item->kind;
965 next_interrupt = & frv_interrupt_table[kind];
966
967 if (next_interrupt->iclass != FRV_PROGRAM_INTERRUPT)
968 break; /* no program interrupts left. */
969
970 if (item->vpc == vpc)
971 continue; /* caused by the same insn. */
972
973 vpc = item->vpc;
974 if (! next_interrupt->precise && ! next_interrupt->deferred)
975 {
976 if (! (mask & (1 << kind)))
977 {
978 /* Set the exception status registers for the additional
979 interrupt. */
980 set_exception_status_registers (current_cpu, item);
981 mask |= (1 << kind);
982 interrupt = & frv_interrupt_table[FRV_COMPOUND_EXCEPTION];
983 }
984 }
985 }
986 }
987
988 /* Return with either the original interrupt, a compound_exception,
989 or no exception. */
990 return interrupt;
991 }
992
993 /* Handle a program interrupt. */
994 void
995 frv_program_interrupt (
996 SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc
997 )
998 {
999 struct frv_interrupt *interrupt;
1000
1001 clear_exception_status_registers (current_cpu);
1002 /* If two or more non-deferred imprecise (non-strict) interrupts occur
1003 on two or more insns, then generate a compound_exception. */
1004 interrupt = check_for_compound_interrupt (current_cpu, item);
1005 if (interrupt != NULL)
1006 {
1007 frv_program_or_software_interrupt (current_cpu, interrupt, pc);
1008 frv_clear_interrupt_classes (FRV_SOFTWARE_INTERRUPT,
1009 FRV_PROGRAM_INTERRUPT);
1010 }
1011 }
1012
1013 /* Handle a software interrupt. */
1014 void
1015 frv_software_interrupt (
1016 SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc
1017 )
1018 {
1019 struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind];
1020 frv_program_or_software_interrupt (current_cpu, interrupt, pc);
1021 }
1022
1023 /* Handle a program interrupt or a software interrupt in non-operating mode. */
1024 void
1025 frv_non_operating_interrupt (
1026 SIM_CPU *current_cpu, enum frv_interrupt_kind kind, IADDR pc
1027 )
1028 {
1029 SIM_DESC sd = CPU_STATE (current_cpu);
1030 switch (kind)
1031 {
1032 case FRV_INTERRUPT_LEVEL_1:
1033 case FRV_INTERRUPT_LEVEL_2:
1034 case FRV_INTERRUPT_LEVEL_3:
1035 case FRV_INTERRUPT_LEVEL_4:
1036 case FRV_INTERRUPT_LEVEL_5:
1037 case FRV_INTERRUPT_LEVEL_6:
1038 case FRV_INTERRUPT_LEVEL_7:
1039 case FRV_INTERRUPT_LEVEL_8:
1040 case FRV_INTERRUPT_LEVEL_9:
1041 case FRV_INTERRUPT_LEVEL_10:
1042 case FRV_INTERRUPT_LEVEL_11:
1043 case FRV_INTERRUPT_LEVEL_12:
1044 case FRV_INTERRUPT_LEVEL_13:
1045 case FRV_INTERRUPT_LEVEL_14:
1046 case FRV_INTERRUPT_LEVEL_15:
1047 sim_engine_abort (sd, current_cpu, pc,
1048 "interrupt: external %d\n", kind + 1);
1049 break;
1050 case FRV_TRAP_INSTRUCTION:
1051 break; /* handle as in operating mode. */
1052 case FRV_COMMIT_EXCEPTION:
1053 sim_engine_abort (sd, current_cpu, pc,
1054 "interrupt: commit_exception\n");
1055 break;
1056 case FRV_DIVISION_EXCEPTION:
1057 sim_engine_abort (sd, current_cpu, pc,
1058 "interrupt: division_exception\n");
1059 break;
1060 case FRV_DATA_STORE_ERROR:
1061 sim_engine_abort (sd, current_cpu, pc,
1062 "interrupt: data_store_error\n");
1063 break;
1064 case FRV_DATA_ACCESS_EXCEPTION:
1065 sim_engine_abort (sd, current_cpu, pc,
1066 "interrupt: data_access_exception\n");
1067 break;
1068 case FRV_DATA_ACCESS_MMU_MISS:
1069 sim_engine_abort (sd, current_cpu, pc,
1070 "interrupt: data_access_mmu_miss\n");
1071 break;
1072 case FRV_DATA_ACCESS_ERROR:
1073 sim_engine_abort (sd, current_cpu, pc,
1074 "interrupt: data_access_error\n");
1075 break;
1076 case FRV_MP_EXCEPTION:
1077 sim_engine_abort (sd, current_cpu, pc,
1078 "interrupt: mp_exception\n");
1079 break;
1080 case FRV_FP_EXCEPTION:
1081 sim_engine_abort (sd, current_cpu, pc,
1082 "interrupt: fp_exception\n");
1083 break;
1084 case FRV_MEM_ADDRESS_NOT_ALIGNED:
1085 sim_engine_abort (sd, current_cpu, pc,
1086 "interrupt: mem_address_not_aligned\n");
1087 break;
1088 case FRV_REGISTER_EXCEPTION:
1089 sim_engine_abort (sd, current_cpu, pc,
1090 "interrupt: register_exception\n");
1091 break;
1092 case FRV_MP_DISABLED:
1093 sim_engine_abort (sd, current_cpu, pc,
1094 "interrupt: mp_disabled\n");
1095 break;
1096 case FRV_FP_DISABLED:
1097 sim_engine_abort (sd, current_cpu, pc,
1098 "interrupt: fp_disabled\n");
1099 break;
1100 case FRV_PRIVILEGED_INSTRUCTION:
1101 sim_engine_abort (sd, current_cpu, pc,
1102 "interrupt: privileged_instruction\n");
1103 break;
1104 case FRV_ILLEGAL_INSTRUCTION:
1105 sim_engine_abort (sd, current_cpu, pc,
1106 "interrupt: illegal_instruction\n");
1107 break;
1108 case FRV_INSTRUCTION_ACCESS_EXCEPTION:
1109 sim_engine_abort (sd, current_cpu, pc,
1110 "interrupt: instruction_access_exception\n");
1111 break;
1112 case FRV_INSTRUCTION_ACCESS_MMU_MISS:
1113 sim_engine_abort (sd, current_cpu, pc,
1114 "interrupt: instruction_access_mmu_miss\n");
1115 break;
1116 case FRV_INSTRUCTION_ACCESS_ERROR:
1117 sim_engine_abort (sd, current_cpu, pc,
1118 "interrupt: insn_access_error\n");
1119 break;
1120 case FRV_COMPOUND_EXCEPTION:
1121 sim_engine_abort (sd, current_cpu, pc,
1122 "interrupt: compound_exception\n");
1123 break;
1124 case FRV_BREAK_EXCEPTION:
1125 sim_engine_abort (sd, current_cpu, pc,
1126 "interrupt: break_exception\n");
1127 break;
1128 case FRV_RESET:
1129 sim_engine_abort (sd, current_cpu, pc,
1130 "interrupt: reset\n");
1131 break;
1132 default:
1133 sim_engine_abort (sd, current_cpu, pc,
1134 "unhandled interrupt kind: %d\n", kind);
1135 break;
1136 }
1137 }
1138
1139 /* Handle a break interrupt. */
1140 void
1141 frv_break_interrupt (
1142 SIM_CPU *current_cpu, struct frv_interrupt *interrupt, IADDR current_pc
1143 )
1144 {
1145 IADDR new_pc;
1146
1147 /* BPCSR=PC
1148 BPSR.BS=PSR.S
1149 BPSR.BET=PSR.ET
1150 PSR.S=1
1151 PSR.ET=0
1152 TBR.TT=0xff
1153 PC=TBR
1154 */
1155 /* Must set PSR.S first to allow access to supervisor-only spr registers. */
1156 SET_H_BPSR_BS (GET_H_PSR_S ());
1157 SET_H_BPSR_BET (GET_H_PSR_ET ());
1158 SET_H_PSR_S (1);
1159 SET_H_PSR_ET (0);
1160 /* Must set PSR.S first to allow access to supervisor-only spr registers. */
1161 SET_H_SPR (H_SPR_BPCSR, current_pc);
1162
1163 /* Set the new PC in the TBR. */
1164 SET_H_TBR_TT (interrupt->handler_offset);
1165 new_pc = GET_H_SPR (H_SPR_TBR);
1166 SET_H_PC (new_pc);
1167
1168 CPU_DEBUG_STATE (current_cpu) = 1;
1169 }
1170
1171 /* Handle a program interrupt or a software interrupt. */
1172 void
1173 frv_program_or_software_interrupt (
1174 SIM_CPU *current_cpu, struct frv_interrupt *interrupt, IADDR current_pc
1175 )
1176 {
1177 USI new_pc;
1178 int original_psr_et;
1179
1180 /* PCSR=PC
1181 PSR.PS=PSR.S
1182 PSR.ET=0
1183 PSR.S=1
1184 if PSR.ESR==1
1185 SR0 through SR3=GR4 through GR7
1186 TBR.TT=interrupt handler offset
1187 PC=TBR
1188 */
1189 original_psr_et = GET_H_PSR_ET ();
1190
1191 SET_H_PSR_PS (GET_H_PSR_S ());
1192 SET_H_PSR_ET (0);
1193 SET_H_PSR_S (1);
1194
1195 /* Must set PSR.S first to allow access to supervisor-only spr registers. */
1196 /* The PCSR depends on the precision of the interrupt. */
1197 if (interrupt->precise)
1198 SET_H_SPR (H_SPR_PCSR, previous_vliw_pc);
1199 else
1200 SET_H_SPR (H_SPR_PCSR, current_pc);
1201
1202 /* Set the new PC in the TBR. */
1203 SET_H_TBR_TT (interrupt->handler_offset);
1204 new_pc = GET_H_SPR (H_SPR_TBR);
1205 SET_H_PC (new_pc);
1206
1207 /* If PSR.ET was not originally set, then enter the stopped state. */
1208 if (! original_psr_et)
1209 {
1210 SIM_DESC sd = CPU_STATE (current_cpu);
1211 frv_non_operating_interrupt (current_cpu, interrupt->kind, current_pc);
1212 sim_engine_halt (sd, current_cpu, NULL, new_pc, sim_stopped, SIM_SIGINT);
1213 }
1214 }
1215
1216 /* Handle a program interrupt or a software interrupt. */
1217 void
1218 frv_external_interrupt (
1219 SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc
1220 )
1221 {
1222 USI new_pc;
1223 struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind];
1224
1225 /* Don't process the interrupt if PSR.ET is not set or if it is masked.
1226 Interrupt 15 is processed even if it appears to be masked. */
1227 if (! GET_H_PSR_ET ()
1228 || (interrupt->kind != FRV_INTERRUPT_LEVEL_15
1229 && interrupt->kind < GET_H_PSR_PIL ()))
1230 return; /* Leave it for later. */
1231
1232 /* Remove the interrupt from the queue. */
1233 --frv_interrupt_state.queue_index;
1234
1235 /* PCSR=PC
1236 PSR.PS=PSR.S
1237 PSR.ET=0
1238 PSR.S=1
1239 if PSR.ESR==1
1240 SR0 through SR3=GR4 through GR7
1241 TBR.TT=interrupt handler offset
1242 PC=TBR
1243 */
1244 SET_H_PSR_PS (GET_H_PSR_S ());
1245 SET_H_PSR_ET (0);
1246 SET_H_PSR_S (1);
1247 /* Must set PSR.S first to allow access to supervisor-only spr registers. */
1248 SET_H_SPR (H_SPR_PCSR, GET_H_PC ());
1249
1250 /* Set the new PC in the TBR. */
1251 SET_H_TBR_TT (interrupt->handler_offset);
1252 new_pc = GET_H_SPR (H_SPR_TBR);
1253 SET_H_PC (new_pc);
1254 }
1255
1256 /* Clear interrupts which fall within the range of classes given. */
1257 void
1258 frv_clear_interrupt_classes (
1259 enum frv_interrupt_class low_class, enum frv_interrupt_class high_class
1260 )
1261 {
1262 int i;
1263 int j;
1264 int limit = frv_interrupt_state.queue_index;
1265
1266 /* Find the lowest priority interrupt to be removed. */
1267 for (i = 0; i < limit; ++i)
1268 {
1269 enum frv_interrupt_kind kind = frv_interrupt_state.queue[i].kind;
1270 struct frv_interrupt* interrupt = & frv_interrupt_table[kind];
1271 if (interrupt->iclass >= low_class)
1272 break;
1273 }
1274
1275 /* Find the highest priority interrupt to be removed. */
1276 for (j = limit - 1; j >= i; --j)
1277 {
1278 enum frv_interrupt_kind kind = frv_interrupt_state.queue[j].kind;
1279 struct frv_interrupt* interrupt = & frv_interrupt_table[kind];
1280 if (interrupt->iclass <= high_class)
1281 break;
1282 }
1283
1284 /* Shuffle the remaining high priority interrupts down into the empty space
1285 left by the deleted interrupts. */
1286 if (j >= i)
1287 {
1288 for (++j; j < limit; ++j)
1289 frv_interrupt_state.queue[i++] = frv_interrupt_state.queue[j];
1290 frv_interrupt_state.queue_index -= (j - i);
1291 }
1292 }
1293
1294 /* Save data written to memory into the interrupt state so that it can be
1295 copied to the appropriate EDR register, if necessary, in the event of an
1296 interrupt. */
1297 void
1298 frv_save_data_written_for_interrupts (
1299 SIM_CPU *current_cpu, CGEN_WRITE_QUEUE_ELEMENT *item
1300 )
1301 {
1302 /* Record the slot containing the insn doing the write in the
1303 interrupt state. */
1304 frv_interrupt_state.slot = CGEN_WRITE_QUEUE_ELEMENT_PIPE (item);
1305
1306 /* Now record any data written to memory in the interrupt state. */
1307 switch (CGEN_WRITE_QUEUE_ELEMENT_KIND (item))
1308 {
1309 case CGEN_BI_WRITE:
1310 case CGEN_QI_WRITE:
1311 case CGEN_SI_WRITE:
1312 case CGEN_SF_WRITE:
1313 case CGEN_PC_WRITE:
1314 case CGEN_FN_HI_WRITE:
1315 case CGEN_FN_SI_WRITE:
1316 case CGEN_FN_SF_WRITE:
1317 case CGEN_FN_DI_WRITE:
1318 case CGEN_FN_DF_WRITE:
1319 case CGEN_FN_XI_WRITE:
1320 case CGEN_FN_PC_WRITE:
1321 break; /* Ignore writes to registers. */
1322 case CGEN_MEM_QI_WRITE:
1323 frv_interrupt_state.data_written.length = 1;
1324 frv_interrupt_state.data_written.words[0]
1325 = item->kinds.mem_qi_write.value;
1326 break;
1327 case CGEN_MEM_HI_WRITE:
1328 frv_interrupt_state.data_written.length = 1;
1329 frv_interrupt_state.data_written.words[0]
1330 = item->kinds.mem_hi_write.value;
1331 break;
1332 case CGEN_MEM_SI_WRITE:
1333 frv_interrupt_state.data_written.length = 1;
1334 frv_interrupt_state.data_written.words[0]
1335 = item->kinds.mem_si_write.value;
1336 break;
1337 case CGEN_MEM_DI_WRITE:
1338 frv_interrupt_state.data_written.length = 2;
1339 frv_interrupt_state.data_written.words[0]
1340 = item->kinds.mem_di_write.value >> 32;
1341 frv_interrupt_state.data_written.words[1]
1342 = item->kinds.mem_di_write.value;
1343 break;
1344 case CGEN_MEM_DF_WRITE:
1345 frv_interrupt_state.data_written.length = 2;
1346 frv_interrupt_state.data_written.words[0]
1347 = item->kinds.mem_df_write.value >> 32;
1348 frv_interrupt_state.data_written.words[1]
1349 = item->kinds.mem_df_write.value;
1350 break;
1351 case CGEN_MEM_XI_WRITE:
1352 frv_interrupt_state.data_written.length = 4;
1353 frv_interrupt_state.data_written.words[0]
1354 = item->kinds.mem_xi_write.value[0];
1355 frv_interrupt_state.data_written.words[1]
1356 = item->kinds.mem_xi_write.value[1];
1357 frv_interrupt_state.data_written.words[2]
1358 = item->kinds.mem_xi_write.value[2];
1359 frv_interrupt_state.data_written.words[3]
1360 = item->kinds.mem_xi_write.value[3];
1361 break;
1362 case CGEN_FN_MEM_QI_WRITE:
1363 frv_interrupt_state.data_written.length = 1;
1364 frv_interrupt_state.data_written.words[0]
1365 = item->kinds.fn_mem_qi_write.value;
1366 break;
1367 case CGEN_FN_MEM_HI_WRITE:
1368 frv_interrupt_state.data_written.length = 1;
1369 frv_interrupt_state.data_written.words[0]
1370 = item->kinds.fn_mem_hi_write.value;
1371 break;
1372 case CGEN_FN_MEM_SI_WRITE:
1373 frv_interrupt_state.data_written.length = 1;
1374 frv_interrupt_state.data_written.words[0]
1375 = item->kinds.fn_mem_si_write.value;
1376 break;
1377 case CGEN_FN_MEM_DI_WRITE:
1378 frv_interrupt_state.data_written.length = 2;
1379 frv_interrupt_state.data_written.words[0]
1380 = item->kinds.fn_mem_di_write.value >> 32;
1381 frv_interrupt_state.data_written.words[1]
1382 = item->kinds.fn_mem_di_write.value;
1383 break;
1384 case CGEN_FN_MEM_DF_WRITE:
1385 frv_interrupt_state.data_written.length = 2;
1386 frv_interrupt_state.data_written.words[0]
1387 = item->kinds.fn_mem_df_write.value >> 32;
1388 frv_interrupt_state.data_written.words[1]
1389 = item->kinds.fn_mem_df_write.value;
1390 break;
1391 case CGEN_FN_MEM_XI_WRITE:
1392 frv_interrupt_state.data_written.length = 4;
1393 frv_interrupt_state.data_written.words[0]
1394 = item->kinds.fn_mem_xi_write.value[0];
1395 frv_interrupt_state.data_written.words[1]
1396 = item->kinds.fn_mem_xi_write.value[1];
1397 frv_interrupt_state.data_written.words[2]
1398 = item->kinds.fn_mem_xi_write.value[2];
1399 frv_interrupt_state.data_written.words[3]
1400 = item->kinds.fn_mem_xi_write.value[3];
1401 break;
1402 default:
1403 {
1404 SIM_DESC sd = CPU_STATE (current_cpu);
1405 IADDR pc = CPU_PC_GET (current_cpu);
1406 sim_engine_abort (sd, current_cpu, pc,
1407 "unknown write kind during save for interrupt\n");
1408 }
1409 break;
1410 }
1411 }
This page took 0.059576 seconds and 4 git commands to generate.