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