1 /* This file is part of the program psim.
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.
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.
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.
22 #ifndef _INTERRUPTS_C_
23 #define _INTERRUPTS_C_
25 #ifndef STATIC_INLINE_INTERRUPTS
26 #define STATIC_INLINE_INTERRUPTS STATIC_INLINE
36 /* Operating environment support code
38 Unlike the VEA, the OEA must fully model the effect an interrupt
39 has on the processors state.
41 Each function below return updated values for registers effected by
45 STATIC_INLINE_INTERRUPTS msreg
46 interrupt_msr(msreg old_msr,
50 msreg msr_set_to_0 = (msr_branch_trace_enable
52 | msr_external_interrupt_enable
53 | msr_floating_point_exception_mode_0
54 | msr_floating_point_exception_mode_1
55 | msr_floating_point_available
56 | msr_instruction_relocate
57 | msr_power_management_enable
59 | msr_recoverable_interrupt
60 | msr_single_step_trace_enable);
61 /* remember, in 32bit mode msr_64bit_mode is zero */
62 msreg new_msr = ((((old_msr & ~msr_set_to_0)
70 STATIC_INLINE_INTERRUPTS msreg
71 interrupt_srr1(msreg old_msr,
75 spreg srr1_mask = (MASK(0,32)
78 spreg srr1 = (old_msr & srr1_mask & ~srr1_clear) | srr1_set;
83 STATIC_INLINE_INTERRUPTS unsigned_word
84 interrupt_base_ea(msreg msr)
86 if (msr & msr_interrupt_prefix)
93 /* finish off an interrupt for the OEA model, updating all registers
94 and forcing a restart of the processor */
96 STATIC_INLINE_INTERRUPTS unsigned_word
97 perform_oea_interrupt(cpu *processor,
99 unsigned_word vector_offset,
106 msreg new_msr = interrupt_msr(old_msr, msr_clear, msr_set);
108 if (!(old_msr & msr_recoverable_interrupt))
109 error("perform_oea_interrupt() recoverable_interrupt bit clear, cia=0x%x, msr=0x%x\n",
112 SRR1 = interrupt_srr1(old_msr, srr1_clear, srr1_set);
114 nia = interrupt_base_ea(new_msr) + vector_offset;
115 cpu_synchronize_context(processor);
120 INLINE_INTERRUPTS void machine_check_interrupt
124 switch (CURRENT_ENVIRONMENT) {
126 case USER_ENVIRONMENT:
127 case VIRTUAL_ENVIRONMENT:
128 error("%s - cia=0x%x\n",
129 "machine_check_interrupt", cia);
131 case OPERATING_ENVIRONMENT:
132 cia = perform_oea_interrupt(processor, cia, 0x00200, 0, 0, 0, 0);
133 cpu_restart(processor, cia);
136 error("machine_check_interrupt() - internal error\n");
142 INLINE_INTERRUPTS void
143 data_storage_interrupt(cpu *processor,
146 storage_interrupt_reasons reason,
149 switch (CURRENT_ENVIRONMENT) {
151 case USER_ENVIRONMENT:
152 case VIRTUAL_ENVIRONMENT:
153 error("data_storage_interrupt() should not be called in VEA mode\n");
155 case OPERATING_ENVIRONMENT:
157 spreg direction = (is_store ? dsisr_store_operation : 0);
159 case direct_store_storage_interrupt:
160 DSISR = dsisr_direct_store_error_exception | direction;
162 case hash_table_miss_storage_interrupt:
163 DSISR = dsisr_hash_table_or_dbat_miss | direction;
165 case protection_violation_storage_interrupt:
166 DSISR = dsisr_protection_violation | direction;
168 case earwax_violation_storage_interrupt:
169 DSISR = dsisr_earwax_violation | direction;
171 case segment_table_miss_storage_interrupt:
172 DSISR = dsisr_segment_table_miss | direction;
174 case earwax_disabled_storage_interrupt:
175 DSISR = dsisr_earwax_disabled | direction;
178 error("data_storage_interrupt: unknown reason %d\n", reason);
182 cia = perform_oea_interrupt(processor, cia, 0x00300, 0, 0, 0, 0);
183 cpu_restart(processor, cia);
187 error("data_storage_interrupt() - internal error\n");
193 INLINE_INTERRUPTS void
194 instruction_storage_interrupt(cpu *processor,
196 storage_interrupt_reasons reason)
198 switch (CURRENT_ENVIRONMENT) {
200 case USER_ENVIRONMENT:
201 case VIRTUAL_ENVIRONMENT:
202 error("instruction_storage_interrupt - cia=0x%x - not implemented\n",
205 case OPERATING_ENVIRONMENT:
210 case hash_table_miss_storage_interrupt:
211 srr1_set = srr1_hash_table_or_ibat_miss;
213 case direct_store_storage_interrupt:
214 srr1_set = srr1_direct_store_error_exception;
216 case protection_violation_storage_interrupt:
217 srr1_set = srr1_protection_violation;
219 case segment_table_miss_storage_interrupt:
220 srr1_set = srr1_segment_table_miss;
224 error("instruction_storage_interrupt: unknown reason %d\n", reason);
227 cia = perform_oea_interrupt(processor, cia, 0x00400, 0, 0, 0, srr1_set);
228 cpu_restart(processor, cia);
232 error("instruction_storage_interrupt() - internal error\n");
239 INLINE_INTERRUPTS void alignment_interrupt
244 switch (CURRENT_ENVIRONMENT) {
246 case USER_ENVIRONMENT:
247 case VIRTUAL_ENVIRONMENT:
248 error("%s - cia=0x%x, ra=0x%x\n",
249 "alignment_interrupt", cia, ra);
251 case OPERATING_ENVIRONMENT:
253 DSISR = 0; /* FIXME */
254 cia = perform_oea_interrupt(processor, cia, 0x00600, 0, 0, 0, 0);
255 cpu_restart(processor, cia);
258 error("alignment_interrupt() - internal error\n");
266 INLINE_INTERRUPTS void
267 program_interrupt(cpu *processor,
269 program_interrupt_reasons reason)
271 switch (CURRENT_ENVIRONMENT) {
273 case USER_ENVIRONMENT:
274 case VIRTUAL_ENVIRONMENT:
277 error("%s - cia=0x%x, reason=%d - not implemented\n",
278 "program_interrupt", cia, reason);
281 case OPERATING_ENVIRONMENT:
285 case illegal_instruction_program_interrupt:
286 srr1_set = srr1_illegal_instruction;
288 case privileged_instruction_program_interrupt:
289 srr1_set = srr1_priviliged_instruction;
291 case trap_program_interrupt:
292 srr1_set = srr1_trap;
296 error("program_interrupt - cia=0x%x, reason=%d(%s) - not implemented\n",
299 cia = perform_oea_interrupt(processor, cia, 0x00700, 0, 0, 0, srr1_set);
300 cpu_restart(processor, cia);
304 error("program_interrupt() - internal error\n");
310 INLINE_INTERRUPTS void
311 floating_point_unavailable_interrupt(cpu *processor,
314 switch (CURRENT_ENVIRONMENT) {
316 case USER_ENVIRONMENT:
317 case VIRTUAL_ENVIRONMENT:
318 error("%s - cia=0x%x - not implemented\n",
319 "floating_point_unavailable_interrupt", cia);
321 case OPERATING_ENVIRONMENT:
322 cia = perform_oea_interrupt(processor, cia, 0x00800, 0, 0, 0, 0);
323 cpu_restart(processor, cia);
326 error("floating_point_unavailable_interrupt() - internal error\n");
332 INLINE_INTERRUPTS void
333 system_call_interrupt(cpu *processor,
336 switch (CURRENT_ENVIRONMENT) {
338 case USER_ENVIRONMENT:
339 case VIRTUAL_ENVIRONMENT:
340 os_emul_call(processor, cia);
341 cpu_restart(processor, cia+4);
343 case OPERATING_ENVIRONMENT:
344 cia = perform_oea_interrupt(processor, cia+4, 0x00c00, 0, 0, 0, 0);
345 cpu_restart(processor, cia);
348 error("system_call_interrupt() - internal error\n");
353 INLINE_INTERRUPTS void
354 trace_interrupt(cpu *processor,
357 INLINE_INTERRUPTS void
358 floating_point_assist_interrupt(cpu *processor,
361 switch (CURRENT_ENVIRONMENT) {
363 case USER_ENVIRONMENT:
364 case VIRTUAL_ENVIRONMENT:
365 error("%s - cia=0x%x - not implemented\n",
366 "floating_point_assist_interrupt", cia);
368 case OPERATING_ENVIRONMENT:
369 cia = perform_oea_interrupt(processor, cia, 0x00e00, 0, 0, 0, 0);
370 cpu_restart(processor, cia);
373 error("floating_point_assist_interrupt() - internal error\n");
380 /* handle an externally generated event */
382 INLINE_INTERRUPTS int
383 decrementer_interrupt(cpu *processor)
385 if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
386 unsigned_word cia = cpu_get_program_counter(processor);
387 unsigned_word nia = perform_oea_interrupt(processor,
388 cia, 0x00900, 0, 0, 0, 0);
389 cpu_set_program_counter(processor, nia);
397 INLINE_INTERRUPTS int
398 external_interrupt(cpu *processor)
400 if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
401 unsigned_word cia = cpu_get_program_counter(processor);
402 unsigned_word nia = perform_oea_interrupt(processor,
403 cia, 0x00500, 0, 0, 0, 0);
404 cpu_set_program_counter(processor, nia);
408 return 0; /* not delivered */
413 #endif /* _INTERRUPTS_C_ */