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
41STATIC_INLINE_INTERRUPTS\
42(msreg)
43interrupt_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
67STATIC_INLINE_INTERRUPTS\
68(msreg)
69interrupt_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
81STATIC_INLINE_INTERRUPTS\
82(unsigned_word)
83interrupt_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
95STATIC_INLINE_INTERRUPTS\
96(unsigned_word)
97perform_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
127INLINE_INTERRUPTS\
128(void)
129machine_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
151INLINE_INTERRUPTS\
152(void)
153data_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
208INLINE_INTERRUPTS\
209(void)
210instruction_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
256INLINE_INTERRUPTS\
257(void)
258alignment_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
287INLINE_INTERRUPTS\
288(void)
289program_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
367INLINE_INTERRUPTS\
368(void)
369floating_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
391INLINE_INTERRUPTS\
392(void)
393system_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
415INLINE_INTERRUPTS\
416(void)
417floating_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
442STATIC_INLINE_INTERRUPTS\
443(void)
444deliver_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
482STATIC_INLINE_INTERRUPTS\
483(void)
484schedule_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
495INLINE_INTERRUPTS\
496(void)
497check_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
507INLINE_INTERRUPTS\
508(void)
509decrementer_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
518INLINE_INTERRUPTS\
519(void)
520external_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_ */
542