This commit was generated by cvs2svn to track changes on a CVS vendor
[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     case mpc860c0_instruction_program_interrupt:
319       cpu_error(processor, cia, "program interrupt - %s",
320                 "problematic branch detected, see MPC860 C0 errata");
321       break;
322     default:
323       error("internal error - program_interrupt - reason %d not implemented", reason);
324     }
325
326   case OPERATING_ENVIRONMENT:
327     {
328       msreg srr1_set;
329       switch (reason) {
330       case floating_point_enabled_program_interrupt:
331         srr1_set = srr1_floating_point_enabled;
332         break;
333       case optional_instruction_program_interrupt:
334       case illegal_instruction_program_interrupt:
335         srr1_set = srr1_illegal_instruction;
336         break;
337       case privileged_instruction_program_interrupt:
338         srr1_set = srr1_priviliged_instruction;
339         break;
340       case trap_program_interrupt:
341         srr1_set = srr1_trap;
342         break;
343       case mpc860c0_instruction_program_interrupt:
344         srr1_set = 0;
345         cpu_error(processor, cia, "program interrupt - %s",
346               "problematic branch detected, see MPC860 C0 errata");
347         break;
348       default:
349         srr1_set = 0;
350         error("internal error - program_interrupt - reason %d not implemented", reason);
351         break;
352       }
353       TRACE(trace_interrupts, ("program interrupt - cia=0x%lx SRR1|=0x%lx\n",
354                                (unsigned long)cia,
355                                (unsigned long)srr1_set));
356       cia = perform_oea_interrupt(processor, cia, 0x00700, 0, 0, 0, srr1_set);
357       cpu_restart(processor, cia);
358     }
359
360   default:
361     error("internal error - program_interrupt - bad switch");
362
363   }
364 }
365
366
367 INLINE_INTERRUPTS\
368 (void)
369 floating_point_unavailable_interrupt(cpu *processor,
370                                      unsigned_word cia)
371 {
372   switch (CURRENT_ENVIRONMENT) {
373     
374   case USER_ENVIRONMENT:
375   case VIRTUAL_ENVIRONMENT:
376     cpu_error(processor, cia, "floating-point unavailable interrupt");
377
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);
383
384   default:
385     error("internal error - floating_point_unavailable_interrupt - bad switch");
386
387   }
388 }
389
390
391 INLINE_INTERRUPTS\
392 (void)
393 system_call_interrupt(cpu *processor,
394                       unsigned_word cia)
395 {
396   TRACE(trace_interrupts, ("system-call interrupt - cia=0x%lx\n", (unsigned long)cia));
397
398   switch (CURRENT_ENVIRONMENT) {
399
400   case USER_ENVIRONMENT:
401   case VIRTUAL_ENVIRONMENT:
402     os_emul_system_call(processor, cia);
403     cpu_restart(processor, cia+4);
404
405   case OPERATING_ENVIRONMENT:
406     cia = perform_oea_interrupt(processor, cia+4, 0x00c00, 0, 0, 0, 0);
407     cpu_restart(processor, cia);
408
409   default:
410     error("internal error - system_call_interrupt - bad switch");
411
412   }
413 }
414
415 INLINE_INTERRUPTS\
416 (void)
417 floating_point_assist_interrupt(cpu *processor,
418                                 unsigned_word cia)
419 {
420   switch (CURRENT_ENVIRONMENT) {
421
422   case USER_ENVIRONMENT:
423   case VIRTUAL_ENVIRONMENT:
424     cpu_error(processor, cia, "floating-point assist interrupt");
425
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);
430
431   default:
432     error("internal error - floating_point_assist_interrupt - bad switch");
433
434   }
435 }
436
437
438
439 /* handle an externally generated event or an interrupt that has just
440    been enabled through changes to the MSR. */
441
442 STATIC_INLINE_INTERRUPTS\
443 (void)
444 deliver_hardware_interrupt(void *data)
445 {
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);
457   }
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);
466     }
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",
473                                (unsigned long)cia,
474                                (unsigned long)event_queue_time(psim_event_queue(cpu_system(processor)))
475                                ));
476       cpu_set_program_counter(processor, nia);
477       ints->pending_interrupts &= ~decrementer_interrupt_pending;
478     }
479   }
480 }
481
482 STATIC_INLINE_INTERRUPTS\
483 (void)
484 schedule_hardware_interrupt_delivery(cpu *processor) 
485 {
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);
491   }
492 }
493
494
495 INLINE_INTERRUPTS\
496 (void)
497 check_masked_interrupts(cpu *processor)
498 {
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);
505 }
506
507 INLINE_INTERRUPTS\
508 (void)
509 decrementer_interrupt(cpu *processor)
510 {
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);
515   }
516 }
517
518 INLINE_INTERRUPTS\
519 (void)
520 external_interrupt(cpu *processor,
521                    int is_asserted)
522 {
523   interrupts *ints = cpu_interrupts(processor);
524   if (is_asserted) {
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);
529     }
530     else {
531       /* check that we haven't missed out on a chance to deliver an
532          interrupt */
533       ASSERT(!(cpu_registers(processor)->msr & msr_external_interrupt_enable));
534     }
535   }
536   else {
537     ints->pending_interrupts &= ~external_interrupt_pending;
538   }
539 }
540
541 #endif /* _INTERRUPTS_C_ */