1 /* This file is part of the program psim.
3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
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 #ifdef WITH_OPTION_MPC860C0
319 case mpc860c0_instruction_program_interrupt
:
320 cpu_error(processor
, cia
, "program interrupt - %s",
321 "problematic branch detected, see MPC860 C0 errata");
323 #endif // WITH_OPTION_MPC860C0
325 error("internal error - program_interrupt - reason %d not implemented", reason
);
328 case OPERATING_ENVIRONMENT
:
332 case floating_point_enabled_program_interrupt
:
333 srr1_set
= srr1_floating_point_enabled
;
335 case optional_instruction_program_interrupt
:
336 case illegal_instruction_program_interrupt
:
337 srr1_set
= srr1_illegal_instruction
;
339 case privileged_instruction_program_interrupt
:
340 srr1_set
= srr1_priviliged_instruction
;
342 case trap_program_interrupt
:
343 srr1_set
= srr1_trap
;
345 #ifdef WITH_OPTION_MPC860C0
346 case mpc860c0_instruction_program_interrupt
:
348 error(processor
, cia
, "program interrupt - %s",
349 "problematic branch detected, see MPC860 C0 errata");
351 #endif // WITH_OPTION_MPC860C0
354 error("internal error - program_interrupt - reason %d not implemented", reason
);
357 TRACE(trace_interrupts
, ("program interrupt - cia=0x%lx SRR1|=0x%lx\n",
359 (unsigned long)srr1_set
));
360 cia
= perform_oea_interrupt(processor
, cia
, 0x00700, 0, 0, 0, srr1_set
);
361 cpu_restart(processor
, cia
);
365 error("internal error - program_interrupt - bad switch");
373 floating_point_unavailable_interrupt(cpu
*processor
,
376 switch (CURRENT_ENVIRONMENT
) {
378 case USER_ENVIRONMENT
:
379 case VIRTUAL_ENVIRONMENT
:
380 cpu_error(processor
, cia
, "floating-point unavailable interrupt");
382 case OPERATING_ENVIRONMENT
:
383 TRACE(trace_interrupts
, ("floating-point unavailable interrupt - cia=0x%lx\n",
384 (unsigned long)cia
));
385 cia
= perform_oea_interrupt(processor
, cia
, 0x00800, 0, 0, 0, 0);
386 cpu_restart(processor
, cia
);
389 error("internal error - floating_point_unavailable_interrupt - bad switch");
397 system_call_interrupt(cpu
*processor
,
400 TRACE(trace_interrupts
, ("system-call interrupt - cia=0x%lx\n", (unsigned long)cia
));
402 switch (CURRENT_ENVIRONMENT
) {
404 case USER_ENVIRONMENT
:
405 case VIRTUAL_ENVIRONMENT
:
406 os_emul_system_call(processor
, cia
);
407 cpu_restart(processor
, cia
+4);
409 case OPERATING_ENVIRONMENT
:
410 cia
= perform_oea_interrupt(processor
, cia
+4, 0x00c00, 0, 0, 0, 0);
411 cpu_restart(processor
, cia
);
414 error("internal error - system_call_interrupt - bad switch");
421 floating_point_assist_interrupt(cpu
*processor
,
424 switch (CURRENT_ENVIRONMENT
) {
426 case USER_ENVIRONMENT
:
427 case VIRTUAL_ENVIRONMENT
:
428 cpu_error(processor
, cia
, "floating-point assist interrupt");
430 case OPERATING_ENVIRONMENT
:
431 TRACE(trace_interrupts
, ("floating-point assist interrupt - cia=0x%lx\n", (unsigned long)cia
));
432 cia
= perform_oea_interrupt(processor
, cia
, 0x00e00, 0, 0, 0, 0);
433 cpu_restart(processor
, cia
);
436 error("internal error - floating_point_assist_interrupt - bad switch");
443 /* handle an externally generated event or an interrupt that has just
444 been enabled through changes to the MSR. */
446 STATIC_INLINE_INTERRUPTS\
448 deliver_hardware_interrupt(void *data
)
450 cpu
*processor
= (cpu
*)data
;
451 interrupts
*ints
= cpu_interrupts(processor
);
452 ints
->delivery_scheduled
= NULL
;
453 if ((cpu_registers(processor
)->msr
& (msr_floating_point_exception_mode_0
454 | msr_floating_point_exception_mode_1
))
455 && cpu_registers(processor
)->fpscr
& fpscr_fex
) {
456 msreg srr1_set
= srr1_floating_point_enabled
| srr1_subsequent_instruction
;
457 unsigned_word cia
= cpu_get_program_counter(processor
);
458 unsigned_word nia
= perform_oea_interrupt(processor
,
459 cia
, 0x00700, 0, 0, 0, srr1_set
);
460 cpu_set_program_counter(processor
, nia
);
462 else if (cpu_registers(processor
)->msr
& msr_external_interrupt_enable
) {
463 /* external interrupts have a high priority and remain pending */
464 if (ints
->pending_interrupts
& external_interrupt_pending
) {
465 unsigned_word cia
= cpu_get_program_counter(processor
);
466 unsigned_word nia
= perform_oea_interrupt(processor
,
467 cia
, 0x00500, 0, 0, 0, 0);
468 TRACE(trace_interrupts
, ("external interrupt - cia=0x%lx\n", (unsigned long)cia
));
469 cpu_set_program_counter(processor
, nia
);
471 /* decrementer interrupts have a lower priority and are once only */
472 else if (ints
->pending_interrupts
& decrementer_interrupt_pending
) {
473 unsigned_word cia
= cpu_get_program_counter(processor
);
474 unsigned_word nia
= perform_oea_interrupt(processor
,
475 cia
, 0x00900, 0, 0, 0, 0);
476 TRACE(trace_interrupts
, ("decrementer interrupt - cia=0x%lx time=0x%lx\n",
478 (unsigned long)event_queue_time(psim_event_queue(cpu_system(processor
)))
480 cpu_set_program_counter(processor
, nia
);
481 ints
->pending_interrupts
&= ~decrementer_interrupt_pending
;
486 STATIC_INLINE_INTERRUPTS\
488 schedule_hardware_interrupt_delivery(cpu
*processor
)
490 interrupts
*ints
= cpu_interrupts(processor
);
491 if (ints
->delivery_scheduled
== NULL
) {
492 ints
->delivery_scheduled
=
493 event_queue_schedule(psim_event_queue(cpu_system(processor
)),
494 0, deliver_hardware_interrupt
, processor
);
501 check_masked_interrupts(cpu
*processor
)
503 if (((cpu_registers(processor
)->msr
& (msr_floating_point_exception_mode_0
504 | msr_floating_point_exception_mode_1
))
505 && cpu_registers(processor
)->fpscr
& fpscr_fex
)
506 || ((cpu_registers(processor
)->msr
& msr_external_interrupt_enable
)
507 && (cpu_interrupts(processor
)->pending_interrupts
)))
508 schedule_hardware_interrupt_delivery(processor
);
513 decrementer_interrupt(cpu
*processor
)
515 interrupts
*ints
= cpu_interrupts(processor
);
516 ints
->pending_interrupts
|= decrementer_interrupt_pending
;
517 if (cpu_registers(processor
)->msr
& msr_external_interrupt_enable
) {
518 schedule_hardware_interrupt_delivery(processor
);
524 external_interrupt(cpu
*processor
,
527 interrupts
*ints
= cpu_interrupts(processor
);
529 if (!ints
->pending_interrupts
& external_interrupt_pending
) {
530 ints
->pending_interrupts
|= external_interrupt_pending
;
531 if (cpu_registers(processor
)->msr
& msr_external_interrupt_enable
)
532 schedule_hardware_interrupt_delivery(processor
);
535 /* check that we haven't missed out on a chance to deliver an
537 ASSERT(!(cpu_registers(processor
)->msr
& msr_external_interrupt_enable
));
541 ints
->pending_interrupts
&= ~external_interrupt_pending
;
545 #endif /* _INTERRUPTS_C_ */