gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.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_ */
This page took 0.040892 seconds and 4 git commands to generate.