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