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