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