]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/ppc/interrupts.c
dafb2b33144ed586f48f12deb0b99f6429a16c94
[thirdparty/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 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_ */