1 /* This file is part of the program psim.
3 Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #ifndef _INTERRUPTS_C_
23 #define _INTERRUPTS_C_
32 /* Operating environment support code
34 Unlike the VEA, the OEA must fully model the effect an interrupt
35 has on the processors state.
37 Each function below return updated values for registers effected by
41 STATIC_INLINE_INTERRUPTS\
43 interrupt_msr(msreg old_msr
,
47 msreg msr_set_to_0
= (msr_branch_trace_enable
49 | msr_external_interrupt_enable
50 | msr_floating_point_exception_mode_0
51 | msr_floating_point_exception_mode_1
52 | msr_floating_point_available
53 | msr_instruction_relocate
54 | msr_power_management_enable
56 | msr_recoverable_interrupt
57 | msr_single_step_trace_enable
);
58 /* remember, in 32bit mode msr_64bit_mode is zero */
59 msreg new_msr
= ((((old_msr
& ~msr_set_to_0
)
67 STATIC_INLINE_INTERRUPTS\
69 interrupt_srr1(msreg old_msr
,
73 spreg srr1_mask
= (MASK(0,32)
76 spreg srr1
= (old_msr
& srr1_mask
& ~srr1_clear
) | srr1_set
;
81 STATIC_INLINE_INTERRUPTS\
83 interrupt_base_ea(msreg msr
)
85 if (msr
& msr_interrupt_prefix
)
92 /* finish off an interrupt for the OEA model, updating all registers
93 and forcing a restart of the processor */
95 STATIC_INLINE_INTERRUPTS\
97 perform_oea_interrupt(cpu
*processor
,
99 unsigned_word vector_offset
,
106 msreg new_msr
= interrupt_msr(old_msr
, msr_clear
, msr_set
);
108 if (!(old_msr
& msr_recoverable_interrupt
)) {
109 cpu_error(processor
, cia
,
110 "double interrupt - MSR[RI] bit clear when attempting to deliver interrupt, cia=0x%lx, msr=0x%lx; srr0=0x%lx(cia), srr1=0x%lx(msr); trap-vector=0x%lx, trap-msr=0x%lx",
112 (unsigned long)old_msr
,
115 (unsigned long)vector_offset
,
116 (unsigned long)new_msr
);
119 SRR1
= interrupt_srr1(old_msr
, srr1_clear
, srr1_set
);
121 nia
= interrupt_base_ea(new_msr
) + vector_offset
;
122 cpu_synchronize_context(processor
, cia
);
129 machine_check_interrupt(cpu
*processor
,
132 switch (CURRENT_ENVIRONMENT
) {
134 case USER_ENVIRONMENT
:
135 case VIRTUAL_ENVIRONMENT
:
136 cpu_error(processor
, cia
, "machine-check interrupt");
138 case OPERATING_ENVIRONMENT
:
139 TRACE(trace_interrupts
, ("machine-check interrupt - cia=0x%lx\n",
140 (unsigned long)cia
));
141 cia
= perform_oea_interrupt(processor
, cia
, 0x00200, 0, 0, 0, 0);
142 cpu_restart(processor
, cia
);
145 error("internal error - machine_check_interrupt - bad switch");
153 data_storage_interrupt(cpu
*processor
,
156 storage_interrupt_reasons reason
,
159 switch (CURRENT_ENVIRONMENT
) {
161 case USER_ENVIRONMENT
:
162 case VIRTUAL_ENVIRONMENT
:
163 error("internal error - data_storage_interrupt - should not be called in VEA mode");
166 case OPERATING_ENVIRONMENT
:
168 spreg direction
= (is_store
? dsisr_store_operation
: 0);
170 case direct_store_storage_interrupt
:
171 DSISR
= dsisr_direct_store_error_exception
| direction
;
173 case hash_table_miss_storage_interrupt
:
174 DSISR
= dsisr_hash_table_or_dbat_miss
| direction
;
176 case protection_violation_storage_interrupt
:
177 DSISR
= dsisr_protection_violation
| direction
;
179 case earwax_violation_storage_interrupt
:
180 DSISR
= dsisr_earwax_violation
| direction
;
182 case segment_table_miss_storage_interrupt
:
183 DSISR
= dsisr_segment_table_miss
| direction
;
185 case earwax_disabled_storage_interrupt
:
186 DSISR
= dsisr_earwax_disabled
| direction
;
189 error("internal error - data_storage_interrupt - reason %d not implemented", reason
);
193 TRACE(trace_interrupts
, ("data storage interrupt - cia=0x%lx DAR=0x%lx DSISR=0x%lx\n",
196 (unsigned long)DSISR
));
197 cia
= perform_oea_interrupt(processor
, cia
, 0x00300, 0, 0, 0, 0);
198 cpu_restart(processor
, cia
);
202 error("internal error - data_storage_interrupt - bad switch");
210 instruction_storage_interrupt(cpu
*processor
,
212 storage_interrupt_reasons reason
)
214 switch (CURRENT_ENVIRONMENT
) {
216 case USER_ENVIRONMENT
:
217 case VIRTUAL_ENVIRONMENT
:
218 error("internal error - instruction_storage_interrupt - should not be called in VEA mode");
220 case OPERATING_ENVIRONMENT
:
224 case hash_table_miss_storage_interrupt
:
225 srr1_set
= srr1_hash_table_or_ibat_miss
;
227 case direct_store_storage_interrupt
:
228 srr1_set
= srr1_direct_store_error_exception
;
230 case protection_violation_storage_interrupt
:
231 srr1_set
= srr1_protection_violation
;
233 case segment_table_miss_storage_interrupt
:
234 srr1_set
= srr1_segment_table_miss
;
238 error("internal error - instruction_storage_interrupt - reason %d not implemented");
241 TRACE(trace_interrupts
, ("instruction storage interrupt - cia=0x%lx SRR1|=0x%lx\n",
243 (unsigned long)srr1_set
));
244 cia
= perform_oea_interrupt(processor
, cia
, 0x00400, 0, 0, 0, srr1_set
);
245 cpu_restart(processor
, cia
);
249 error("internal error - instruction_storage_interrupt - bad switch");
258 alignment_interrupt(cpu
*processor
,
262 switch (CURRENT_ENVIRONMENT
) {
264 case USER_ENVIRONMENT
:
265 case VIRTUAL_ENVIRONMENT
:
266 cpu_error(processor
, cia
, "alignment interrupt - ra=0x%lx", ra
);
268 case OPERATING_ENVIRONMENT
:
270 DSISR
= 0; /* FIXME */
271 TRACE(trace_interrupts
, ("alignment interrupt - cia=0x%lx DAR=0x%lx DSISR=0x%lx\n",
274 (unsigned long)DSISR
));
275 cia
= perform_oea_interrupt(processor
, cia
, 0x00600, 0, 0, 0, 0);
276 cpu_restart(processor
, cia
);
279 error("internal error - alignment_interrupt - bad switch");
289 program_interrupt(cpu
*processor
,
291 program_interrupt_reasons reason
)
293 switch (CURRENT_ENVIRONMENT
) {
295 case USER_ENVIRONMENT
:
296 case VIRTUAL_ENVIRONMENT
:
298 case floating_point_enabled_program_interrupt
:
299 cpu_error(processor
, cia
, "program interrupt - %s",
300 "floating point enabled");
302 case illegal_instruction_program_interrupt
:
303 cpu_error(processor
, cia
, "program interrupt - %s",
304 "illegal instruction");
306 case privileged_instruction_program_interrupt
:
307 cpu_error(processor
, cia
, "program interrupt - %s",
308 "privileged instruction");
310 case trap_program_interrupt
:
311 cpu_error(processor
, cia
, "program interrupt - %s",
314 case optional_instruction_program_interrupt
:
315 cpu_error(processor
, cia
, "program interrupt - %s",
316 "illegal instruction (optional instruction not supported)");
318 case mpc860c0_instruction_program_interrupt
:
319 cpu_error(processor
, cia
, "program interrupt - %s",
320 "problematic branch detected, see MPC860 C0 errata");
323 error("internal error - program_interrupt - reason %d not implemented", reason
);
326 case OPERATING_ENVIRONMENT
:
330 case floating_point_enabled_program_interrupt
:
331 srr1_set
= srr1_floating_point_enabled
;
333 case optional_instruction_program_interrupt
:
334 case illegal_instruction_program_interrupt
:
335 srr1_set
= srr1_illegal_instruction
;
337 case privileged_instruction_program_interrupt
:
338 srr1_set
= srr1_priviliged_instruction
;
340 case trap_program_interrupt
:
341 srr1_set
= srr1_trap
;
343 case mpc860c0_instruction_program_interrupt
:
345 cpu_error(processor
, cia
, "program interrupt - %s",
346 "problematic branch detected, see MPC860 C0 errata");
350 error("internal error - program_interrupt - reason %d not implemented", reason
);
353 TRACE(trace_interrupts
, ("program interrupt - cia=0x%lx SRR1|=0x%lx\n",
355 (unsigned long)srr1_set
));
356 cia
= perform_oea_interrupt(processor
, cia
, 0x00700, 0, 0, 0, srr1_set
);
357 cpu_restart(processor
, cia
);
361 error("internal error - program_interrupt - bad switch");
369 floating_point_unavailable_interrupt(cpu
*processor
,
372 switch (CURRENT_ENVIRONMENT
) {
374 case USER_ENVIRONMENT
:
375 case VIRTUAL_ENVIRONMENT
:
376 cpu_error(processor
, cia
, "floating-point unavailable interrupt");
378 case OPERATING_ENVIRONMENT
:
379 TRACE(trace_interrupts
, ("floating-point unavailable interrupt - cia=0x%lx\n",
380 (unsigned long)cia
));
381 cia
= perform_oea_interrupt(processor
, cia
, 0x00800, 0, 0, 0, 0);
382 cpu_restart(processor
, cia
);
385 error("internal error - floating_point_unavailable_interrupt - bad switch");
393 system_call_interrupt(cpu
*processor
,
396 TRACE(trace_interrupts
, ("system-call interrupt - cia=0x%lx\n", (unsigned long)cia
));
398 switch (CURRENT_ENVIRONMENT
) {
400 case USER_ENVIRONMENT
:
401 case VIRTUAL_ENVIRONMENT
:
402 os_emul_system_call(processor
, cia
);
403 cpu_restart(processor
, cia
+4);
405 case OPERATING_ENVIRONMENT
:
406 cia
= perform_oea_interrupt(processor
, cia
+4, 0x00c00, 0, 0, 0, 0);
407 cpu_restart(processor
, cia
);
410 error("internal error - system_call_interrupt - bad switch");
417 floating_point_assist_interrupt(cpu
*processor
,
420 switch (CURRENT_ENVIRONMENT
) {
422 case USER_ENVIRONMENT
:
423 case VIRTUAL_ENVIRONMENT
:
424 cpu_error(processor
, cia
, "floating-point assist interrupt");
426 case OPERATING_ENVIRONMENT
:
427 TRACE(trace_interrupts
, ("floating-point assist interrupt - cia=0x%lx\n", (unsigned long)cia
));
428 cia
= perform_oea_interrupt(processor
, cia
, 0x00e00, 0, 0, 0, 0);
429 cpu_restart(processor
, cia
);
432 error("internal error - floating_point_assist_interrupt - bad switch");
439 /* handle an externally generated event or an interrupt that has just
440 been enabled through changes to the MSR. */
442 STATIC_INLINE_INTERRUPTS\
444 deliver_hardware_interrupt(void *data
)
446 cpu
*processor
= (cpu
*)data
;
447 interrupts
*ints
= cpu_interrupts(processor
);
448 ints
->delivery_scheduled
= NULL
;
449 if ((cpu_registers(processor
)->msr
& (msr_floating_point_exception_mode_0
450 | msr_floating_point_exception_mode_1
))
451 && cpu_registers(processor
)->fpscr
& fpscr_fex
) {
452 msreg srr1_set
= srr1_floating_point_enabled
| srr1_subsequent_instruction
;
453 unsigned_word cia
= cpu_get_program_counter(processor
);
454 unsigned_word nia
= perform_oea_interrupt(processor
,
455 cia
, 0x00700, 0, 0, 0, srr1_set
);
456 cpu_set_program_counter(processor
, nia
);
458 else if (cpu_registers(processor
)->msr
& msr_external_interrupt_enable
) {
459 /* external interrupts have a high priority and remain pending */
460 if (ints
->pending_interrupts
& external_interrupt_pending
) {
461 unsigned_word cia
= cpu_get_program_counter(processor
);
462 unsigned_word nia
= perform_oea_interrupt(processor
,
463 cia
, 0x00500, 0, 0, 0, 0);
464 TRACE(trace_interrupts
, ("external interrupt - cia=0x%lx\n", (unsigned long)cia
));
465 cpu_set_program_counter(processor
, nia
);
467 /* decrementer interrupts have a lower priority and are once only */
468 else if (ints
->pending_interrupts
& decrementer_interrupt_pending
) {
469 unsigned_word cia
= cpu_get_program_counter(processor
);
470 unsigned_word nia
= perform_oea_interrupt(processor
,
471 cia
, 0x00900, 0, 0, 0, 0);
472 TRACE(trace_interrupts
, ("decrementer interrupt - cia 0x%lx, time %ld\n",
474 (unsigned long)event_queue_time(psim_event_queue(cpu_system(processor
)))
476 cpu_set_program_counter(processor
, nia
);
477 ints
->pending_interrupts
&= ~decrementer_interrupt_pending
;
482 STATIC_INLINE_INTERRUPTS\
484 schedule_hardware_interrupt_delivery(cpu
*processor
)
486 interrupts
*ints
= cpu_interrupts(processor
);
487 if (ints
->delivery_scheduled
== NULL
) {
488 ints
->delivery_scheduled
=
489 event_queue_schedule(psim_event_queue(cpu_system(processor
)),
490 0, deliver_hardware_interrupt
, processor
);
497 check_masked_interrupts(cpu
*processor
)
499 if (((cpu_registers(processor
)->msr
& (msr_floating_point_exception_mode_0
500 | msr_floating_point_exception_mode_1
))
501 && cpu_registers(processor
)->fpscr
& fpscr_fex
)
502 || ((cpu_registers(processor
)->msr
& msr_external_interrupt_enable
)
503 && (cpu_interrupts(processor
)->pending_interrupts
)))
504 schedule_hardware_interrupt_delivery(processor
);
509 decrementer_interrupt(cpu
*processor
)
511 interrupts
*ints
= cpu_interrupts(processor
);
512 ints
->pending_interrupts
|= decrementer_interrupt_pending
;
513 if (cpu_registers(processor
)->msr
& msr_external_interrupt_enable
) {
514 schedule_hardware_interrupt_delivery(processor
);
520 external_interrupt(cpu
*processor
,
523 interrupts
*ints
= cpu_interrupts(processor
);
525 if (!(ints
->pending_interrupts
& external_interrupt_pending
)) {
526 ints
->pending_interrupts
|= external_interrupt_pending
;
527 if (cpu_registers(processor
)->msr
& msr_external_interrupt_enable
)
528 schedule_hardware_interrupt_delivery(processor
);
531 /* check that we haven't missed out on a chance to deliver an
533 ASSERT(!(cpu_registers(processor
)->msr
& msr_external_interrupt_enable
));
537 ints
->pending_interrupts
&= ~external_interrupt_pending
;
541 #endif /* _INTERRUPTS_C_ */