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 3 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, see <http://www.gnu.org/licenses/>.
21 #ifndef _INTERRUPTS_C_
22 #define _INTERRUPTS_C_
31 /* Operating environment support code
33 Unlike the VEA, the OEA must fully model the effect an interrupt
34 has on the processors state.
36 Each function below return updated values for registers effected by
40 STATIC_INLINE_INTERRUPTS\
42 interrupt_msr(msreg old_msr,
46 msreg msr_set_to_0 = (msr_branch_trace_enable
48 | msr_external_interrupt_enable
49 | msr_floating_point_exception_mode_0
50 | msr_floating_point_exception_mode_1
51 | msr_floating_point_available
52 | msr_instruction_relocate
53 | msr_power_management_enable
55 | msr_recoverable_interrupt
56 | msr_single_step_trace_enable);
57 /* remember, in 32bit mode msr_64bit_mode is zero */
58 msreg new_msr = ((((old_msr & ~msr_set_to_0)
66 STATIC_INLINE_INTERRUPTS\
68 interrupt_srr1(msreg old_msr,
72 spreg srr1_mask = (MASK(0,32)
75 spreg srr1 = (old_msr & srr1_mask & ~srr1_clear) | srr1_set;
80 STATIC_INLINE_INTERRUPTS\
82 interrupt_base_ea(msreg msr)
84 if (msr & msr_interrupt_prefix)
91 /* finish off an interrupt for the OEA model, updating all registers
92 and forcing a restart of the processor */
94 STATIC_INLINE_INTERRUPTS\
96 perform_oea_interrupt(cpu *processor,
98 unsigned_word vector_offset,
105 msreg new_msr = interrupt_msr(old_msr, msr_clear, msr_set);
107 if (!(old_msr & msr_recoverable_interrupt)) {
108 cpu_error(processor, cia,
109 "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",
111 (unsigned long)old_msr,
114 (unsigned long)vector_offset,
115 (unsigned long)new_msr);
118 SRR1 = interrupt_srr1(old_msr, srr1_clear, srr1_set);
120 nia = interrupt_base_ea(new_msr) + vector_offset;
121 cpu_synchronize_context(processor, cia);
128 machine_check_interrupt(cpu *processor,
131 switch (CURRENT_ENVIRONMENT) {
133 case USER_ENVIRONMENT:
134 case VIRTUAL_ENVIRONMENT:
135 cpu_error(processor, cia, "machine-check interrupt");
137 case OPERATING_ENVIRONMENT:
138 TRACE(trace_interrupts, ("machine-check interrupt - cia=0x%lx\n",
139 (unsigned long)cia));
140 cia = perform_oea_interrupt(processor, cia, 0x00200, 0, 0, 0, 0);
141 cpu_restart(processor, cia);
144 error("internal error - machine_check_interrupt - bad switch");
152 data_storage_interrupt(cpu *processor,
155 storage_interrupt_reasons reason,
158 switch (CURRENT_ENVIRONMENT) {
160 case USER_ENVIRONMENT:
161 case VIRTUAL_ENVIRONMENT:
162 error("internal error - data_storage_interrupt - should not be called in VEA mode");
165 case OPERATING_ENVIRONMENT:
167 spreg direction = (is_store ? dsisr_store_operation : 0);
169 case direct_store_storage_interrupt:
170 DSISR = dsisr_direct_store_error_exception | direction;
172 case hash_table_miss_storage_interrupt:
173 DSISR = dsisr_hash_table_or_dbat_miss | direction;
175 case protection_violation_storage_interrupt:
176 DSISR = dsisr_protection_violation | direction;
178 case earwax_violation_storage_interrupt:
179 DSISR = dsisr_earwax_violation | direction;
181 case segment_table_miss_storage_interrupt:
182 DSISR = dsisr_segment_table_miss | direction;
184 case earwax_disabled_storage_interrupt:
185 DSISR = dsisr_earwax_disabled | direction;
188 error("internal error - data_storage_interrupt - reason %d not implemented", reason);
192 TRACE(trace_interrupts, ("data storage interrupt - cia=0x%lx DAR=0x%lx DSISR=0x%lx\n",
195 (unsigned long)DSISR));
196 cia = perform_oea_interrupt(processor, cia, 0x00300, 0, 0, 0, 0);
197 cpu_restart(processor, cia);
201 error("internal error - data_storage_interrupt - bad switch");
209 instruction_storage_interrupt(cpu *processor,
211 storage_interrupt_reasons reason)
213 switch (CURRENT_ENVIRONMENT) {
215 case USER_ENVIRONMENT:
216 case VIRTUAL_ENVIRONMENT:
217 error("internal error - instruction_storage_interrupt - should not be called in VEA mode");
219 case OPERATING_ENVIRONMENT:
223 case hash_table_miss_storage_interrupt:
224 srr1_set = srr1_hash_table_or_ibat_miss;
226 case direct_store_storage_interrupt:
227 srr1_set = srr1_direct_store_error_exception;
229 case protection_violation_storage_interrupt:
230 srr1_set = srr1_protection_violation;
232 case segment_table_miss_storage_interrupt:
233 srr1_set = srr1_segment_table_miss;
237 error("internal error - instruction_storage_interrupt - reason %d not implemented");
240 TRACE(trace_interrupts, ("instruction storage interrupt - cia=0x%lx SRR1|=0x%lx\n",
242 (unsigned long)srr1_set));
243 cia = perform_oea_interrupt(processor, cia, 0x00400, 0, 0, 0, srr1_set);
244 cpu_restart(processor, cia);
248 error("internal error - instruction_storage_interrupt - bad switch");
257 alignment_interrupt(cpu *processor,
261 switch (CURRENT_ENVIRONMENT) {
263 case USER_ENVIRONMENT:
264 case VIRTUAL_ENVIRONMENT:
265 cpu_error(processor, cia, "alignment interrupt - ra=0x%lx", ra);
267 case OPERATING_ENVIRONMENT:
269 DSISR = 0; /* FIXME */
270 TRACE(trace_interrupts, ("alignment interrupt - cia=0x%lx DAR=0x%lx DSISR=0x%lx\n",
273 (unsigned long)DSISR));
274 cia = perform_oea_interrupt(processor, cia, 0x00600, 0, 0, 0, 0);
275 cpu_restart(processor, cia);
278 error("internal error - alignment_interrupt - bad switch");
288 program_interrupt(cpu *processor,
290 program_interrupt_reasons reason)
292 switch (CURRENT_ENVIRONMENT) {
294 case USER_ENVIRONMENT:
295 case VIRTUAL_ENVIRONMENT:
297 case floating_point_enabled_program_interrupt:
298 cpu_error(processor, cia, "program interrupt - %s",
299 "floating point enabled");
301 case illegal_instruction_program_interrupt:
302 cpu_error(processor, cia, "program interrupt - %s",
303 "illegal instruction");
305 case privileged_instruction_program_interrupt:
306 cpu_error(processor, cia, "program interrupt - %s",
307 "privileged instruction");
309 case trap_program_interrupt:
310 cpu_error(processor, cia, "program interrupt - %s",
313 case optional_instruction_program_interrupt:
314 cpu_error(processor, cia, "program interrupt - %s",
315 "illegal instruction (optional instruction not supported)");
317 case mpc860c0_instruction_program_interrupt:
318 cpu_error(processor, cia, "program interrupt - %s",
319 "problematic branch detected, see MPC860 C0 errata");
322 error("internal error - program_interrupt - reason %d not implemented", reason);
325 case OPERATING_ENVIRONMENT:
329 case floating_point_enabled_program_interrupt:
330 srr1_set = srr1_floating_point_enabled;
332 case optional_instruction_program_interrupt:
333 case illegal_instruction_program_interrupt:
334 srr1_set = srr1_illegal_instruction;
336 case privileged_instruction_program_interrupt:
337 srr1_set = srr1_priviliged_instruction;
339 case trap_program_interrupt:
340 srr1_set = srr1_trap;
342 case mpc860c0_instruction_program_interrupt:
344 cpu_error(processor, cia, "program interrupt - %s",
345 "problematic branch detected, see MPC860 C0 errata");
349 error("internal error - program_interrupt - reason %d not implemented", reason);
352 TRACE(trace_interrupts, ("program interrupt - cia=0x%lx SRR1|=0x%lx\n",
354 (unsigned long)srr1_set));
355 cia = perform_oea_interrupt(processor, cia, 0x00700, 0, 0, 0, srr1_set);
356 cpu_restart(processor, cia);
360 error("internal error - program_interrupt - bad switch");
368 floating_point_unavailable_interrupt(cpu *processor,
371 switch (CURRENT_ENVIRONMENT) {
373 case USER_ENVIRONMENT:
374 case VIRTUAL_ENVIRONMENT:
375 cpu_error(processor, cia, "floating-point unavailable interrupt");
377 case OPERATING_ENVIRONMENT:
378 TRACE(trace_interrupts, ("floating-point unavailable interrupt - cia=0x%lx\n",
379 (unsigned long)cia));
380 cia = perform_oea_interrupt(processor, cia, 0x00800, 0, 0, 0, 0);
381 cpu_restart(processor, cia);
384 error("internal error - floating_point_unavailable_interrupt - bad switch");
392 system_call_interrupt(cpu *processor,
395 TRACE(trace_interrupts, ("system-call interrupt - cia=0x%lx\n", (unsigned long)cia));
397 switch (CURRENT_ENVIRONMENT) {
399 case USER_ENVIRONMENT:
400 case VIRTUAL_ENVIRONMENT:
401 os_emul_system_call(processor, cia);
402 cpu_restart(processor, cia+4);
404 case OPERATING_ENVIRONMENT:
405 cia = perform_oea_interrupt(processor, cia+4, 0x00c00, 0, 0, 0, 0);
406 cpu_restart(processor, cia);
409 error("internal error - system_call_interrupt - bad switch");
416 floating_point_assist_interrupt(cpu *processor,
419 switch (CURRENT_ENVIRONMENT) {
421 case USER_ENVIRONMENT:
422 case VIRTUAL_ENVIRONMENT:
423 cpu_error(processor, cia, "floating-point assist interrupt");
425 case OPERATING_ENVIRONMENT:
426 TRACE(trace_interrupts, ("floating-point assist interrupt - cia=0x%lx\n", (unsigned long)cia));
427 cia = perform_oea_interrupt(processor, cia, 0x00e00, 0, 0, 0, 0);
428 cpu_restart(processor, cia);
431 error("internal error - floating_point_assist_interrupt - bad switch");
438 /* handle an externally generated event or an interrupt that has just
439 been enabled through changes to the MSR. */
441 STATIC_INLINE_INTERRUPTS\
443 deliver_hardware_interrupt(void *data)
445 cpu *processor = (cpu*)data;
446 interrupts *ints = cpu_interrupts(processor);
447 ints->delivery_scheduled = NULL;
448 if ((cpu_registers(processor)->msr & (msr_floating_point_exception_mode_0
449 | msr_floating_point_exception_mode_1))
450 && cpu_registers(processor)->fpscr & fpscr_fex) {
451 msreg srr1_set = srr1_floating_point_enabled | srr1_subsequent_instruction;
452 unsigned_word cia = cpu_get_program_counter(processor);
453 unsigned_word nia = perform_oea_interrupt(processor,
454 cia, 0x00700, 0, 0, 0, srr1_set);
455 cpu_set_program_counter(processor, nia);
457 else if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
458 /* external interrupts have a high priority and remain pending */
459 if (ints->pending_interrupts & external_interrupt_pending) {
460 unsigned_word cia = cpu_get_program_counter(processor);
461 unsigned_word nia = perform_oea_interrupt(processor,
462 cia, 0x00500, 0, 0, 0, 0);
463 TRACE(trace_interrupts, ("external interrupt - cia=0x%lx\n", (unsigned long)cia));
464 cpu_set_program_counter(processor, nia);
466 /* decrementer interrupts have a lower priority and are once only */
467 else if (ints->pending_interrupts & decrementer_interrupt_pending) {
468 unsigned_word cia = cpu_get_program_counter(processor);
469 unsigned_word nia = perform_oea_interrupt(processor,
470 cia, 0x00900, 0, 0, 0, 0);
471 TRACE(trace_interrupts, ("decrementer interrupt - cia 0x%lx, time %ld\n",
473 (unsigned long)event_queue_time(psim_event_queue(cpu_system(processor)))
475 cpu_set_program_counter(processor, nia);
476 ints->pending_interrupts &= ~decrementer_interrupt_pending;
481 STATIC_INLINE_INTERRUPTS\
483 schedule_hardware_interrupt_delivery(cpu *processor)
485 interrupts *ints = cpu_interrupts(processor);
486 if (ints->delivery_scheduled == NULL) {
487 ints->delivery_scheduled =
488 event_queue_schedule(psim_event_queue(cpu_system(processor)),
489 0, deliver_hardware_interrupt, processor);
496 check_masked_interrupts(cpu *processor)
498 if (((cpu_registers(processor)->msr & (msr_floating_point_exception_mode_0
499 | msr_floating_point_exception_mode_1))
500 && cpu_registers(processor)->fpscr & fpscr_fex)
501 || ((cpu_registers(processor)->msr & msr_external_interrupt_enable)
502 && (cpu_interrupts(processor)->pending_interrupts)))
503 schedule_hardware_interrupt_delivery(processor);
508 decrementer_interrupt(cpu *processor)
510 interrupts *ints = cpu_interrupts(processor);
511 ints->pending_interrupts |= decrementer_interrupt_pending;
512 if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
513 schedule_hardware_interrupt_delivery(processor);
519 external_interrupt(cpu *processor,
522 interrupts *ints = cpu_interrupts(processor);
524 if (!(ints->pending_interrupts & external_interrupt_pending)) {
525 ints->pending_interrupts |= external_interrupt_pending;
526 if (cpu_registers(processor)->msr & msr_external_interrupt_enable)
527 schedule_hardware_interrupt_delivery(processor);
530 /* check that we haven't missed out on a chance to deliver an
532 ASSERT(!(cpu_registers(processor)->msr & msr_external_interrupt_enable));
536 ints->pending_interrupts &= ~external_interrupt_pending;
540 #endif /* _INTERRUPTS_C_ */