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