1*6ca2c52aSchristos /*  This file is part of the program psim.
2*6ca2c52aSchristos 
3*6ca2c52aSchristos     Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney
4*6ca2c52aSchristos 
5*6ca2c52aSchristos     This program is free software; you can redistribute it and/or modify
6*6ca2c52aSchristos     it under the terms of the GNU General Public License as published by
7*6ca2c52aSchristos     the Free Software Foundation; either version 3 of the License, or
8*6ca2c52aSchristos     (at your option) any later version.
9*6ca2c52aSchristos 
10*6ca2c52aSchristos     This program is distributed in the hope that it will be useful,
11*6ca2c52aSchristos     but WITHOUT ANY WARRANTY; without even the implied warranty of
12*6ca2c52aSchristos     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*6ca2c52aSchristos     GNU General Public License for more details.
14*6ca2c52aSchristos 
15*6ca2c52aSchristos     You should have received a copy of the GNU General Public License
16*6ca2c52aSchristos     along with this program; if not, see <http://www.gnu.org/licenses/>.
17*6ca2c52aSchristos 
18*6ca2c52aSchristos     */
19*6ca2c52aSchristos 
20*6ca2c52aSchristos 
21*6ca2c52aSchristos #ifndef _INTERRUPTS_C_
22*6ca2c52aSchristos #define _INTERRUPTS_C_
23*6ca2c52aSchristos 
24*6ca2c52aSchristos #include <signal.h>
25*6ca2c52aSchristos 
26*6ca2c52aSchristos #include "cpu.h"
27*6ca2c52aSchristos #include "idecode.h"
28*6ca2c52aSchristos #include "os_emul.h"
29*6ca2c52aSchristos 
30*6ca2c52aSchristos 
31*6ca2c52aSchristos /* Operating environment support code
32*6ca2c52aSchristos 
33*6ca2c52aSchristos    Unlike the VEA, the OEA must fully model the effect an interrupt
34*6ca2c52aSchristos    has on the processors state.
35*6ca2c52aSchristos 
36*6ca2c52aSchristos    Each function below return updated values for registers effected by
37*6ca2c52aSchristos    interrupts */
38*6ca2c52aSchristos 
39*6ca2c52aSchristos 
40*6ca2c52aSchristos STATIC_INLINE_INTERRUPTS\
41*6ca2c52aSchristos (msreg)
interrupt_msr(msreg old_msr,msreg msr_clear,msreg msr_set)42*6ca2c52aSchristos interrupt_msr(msreg old_msr,
43*6ca2c52aSchristos 	      msreg msr_clear,
44*6ca2c52aSchristos 	      msreg msr_set)
45*6ca2c52aSchristos {
46*6ca2c52aSchristos   msreg msr_set_to_0 = (msr_branch_trace_enable
47*6ca2c52aSchristos 			| msr_data_relocate
48*6ca2c52aSchristos 			| msr_external_interrupt_enable
49*6ca2c52aSchristos 			| msr_floating_point_exception_mode_0
50*6ca2c52aSchristos 			| msr_floating_point_exception_mode_1
51*6ca2c52aSchristos 			| msr_floating_point_available
52*6ca2c52aSchristos 			| msr_instruction_relocate
53*6ca2c52aSchristos 			| msr_power_management_enable
54*6ca2c52aSchristos 			| msr_problem_state
55*6ca2c52aSchristos 			| msr_recoverable_interrupt
56*6ca2c52aSchristos 			| msr_single_step_trace_enable);
57*6ca2c52aSchristos   /* remember, in 32bit mode msr_64bit_mode is zero */
58*6ca2c52aSchristos   msreg new_msr = ((((old_msr & ~msr_set_to_0)
59*6ca2c52aSchristos 		     | msr_64bit_mode)
60*6ca2c52aSchristos 		    & ~msr_clear)
61*6ca2c52aSchristos 		   | msr_set);
62*6ca2c52aSchristos   return new_msr;
63*6ca2c52aSchristos }
64*6ca2c52aSchristos 
65*6ca2c52aSchristos 
66*6ca2c52aSchristos STATIC_INLINE_INTERRUPTS\
67*6ca2c52aSchristos (msreg)
interrupt_srr1(msreg old_msr,msreg srr1_clear,msreg srr1_set)68*6ca2c52aSchristos interrupt_srr1(msreg old_msr,
69*6ca2c52aSchristos 	       msreg srr1_clear,
70*6ca2c52aSchristos 	       msreg srr1_set)
71*6ca2c52aSchristos {
72*6ca2c52aSchristos   spreg srr1_mask = (MASK(0,32)
73*6ca2c52aSchristos 		     | MASK(37, 41)
74*6ca2c52aSchristos 		     | MASK(48, 63));
75*6ca2c52aSchristos   spreg srr1 = (old_msr & srr1_mask & ~srr1_clear) | srr1_set;
76*6ca2c52aSchristos   return srr1;
77*6ca2c52aSchristos }
78*6ca2c52aSchristos 
79*6ca2c52aSchristos 
80*6ca2c52aSchristos STATIC_INLINE_INTERRUPTS\
81*6ca2c52aSchristos (unsigned_word)
interrupt_base_ea(msreg msr)82*6ca2c52aSchristos interrupt_base_ea(msreg msr)
83*6ca2c52aSchristos {
84*6ca2c52aSchristos   if (msr & msr_interrupt_prefix)
85*6ca2c52aSchristos     return MASK(0, 43);
86*6ca2c52aSchristos   else
87*6ca2c52aSchristos     return 0;
88*6ca2c52aSchristos }
89*6ca2c52aSchristos 
90*6ca2c52aSchristos 
91*6ca2c52aSchristos /* finish off an interrupt for the OEA model, updating all registers
92*6ca2c52aSchristos    and forcing a restart of the processor */
93*6ca2c52aSchristos 
94*6ca2c52aSchristos STATIC_INLINE_INTERRUPTS\
95*6ca2c52aSchristos (unsigned_word)
perform_oea_interrupt(cpu * processor,unsigned_word cia,unsigned_word vector_offset,msreg msr_clear,msreg msr_set,msreg srr1_clear,msreg srr1_set)96*6ca2c52aSchristos perform_oea_interrupt(cpu *processor,
97*6ca2c52aSchristos 		      unsigned_word cia,
98*6ca2c52aSchristos 		      unsigned_word vector_offset,
99*6ca2c52aSchristos 		      msreg msr_clear,
100*6ca2c52aSchristos 		      msreg msr_set,
101*6ca2c52aSchristos 		      msreg srr1_clear,
102*6ca2c52aSchristos 		      msreg srr1_set)
103*6ca2c52aSchristos {
104*6ca2c52aSchristos   msreg old_msr = MSR;
105*6ca2c52aSchristos   msreg new_msr = interrupt_msr(old_msr, msr_clear, msr_set);
106*6ca2c52aSchristos   unsigned_word nia;
107*6ca2c52aSchristos   if (!(old_msr & msr_recoverable_interrupt)) {
108*6ca2c52aSchristos     cpu_error(processor, cia,
109*6ca2c52aSchristos 	      "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*6ca2c52aSchristos 	      (unsigned long)cia,
111*6ca2c52aSchristos 	      (unsigned long)old_msr,
112*6ca2c52aSchristos 	      (unsigned long)SRR0,
113*6ca2c52aSchristos 	      (unsigned long)SRR1,
114*6ca2c52aSchristos 	      (unsigned long)vector_offset,
115*6ca2c52aSchristos 	      (unsigned long)new_msr);
116*6ca2c52aSchristos   }
117*6ca2c52aSchristos   SRR0 = (spreg)(cia);
118*6ca2c52aSchristos   SRR1 = interrupt_srr1(old_msr, srr1_clear, srr1_set);
119*6ca2c52aSchristos   MSR = new_msr;
120*6ca2c52aSchristos   nia = interrupt_base_ea(new_msr) + vector_offset;
121*6ca2c52aSchristos   cpu_synchronize_context(processor, cia);
122*6ca2c52aSchristos   return nia;
123*6ca2c52aSchristos }
124*6ca2c52aSchristos 
125*6ca2c52aSchristos 
126*6ca2c52aSchristos INLINE_INTERRUPTS\
127*6ca2c52aSchristos (void)
machine_check_interrupt(cpu * processor,unsigned_word cia)128*6ca2c52aSchristos machine_check_interrupt(cpu *processor,
129*6ca2c52aSchristos 			unsigned_word cia)
130*6ca2c52aSchristos {
131*6ca2c52aSchristos   switch (CURRENT_ENVIRONMENT) {
132*6ca2c52aSchristos 
133*6ca2c52aSchristos   case USER_ENVIRONMENT:
134*6ca2c52aSchristos   case VIRTUAL_ENVIRONMENT:
135*6ca2c52aSchristos     cpu_error(processor, cia, "machine-check interrupt");
136*6ca2c52aSchristos 
137*6ca2c52aSchristos   case OPERATING_ENVIRONMENT:
138*6ca2c52aSchristos     TRACE(trace_interrupts, ("machine-check interrupt - cia=0x%lx\n",
139*6ca2c52aSchristos 			     (unsigned long)cia));
140*6ca2c52aSchristos     cia = perform_oea_interrupt(processor, cia, 0x00200, 0, 0, 0, 0);
141*6ca2c52aSchristos     cpu_restart(processor, cia);
142*6ca2c52aSchristos 
143*6ca2c52aSchristos   default:
144*6ca2c52aSchristos     error("internal error - machine_check_interrupt - bad switch");
145*6ca2c52aSchristos 
146*6ca2c52aSchristos   }
147*6ca2c52aSchristos }
148*6ca2c52aSchristos 
149*6ca2c52aSchristos 
150*6ca2c52aSchristos INLINE_INTERRUPTS\
151*6ca2c52aSchristos (void)
data_storage_interrupt(cpu * processor,unsigned_word cia,unsigned_word ea,storage_interrupt_reasons reason,int is_store)152*6ca2c52aSchristos data_storage_interrupt(cpu *processor,
153*6ca2c52aSchristos 		       unsigned_word cia,
154*6ca2c52aSchristos 		       unsigned_word ea,
155*6ca2c52aSchristos 		       storage_interrupt_reasons reason,
156*6ca2c52aSchristos 		       int is_store)
157*6ca2c52aSchristos {
158*6ca2c52aSchristos   switch (CURRENT_ENVIRONMENT) {
159*6ca2c52aSchristos 
160*6ca2c52aSchristos   case USER_ENVIRONMENT:
161*6ca2c52aSchristos   case VIRTUAL_ENVIRONMENT:
162*6ca2c52aSchristos     error("internal error - data_storage_interrupt - should not be called in VEA mode");
163*6ca2c52aSchristos     break;
164*6ca2c52aSchristos 
165*6ca2c52aSchristos   case OPERATING_ENVIRONMENT:
166*6ca2c52aSchristos     {
167*6ca2c52aSchristos       spreg direction = (is_store ? dsisr_store_operation : 0);
168*6ca2c52aSchristos       switch (reason) {
169*6ca2c52aSchristos       case direct_store_storage_interrupt:
170*6ca2c52aSchristos 	DSISR = dsisr_direct_store_error_exception | direction;
171*6ca2c52aSchristos 	break;
172*6ca2c52aSchristos       case hash_table_miss_storage_interrupt:
173*6ca2c52aSchristos 	DSISR = dsisr_hash_table_or_dbat_miss | direction;
174*6ca2c52aSchristos 	break;
175*6ca2c52aSchristos       case protection_violation_storage_interrupt:
176*6ca2c52aSchristos 	DSISR = dsisr_protection_violation | direction;
177*6ca2c52aSchristos 	break;
178*6ca2c52aSchristos       case earwax_violation_storage_interrupt:
179*6ca2c52aSchristos 	DSISR = dsisr_earwax_violation | direction;
180*6ca2c52aSchristos 	break;
181*6ca2c52aSchristos       case segment_table_miss_storage_interrupt:
182*6ca2c52aSchristos 	DSISR = dsisr_segment_table_miss | direction;
183*6ca2c52aSchristos 	break;
184*6ca2c52aSchristos       case earwax_disabled_storage_interrupt:
185*6ca2c52aSchristos 	DSISR = dsisr_earwax_disabled | direction;
186*6ca2c52aSchristos 	break;
187*6ca2c52aSchristos       default:
188*6ca2c52aSchristos 	error("internal error - data_storage_interrupt - reason %d not implemented", reason);
189*6ca2c52aSchristos 	break;
190*6ca2c52aSchristos       }
191*6ca2c52aSchristos       DAR = (spreg)ea;
192*6ca2c52aSchristos       TRACE(trace_interrupts, ("data storage interrupt - cia=0x%lx DAR=0x%lx DSISR=0x%lx\n",
193*6ca2c52aSchristos 			       (unsigned long)cia,
194*6ca2c52aSchristos 			       (unsigned long)DAR,
195*6ca2c52aSchristos 			       (unsigned long)DSISR));
196*6ca2c52aSchristos       cia = perform_oea_interrupt(processor, cia, 0x00300, 0, 0, 0, 0);
197*6ca2c52aSchristos       cpu_restart(processor, cia);
198*6ca2c52aSchristos     }
199*6ca2c52aSchristos 
200*6ca2c52aSchristos   default:
201*6ca2c52aSchristos     error("internal error - data_storage_interrupt - bad switch");
202*6ca2c52aSchristos 
203*6ca2c52aSchristos   }
204*6ca2c52aSchristos }
205*6ca2c52aSchristos 
206*6ca2c52aSchristos 
207*6ca2c52aSchristos INLINE_INTERRUPTS\
208*6ca2c52aSchristos (void)
instruction_storage_interrupt(cpu * processor,unsigned_word cia,storage_interrupt_reasons reason)209*6ca2c52aSchristos instruction_storage_interrupt(cpu *processor,
210*6ca2c52aSchristos 			      unsigned_word cia,
211*6ca2c52aSchristos 			      storage_interrupt_reasons reason)
212*6ca2c52aSchristos {
213*6ca2c52aSchristos   switch (CURRENT_ENVIRONMENT) {
214*6ca2c52aSchristos 
215*6ca2c52aSchristos   case USER_ENVIRONMENT:
216*6ca2c52aSchristos   case VIRTUAL_ENVIRONMENT:
217*6ca2c52aSchristos     error("internal error - instruction_storage_interrupt - should not be called in VEA mode");
218*6ca2c52aSchristos 
219*6ca2c52aSchristos   case OPERATING_ENVIRONMENT:
220*6ca2c52aSchristos     {
221*6ca2c52aSchristos       msreg srr1_set;
222*6ca2c52aSchristos       switch(reason) {
223*6ca2c52aSchristos       case hash_table_miss_storage_interrupt:
224*6ca2c52aSchristos 	srr1_set = srr1_hash_table_or_ibat_miss;
225*6ca2c52aSchristos 	break;
226*6ca2c52aSchristos       case direct_store_storage_interrupt:
227*6ca2c52aSchristos 	srr1_set = srr1_direct_store_error_exception;
228*6ca2c52aSchristos 	break;
229*6ca2c52aSchristos       case protection_violation_storage_interrupt:
230*6ca2c52aSchristos 	srr1_set = srr1_protection_violation;
231*6ca2c52aSchristos 	break;
232*6ca2c52aSchristos       case segment_table_miss_storage_interrupt:
233*6ca2c52aSchristos 	srr1_set = srr1_segment_table_miss;
234*6ca2c52aSchristos 	break;
235*6ca2c52aSchristos       default:
236*6ca2c52aSchristos 	srr1_set = 0;
237*6ca2c52aSchristos 	error("internal error - instruction_storage_interrupt - reason %d not implemented");
238*6ca2c52aSchristos 	break;
239*6ca2c52aSchristos       }
240*6ca2c52aSchristos       TRACE(trace_interrupts, ("instruction storage interrupt - cia=0x%lx SRR1|=0x%lx\n",
241*6ca2c52aSchristos 			       (unsigned long)cia,
242*6ca2c52aSchristos 			       (unsigned long)srr1_set));
243*6ca2c52aSchristos       cia = perform_oea_interrupt(processor, cia, 0x00400, 0, 0, 0, srr1_set);
244*6ca2c52aSchristos       cpu_restart(processor, cia);
245*6ca2c52aSchristos     }
246*6ca2c52aSchristos 
247*6ca2c52aSchristos   default:
248*6ca2c52aSchristos     error("internal error - instruction_storage_interrupt - bad switch");
249*6ca2c52aSchristos 
250*6ca2c52aSchristos   }
251*6ca2c52aSchristos }
252*6ca2c52aSchristos 
253*6ca2c52aSchristos 
254*6ca2c52aSchristos 
255*6ca2c52aSchristos INLINE_INTERRUPTS\
256*6ca2c52aSchristos (void)
alignment_interrupt(cpu * processor,unsigned_word cia,unsigned_word ra)257*6ca2c52aSchristos alignment_interrupt(cpu *processor,
258*6ca2c52aSchristos 		    unsigned_word cia,
259*6ca2c52aSchristos 		    unsigned_word ra)
260*6ca2c52aSchristos {
261*6ca2c52aSchristos   switch (CURRENT_ENVIRONMENT) {
262*6ca2c52aSchristos 
263*6ca2c52aSchristos   case USER_ENVIRONMENT:
264*6ca2c52aSchristos   case VIRTUAL_ENVIRONMENT:
265*6ca2c52aSchristos     cpu_error(processor, cia, "alignment interrupt - ra=0x%lx", ra);
266*6ca2c52aSchristos 
267*6ca2c52aSchristos   case OPERATING_ENVIRONMENT:
268*6ca2c52aSchristos     DAR = (spreg)ra;
269*6ca2c52aSchristos     DSISR = 0; /* FIXME */
270*6ca2c52aSchristos     TRACE(trace_interrupts, ("alignment interrupt - cia=0x%lx DAR=0x%lx DSISR=0x%lx\n",
271*6ca2c52aSchristos 			     (unsigned long)cia,
272*6ca2c52aSchristos 			     (unsigned long)DAR,
273*6ca2c52aSchristos 			     (unsigned long)DSISR));
274*6ca2c52aSchristos     cia = perform_oea_interrupt(processor, cia, 0x00600, 0, 0, 0, 0);
275*6ca2c52aSchristos     cpu_restart(processor, cia);
276*6ca2c52aSchristos 
277*6ca2c52aSchristos   default:
278*6ca2c52aSchristos     error("internal error - alignment_interrupt - bad switch");
279*6ca2c52aSchristos 
280*6ca2c52aSchristos   }
281*6ca2c52aSchristos }
282*6ca2c52aSchristos 
283*6ca2c52aSchristos 
284*6ca2c52aSchristos 
285*6ca2c52aSchristos 
286*6ca2c52aSchristos INLINE_INTERRUPTS\
287*6ca2c52aSchristos (void)
program_interrupt(cpu * processor,unsigned_word cia,program_interrupt_reasons reason)288*6ca2c52aSchristos program_interrupt(cpu *processor,
289*6ca2c52aSchristos 		  unsigned_word cia,
290*6ca2c52aSchristos 		  program_interrupt_reasons reason)
291*6ca2c52aSchristos {
292*6ca2c52aSchristos   switch (CURRENT_ENVIRONMENT) {
293*6ca2c52aSchristos 
294*6ca2c52aSchristos   case USER_ENVIRONMENT:
295*6ca2c52aSchristos   case VIRTUAL_ENVIRONMENT:
296*6ca2c52aSchristos     switch (reason) {
297*6ca2c52aSchristos     case floating_point_enabled_program_interrupt:
298*6ca2c52aSchristos       cpu_error(processor, cia, "program interrupt - %s",
299*6ca2c52aSchristos 		"floating point enabled");
300*6ca2c52aSchristos       break;
301*6ca2c52aSchristos     case illegal_instruction_program_interrupt:
302*6ca2c52aSchristos       cpu_error(processor, cia, "program interrupt - %s",
303*6ca2c52aSchristos 		"illegal instruction");
304*6ca2c52aSchristos       break;
305*6ca2c52aSchristos     case privileged_instruction_program_interrupt:
306*6ca2c52aSchristos       cpu_error(processor, cia, "program interrupt - %s",
307*6ca2c52aSchristos 		"privileged instruction");
308*6ca2c52aSchristos       break;
309*6ca2c52aSchristos     case trap_program_interrupt:
310*6ca2c52aSchristos       cpu_error(processor, cia, "program interrupt - %s",
311*6ca2c52aSchristos 		"trap");
312*6ca2c52aSchristos       break;
313*6ca2c52aSchristos     case optional_instruction_program_interrupt:
314*6ca2c52aSchristos       cpu_error(processor, cia, "program interrupt - %s",
315*6ca2c52aSchristos 		"illegal instruction (optional instruction not supported)");
316*6ca2c52aSchristos       break;
317*6ca2c52aSchristos     case mpc860c0_instruction_program_interrupt:
318*6ca2c52aSchristos       cpu_error(processor, cia, "program interrupt - %s",
319*6ca2c52aSchristos         	"problematic branch detected, see MPC860 C0 errata");
320*6ca2c52aSchristos       break;
321*6ca2c52aSchristos     default:
322*6ca2c52aSchristos       error("internal error - program_interrupt - reason %d not implemented", reason);
323*6ca2c52aSchristos     }
324*6ca2c52aSchristos 
325*6ca2c52aSchristos   case OPERATING_ENVIRONMENT:
326*6ca2c52aSchristos     {
327*6ca2c52aSchristos       msreg srr1_set;
328*6ca2c52aSchristos       switch (reason) {
329*6ca2c52aSchristos       case floating_point_enabled_program_interrupt:
330*6ca2c52aSchristos 	srr1_set = srr1_floating_point_enabled;
331*6ca2c52aSchristos 	break;
332*6ca2c52aSchristos       case optional_instruction_program_interrupt:
333*6ca2c52aSchristos       case illegal_instruction_program_interrupt:
334*6ca2c52aSchristos 	srr1_set = srr1_illegal_instruction;
335*6ca2c52aSchristos 	break;
336*6ca2c52aSchristos       case privileged_instruction_program_interrupt:
337*6ca2c52aSchristos 	srr1_set = srr1_priviliged_instruction;
338*6ca2c52aSchristos 	break;
339*6ca2c52aSchristos       case trap_program_interrupt:
340*6ca2c52aSchristos 	srr1_set = srr1_trap;
341*6ca2c52aSchristos 	break;
342*6ca2c52aSchristos       case mpc860c0_instruction_program_interrupt:
343*6ca2c52aSchristos         srr1_set = 0;
344*6ca2c52aSchristos         cpu_error(processor, cia, "program interrupt - %s",
345*6ca2c52aSchristos               "problematic branch detected, see MPC860 C0 errata");
346*6ca2c52aSchristos         break;
347*6ca2c52aSchristos       default:
348*6ca2c52aSchristos 	srr1_set = 0;
349*6ca2c52aSchristos 	error("internal error - program_interrupt - reason %d not implemented", reason);
350*6ca2c52aSchristos 	break;
351*6ca2c52aSchristos       }
352*6ca2c52aSchristos       TRACE(trace_interrupts, ("program interrupt - cia=0x%lx SRR1|=0x%lx\n",
353*6ca2c52aSchristos 			       (unsigned long)cia,
354*6ca2c52aSchristos 			       (unsigned long)srr1_set));
355*6ca2c52aSchristos       cia = perform_oea_interrupt(processor, cia, 0x00700, 0, 0, 0, srr1_set);
356*6ca2c52aSchristos       cpu_restart(processor, cia);
357*6ca2c52aSchristos     }
358*6ca2c52aSchristos 
359*6ca2c52aSchristos   default:
360*6ca2c52aSchristos     error("internal error - program_interrupt - bad switch");
361*6ca2c52aSchristos 
362*6ca2c52aSchristos   }
363*6ca2c52aSchristos }
364*6ca2c52aSchristos 
365*6ca2c52aSchristos 
366*6ca2c52aSchristos INLINE_INTERRUPTS\
367*6ca2c52aSchristos (void)
floating_point_unavailable_interrupt(cpu * processor,unsigned_word cia)368*6ca2c52aSchristos floating_point_unavailable_interrupt(cpu *processor,
369*6ca2c52aSchristos 				     unsigned_word cia)
370*6ca2c52aSchristos {
371*6ca2c52aSchristos   switch (CURRENT_ENVIRONMENT) {
372*6ca2c52aSchristos 
373*6ca2c52aSchristos   case USER_ENVIRONMENT:
374*6ca2c52aSchristos   case VIRTUAL_ENVIRONMENT:
375*6ca2c52aSchristos     cpu_error(processor, cia, "floating-point unavailable interrupt");
376*6ca2c52aSchristos 
377*6ca2c52aSchristos   case OPERATING_ENVIRONMENT:
378*6ca2c52aSchristos     TRACE(trace_interrupts, ("floating-point unavailable interrupt - cia=0x%lx\n",
379*6ca2c52aSchristos 			     (unsigned long)cia));
380*6ca2c52aSchristos     cia = perform_oea_interrupt(processor, cia, 0x00800, 0, 0, 0, 0);
381*6ca2c52aSchristos     cpu_restart(processor, cia);
382*6ca2c52aSchristos 
383*6ca2c52aSchristos   default:
384*6ca2c52aSchristos     error("internal error - floating_point_unavailable_interrupt - bad switch");
385*6ca2c52aSchristos 
386*6ca2c52aSchristos   }
387*6ca2c52aSchristos }
388*6ca2c52aSchristos 
389*6ca2c52aSchristos 
390*6ca2c52aSchristos INLINE_INTERRUPTS\
391*6ca2c52aSchristos (void)
system_call_interrupt(cpu * processor,unsigned_word cia)392*6ca2c52aSchristos system_call_interrupt(cpu *processor,
393*6ca2c52aSchristos 		      unsigned_word cia)
394*6ca2c52aSchristos {
395*6ca2c52aSchristos   TRACE(trace_interrupts, ("system-call interrupt - cia=0x%lx\n", (unsigned long)cia));
396*6ca2c52aSchristos 
397*6ca2c52aSchristos   switch (CURRENT_ENVIRONMENT) {
398*6ca2c52aSchristos 
399*6ca2c52aSchristos   case USER_ENVIRONMENT:
400*6ca2c52aSchristos   case VIRTUAL_ENVIRONMENT:
401*6ca2c52aSchristos     os_emul_system_call(processor, cia);
402*6ca2c52aSchristos     cpu_restart(processor, cia+4);
403*6ca2c52aSchristos 
404*6ca2c52aSchristos   case OPERATING_ENVIRONMENT:
405*6ca2c52aSchristos     cia = perform_oea_interrupt(processor, cia+4, 0x00c00, 0, 0, 0, 0);
406*6ca2c52aSchristos     cpu_restart(processor, cia);
407*6ca2c52aSchristos 
408*6ca2c52aSchristos   default:
409*6ca2c52aSchristos     error("internal error - system_call_interrupt - bad switch");
410*6ca2c52aSchristos 
411*6ca2c52aSchristos   }
412*6ca2c52aSchristos }
413*6ca2c52aSchristos 
414*6ca2c52aSchristos INLINE_INTERRUPTS\
415*6ca2c52aSchristos (void)
floating_point_assist_interrupt(cpu * processor,unsigned_word cia)416*6ca2c52aSchristos floating_point_assist_interrupt(cpu *processor,
417*6ca2c52aSchristos 				unsigned_word cia)
418*6ca2c52aSchristos {
419*6ca2c52aSchristos   switch (CURRENT_ENVIRONMENT) {
420*6ca2c52aSchristos 
421*6ca2c52aSchristos   case USER_ENVIRONMENT:
422*6ca2c52aSchristos   case VIRTUAL_ENVIRONMENT:
423*6ca2c52aSchristos     cpu_error(processor, cia, "floating-point assist interrupt");
424*6ca2c52aSchristos 
425*6ca2c52aSchristos   case OPERATING_ENVIRONMENT:
426*6ca2c52aSchristos     TRACE(trace_interrupts, ("floating-point assist interrupt - cia=0x%lx\n", (unsigned long)cia));
427*6ca2c52aSchristos     cia = perform_oea_interrupt(processor, cia, 0x00e00, 0, 0, 0, 0);
428*6ca2c52aSchristos     cpu_restart(processor, cia);
429*6ca2c52aSchristos 
430*6ca2c52aSchristos   default:
431*6ca2c52aSchristos     error("internal error - floating_point_assist_interrupt - bad switch");
432*6ca2c52aSchristos 
433*6ca2c52aSchristos   }
434*6ca2c52aSchristos }
435*6ca2c52aSchristos 
436*6ca2c52aSchristos 
437*6ca2c52aSchristos 
438*6ca2c52aSchristos /* handle an externally generated event or an interrupt that has just
439*6ca2c52aSchristos    been enabled through changes to the MSR. */
440*6ca2c52aSchristos 
441*6ca2c52aSchristos STATIC_INLINE_INTERRUPTS\
442*6ca2c52aSchristos (void)
deliver_hardware_interrupt(void * data)443*6ca2c52aSchristos deliver_hardware_interrupt(void *data)
444*6ca2c52aSchristos {
445*6ca2c52aSchristos   cpu *processor = (cpu*)data;
446*6ca2c52aSchristos   interrupts *ints = cpu_interrupts(processor);
447*6ca2c52aSchristos   ints->delivery_scheduled = NULL;
448*6ca2c52aSchristos   if ((cpu_registers(processor)->msr & (msr_floating_point_exception_mode_0
449*6ca2c52aSchristos 					| msr_floating_point_exception_mode_1))
450*6ca2c52aSchristos       && cpu_registers(processor)->fpscr & fpscr_fex) {
451*6ca2c52aSchristos     msreg srr1_set = srr1_floating_point_enabled | srr1_subsequent_instruction;
452*6ca2c52aSchristos     unsigned_word cia = cpu_get_program_counter(processor);
453*6ca2c52aSchristos     unsigned_word nia = perform_oea_interrupt(processor,
454*6ca2c52aSchristos 					      cia, 0x00700, 0, 0, 0, srr1_set);
455*6ca2c52aSchristos     cpu_set_program_counter(processor, nia);
456*6ca2c52aSchristos   }
457*6ca2c52aSchristos   else if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
458*6ca2c52aSchristos     /* external interrupts have a high priority and remain pending */
459*6ca2c52aSchristos     if (ints->pending_interrupts & external_interrupt_pending) {
460*6ca2c52aSchristos       unsigned_word cia = cpu_get_program_counter(processor);
461*6ca2c52aSchristos       unsigned_word nia = perform_oea_interrupt(processor,
462*6ca2c52aSchristos 						cia, 0x00500, 0, 0, 0, 0);
463*6ca2c52aSchristos       TRACE(trace_interrupts, ("external interrupt - cia=0x%lx\n", (unsigned long)cia));
464*6ca2c52aSchristos       cpu_set_program_counter(processor, nia);
465*6ca2c52aSchristos     }
466*6ca2c52aSchristos     /* decrementer interrupts have a lower priority and are once only */
467*6ca2c52aSchristos     else if (ints->pending_interrupts & decrementer_interrupt_pending) {
468*6ca2c52aSchristos       unsigned_word cia = cpu_get_program_counter(processor);
469*6ca2c52aSchristos       unsigned_word nia = perform_oea_interrupt(processor,
470*6ca2c52aSchristos 						cia, 0x00900, 0, 0, 0, 0);
471*6ca2c52aSchristos       TRACE(trace_interrupts, ("decrementer interrupt - cia 0x%lx, time %ld\n",
472*6ca2c52aSchristos 			       (unsigned long)cia,
473*6ca2c52aSchristos 			       (unsigned long)event_queue_time(psim_event_queue(cpu_system(processor)))
474*6ca2c52aSchristos 			       ));
475*6ca2c52aSchristos       cpu_set_program_counter(processor, nia);
476*6ca2c52aSchristos       ints->pending_interrupts &= ~decrementer_interrupt_pending;
477*6ca2c52aSchristos     }
478*6ca2c52aSchristos   }
479*6ca2c52aSchristos }
480*6ca2c52aSchristos 
481*6ca2c52aSchristos STATIC_INLINE_INTERRUPTS\
482*6ca2c52aSchristos (void)
schedule_hardware_interrupt_delivery(cpu * processor)483*6ca2c52aSchristos schedule_hardware_interrupt_delivery(cpu *processor)
484*6ca2c52aSchristos {
485*6ca2c52aSchristos   interrupts *ints = cpu_interrupts(processor);
486*6ca2c52aSchristos   if (ints->delivery_scheduled == NULL) {
487*6ca2c52aSchristos     ints->delivery_scheduled =
488*6ca2c52aSchristos       event_queue_schedule(psim_event_queue(cpu_system(processor)),
489*6ca2c52aSchristos 			   0, deliver_hardware_interrupt, processor);
490*6ca2c52aSchristos   }
491*6ca2c52aSchristos }
492*6ca2c52aSchristos 
493*6ca2c52aSchristos 
494*6ca2c52aSchristos INLINE_INTERRUPTS\
495*6ca2c52aSchristos (void)
check_masked_interrupts(cpu * processor)496*6ca2c52aSchristos check_masked_interrupts(cpu *processor)
497*6ca2c52aSchristos {
498*6ca2c52aSchristos   if (((cpu_registers(processor)->msr & (msr_floating_point_exception_mode_0
499*6ca2c52aSchristos 					 | msr_floating_point_exception_mode_1))
500*6ca2c52aSchristos        && cpu_registers(processor)->fpscr & fpscr_fex)
501*6ca2c52aSchristos       || ((cpu_registers(processor)->msr & msr_external_interrupt_enable)
502*6ca2c52aSchristos 	  && (cpu_interrupts(processor)->pending_interrupts)))
503*6ca2c52aSchristos     schedule_hardware_interrupt_delivery(processor);
504*6ca2c52aSchristos }
505*6ca2c52aSchristos 
506*6ca2c52aSchristos INLINE_INTERRUPTS\
507*6ca2c52aSchristos (void)
decrementer_interrupt(cpu * processor)508*6ca2c52aSchristos decrementer_interrupt(cpu *processor)
509*6ca2c52aSchristos {
510*6ca2c52aSchristos   interrupts *ints = cpu_interrupts(processor);
511*6ca2c52aSchristos   ints->pending_interrupts |= decrementer_interrupt_pending;
512*6ca2c52aSchristos   if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
513*6ca2c52aSchristos     schedule_hardware_interrupt_delivery(processor);
514*6ca2c52aSchristos   }
515*6ca2c52aSchristos }
516*6ca2c52aSchristos 
517*6ca2c52aSchristos INLINE_INTERRUPTS\
518*6ca2c52aSchristos (void)
external_interrupt(cpu * processor,int is_asserted)519*6ca2c52aSchristos external_interrupt(cpu *processor,
520*6ca2c52aSchristos 		   int is_asserted)
521*6ca2c52aSchristos {
522*6ca2c52aSchristos   interrupts *ints = cpu_interrupts(processor);
523*6ca2c52aSchristos   if (is_asserted) {
524*6ca2c52aSchristos     if (!(ints->pending_interrupts & external_interrupt_pending)) {
525*6ca2c52aSchristos       ints->pending_interrupts |= external_interrupt_pending;
526*6ca2c52aSchristos       if (cpu_registers(processor)->msr & msr_external_interrupt_enable)
527*6ca2c52aSchristos 	schedule_hardware_interrupt_delivery(processor);
528*6ca2c52aSchristos     }
529*6ca2c52aSchristos     else {
530*6ca2c52aSchristos       /* check that we haven't missed out on a chance to deliver an
531*6ca2c52aSchristos          interrupt */
532*6ca2c52aSchristos       ASSERT(!(cpu_registers(processor)->msr & msr_external_interrupt_enable));
533*6ca2c52aSchristos     }
534*6ca2c52aSchristos   }
535*6ca2c52aSchristos   else {
536*6ca2c52aSchristos     ints->pending_interrupts &= ~external_interrupt_pending;
537*6ca2c52aSchristos   }
538*6ca2c52aSchristos }
539*6ca2c52aSchristos 
540*6ca2c52aSchristos #endif /* _INTERRUPTS_C_ */
541