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