]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/ppc/interrupts.c
Initial creation of sourceware repository
[thirdparty/binutils-gdb.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 #ifdef WITH_OPTION_MPC860C0
319 case mpc860c0_instruction_program_interrupt:
320 cpu_error(processor, cia, "program interrupt - %s",
321 "problematic branch detected, see MPC860 C0 errata");
322 break;
323 #endif // WITH_OPTION_MPC860C0
324 default:
325 error("internal error - program_interrupt - reason %d not implemented", reason);
326 }
327
328 case OPERATING_ENVIRONMENT:
329 {
330 msreg srr1_set;
331 switch (reason) {
332 case floating_point_enabled_program_interrupt:
333 srr1_set = srr1_floating_point_enabled;
334 break;
335 case optional_instruction_program_interrupt:
336 case illegal_instruction_program_interrupt:
337 srr1_set = srr1_illegal_instruction;
338 break;
339 case privileged_instruction_program_interrupt:
340 srr1_set = srr1_priviliged_instruction;
341 break;
342 case trap_program_interrupt:
343 srr1_set = srr1_trap;
344 break;
345 #ifdef WITH_OPTION_MPC860C0
346 case mpc860c0_instruction_program_interrupt:
347 srr1_set = 0;
348 error(processor, cia, "program interrupt - %s",
349 "problematic branch detected, see MPC860 C0 errata");
350 break;
351 #endif // WITH_OPTION_MPC860C0
352 default:
353 srr1_set = 0;
354 error("internal error - program_interrupt - reason %d not implemented", reason);
355 break;
356 }
357 TRACE(trace_interrupts, ("program interrupt - cia=0x%lx SRR1|=0x%lx\n",
358 (unsigned long)cia,
359 (unsigned long)srr1_set));
360 cia = perform_oea_interrupt(processor, cia, 0x00700, 0, 0, 0, srr1_set);
361 cpu_restart(processor, cia);
362 }
363
364 default:
365 error("internal error - program_interrupt - bad switch");
366
367 }
368 }
369
370
371 INLINE_INTERRUPTS\
372 (void)
373 floating_point_unavailable_interrupt(cpu *processor,
374 unsigned_word cia)
375 {
376 switch (CURRENT_ENVIRONMENT) {
377
378 case USER_ENVIRONMENT:
379 case VIRTUAL_ENVIRONMENT:
380 cpu_error(processor, cia, "floating-point unavailable interrupt");
381
382 case OPERATING_ENVIRONMENT:
383 TRACE(trace_interrupts, ("floating-point unavailable interrupt - cia=0x%lx\n",
384 (unsigned long)cia));
385 cia = perform_oea_interrupt(processor, cia, 0x00800, 0, 0, 0, 0);
386 cpu_restart(processor, cia);
387
388 default:
389 error("internal error - floating_point_unavailable_interrupt - bad switch");
390
391 }
392 }
393
394
395 INLINE_INTERRUPTS\
396 (void)
397 system_call_interrupt(cpu *processor,
398 unsigned_word cia)
399 {
400 TRACE(trace_interrupts, ("system-call interrupt - cia=0x%lx\n", (unsigned long)cia));
401
402 switch (CURRENT_ENVIRONMENT) {
403
404 case USER_ENVIRONMENT:
405 case VIRTUAL_ENVIRONMENT:
406 os_emul_system_call(processor, cia);
407 cpu_restart(processor, cia+4);
408
409 case OPERATING_ENVIRONMENT:
410 cia = perform_oea_interrupt(processor, cia+4, 0x00c00, 0, 0, 0, 0);
411 cpu_restart(processor, cia);
412
413 default:
414 error("internal error - system_call_interrupt - bad switch");
415
416 }
417 }
418
419 INLINE_INTERRUPTS\
420 (void)
421 floating_point_assist_interrupt(cpu *processor,
422 unsigned_word cia)
423 {
424 switch (CURRENT_ENVIRONMENT) {
425
426 case USER_ENVIRONMENT:
427 case VIRTUAL_ENVIRONMENT:
428 cpu_error(processor, cia, "floating-point assist interrupt");
429
430 case OPERATING_ENVIRONMENT:
431 TRACE(trace_interrupts, ("floating-point assist interrupt - cia=0x%lx\n", (unsigned long)cia));
432 cia = perform_oea_interrupt(processor, cia, 0x00e00, 0, 0, 0, 0);
433 cpu_restart(processor, cia);
434
435 default:
436 error("internal error - floating_point_assist_interrupt - bad switch");
437
438 }
439 }
440
441
442
443 /* handle an externally generated event or an interrupt that has just
444 been enabled through changes to the MSR. */
445
446 STATIC_INLINE_INTERRUPTS\
447 (void)
448 deliver_hardware_interrupt(void *data)
449 {
450 cpu *processor = (cpu*)data;
451 interrupts *ints = cpu_interrupts(processor);
452 ints->delivery_scheduled = NULL;
453 if ((cpu_registers(processor)->msr & (msr_floating_point_exception_mode_0
454 | msr_floating_point_exception_mode_1))
455 && cpu_registers(processor)->fpscr & fpscr_fex) {
456 msreg srr1_set = srr1_floating_point_enabled | srr1_subsequent_instruction;
457 unsigned_word cia = cpu_get_program_counter(processor);
458 unsigned_word nia = perform_oea_interrupt(processor,
459 cia, 0x00700, 0, 0, 0, srr1_set);
460 cpu_set_program_counter(processor, nia);
461 }
462 else if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
463 /* external interrupts have a high priority and remain pending */
464 if (ints->pending_interrupts & external_interrupt_pending) {
465 unsigned_word cia = cpu_get_program_counter(processor);
466 unsigned_word nia = perform_oea_interrupt(processor,
467 cia, 0x00500, 0, 0, 0, 0);
468 TRACE(trace_interrupts, ("external interrupt - cia=0x%lx\n", (unsigned long)cia));
469 cpu_set_program_counter(processor, nia);
470 }
471 /* decrementer interrupts have a lower priority and are once only */
472 else if (ints->pending_interrupts & decrementer_interrupt_pending) {
473 unsigned_word cia = cpu_get_program_counter(processor);
474 unsigned_word nia = perform_oea_interrupt(processor,
475 cia, 0x00900, 0, 0, 0, 0);
476 TRACE(trace_interrupts, ("decrementer interrupt - cia=0x%lx time=0x%lx\n",
477 (unsigned long)cia,
478 (unsigned long)event_queue_time(psim_event_queue(cpu_system(processor)))
479 ));
480 cpu_set_program_counter(processor, nia);
481 ints->pending_interrupts &= ~decrementer_interrupt_pending;
482 }
483 }
484 }
485
486 STATIC_INLINE_INTERRUPTS\
487 (void)
488 schedule_hardware_interrupt_delivery(cpu *processor)
489 {
490 interrupts *ints = cpu_interrupts(processor);
491 if (ints->delivery_scheduled == NULL) {
492 ints->delivery_scheduled =
493 event_queue_schedule(psim_event_queue(cpu_system(processor)),
494 0, deliver_hardware_interrupt, processor);
495 }
496 }
497
498
499 INLINE_INTERRUPTS\
500 (void)
501 check_masked_interrupts(cpu *processor)
502 {
503 if (((cpu_registers(processor)->msr & (msr_floating_point_exception_mode_0
504 | msr_floating_point_exception_mode_1))
505 && cpu_registers(processor)->fpscr & fpscr_fex)
506 || ((cpu_registers(processor)->msr & msr_external_interrupt_enable)
507 && (cpu_interrupts(processor)->pending_interrupts)))
508 schedule_hardware_interrupt_delivery(processor);
509 }
510
511 INLINE_INTERRUPTS\
512 (void)
513 decrementer_interrupt(cpu *processor)
514 {
515 interrupts *ints = cpu_interrupts(processor);
516 ints->pending_interrupts |= decrementer_interrupt_pending;
517 if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
518 schedule_hardware_interrupt_delivery(processor);
519 }
520 }
521
522 INLINE_INTERRUPTS\
523 (void)
524 external_interrupt(cpu *processor,
525 int is_asserted)
526 {
527 interrupts *ints = cpu_interrupts(processor);
528 if (is_asserted) {
529 if (!ints->pending_interrupts & external_interrupt_pending) {
530 ints->pending_interrupts |= external_interrupt_pending;
531 if (cpu_registers(processor)->msr & msr_external_interrupt_enable)
532 schedule_hardware_interrupt_delivery(processor);
533 }
534 else {
535 /* check that we haven't missed out on a chance to deliver an
536 interrupt */
537 ASSERT(!(cpu_registers(processor)->msr & msr_external_interrupt_enable));
538 }
539 }
540 else {
541 ints->pending_interrupts &= ~external_interrupt_pending;
542 }
543 }
544
545 #endif /* _INTERRUPTS_C_ */