1 /* frv exception and interrupt support
2 Copyright (C) 1999-2021 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. */
23 #define WANT_CPU frvbf
24 #define WANT_CPU_FRVBF
27 #include "sim-signal.h"
31 /* FR-V Interrupt table.
32 Describes the interrupts supported by the FR-V.
33 This table *must* be maintained in order of interrupt priority as defined by
34 frv_interrupt_kind. */
37 #define ITABLE_ENTRY(name, class, deferral, precision, offset) \
38 {FRV_##name, FRV_EC_##name, class, deferral, precision, offset}
40 struct frv_interrupt frv_interrupt_table
[NUM_FRV_INTERRUPT_KINDS
] =
42 /* External interrupts */
43 ITABLE_ENTRY(INTERRUPT_LEVEL_1
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x21),
44 ITABLE_ENTRY(INTERRUPT_LEVEL_2
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x22),
45 ITABLE_ENTRY(INTERRUPT_LEVEL_3
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x23),
46 ITABLE_ENTRY(INTERRUPT_LEVEL_4
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x24),
47 ITABLE_ENTRY(INTERRUPT_LEVEL_5
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x25),
48 ITABLE_ENTRY(INTERRUPT_LEVEL_6
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x26),
49 ITABLE_ENTRY(INTERRUPT_LEVEL_7
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x27),
50 ITABLE_ENTRY(INTERRUPT_LEVEL_8
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x28),
51 ITABLE_ENTRY(INTERRUPT_LEVEL_9
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x29),
52 ITABLE_ENTRY(INTERRUPT_LEVEL_10
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x2a),
53 ITABLE_ENTRY(INTERRUPT_LEVEL_11
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x2b),
54 ITABLE_ENTRY(INTERRUPT_LEVEL_12
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x2c),
55 ITABLE_ENTRY(INTERRUPT_LEVEL_13
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x2d),
56 ITABLE_ENTRY(INTERRUPT_LEVEL_14
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x2e),
57 ITABLE_ENTRY(INTERRUPT_LEVEL_15
, FRV_EXTERNAL_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x2f),
58 /* Software interrupt */
59 ITABLE_ENTRY(TRAP_INSTRUCTION
, FRV_SOFTWARE_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x80),
60 /* Program interrupts */
61 ITABLE_ENTRY(COMMIT_EXCEPTION
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x19),
62 ITABLE_ENTRY(DIVISION_EXCEPTION
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x17),
63 ITABLE_ENTRY(DATA_STORE_ERROR
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x14),
64 ITABLE_ENTRY(DATA_ACCESS_EXCEPTION
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x13),
65 ITABLE_ENTRY(DATA_ACCESS_MMU_MISS
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x12),
66 ITABLE_ENTRY(DATA_ACCESS_ERROR
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x11),
67 ITABLE_ENTRY(MP_EXCEPTION
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x0e),
68 ITABLE_ENTRY(FP_EXCEPTION
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x0d),
69 ITABLE_ENTRY(MEM_ADDRESS_NOT_ALIGNED
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x10),
70 ITABLE_ENTRY(REGISTER_EXCEPTION
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, PRECISE
, 0x08),
71 ITABLE_ENTRY(MP_DISABLED
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, PRECISE
, 0x0b),
72 ITABLE_ENTRY(FP_DISABLED
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, PRECISE
, 0x0a),
73 ITABLE_ENTRY(PRIVILEGED_INSTRUCTION
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, PRECISE
, 0x06),
74 ITABLE_ENTRY(ILLEGAL_INSTRUCTION
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, PRECISE
, 0x07),
75 ITABLE_ENTRY(INSTRUCTION_ACCESS_EXCEPTION
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, PRECISE
, 0x03),
76 ITABLE_ENTRY(INSTRUCTION_ACCESS_ERROR
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, PRECISE
, 0x02),
77 ITABLE_ENTRY(INSTRUCTION_ACCESS_MMU_MISS
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, PRECISE
, 0x01),
78 ITABLE_ENTRY(COMPOUND_EXCEPTION
, FRV_PROGRAM_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x20),
80 ITABLE_ENTRY(BREAK_EXCEPTION
, FRV_BREAK_INTERRUPT
, !DEFERRED
, !PRECISE
, 0xff),
82 ITABLE_ENTRY(RESET
, FRV_RESET_INTERRUPT
, !DEFERRED
, !PRECISE
, 0x00)
85 /* The current interrupt state. */
86 struct frv_interrupt_state frv_interrupt_state
;
88 /* maintain the address of the start of the previous VLIW insn sequence. */
89 IADDR previous_vliw_pc
;
91 /* Add a break interrupt to the interrupt queue. */
92 struct frv_interrupt_queue_element
*
93 frv_queue_break_interrupt (SIM_CPU
*current_cpu
)
95 return frv_queue_interrupt (current_cpu
, FRV_BREAK_EXCEPTION
);
98 /* Add a software interrupt to the interrupt queue. */
99 struct frv_interrupt_queue_element
*
100 frv_queue_software_interrupt (SIM_CPU
*current_cpu
, SI offset
)
102 struct frv_interrupt_queue_element
*new_element
103 = frv_queue_interrupt (current_cpu
, FRV_TRAP_INSTRUCTION
);
105 struct frv_interrupt
*interrupt
= & frv_interrupt_table
[new_element
->kind
];
106 interrupt
->handler_offset
= offset
;
111 /* Add a program interrupt to the interrupt queue. */
112 struct frv_interrupt_queue_element
*
113 frv_queue_program_interrupt (
114 SIM_CPU
*current_cpu
, enum frv_interrupt_kind kind
117 return frv_queue_interrupt (current_cpu
, kind
);
120 /* Add an external interrupt to the interrupt queue. */
121 struct frv_interrupt_queue_element
*
122 frv_queue_external_interrupt (
123 SIM_CPU
*current_cpu
, enum frv_interrupt_kind kind
126 if (! GET_H_PSR_ET ()
127 || (kind
!= FRV_INTERRUPT_LEVEL_15
&& kind
< GET_H_PSR_PIL ()))
128 return NULL
; /* Leave it for later. */
130 return frv_queue_interrupt (current_cpu
, kind
);
133 /* Add any interrupt to the interrupt queue. It will be added in reverse
134 priority order. This makes it easy to find the highest priority interrupt
135 at the end of the queue and to remove it after processing. */
136 struct frv_interrupt_queue_element
*
137 frv_queue_interrupt (SIM_CPU
*current_cpu
, enum frv_interrupt_kind kind
)
141 int limit
= frv_interrupt_state
.queue_index
;
142 struct frv_interrupt_queue_element
*new_element
;
143 enum frv_interrupt_class iclass
;
145 if (limit
>= FRV_INTERRUPT_QUEUE_SIZE
)
146 abort (); /* TODO: Make the queue dynamic */
148 /* Find the right place in the queue. */
149 for (i
= 0; i
< limit
; ++i
)
151 if (frv_interrupt_state
.queue
[i
].kind
>= kind
)
155 /* Don't queue two external interrupts of the same priority. */
156 iclass
= frv_interrupt_table
[kind
].iclass
;
157 if (i
< limit
&& iclass
== FRV_EXTERNAL_INTERRUPT
)
159 if (frv_interrupt_state
.queue
[i
].kind
== kind
)
160 return & frv_interrupt_state
.queue
[i
];
163 /* Make room for the new interrupt in this spot. */
164 for (j
= limit
- 1; j
>= i
; --j
)
165 frv_interrupt_state
.queue
[j
+ 1] = frv_interrupt_state
.queue
[j
];
167 /* Add the new interrupt. */
168 frv_interrupt_state
.queue_index
++;
169 new_element
= & frv_interrupt_state
.queue
[i
];
170 new_element
->kind
= kind
;
171 new_element
->vpc
= CPU_PC_GET (current_cpu
);
172 new_element
->u
.data_written
.length
= 0;
173 frv_set_interrupt_queue_slot (current_cpu
, new_element
);
178 struct frv_interrupt_queue_element
*
179 frv_queue_register_exception_interrupt (SIM_CPU
*current_cpu
, enum frv_rec rec
)
181 struct frv_interrupt_queue_element
*new_element
=
182 frv_queue_program_interrupt (current_cpu
, FRV_REGISTER_EXCEPTION
);
184 new_element
->u
.rec
= rec
;
189 struct frv_interrupt_queue_element
*
190 frv_queue_mem_address_not_aligned_interrupt (SIM_CPU
*current_cpu
, USI addr
)
192 struct frv_interrupt_queue_element
*new_element
;
193 USI isr
= GET_ISR ();
195 /* Make sure that this exception is not masked. */
196 if (GET_ISR_EMAM (isr
))
199 /* Queue the interrupt. */
200 new_element
= frv_queue_program_interrupt (current_cpu
,
201 FRV_MEM_ADDRESS_NOT_ALIGNED
);
202 new_element
->eaddress
= addr
;
203 new_element
->u
.data_written
= frv_interrupt_state
.data_written
;
204 frv_interrupt_state
.data_written
.length
= 0;
209 struct frv_interrupt_queue_element
*
210 frv_queue_data_access_error_interrupt (SIM_CPU
*current_cpu
, USI addr
)
212 struct frv_interrupt_queue_element
*new_element
;
213 new_element
= frv_queue_program_interrupt (current_cpu
,
214 FRV_DATA_ACCESS_ERROR
);
215 new_element
->eaddress
= addr
;
219 struct frv_interrupt_queue_element
*
220 frv_queue_data_access_exception_interrupt (SIM_CPU
*current_cpu
)
222 return frv_queue_program_interrupt (current_cpu
, FRV_DATA_ACCESS_EXCEPTION
);
225 struct frv_interrupt_queue_element
*
226 frv_queue_instruction_access_error_interrupt (SIM_CPU
*current_cpu
)
228 return frv_queue_program_interrupt (current_cpu
, FRV_INSTRUCTION_ACCESS_ERROR
);
231 struct frv_interrupt_queue_element
*
232 frv_queue_instruction_access_exception_interrupt (SIM_CPU
*current_cpu
)
234 return frv_queue_program_interrupt (current_cpu
, FRV_INSTRUCTION_ACCESS_EXCEPTION
);
237 struct frv_interrupt_queue_element
*
238 frv_queue_illegal_instruction_interrupt (
239 SIM_CPU
*current_cpu
, const CGEN_INSN
*insn
242 SIM_DESC sd
= CPU_STATE (current_cpu
);
243 switch (STATE_ARCHITECTURE (sd
)->mach
)
250 /* Some machines generate fp_exception for this case. */
251 if (frv_is_float_insn (insn
) || frv_is_media_insn (insn
))
253 struct frv_fp_exception_info fp_info
= {
254 FSR_NO_EXCEPTION
, FTT_SEQUENCE_ERROR
256 return frv_queue_fp_exception_interrupt (current_cpu
, & fp_info
);
261 return frv_queue_program_interrupt (current_cpu
, FRV_ILLEGAL_INSTRUCTION
);
264 struct frv_interrupt_queue_element
*
265 frv_queue_privileged_instruction_interrupt (SIM_CPU
*current_cpu
, const CGEN_INSN
*insn
)
267 /* The fr550 has no privileged instruction interrupt. It uses
268 illegal_instruction. */
269 SIM_DESC sd
= CPU_STATE (current_cpu
);
270 if (STATE_ARCHITECTURE (sd
)->mach
== bfd_mach_fr550
)
271 return frv_queue_program_interrupt (current_cpu
, FRV_ILLEGAL_INSTRUCTION
);
273 return frv_queue_program_interrupt (current_cpu
, FRV_PRIVILEGED_INSTRUCTION
);
276 struct frv_interrupt_queue_element
*
277 frv_queue_float_disabled_interrupt (SIM_CPU
*current_cpu
)
279 /* The fr550 has no fp_disabled interrupt. It uses illegal_instruction. */
280 SIM_DESC sd
= CPU_STATE (current_cpu
);
281 if (STATE_ARCHITECTURE (sd
)->mach
== bfd_mach_fr550
)
282 return frv_queue_program_interrupt (current_cpu
, FRV_ILLEGAL_INSTRUCTION
);
284 return frv_queue_program_interrupt (current_cpu
, FRV_FP_DISABLED
);
287 struct frv_interrupt_queue_element
*
288 frv_queue_media_disabled_interrupt (SIM_CPU
*current_cpu
)
290 /* The fr550 has no mp_disabled interrupt. It uses illegal_instruction. */
291 SIM_DESC sd
= CPU_STATE (current_cpu
);
292 if (STATE_ARCHITECTURE (sd
)->mach
== bfd_mach_fr550
)
293 return frv_queue_program_interrupt (current_cpu
, FRV_ILLEGAL_INSTRUCTION
);
295 return frv_queue_program_interrupt (current_cpu
, FRV_MP_DISABLED
);
298 struct frv_interrupt_queue_element
*
299 frv_queue_non_implemented_instruction_interrupt (
300 SIM_CPU
*current_cpu
, const CGEN_INSN
*insn
303 SIM_DESC sd
= CPU_STATE (current_cpu
);
304 switch (STATE_ARCHITECTURE (sd
)->mach
)
311 /* Some machines generate fp_exception or mp_exception for this case. */
312 if (frv_is_float_insn (insn
))
314 struct frv_fp_exception_info fp_info
= {
315 FSR_NO_EXCEPTION
, FTT_UNIMPLEMENTED_FPOP
317 return frv_queue_fp_exception_interrupt (current_cpu
, & fp_info
);
319 if (frv_is_media_insn (insn
))
321 frv_set_mp_exception_registers (current_cpu
, MTT_UNIMPLEMENTED_MPOP
,
323 return NULL
; /* no interrupt queued at this time. */
328 return frv_queue_program_interrupt (current_cpu
, FRV_ILLEGAL_INSTRUCTION
);
331 /* Queue the given fp_exception interrupt. Also update fp_info by removing
332 masked interrupts and updating the 'slot' flield. */
333 struct frv_interrupt_queue_element
*
334 frv_queue_fp_exception_interrupt (
335 SIM_CPU
*current_cpu
, struct frv_fp_exception_info
*fp_info
338 SI fsr0
= GET_FSR (0);
339 int tem
= GET_FSR_TEM (fsr0
);
340 int aexc
= GET_FSR_AEXC (fsr0
);
341 struct frv_interrupt_queue_element
*new_element
= NULL
;
343 /* Update AEXC with the interrupts that are masked. */
344 aexc
|= fp_info
->fsr_mask
& ~tem
;
345 SET_FSR_AEXC (fsr0
, aexc
);
348 /* update fsr_mask with the exceptions that are enabled. */
349 fp_info
->fsr_mask
&= tem
;
351 /* If there is an unmasked interrupt then queue it, unless
352 this was a non-excepting insn, in which case simply set the NE
354 if (frv_interrupt_state
.ne_index
!= NE_NOFLAG
355 && fp_info
->fsr_mask
!= FSR_NO_EXCEPTION
)
357 SET_NE_FLAG (frv_interrupt_state
.f_ne_flags
,
358 frv_interrupt_state
.ne_index
);
359 /* TODO -- Set NESR for chips which support it. */
362 else if (fp_info
->fsr_mask
!= FSR_NO_EXCEPTION
363 || fp_info
->ftt
== FTT_UNIMPLEMENTED_FPOP
364 || fp_info
->ftt
== FTT_SEQUENCE_ERROR
365 || fp_info
->ftt
== FTT_INVALID_FR
)
367 new_element
= frv_queue_program_interrupt (current_cpu
, FRV_FP_EXCEPTION
);
368 new_element
->u
.fp_info
= *fp_info
;
374 struct frv_interrupt_queue_element
*
375 frv_queue_division_exception_interrupt (SIM_CPU
*current_cpu
, enum frv_dtt dtt
)
377 struct frv_interrupt_queue_element
*new_element
=
378 frv_queue_program_interrupt (current_cpu
, FRV_DIVISION_EXCEPTION
);
380 new_element
->u
.dtt
= dtt
;
385 /* Check for interrupts caused by illegal insn access. These conditions are
386 checked in the order specified by the fr400 and fr500 LSI specs. */
388 frv_detect_insn_access_interrupts (SIM_CPU
*current_cpu
, SCACHE
*sc
)
391 const CGEN_INSN
*insn
= sc
->argbuf
.idesc
->idata
;
392 SIM_DESC sd
= CPU_STATE (current_cpu
);
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
) &&
426 frv_queue_privileged_instruction_interrupt (current_cpu
, insn
);
427 #if 0 /* disable for now until we find out how FSR0.QNE gets reset. */
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
433 SI fsr0
= GET_FSR (0);
434 if (GET_FSR_QNE (fsr0
)
435 && (frv_is_float_insn (insn
) || frv_is_media_insn (insn
)
436 || CGEN_INSN_ATTR_VALUE (insn
, CGEN_INSN_FR_ACCESS
)))
438 sim_engine_halt (sd
, current_cpu
, NULL
, GET_H_PC (), sim_stopped
,
445 /* Record the current VLIW slot in the given interrupt queue element. */
447 frv_set_interrupt_queue_slot (
448 SIM_CPU
*current_cpu
, struct frv_interrupt_queue_element
*item
451 FRV_VLIW
*vliw
= CPU_VLIW (current_cpu
);
452 int slot
= vliw
->next_slot
- 1;
453 item
->slot
= (*vliw
->current_vliw
)[slot
];
456 /* Handle an individual interrupt. */
458 handle_interrupt (SIM_CPU
*current_cpu
, IADDR pc
)
460 struct frv_interrupt
*interrupt
;
461 int writeback_done
= 0;
464 /* Interrupts are queued in priority order with the highest priority
466 int index
= frv_interrupt_state
.queue_index
- 1;
467 struct frv_interrupt_queue_element
*item
468 = & frv_interrupt_state
.queue
[index
];
469 interrupt
= & frv_interrupt_table
[item
->kind
];
471 switch (interrupt
->iclass
)
473 case FRV_EXTERNAL_INTERRUPT
:
474 /* Perform writeback first. This may cause a higher priority
476 if (! writeback_done
)
478 frvbf_perform_writeback (current_cpu
);
482 frv_external_interrupt (current_cpu
, item
, pc
);
484 case FRV_SOFTWARE_INTERRUPT
:
485 frv_interrupt_state
.queue_index
= index
;
486 frv_software_interrupt (current_cpu
, item
, pc
);
488 case FRV_PROGRAM_INTERRUPT
:
489 /* If the program interrupt is not strict (imprecise), then perform
490 writeback first. This may, in turn, cause a higher priority
492 if (! interrupt
->precise
&& ! writeback_done
)
494 frv_interrupt_state
.imprecise_interrupt
= item
;
495 frvbf_perform_writeback (current_cpu
);
499 frv_interrupt_state
.queue_index
= index
;
500 frv_program_interrupt (current_cpu
, item
, pc
);
502 case FRV_BREAK_INTERRUPT
:
503 frv_interrupt_state
.queue_index
= index
;
504 frv_break_interrupt (current_cpu
, interrupt
, pc
);
506 case FRV_RESET_INTERRUPT
:
511 frv_interrupt_state
.queue_index
= index
;
512 break; /* out of loop. */
515 /* We should never get here. */
517 SIM_DESC sd
= CPU_STATE (current_cpu
);
518 sim_engine_abort (sd
, current_cpu
, pc
,
519 "interrupt class not supported %d\n",
524 /* Check to see the if the RSTR.HR or RSTR.SR bits have been set. If so, handle
525 the appropriate reset interrupt. */
527 check_reset (SIM_CPU
*current_cpu
, IADDR pc
)
533 FRV_CACHE
*cache
= CPU_DATA_CACHE (current_cpu
);
534 IADDR address
= RSTR_ADDRESS
;
536 /* We don't want this to show up in the cache statistics, so read the
538 if (! frv_cache_read_passive_SI (cache
, address
, & rstr
))
539 rstr
= sim_core_read_unaligned_4 (current_cpu
, pc
, read_map
, address
);
541 hr
= GET_RSTR_HR (rstr
);
542 sr
= GET_RSTR_SR (rstr
);
545 return 0; /* no reset. */
547 /* Reinitialize the machine state. */
549 frv_hardware_reset (current_cpu
);
551 frv_software_reset (current_cpu
);
553 /* Branch to the reset address. */
555 if (GET_HSR0_SA (hsr0
))
556 SET_H_PC (0xff000000);
560 return 1; /* reset */
563 /* Process any pending interrupt(s) after a group of parallel insns. */
565 frv_process_interrupts (SIM_CPU
*current_cpu
)
568 /* Need to save the pc here because writeback may change it (due to a
570 IADDR pc
= CPU_PC_GET (current_cpu
);
572 /* Check for a reset before anything else. */
573 if (check_reset (current_cpu
, pc
))
576 /* First queue the writes for any accumulated NE flags. */
577 if (frv_interrupt_state
.f_ne_flags
[0] != 0
578 || frv_interrupt_state
.f_ne_flags
[1] != 0)
580 GET_NE_FLAGS (NE_flags
, H_SPR_FNER0
);
581 NE_flags
[0] |= frv_interrupt_state
.f_ne_flags
[0];
582 NE_flags
[1] |= frv_interrupt_state
.f_ne_flags
[1];
583 SET_NE_FLAGS (H_SPR_FNER0
, NE_flags
);
586 /* If there is no interrupt pending, then perform parallel writeback. This
587 may cause an interrupt. */
588 if (frv_interrupt_state
.queue_index
<= 0)
589 frvbf_perform_writeback (current_cpu
);
591 /* If there is an interrupt pending, then process it. */
592 if (frv_interrupt_state
.queue_index
> 0)
593 handle_interrupt (current_cpu
, pc
);
596 /* Find the next available ESR and return its index */
598 esr_for_data_access_exception (
599 SIM_CPU
*current_cpu
, struct frv_interrupt_queue_element
*item
602 SIM_DESC sd
= CPU_STATE (current_cpu
);
603 if (STATE_ARCHITECTURE (sd
)->mach
== bfd_mach_fr550
)
604 return 8; /* Use ESR8, EPCR8. */
606 if (item
->slot
== UNIT_I0
)
607 return 8; /* Use ESR8, EPCR8, EAR8, EDR8. */
609 return 9; /* Use ESR9, EPCR9, EAR9. */
612 /* Set the next available EDR register with the data which was to be stored
613 and return the index of the register. */
616 SIM_CPU
*current_cpu
, struct frv_interrupt_queue_element
*item
, int edr_index
619 /* EDR0, EDR4 and EDR8 are available as blocks of 4.
620 SI data uses EDR3, EDR7 and EDR11
621 DI data uses EDR2, EDR6 and EDR10
622 XI data uses EDR0, EDR4 and EDR8. */
624 edr_index
+= 4 - item
->u
.data_written
.length
;
625 for (i
= 0; i
< item
->u
.data_written
.length
; ++i
)
626 SET_EDR (edr_index
+ i
, item
->u
.data_written
.words
[i
]);
631 /* Clear ESFR0, EPCRx, ESRx, EARx and EDRx. */
633 clear_exception_status_registers (SIM_CPU
*current_cpu
)
636 /* It is only necessary to clear the flag bits indicating which registers
641 for (i
= 0; i
<= 2; ++i
)
643 SI esr
= GET_ESR (i
);
644 CLEAR_ESR_VALID (esr
);
647 for (i
= 8; i
<= 15; ++i
)
649 SI esr
= GET_ESR (i
);
650 CLEAR_ESR_VALID (esr
);
655 /* Record state for media exception. */
657 frv_set_mp_exception_registers (
658 SIM_CPU
*current_cpu
, enum frv_msr_mtt mtt
, int sie
661 /* Record the interrupt factor in MSR0. */
662 SI msr0
= GET_MSR (0);
663 if (GET_MSR_MTT (msr0
) == MTT_NONE
)
664 SET_MSR_MTT (msr0
, mtt
);
666 /* Also set the OVF bit in the appropriate MSR as well as MSR0.AOVF. */
667 if (mtt
== MTT_OVERFLOW
)
669 FRV_VLIW
*vliw
= CPU_VLIW (current_cpu
);
670 int slot
= vliw
->next_slot
- 1;
671 SIM_DESC sd
= CPU_STATE (current_cpu
);
673 /* If this insn is in the M2 slot, then set MSR1.OVF and MSR1.SIE,
674 otherwise set MSR0.OVF and MSR0.SIE. */
675 if (STATE_ARCHITECTURE (sd
)->mach
!= bfd_mach_fr550
&& (*vliw
->current_vliw
)[slot
] == UNIT_FM1
)
677 SI msr
= GET_MSR (1);
678 OR_MSR_SIE (msr
, sie
);
684 OR_MSR_SIE (msr0
, sie
);
688 /* Generate the interrupt now if MSR0.MPEM is set on fr550 */
689 if (STATE_ARCHITECTURE (sd
)->mach
== bfd_mach_fr550
&& GET_MSR_MPEM (msr0
))
690 frv_queue_program_interrupt (current_cpu
, FRV_MP_EXCEPTION
);
693 /* Regardless of the slot, set MSR0.AOVF. */
701 /* Determine the correct FQ register to use for the given exception.
702 Return -1 if a register is not available. */
705 SIM_CPU
*current_cpu
, struct frv_interrupt_queue_element
*item
709 struct frv_fp_exception_info
*fp_info
= & item
->u
.fp_info
;
711 /* For fp_exception overflow, underflow or inexact, use FQ0 or FQ1. */
712 if (fp_info
->ftt
== FTT_IEEE_754_EXCEPTION
713 && (fp_info
->fsr_mask
& (FSR_OVERFLOW
| FSR_UNDERFLOW
| FSR_INEXACT
)))
716 if (! GET_FQ_VALID (fq
))
717 return 0; /* FQ0 is available. */
719 if (! GET_FQ_VALID (fq
))
720 return 1; /* FQ1 is available. */
722 /* No FQ register is available */
724 SIM_DESC sd
= CPU_STATE (current_cpu
);
725 IADDR pc
= CPU_PC_GET (current_cpu
);
726 sim_engine_abort (sd
, current_cpu
, pc
, "No FQ register available\n");
730 /* For other exceptions, use FQ2 if the insn was in slot F0/I0 and FQ3
732 if (item
->slot
== UNIT_FM0
|| item
->slot
== UNIT_I0
)
738 /* Set FSR0, FQ0-FQ9, depending on the interrupt. */
740 set_fp_exception_registers (
741 SIM_CPU
*current_cpu
, struct frv_interrupt_queue_element
*item
749 struct frv_fp_exception_info
*fp_info
;
750 SIM_DESC sd
= CPU_STATE (current_cpu
);
752 /* No FQ registers on fr550 */
753 if (STATE_ARCHITECTURE (sd
)->mach
== bfd_mach_fr550
)
755 /* Update the fsr. */
756 fp_info
= & item
->u
.fp_info
;
758 SET_FSR_FTT (fsr0
, fp_info
->ftt
);
763 /* Select an FQ and update it with the exception information. */
764 fq_index
= fq_for_exception (current_cpu
, item
);
768 fp_info
= & item
->u
.fp_info
;
769 fq
= GET_FQ (fq_index
);
770 SET_FQ_MIV (fq
, MIV_FLOAT
);
771 SET_FQ_SIE (fq
, SIE_NIL
);
772 SET_FQ_FTT (fq
, fp_info
->ftt
);
773 SET_FQ_CEXC (fq
, fp_info
->fsr_mask
);
775 SET_FQ (fq_index
, fq
);
777 /* Write the failing insn into FQx.OPC. */
779 insn
= GETMEMSI (current_cpu
, pc
, pc
);
780 SET_FQ_OPC (fq_index
, insn
);
782 /* Update the fsr. */
784 SET_FSR_QNE (fsr0
); /* FQ not empty */
785 SET_FSR_FTT (fsr0
, fp_info
->ftt
);
789 /* Record the state of a division exception in the ISR. */
791 set_isr_exception_fields (
792 SIM_CPU
*current_cpu
, struct frv_interrupt_queue_element
*item
795 USI isr
= GET_ISR ();
796 int dtt
= GET_ISR_DTT (isr
);
798 SET_ISR_DTT (isr
, dtt
);
802 /* Set ESFR0, EPCRx, ESRx, EARx and EDRx, according to the given program
805 set_exception_status_registers (
806 SIM_CPU
*current_cpu
, struct frv_interrupt_queue_element
*item
809 struct frv_interrupt
*interrupt
= & frv_interrupt_table
[item
->kind
];
810 int slot
= (item
->vpc
- previous_vliw_pc
) / 4;
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
)
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
)
834 switch (interrupt
->kind
)
836 case FRV_DIVISION_EXCEPTION
:
837 set_isr_exception_fields (current_cpu
, item
);
838 /* fall thru to set reg_index. */
839 case FRV_COMMIT_EXCEPTION
:
840 /* For fr550, always use ESR0. */
841 if (STATE_ARCHITECTURE (sd
)->mach
== bfd_mach_fr550
)
843 else if (item
->slot
== UNIT_I0
)
845 else if (item
->slot
== UNIT_I1
)
849 case FRV_DATA_STORE_ERROR
:
850 reg_index
= 14; /* Use ESR14. */
852 case FRV_DATA_ACCESS_ERROR
:
853 reg_index
= 15; /* Use ESR15, EPCR15. */
856 case FRV_DATA_ACCESS_EXCEPTION
:
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. */
864 /* For fr550, never use EDRx. */
865 if (STATE_ARCHITECTURE (sd
)->mach
!= bfd_mach_fr550
)
866 if (item
->u
.data_written
.length
!= 0)
868 reg_index
= esr_for_data_access_exception (current_cpu
, item
);
871 case FRV_MP_EXCEPTION
:
872 /* For fr550, use EPCR2 and ESR2. */
873 if (STATE_ARCHITECTURE (sd
)->mach
== bfd_mach_fr550
)
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
)
890 SIM_DESC sd
= CPU_STATE (current_cpu
);
891 IADDR pc
= CPU_PC_GET (current_cpu
);
892 sim_engine_abort (sd
, current_cpu
, pc
,
893 "invalid non-strict program interrupt kind: %d\n",
898 } /* non-strict (imprecise) interrupt */
900 /* Now fill in the selected exception status registers. */
903 /* Now set the exception status registers. */
904 SET_ESFR_FLAG (reg_index
);
905 SET_ESR_EC (esr
, interrupt
->ec
);
909 if (STATE_ARCHITECTURE (sd
)->mach
== bfd_mach_fr400
)
910 SET_EPCR (reg_index
, previous_vliw_pc
);
912 SET_EPCR (reg_index
, item
->vpc
);
917 SET_EAR (reg_index
, item
->eaddress
);
925 int edn
= set_edr_register (current_cpu
, item
, 0/* EDR0-3 */);
926 SET_ESR_EDN (esr
, edn
);
933 SET_ESR_DAEC (esr
, item
->u
.daec
);
936 SET_ESR (reg_index
, esr
);
940 /* Check for compound interrupts.
941 Returns NULL if no interrupt is to be processed. */
942 static struct frv_interrupt
*
943 check_for_compound_interrupt (
944 SIM_CPU
*current_cpu
, struct frv_interrupt_queue_element
*item
947 struct frv_interrupt
*interrupt
;
949 /* Set the exception status registers for the original interrupt. */
950 set_exception_status_registers (current_cpu
, item
);
951 interrupt
= & frv_interrupt_table
[item
->kind
];
953 if (! interrupt
->precise
)
959 mask
= (1 << item
->kind
);
961 /* Look for more queued program interrupts which are non-deferred
962 (pending inhibit), imprecise (non-strict) different than an interrupt
963 already found and caused by a different insn. A bit mask is used
964 to keep track of interrupts which have already been detected. */
965 while (item
!= frv_interrupt_state
.queue
)
967 enum frv_interrupt_kind kind
;
968 struct frv_interrupt
*next_interrupt
;
971 next_interrupt
= & frv_interrupt_table
[kind
];
973 if (next_interrupt
->iclass
!= FRV_PROGRAM_INTERRUPT
)
974 break; /* no program interrupts left. */
976 if (item
->vpc
== vpc
)
977 continue; /* caused by the same insn. */
980 if (! next_interrupt
->precise
&& ! next_interrupt
->deferred
)
982 if (! (mask
& (1 << kind
)))
984 /* Set the exception status registers for the additional
986 set_exception_status_registers (current_cpu
, item
);
988 interrupt
= & frv_interrupt_table
[FRV_COMPOUND_EXCEPTION
];
994 /* Return with either the original interrupt, a compound_exception,
999 /* Handle a program interrupt. */
1001 frv_program_interrupt (
1002 SIM_CPU
*current_cpu
, struct frv_interrupt_queue_element
*item
, IADDR pc
1005 struct frv_interrupt
*interrupt
;
1007 clear_exception_status_registers (current_cpu
);
1008 /* If two or more non-deferred imprecise (non-strict) interrupts occur
1009 on two or more insns, then generate a compound_exception. */
1010 interrupt
= check_for_compound_interrupt (current_cpu
, item
);
1011 if (interrupt
!= NULL
)
1013 frv_program_or_software_interrupt (current_cpu
, interrupt
, pc
);
1014 frv_clear_interrupt_classes (FRV_SOFTWARE_INTERRUPT
,
1015 FRV_PROGRAM_INTERRUPT
);
1019 /* Handle a software interrupt. */
1021 frv_software_interrupt (
1022 SIM_CPU
*current_cpu
, struct frv_interrupt_queue_element
*item
, IADDR pc
1025 struct frv_interrupt
*interrupt
= & frv_interrupt_table
[item
->kind
];
1026 frv_program_or_software_interrupt (current_cpu
, interrupt
, pc
);
1029 /* Handle a program interrupt or a software interrupt in non-operating mode. */
1031 frv_non_operating_interrupt (
1032 SIM_CPU
*current_cpu
, enum frv_interrupt_kind kind
, IADDR pc
1035 SIM_DESC sd
= CPU_STATE (current_cpu
);
1038 case FRV_INTERRUPT_LEVEL_1
:
1039 case FRV_INTERRUPT_LEVEL_2
:
1040 case FRV_INTERRUPT_LEVEL_3
:
1041 case FRV_INTERRUPT_LEVEL_4
:
1042 case FRV_INTERRUPT_LEVEL_5
:
1043 case FRV_INTERRUPT_LEVEL_6
:
1044 case FRV_INTERRUPT_LEVEL_7
:
1045 case FRV_INTERRUPT_LEVEL_8
:
1046 case FRV_INTERRUPT_LEVEL_9
:
1047 case FRV_INTERRUPT_LEVEL_10
:
1048 case FRV_INTERRUPT_LEVEL_11
:
1049 case FRV_INTERRUPT_LEVEL_12
:
1050 case FRV_INTERRUPT_LEVEL_13
:
1051 case FRV_INTERRUPT_LEVEL_14
:
1052 case FRV_INTERRUPT_LEVEL_15
:
1053 sim_engine_abort (sd
, current_cpu
, pc
,
1054 "interrupt: external %d\n", kind
+ 1);
1056 case FRV_TRAP_INSTRUCTION
:
1057 break; /* handle as in operating mode. */
1058 case FRV_COMMIT_EXCEPTION
:
1059 sim_engine_abort (sd
, current_cpu
, pc
,
1060 "interrupt: commit_exception\n");
1062 case FRV_DIVISION_EXCEPTION
:
1063 sim_engine_abort (sd
, current_cpu
, pc
,
1064 "interrupt: division_exception\n");
1066 case FRV_DATA_STORE_ERROR
:
1067 sim_engine_abort (sd
, current_cpu
, pc
,
1068 "interrupt: data_store_error\n");
1070 case FRV_DATA_ACCESS_EXCEPTION
:
1071 sim_engine_abort (sd
, current_cpu
, pc
,
1072 "interrupt: data_access_exception\n");
1074 case FRV_DATA_ACCESS_MMU_MISS
:
1075 sim_engine_abort (sd
, current_cpu
, pc
,
1076 "interrupt: data_access_mmu_miss\n");
1078 case FRV_DATA_ACCESS_ERROR
:
1079 sim_engine_abort (sd
, current_cpu
, pc
,
1080 "interrupt: data_access_error\n");
1082 case FRV_MP_EXCEPTION
:
1083 sim_engine_abort (sd
, current_cpu
, pc
,
1084 "interrupt: mp_exception\n");
1086 case FRV_FP_EXCEPTION
:
1087 sim_engine_abort (sd
, current_cpu
, pc
,
1088 "interrupt: fp_exception\n");
1090 case FRV_MEM_ADDRESS_NOT_ALIGNED
:
1091 sim_engine_abort (sd
, current_cpu
, pc
,
1092 "interrupt: mem_address_not_aligned\n");
1094 case FRV_REGISTER_EXCEPTION
:
1095 sim_engine_abort (sd
, current_cpu
, pc
,
1096 "interrupt: register_exception\n");
1098 case FRV_MP_DISABLED
:
1099 sim_engine_abort (sd
, current_cpu
, pc
,
1100 "interrupt: mp_disabled\n");
1102 case FRV_FP_DISABLED
:
1103 sim_engine_abort (sd
, current_cpu
, pc
,
1104 "interrupt: fp_disabled\n");
1106 case FRV_PRIVILEGED_INSTRUCTION
:
1107 sim_engine_abort (sd
, current_cpu
, pc
,
1108 "interrupt: privileged_instruction\n");
1110 case FRV_ILLEGAL_INSTRUCTION
:
1111 sim_engine_abort (sd
, current_cpu
, pc
,
1112 "interrupt: illegal_instruction\n");
1114 case FRV_INSTRUCTION_ACCESS_EXCEPTION
:
1115 sim_engine_abort (sd
, current_cpu
, pc
,
1116 "interrupt: instruction_access_exception\n");
1118 case FRV_INSTRUCTION_ACCESS_MMU_MISS
:
1119 sim_engine_abort (sd
, current_cpu
, pc
,
1120 "interrupt: instruction_access_mmu_miss\n");
1122 case FRV_INSTRUCTION_ACCESS_ERROR
:
1123 sim_engine_abort (sd
, current_cpu
, pc
,
1124 "interrupt: insn_access_error\n");
1126 case FRV_COMPOUND_EXCEPTION
:
1127 sim_engine_abort (sd
, current_cpu
, pc
,
1128 "interrupt: compound_exception\n");
1130 case FRV_BREAK_EXCEPTION
:
1131 sim_engine_abort (sd
, current_cpu
, pc
,
1132 "interrupt: break_exception\n");
1135 sim_engine_abort (sd
, current_cpu
, pc
,
1136 "interrupt: reset\n");
1139 sim_engine_abort (sd
, current_cpu
, pc
,
1140 "unhandled interrupt kind: %d\n", kind
);
1145 /* Handle a break interrupt. */
1147 frv_break_interrupt (
1148 SIM_CPU
*current_cpu
, struct frv_interrupt
*interrupt
, IADDR current_pc
1161 /* Must set PSR.S first to allow access to supervisor-only spr registers. */
1162 SET_H_BPSR_BS (GET_H_PSR_S ());
1163 SET_H_BPSR_BET (GET_H_PSR_ET ());
1166 /* Must set PSR.S first to allow access to supervisor-only spr registers. */
1167 SET_H_SPR (H_SPR_BPCSR
, current_pc
);
1169 /* Set the new PC in the TBR. */
1170 SET_H_TBR_TT (interrupt
->handler_offset
);
1171 new_pc
= GET_H_SPR (H_SPR_TBR
);
1174 CPU_DEBUG_STATE (current_cpu
) = 1;
1177 /* Handle a program interrupt or a software interrupt. */
1179 frv_program_or_software_interrupt (
1180 SIM_CPU
*current_cpu
, struct frv_interrupt
*interrupt
, IADDR current_pc
1184 int original_psr_et
;
1191 SR0 through SR3=GR4 through GR7
1192 TBR.TT=interrupt handler offset
1195 original_psr_et
= GET_H_PSR_ET ();
1197 SET_H_PSR_PS (GET_H_PSR_S ());
1201 /* Must set PSR.S first to allow access to supervisor-only spr registers. */
1202 /* The PCSR depends on the precision of the interrupt. */
1203 if (interrupt
->precise
)
1204 SET_H_SPR (H_SPR_PCSR
, previous_vliw_pc
);
1206 SET_H_SPR (H_SPR_PCSR
, current_pc
);
1208 /* Set the new PC in the TBR. */
1209 SET_H_TBR_TT (interrupt
->handler_offset
);
1210 new_pc
= GET_H_SPR (H_SPR_TBR
);
1213 /* If PSR.ET was not originally set, then enter the stopped state. */
1214 if (! original_psr_et
)
1216 SIM_DESC sd
= CPU_STATE (current_cpu
);
1217 frv_non_operating_interrupt (current_cpu
, interrupt
->kind
, current_pc
);
1218 sim_engine_halt (sd
, current_cpu
, NULL
, new_pc
, sim_stopped
, SIM_SIGINT
);
1222 /* Handle a program interrupt or a software interrupt. */
1224 frv_external_interrupt (
1225 SIM_CPU
*current_cpu
, struct frv_interrupt_queue_element
*item
, IADDR pc
1229 struct frv_interrupt
*interrupt
= & frv_interrupt_table
[item
->kind
];
1231 /* Don't process the interrupt if PSR.ET is not set or if it is masked.
1232 Interrupt 15 is processed even if it appears to be masked. */
1233 if (! GET_H_PSR_ET ()
1234 || (interrupt
->kind
!= FRV_INTERRUPT_LEVEL_15
1235 && interrupt
->kind
< GET_H_PSR_PIL ()))
1236 return; /* Leave it for later. */
1238 /* Remove the interrupt from the queue. */
1239 --frv_interrupt_state
.queue_index
;
1246 SR0 through SR3=GR4 through GR7
1247 TBR.TT=interrupt handler offset
1250 SET_H_PSR_PS (GET_H_PSR_S ());
1253 /* Must set PSR.S first to allow access to supervisor-only spr registers. */
1254 SET_H_SPR (H_SPR_PCSR
, GET_H_PC ());
1256 /* Set the new PC in the TBR. */
1257 SET_H_TBR_TT (interrupt
->handler_offset
);
1258 new_pc
= GET_H_SPR (H_SPR_TBR
);
1262 /* Clear interrupts which fall within the range of classes given. */
1264 frv_clear_interrupt_classes (
1265 enum frv_interrupt_class low_class
, enum frv_interrupt_class high_class
1270 int limit
= frv_interrupt_state
.queue_index
;
1272 /* Find the lowest priority interrupt to be removed. */
1273 for (i
= 0; i
< limit
; ++i
)
1275 enum frv_interrupt_kind kind
= frv_interrupt_state
.queue
[i
].kind
;
1276 struct frv_interrupt
* interrupt
= & frv_interrupt_table
[kind
];
1277 if (interrupt
->iclass
>= low_class
)
1281 /* Find the highest priority interrupt to be removed. */
1282 for (j
= limit
- 1; j
>= i
; --j
)
1284 enum frv_interrupt_kind kind
= frv_interrupt_state
.queue
[j
].kind
;
1285 struct frv_interrupt
* interrupt
= & frv_interrupt_table
[kind
];
1286 if (interrupt
->iclass
<= high_class
)
1290 /* Shuffle the remaining high priority interrupts down into the empty space
1291 left by the deleted interrupts. */
1294 for (++j
; j
< limit
; ++j
)
1295 frv_interrupt_state
.queue
[i
++] = frv_interrupt_state
.queue
[j
];
1296 frv_interrupt_state
.queue_index
-= (j
- i
);
1300 /* Save data written to memory into the interrupt state so that it can be
1301 copied to the appropriate EDR register, if necessary, in the event of an
1304 frv_save_data_written_for_interrupts (
1305 SIM_CPU
*current_cpu
, CGEN_WRITE_QUEUE_ELEMENT
*item
1308 /* Record the slot containing the insn doing the write in the
1310 frv_interrupt_state
.slot
= CGEN_WRITE_QUEUE_ELEMENT_PIPE (item
);
1312 /* Now record any data written to memory in the interrupt state. */
1313 switch (CGEN_WRITE_QUEUE_ELEMENT_KIND (item
))
1320 case CGEN_FN_HI_WRITE
:
1321 case CGEN_FN_SI_WRITE
:
1322 case CGEN_FN_SF_WRITE
:
1323 case CGEN_FN_DI_WRITE
:
1324 case CGEN_FN_DF_WRITE
:
1325 case CGEN_FN_XI_WRITE
:
1326 case CGEN_FN_PC_WRITE
:
1327 break; /* Ignore writes to registers. */
1328 case CGEN_MEM_QI_WRITE
:
1329 frv_interrupt_state
.data_written
.length
= 1;
1330 frv_interrupt_state
.data_written
.words
[0]
1331 = item
->kinds
.mem_qi_write
.value
;
1333 case CGEN_MEM_HI_WRITE
:
1334 frv_interrupt_state
.data_written
.length
= 1;
1335 frv_interrupt_state
.data_written
.words
[0]
1336 = item
->kinds
.mem_hi_write
.value
;
1338 case CGEN_MEM_SI_WRITE
:
1339 frv_interrupt_state
.data_written
.length
= 1;
1340 frv_interrupt_state
.data_written
.words
[0]
1341 = item
->kinds
.mem_si_write
.value
;
1343 case CGEN_MEM_DI_WRITE
:
1344 frv_interrupt_state
.data_written
.length
= 2;
1345 frv_interrupt_state
.data_written
.words
[0]
1346 = item
->kinds
.mem_di_write
.value
>> 32;
1347 frv_interrupt_state
.data_written
.words
[1]
1348 = item
->kinds
.mem_di_write
.value
;
1350 case CGEN_MEM_DF_WRITE
:
1351 frv_interrupt_state
.data_written
.length
= 2;
1352 frv_interrupt_state
.data_written
.words
[0]
1353 = item
->kinds
.mem_df_write
.value
>> 32;
1354 frv_interrupt_state
.data_written
.words
[1]
1355 = item
->kinds
.mem_df_write
.value
;
1357 case CGEN_MEM_XI_WRITE
:
1358 frv_interrupt_state
.data_written
.length
= 4;
1359 frv_interrupt_state
.data_written
.words
[0]
1360 = item
->kinds
.mem_xi_write
.value
[0];
1361 frv_interrupt_state
.data_written
.words
[1]
1362 = item
->kinds
.mem_xi_write
.value
[1];
1363 frv_interrupt_state
.data_written
.words
[2]
1364 = item
->kinds
.mem_xi_write
.value
[2];
1365 frv_interrupt_state
.data_written
.words
[3]
1366 = item
->kinds
.mem_xi_write
.value
[3];
1368 case CGEN_FN_MEM_QI_WRITE
:
1369 frv_interrupt_state
.data_written
.length
= 1;
1370 frv_interrupt_state
.data_written
.words
[0]
1371 = item
->kinds
.fn_mem_qi_write
.value
;
1373 case CGEN_FN_MEM_HI_WRITE
:
1374 frv_interrupt_state
.data_written
.length
= 1;
1375 frv_interrupt_state
.data_written
.words
[0]
1376 = item
->kinds
.fn_mem_hi_write
.value
;
1378 case CGEN_FN_MEM_SI_WRITE
:
1379 frv_interrupt_state
.data_written
.length
= 1;
1380 frv_interrupt_state
.data_written
.words
[0]
1381 = item
->kinds
.fn_mem_si_write
.value
;
1383 case CGEN_FN_MEM_DI_WRITE
:
1384 frv_interrupt_state
.data_written
.length
= 2;
1385 frv_interrupt_state
.data_written
.words
[0]
1386 = item
->kinds
.fn_mem_di_write
.value
>> 32;
1387 frv_interrupt_state
.data_written
.words
[1]
1388 = item
->kinds
.fn_mem_di_write
.value
;
1390 case CGEN_FN_MEM_DF_WRITE
:
1391 frv_interrupt_state
.data_written
.length
= 2;
1392 frv_interrupt_state
.data_written
.words
[0]
1393 = item
->kinds
.fn_mem_df_write
.value
>> 32;
1394 frv_interrupt_state
.data_written
.words
[1]
1395 = item
->kinds
.fn_mem_df_write
.value
;
1397 case CGEN_FN_MEM_XI_WRITE
:
1398 frv_interrupt_state
.data_written
.length
= 4;
1399 frv_interrupt_state
.data_written
.words
[0]
1400 = item
->kinds
.fn_mem_xi_write
.value
[0];
1401 frv_interrupt_state
.data_written
.words
[1]
1402 = item
->kinds
.fn_mem_xi_write
.value
[1];
1403 frv_interrupt_state
.data_written
.words
[2]
1404 = item
->kinds
.fn_mem_xi_write
.value
[2];
1405 frv_interrupt_state
.data_written
.words
[3]
1406 = item
->kinds
.fn_mem_xi_write
.value
[3];
1410 SIM_DESC sd
= CPU_STATE (current_cpu
);
1411 IADDR pc
= CPU_PC_GET (current_cpu
);
1412 sim_engine_abort (sd
, current_cpu
, pc
,
1413 "unknown write kind during save for interrupt\n");