sim/ppc/*: Change immediatly to immediately
[external/binutils.git] / sim / ppc / interrupts.c
1 /*  This file is part of the program psim.
2
3     Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney
4
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.
9
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.
14  
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/>.
17  
18     */
19
20
21 #ifndef _INTERRUPTS_C_
22 #define _INTERRUPTS_C_
23
24 #include <signal.h>
25
26 #include "cpu.h"
27 #include "idecode.h"
28 #include "os_emul.h"
29
30
31 /* Operating environment support code
32
33    Unlike the VEA, the OEA must fully model the effect an interrupt
34    has on the processors state.
35
36    Each function below return updated values for registers effected by
37    interrupts */
38
39
40 STATIC_INLINE_INTERRUPTS\
41 (msreg)
42 interrupt_msr(msreg old_msr,
43               msreg msr_clear,
44               msreg msr_set)
45 {
46   msreg msr_set_to_0 = (msr_branch_trace_enable
47                         | msr_data_relocate
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
54                         | msr_problem_state
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)
59                      | msr_64bit_mode)
60                     & ~msr_clear)
61                    | msr_set);
62   return new_msr;
63 }
64
65
66 STATIC_INLINE_INTERRUPTS\
67 (msreg)
68 interrupt_srr1(msreg old_msr,
69                msreg srr1_clear,
70                msreg srr1_set)
71 {
72   spreg srr1_mask = (MASK(0,32)
73                      | MASK(37, 41)
74                      | MASK(48, 63));
75   spreg srr1 = (old_msr & srr1_mask & ~srr1_clear) | srr1_set;
76   return srr1;
77 }
78
79
80 STATIC_INLINE_INTERRUPTS\
81 (unsigned_word)
82 interrupt_base_ea(msreg msr)
83 {
84   if (msr & msr_interrupt_prefix)
85     return MASK(0, 43);
86   else
87     return 0;
88 }
89
90
91 /* finish off an interrupt for the OEA model, updating all registers
92    and forcing a restart of the processor */
93
94 STATIC_INLINE_INTERRUPTS\
95 (unsigned_word)
96 perform_oea_interrupt(cpu *processor,
97                       unsigned_word cia,
98                       unsigned_word vector_offset,
99                       msreg msr_clear,
100                       msreg msr_set,
101                       msreg srr1_clear,
102                       msreg srr1_set)
103 {
104   msreg old_msr = MSR;
105   msreg new_msr = interrupt_msr(old_msr, msr_clear, msr_set);
106   unsigned_word nia;
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",
110               (unsigned long)cia,
111               (unsigned long)old_msr,
112               (unsigned long)SRR0,
113               (unsigned long)SRR1,
114               (unsigned long)vector_offset,
115               (unsigned long)new_msr);
116   }
117   SRR0 = (spreg)(cia);
118   SRR1 = interrupt_srr1(old_msr, srr1_clear, srr1_set);
119   MSR = new_msr;
120   nia = interrupt_base_ea(new_msr) + vector_offset;
121   cpu_synchronize_context(processor, cia);
122   return nia;
123 }
124
125
126 INLINE_INTERRUPTS\
127 (void)
128 machine_check_interrupt(cpu *processor,
129                         unsigned_word cia)
130 {
131   switch (CURRENT_ENVIRONMENT) {
132
133   case USER_ENVIRONMENT:
134   case VIRTUAL_ENVIRONMENT:
135     cpu_error(processor, cia, "machine-check interrupt");
136
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);
142
143   default:
144     error("internal error - machine_check_interrupt - bad switch");
145
146   }
147 }
148
149
150 INLINE_INTERRUPTS\
151 (void)
152 data_storage_interrupt(cpu *processor,
153                        unsigned_word cia,
154                        unsigned_word ea,
155                        storage_interrupt_reasons reason,
156                        int is_store)
157 {
158   switch (CURRENT_ENVIRONMENT) {
159
160   case USER_ENVIRONMENT:
161   case VIRTUAL_ENVIRONMENT:
162     error("internal error - data_storage_interrupt - should not be called in VEA mode");
163     break;
164
165   case OPERATING_ENVIRONMENT:
166     {
167       spreg direction = (is_store ? dsisr_store_operation : 0);
168       switch (reason) {
169       case direct_store_storage_interrupt:
170         DSISR = dsisr_direct_store_error_exception | direction;
171         break;
172       case hash_table_miss_storage_interrupt:
173         DSISR = dsisr_hash_table_or_dbat_miss | direction;
174         break;
175       case protection_violation_storage_interrupt:
176         DSISR = dsisr_protection_violation | direction;
177         break;
178       case earwax_violation_storage_interrupt:
179         DSISR = dsisr_earwax_violation | direction;
180         break;
181       case segment_table_miss_storage_interrupt:
182         DSISR = dsisr_segment_table_miss | direction;
183         break;
184       case earwax_disabled_storage_interrupt:
185         DSISR = dsisr_earwax_disabled | direction;
186         break;
187       default:
188         error("internal error - data_storage_interrupt - reason %d not implemented", reason);
189         break;
190       }
191       DAR = (spreg)ea;
192       TRACE(trace_interrupts, ("data storage interrupt - cia=0x%lx DAR=0x%lx DSISR=0x%lx\n",
193                                (unsigned long)cia,
194                                (unsigned long)DAR,
195                                (unsigned long)DSISR));
196       cia = perform_oea_interrupt(processor, cia, 0x00300, 0, 0, 0, 0);
197       cpu_restart(processor, cia);
198     }
199
200   default:
201     error("internal error - data_storage_interrupt - bad switch");
202
203   }
204 }
205
206
207 INLINE_INTERRUPTS\
208 (void)
209 instruction_storage_interrupt(cpu *processor,
210                               unsigned_word cia,
211                               storage_interrupt_reasons reason)
212 {
213   switch (CURRENT_ENVIRONMENT) {
214
215   case USER_ENVIRONMENT:
216   case VIRTUAL_ENVIRONMENT:
217     error("internal error - instruction_storage_interrupt - should not be called in VEA mode");
218
219   case OPERATING_ENVIRONMENT:
220     {
221       msreg srr1_set;
222       switch(reason) {
223       case hash_table_miss_storage_interrupt:
224         srr1_set = srr1_hash_table_or_ibat_miss;
225         break;
226       case direct_store_storage_interrupt:
227         srr1_set = srr1_direct_store_error_exception;
228         break;
229       case protection_violation_storage_interrupt:
230         srr1_set = srr1_protection_violation;
231         break;
232       case segment_table_miss_storage_interrupt:
233         srr1_set = srr1_segment_table_miss;
234         break;
235       default:
236         srr1_set = 0;
237         error("internal error - instruction_storage_interrupt - reason %d not implemented");
238         break;
239       }
240       TRACE(trace_interrupts, ("instruction storage interrupt - cia=0x%lx SRR1|=0x%lx\n",
241                                (unsigned long)cia,
242                                (unsigned long)srr1_set));
243       cia = perform_oea_interrupt(processor, cia, 0x00400, 0, 0, 0, srr1_set);
244       cpu_restart(processor, cia);
245     }
246
247   default:
248     error("internal error - instruction_storage_interrupt - bad switch");
249
250   }
251 }
252
253
254
255 INLINE_INTERRUPTS\
256 (void)
257 alignment_interrupt(cpu *processor,
258                     unsigned_word cia,
259                     unsigned_word ra)
260 {
261   switch (CURRENT_ENVIRONMENT) {
262
263   case USER_ENVIRONMENT:
264   case VIRTUAL_ENVIRONMENT:
265     cpu_error(processor, cia, "alignment interrupt - ra=0x%lx", ra);
266     
267   case OPERATING_ENVIRONMENT:
268     DAR = (spreg)ra;
269     DSISR = 0; /* FIXME */
270     TRACE(trace_interrupts, ("alignment interrupt - cia=0x%lx DAR=0x%lx DSISR=0x%lx\n",
271                              (unsigned long)cia,
272                              (unsigned long)DAR,
273                              (unsigned long)DSISR));
274     cia = perform_oea_interrupt(processor, cia, 0x00600, 0, 0, 0, 0);
275     cpu_restart(processor, cia);
276
277   default:
278     error("internal error - alignment_interrupt - bad switch");
279     
280   }
281 }
282
283
284
285
286 INLINE_INTERRUPTS\
287 (void)
288 program_interrupt(cpu *processor,
289                   unsigned_word cia,
290                   program_interrupt_reasons reason)
291 {
292   switch (CURRENT_ENVIRONMENT) {
293
294   case USER_ENVIRONMENT:
295   case VIRTUAL_ENVIRONMENT:
296     switch (reason) {
297     case floating_point_enabled_program_interrupt:
298       cpu_error(processor, cia, "program interrupt - %s",
299                 "floating point enabled");
300       break;
301     case illegal_instruction_program_interrupt:
302       cpu_error(processor, cia, "program interrupt - %s",
303                 "illegal instruction");
304       break;
305     case privileged_instruction_program_interrupt:
306       cpu_error(processor, cia, "program interrupt - %s",
307                 "privileged instruction");
308       break;
309     case trap_program_interrupt:
310       cpu_error(processor, cia, "program interrupt - %s",
311                 "trap");
312       break;
313     case optional_instruction_program_interrupt:
314       cpu_error(processor, cia, "program interrupt - %s",
315                 "illegal instruction (optional instruction not supported)");
316       break;
317     case mpc860c0_instruction_program_interrupt:
318       cpu_error(processor, cia, "program interrupt - %s",
319                 "problematic branch detected, see MPC860 C0 errata");
320       break;
321     default:
322       error("internal error - program_interrupt - reason %d not implemented", reason);
323     }
324
325   case OPERATING_ENVIRONMENT:
326     {
327       msreg srr1_set;
328       switch (reason) {
329       case floating_point_enabled_program_interrupt:
330         srr1_set = srr1_floating_point_enabled;
331         break;
332       case optional_instruction_program_interrupt:
333       case illegal_instruction_program_interrupt:
334         srr1_set = srr1_illegal_instruction;
335         break;
336       case privileged_instruction_program_interrupt:
337         srr1_set = srr1_priviliged_instruction;
338         break;
339       case trap_program_interrupt:
340         srr1_set = srr1_trap;
341         break;
342       case mpc860c0_instruction_program_interrupt:
343         srr1_set = 0;
344         cpu_error(processor, cia, "program interrupt - %s",
345               "problematic branch detected, see MPC860 C0 errata");
346         break;
347       default:
348         srr1_set = 0;
349         error("internal error - program_interrupt - reason %d not implemented", reason);
350         break;
351       }
352       TRACE(trace_interrupts, ("program interrupt - cia=0x%lx SRR1|=0x%lx\n",
353                                (unsigned long)cia,
354                                (unsigned long)srr1_set));
355       cia = perform_oea_interrupt(processor, cia, 0x00700, 0, 0, 0, srr1_set);
356       cpu_restart(processor, cia);
357     }
358
359   default:
360     error("internal error - program_interrupt - bad switch");
361
362   }
363 }
364
365
366 INLINE_INTERRUPTS\
367 (void)
368 floating_point_unavailable_interrupt(cpu *processor,
369                                      unsigned_word cia)
370 {
371   switch (CURRENT_ENVIRONMENT) {
372     
373   case USER_ENVIRONMENT:
374   case VIRTUAL_ENVIRONMENT:
375     cpu_error(processor, cia, "floating-point unavailable interrupt");
376
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);
382
383   default:
384     error("internal error - floating_point_unavailable_interrupt - bad switch");
385
386   }
387 }
388
389
390 INLINE_INTERRUPTS\
391 (void)
392 system_call_interrupt(cpu *processor,
393                       unsigned_word cia)
394 {
395   TRACE(trace_interrupts, ("system-call interrupt - cia=0x%lx\n", (unsigned long)cia));
396
397   switch (CURRENT_ENVIRONMENT) {
398
399   case USER_ENVIRONMENT:
400   case VIRTUAL_ENVIRONMENT:
401     os_emul_system_call(processor, cia);
402     cpu_restart(processor, cia+4);
403
404   case OPERATING_ENVIRONMENT:
405     cia = perform_oea_interrupt(processor, cia+4, 0x00c00, 0, 0, 0, 0);
406     cpu_restart(processor, cia);
407
408   default:
409     error("internal error - system_call_interrupt - bad switch");
410
411   }
412 }
413
414 INLINE_INTERRUPTS\
415 (void)
416 floating_point_assist_interrupt(cpu *processor,
417                                 unsigned_word cia)
418 {
419   switch (CURRENT_ENVIRONMENT) {
420
421   case USER_ENVIRONMENT:
422   case VIRTUAL_ENVIRONMENT:
423     cpu_error(processor, cia, "floating-point assist interrupt");
424
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);
429
430   default:
431     error("internal error - floating_point_assist_interrupt - bad switch");
432
433   }
434 }
435
436
437
438 /* handle an externally generated event or an interrupt that has just
439    been enabled through changes to the MSR. */
440
441 STATIC_INLINE_INTERRUPTS\
442 (void)
443 deliver_hardware_interrupt(void *data)
444 {
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);
456   }
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);
465     }
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",
472                                (unsigned long)cia,
473                                (unsigned long)event_queue_time(psim_event_queue(cpu_system(processor)))
474                                ));
475       cpu_set_program_counter(processor, nia);
476       ints->pending_interrupts &= ~decrementer_interrupt_pending;
477     }
478   }
479 }
480
481 STATIC_INLINE_INTERRUPTS\
482 (void)
483 schedule_hardware_interrupt_delivery(cpu *processor) 
484 {
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);
490   }
491 }
492
493
494 INLINE_INTERRUPTS\
495 (void)
496 check_masked_interrupts(cpu *processor)
497 {
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);
504 }
505
506 INLINE_INTERRUPTS\
507 (void)
508 decrementer_interrupt(cpu *processor)
509 {
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);
514   }
515 }
516
517 INLINE_INTERRUPTS\
518 (void)
519 external_interrupt(cpu *processor,
520                    int is_asserted)
521 {
522   interrupts *ints = cpu_interrupts(processor);
523   if (is_asserted) {
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);
528     }
529     else {
530       /* check that we haven't missed out on a chance to deliver an
531          interrupt */
532       ASSERT(!(cpu_registers(processor)->msr & msr_external_interrupt_enable));
533     }
534   }
535   else {
536     ints->pending_interrupts &= ~external_interrupt_pending;
537   }
538 }
539
540 #endif /* _INTERRUPTS_C_ */