Andrew's latest changes & print all instruction counts if -I
[external/binutils.git] / sim / ppc / interrupts.c
1 /*  This file is part of the program psim.
2
3     Copyright (C) 1994-1995, 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 #ifndef STATIC_INLINE_INTERRUPTS
26 #define STATIC_INLINE_INTERRUPTS STATIC_INLINE
27 #endif
28
29 #include <signal.h>
30
31 #include "cpu.h"
32 #include "idecode.h"
33 #include "os_emul.h"
34
35
36 /* Operating environment support code
37
38    Unlike the VEA, the OEA must fully model the effect an interrupt
39    has on the processors state.
40
41    Each function below return updated values for registers effected by
42    interrupts */
43
44
45 STATIC_INLINE_INTERRUPTS msreg
46 interrupt_msr(msreg old_msr,
47               msreg msr_clear,
48               msreg msr_set)
49 {
50   msreg msr_set_to_0 = (msr_branch_trace_enable
51                         | msr_data_relocate
52                         | msr_external_interrupt_enable
53                         | msr_floating_point_exception_mode_0
54                         | msr_floating_point_exception_mode_1
55                         | msr_floating_point_available
56                         | msr_instruction_relocate
57                         | msr_power_management_enable
58                         | msr_problem_state
59                         | msr_recoverable_interrupt
60                         | msr_single_step_trace_enable);
61   /* remember, in 32bit mode msr_64bit_mode is zero */
62   msreg new_msr = ((((old_msr & ~msr_set_to_0)
63                      | msr_64bit_mode)
64                     & ~msr_clear)
65                    | msr_set);
66   return new_msr;
67 }
68
69
70 STATIC_INLINE_INTERRUPTS msreg
71 interrupt_srr1(msreg old_msr,
72                msreg srr1_clear,
73                msreg srr1_set)
74 {
75   spreg srr1_mask = (MASK(0,32)
76                        | MASK(37, 41)
77                        | MASK(48, 63));
78   spreg srr1 = (old_msr & srr1_mask & ~srr1_clear) | srr1_set;
79   return srr1;
80 }
81
82
83 STATIC_INLINE_INTERRUPTS unsigned_word
84 interrupt_base_ea(msreg msr)
85 {
86   if (msr & msr_interrupt_prefix)
87     return MASK(0, 43);
88   else
89     return 0;
90 }
91
92
93 /* finish off an interrupt for the OEA model, updating all registers
94    and forcing a restart of the processor */
95
96 STATIC_INLINE_INTERRUPTS 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     error("perform_oea_interrupt() recoverable_interrupt bit clear, cia=0x%x, msr=0x%x\n",
110           cia, old_msr);
111   SRR0 = (spreg)(cia);
112   SRR1 = interrupt_srr1(old_msr, srr1_clear, srr1_set);
113   MSR = new_msr;
114   nia = interrupt_base_ea(new_msr) + vector_offset;
115   cpu_synchronize_context(processor);
116   return nia;
117 }
118
119
120 INLINE_INTERRUPTS void machine_check_interrupt
121 (cpu *processor,
122  unsigned_word cia)
123 {
124   switch (CURRENT_ENVIRONMENT) {
125
126   case USER_ENVIRONMENT:
127   case VIRTUAL_ENVIRONMENT:
128     error("%s - cia=0x%x\n",
129           "machine_check_interrupt", cia);
130
131   case OPERATING_ENVIRONMENT:
132     cia = perform_oea_interrupt(processor, cia, 0x00200, 0, 0, 0, 0);
133     cpu_restart(processor, cia);
134
135   default:
136     error("machine_check_interrupt() - internal error\n");
137
138   }
139 }
140
141
142 INLINE_INTERRUPTS void
143 data_storage_interrupt(cpu *processor,
144                        unsigned_word cia,
145                        unsigned_word ea,
146                        storage_interrupt_reasons reason,
147                        int is_store)
148 {
149   switch (CURRENT_ENVIRONMENT) {
150
151   case USER_ENVIRONMENT:
152   case VIRTUAL_ENVIRONMENT:
153     error("data_storage_interrupt() should not be called in VEA mode\n");
154
155   case OPERATING_ENVIRONMENT:
156     {
157       spreg direction = (is_store ? dsisr_store_operation : 0);
158       switch (reason) {
159       case direct_store_storage_interrupt:
160         DSISR = dsisr_direct_store_error_exception | direction;
161         break;
162       case hash_table_miss_storage_interrupt:
163         DSISR = dsisr_hash_table_or_dbat_miss | direction;
164         break;
165       case protection_violation_storage_interrupt:
166         DSISR = dsisr_protection_violation | direction;
167         break;
168       case earwax_violation_storage_interrupt:
169         DSISR = dsisr_earwax_violation | direction;
170         break;
171       case segment_table_miss_storage_interrupt:
172         DSISR = dsisr_segment_table_miss | direction;
173         break;
174       case earwax_disabled_storage_interrupt:
175         DSISR = dsisr_earwax_disabled | direction;
176         break;
177       default:
178         error("data_storage_interrupt: unknown reason %d\n", reason);
179         break;
180       }
181       DAR = (spreg)ea;
182       cia = perform_oea_interrupt(processor, cia, 0x00300, 0, 0, 0, 0);
183       cpu_restart(processor, cia);
184     }
185
186   default:
187     error("data_storage_interrupt() - internal error\n");
188
189   }
190 }
191
192
193 INLINE_INTERRUPTS void
194 instruction_storage_interrupt(cpu *processor,
195                               unsigned_word cia,
196                               storage_interrupt_reasons reason)
197 {
198   switch (CURRENT_ENVIRONMENT) {
199
200   case USER_ENVIRONMENT:
201   case VIRTUAL_ENVIRONMENT:
202     error("instruction_storage_interrupt - cia=0x%x - not implemented\n",
203           cia);
204
205   case OPERATING_ENVIRONMENT:
206     {
207       unsigned_word nia;
208       msreg srr1_set;
209       switch(reason) {
210       case hash_table_miss_storage_interrupt:
211         srr1_set = srr1_hash_table_or_ibat_miss;
212         break;
213       case direct_store_storage_interrupt:
214         srr1_set = srr1_direct_store_error_exception;
215         break;
216       case protection_violation_storage_interrupt:
217         srr1_set = srr1_protection_violation;
218         break;
219       case segment_table_miss_storage_interrupt:
220         srr1_set = srr1_segment_table_miss;
221         break;
222       default:
223         srr1_set = 0;
224         error("instruction_storage_interrupt: unknown reason %d\n", reason);
225         break;
226       }
227       cia = perform_oea_interrupt(processor, cia, 0x00400, 0, 0, 0, srr1_set);
228       cpu_restart(processor, cia);
229     }
230
231   default:
232     error("instruction_storage_interrupt() - internal error\n");
233
234   }
235 }
236
237
238
239 INLINE_INTERRUPTS void alignment_interrupt
240 (cpu *processor,
241  unsigned_word cia,
242  unsigned_word ra)
243 {
244   switch (CURRENT_ENVIRONMENT) {
245
246   case USER_ENVIRONMENT:
247   case VIRTUAL_ENVIRONMENT:
248     error("%s - cia=0x%x, ra=0x%x\n",
249           "alignment_interrupt", cia, ra);
250     
251   case OPERATING_ENVIRONMENT:
252     DAR = (spreg)ra;
253     DSISR = 0; /* FIXME */
254     cia = perform_oea_interrupt(processor, cia, 0x00600, 0, 0, 0, 0);
255     cpu_restart(processor, cia);
256
257   default:
258     error("alignment_interrupt() - internal error\n");
259     
260   }
261 }
262
263
264
265
266 INLINE_INTERRUPTS void
267 program_interrupt(cpu *processor,
268                   unsigned_word cia,
269                   program_interrupt_reasons reason)
270 {
271   switch (CURRENT_ENVIRONMENT) {
272
273   case USER_ENVIRONMENT:
274   case VIRTUAL_ENVIRONMENT:
275     switch (reason) {
276     default:
277       error("%s - cia=0x%x, reason=%d - not implemented\n",
278             "program_interrupt", cia, reason);
279     }
280
281   case OPERATING_ENVIRONMENT:
282     {
283       msreg srr1_set;
284       switch (reason) {
285       case illegal_instruction_program_interrupt:
286         srr1_set = srr1_illegal_instruction;
287         break;
288       case privileged_instruction_program_interrupt:
289         srr1_set = srr1_priviliged_instruction;
290         break;
291       case trap_program_interrupt:
292         srr1_set = srr1_trap;
293         break;
294       default:
295         srr1_set = 0;
296         error("program_interrupt - cia=0x%x, reason=%d(%s) - not implemented\n",
297               cia, reason);
298       }
299       cia = perform_oea_interrupt(processor, cia, 0x00700, 0, 0, 0, srr1_set);
300       cpu_restart(processor, cia);
301     }
302
303   default:
304     error("program_interrupt() - internal error\n");
305
306   }
307 }
308
309
310 INLINE_INTERRUPTS void
311 floating_point_unavailable_interrupt(cpu *processor,
312                                      unsigned_word cia)
313 {
314   switch (CURRENT_ENVIRONMENT) {
315     
316   case USER_ENVIRONMENT:
317   case VIRTUAL_ENVIRONMENT:
318     error("%s - cia=0x%x - not implemented\n",
319           "floating_point_unavailable_interrupt", cia);
320
321   case OPERATING_ENVIRONMENT:
322     cia = perform_oea_interrupt(processor, cia, 0x00800, 0, 0, 0, 0);
323     cpu_restart(processor, cia);
324
325   default:
326     error("floating_point_unavailable_interrupt() - internal error\n");
327
328   }
329 }
330
331
332 INLINE_INTERRUPTS void
333 system_call_interrupt(cpu *processor,
334                       unsigned_word cia)
335 {
336   switch (CURRENT_ENVIRONMENT) {
337
338   case USER_ENVIRONMENT:
339   case VIRTUAL_ENVIRONMENT:
340     os_emul_call(processor, cia);
341     cpu_restart(processor, cia+4);
342
343   case OPERATING_ENVIRONMENT:
344     cia = perform_oea_interrupt(processor, cia+4, 0x00c00, 0, 0, 0, 0);
345     cpu_restart(processor, cia);
346
347   default:
348     error("system_call_interrupt() - internal error\n");
349
350   }
351 }
352
353 INLINE_INTERRUPTS void
354 trace_interrupt(cpu *processor,
355                 unsigned_word cia);
356
357 INLINE_INTERRUPTS void
358 floating_point_assist_interrupt(cpu *processor,
359                                 unsigned_word cia)
360 {
361   switch (CURRENT_ENVIRONMENT) {
362
363   case USER_ENVIRONMENT:
364   case VIRTUAL_ENVIRONMENT:
365     error("%s - cia=0x%x - not implemented\n",
366           "floating_point_assist_interrupt", cia);
367
368   case OPERATING_ENVIRONMENT:
369     cia = perform_oea_interrupt(processor, cia, 0x00e00, 0, 0, 0, 0);
370     cpu_restart(processor, cia);
371
372   default:
373     error("floating_point_assist_interrupt() - internal error\n");
374
375   }
376 }
377
378
379
380 /* handle an externally generated event */
381
382 INLINE_INTERRUPTS int
383 decrementer_interrupt(cpu *processor)
384 {
385   if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
386     unsigned_word cia = cpu_get_program_counter(processor);
387     unsigned_word nia = perform_oea_interrupt(processor,
388                                               cia, 0x00900, 0, 0, 0, 0);
389     cpu_set_program_counter(processor, nia);
390     return 1;
391   }
392   else {
393     return 0;
394   }
395 }
396
397 INLINE_INTERRUPTS int
398 external_interrupt(cpu *processor)
399 {
400   if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
401     unsigned_word cia = cpu_get_program_counter(processor);
402     unsigned_word nia = perform_oea_interrupt(processor,
403                                               cia, 0x00500, 0, 0, 0, 0);
404     cpu_set_program_counter(processor, nia);
405     return 1;
406   }
407   else {
408     return 0; /* not delivered */
409   }
410 }
411
412
413 #endif /* _INTERRUPTS_C_ */