Home | History | Annotate | Line # | Download | only in frv
      1       1.1  christos /* frv exception and interrupt support
      2  1.1.1.10  christos    Copyright (C) 1999-2024 Free Software Foundation, Inc.
      3       1.1  christos    Contributed by Red Hat.
      4       1.1  christos 
      5       1.1  christos This file is part of the GNU simulators.
      6       1.1  christos 
      7       1.1  christos This program is free software; you can redistribute it and/or modify
      8       1.1  christos it under the terms of the GNU General Public License as published by
      9       1.1  christos the Free Software Foundation; either version 3 of the License, or
     10       1.1  christos (at your option) any later version.
     11       1.1  christos 
     12       1.1  christos This program is distributed in the hope that it will be useful,
     13       1.1  christos but WITHOUT ANY WARRANTY; without even the implied warranty of
     14       1.1  christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15       1.1  christos GNU General Public License for more details.
     16       1.1  christos 
     17       1.1  christos You should have received a copy of the GNU General Public License
     18       1.1  christos along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19       1.1  christos 
     20   1.1.1.9  christos /* This must come before any other includes.  */
     21   1.1.1.9  christos #include "defs.h"
     22   1.1.1.9  christos 
     23       1.1  christos #define WANT_CPU frvbf
     24       1.1  christos #define WANT_CPU_FRVBF
     25       1.1  christos 
     26       1.1  christos #include "sim-main.h"
     27   1.1.1.9  christos #include "sim-signal.h"
     28       1.1  christos #include "bfd.h"
     29   1.1.1.9  christos #include <stdlib.h>
     30   1.1.1.9  christos #include "cgen-mem.h"
     31       1.1  christos 
     32       1.1  christos /* FR-V Interrupt table.
     33       1.1  christos    Describes the interrupts supported by the FR-V.
     34       1.1  christos    This table *must* be maintained in order of interrupt priority as defined by
     35       1.1  christos    frv_interrupt_kind.  */
     36       1.1  christos #define DEFERRED 1
     37       1.1  christos #define PRECISE  1
     38       1.1  christos #define ITABLE_ENTRY(name, class, deferral, precision, offset) \
     39       1.1  christos   {FRV_##name, FRV_EC_##name, class, deferral, precision, offset}
     40       1.1  christos 
     41       1.1  christos struct frv_interrupt frv_interrupt_table[NUM_FRV_INTERRUPT_KINDS] =
     42       1.1  christos {
     43       1.1  christos   /* External interrupts */
     44       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_1,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x21),
     45       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_2,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x22),
     46       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_3,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x23),
     47       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_4,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x24),
     48       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_5,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x25),
     49       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_6,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x26),
     50       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_7,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x27),
     51       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_8,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x28),
     52       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_9,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x29),
     53       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_10,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2a),
     54       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_11,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2b),
     55       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_12,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2c),
     56       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_13,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2d),
     57       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_14,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2e),
     58       1.1  christos   ITABLE_ENTRY(INTERRUPT_LEVEL_15,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2f),
     59       1.1  christos   /* Software interrupt */
     60       1.1  christos   ITABLE_ENTRY(TRAP_INSTRUCTION,             FRV_SOFTWARE_INTERRUPT, !DEFERRED, !PRECISE, 0x80),
     61       1.1  christos   /* Program interrupts */
     62       1.1  christos   ITABLE_ENTRY(COMMIT_EXCEPTION,             FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x19),
     63       1.1  christos   ITABLE_ENTRY(DIVISION_EXCEPTION,           FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x17),
     64       1.1  christos   ITABLE_ENTRY(DATA_STORE_ERROR,             FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x14),
     65       1.1  christos   ITABLE_ENTRY(DATA_ACCESS_EXCEPTION,        FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x13),
     66       1.1  christos   ITABLE_ENTRY(DATA_ACCESS_MMU_MISS,         FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x12),
     67       1.1  christos   ITABLE_ENTRY(DATA_ACCESS_ERROR,            FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x11),
     68       1.1  christos   ITABLE_ENTRY(MP_EXCEPTION,                 FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x0e),
     69       1.1  christos   ITABLE_ENTRY(FP_EXCEPTION,                 FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x0d),
     70       1.1  christos   ITABLE_ENTRY(MEM_ADDRESS_NOT_ALIGNED,      FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x10),
     71       1.1  christos   ITABLE_ENTRY(REGISTER_EXCEPTION,           FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x08),
     72       1.1  christos   ITABLE_ENTRY(MP_DISABLED,                  FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x0b),
     73       1.1  christos   ITABLE_ENTRY(FP_DISABLED,                  FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x0a),
     74       1.1  christos   ITABLE_ENTRY(PRIVILEGED_INSTRUCTION,       FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x06),
     75       1.1  christos   ITABLE_ENTRY(ILLEGAL_INSTRUCTION,          FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x07),
     76       1.1  christos   ITABLE_ENTRY(INSTRUCTION_ACCESS_EXCEPTION, FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x03),
     77       1.1  christos   ITABLE_ENTRY(INSTRUCTION_ACCESS_ERROR,     FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x02),
     78       1.1  christos   ITABLE_ENTRY(INSTRUCTION_ACCESS_MMU_MISS,  FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x01),
     79       1.1  christos   ITABLE_ENTRY(COMPOUND_EXCEPTION,           FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x20),
     80       1.1  christos   /* Break interrupt */
     81       1.1  christos   ITABLE_ENTRY(BREAK_EXCEPTION,              FRV_BREAK_INTERRUPT,    !DEFERRED, !PRECISE, 0xff),
     82       1.1  christos   /* Reset interrupt */
     83       1.1  christos   ITABLE_ENTRY(RESET,                        FRV_RESET_INTERRUPT,    !DEFERRED, !PRECISE, 0x00)
     84       1.1  christos };
     85       1.1  christos 
     86       1.1  christos /* The current interrupt state.  */
     87       1.1  christos struct frv_interrupt_state frv_interrupt_state;
     88       1.1  christos 
     89       1.1  christos /* maintain the address of the start of the previous VLIW insn sequence.  */
     90       1.1  christos IADDR previous_vliw_pc;
     91       1.1  christos 
     92       1.1  christos /* Add a break interrupt to the interrupt queue.  */
     93       1.1  christos struct frv_interrupt_queue_element *
     94       1.1  christos frv_queue_break_interrupt (SIM_CPU *current_cpu)
     95       1.1  christos {
     96       1.1  christos   return frv_queue_interrupt (current_cpu, FRV_BREAK_EXCEPTION);
     97       1.1  christos }
     98       1.1  christos 
     99       1.1  christos /* Add a software interrupt to the interrupt queue.  */
    100       1.1  christos struct frv_interrupt_queue_element *
    101       1.1  christos frv_queue_software_interrupt (SIM_CPU *current_cpu, SI offset)
    102       1.1  christos {
    103       1.1  christos   struct frv_interrupt_queue_element *new_element
    104       1.1  christos     = frv_queue_interrupt (current_cpu, FRV_TRAP_INSTRUCTION);
    105       1.1  christos 
    106       1.1  christos   struct frv_interrupt *interrupt = & frv_interrupt_table[new_element->kind];
    107       1.1  christos   interrupt->handler_offset = offset;
    108       1.1  christos 
    109       1.1  christos   return new_element;
    110       1.1  christos }
    111       1.1  christos 
    112       1.1  christos /* Add a program interrupt to the interrupt queue.  */
    113       1.1  christos struct frv_interrupt_queue_element *
    114       1.1  christos frv_queue_program_interrupt (
    115       1.1  christos   SIM_CPU *current_cpu, enum frv_interrupt_kind kind
    116       1.1  christos )
    117       1.1  christos {
    118       1.1  christos   return frv_queue_interrupt (current_cpu, kind);
    119       1.1  christos }
    120       1.1  christos 
    121       1.1  christos /* Add an external interrupt to the interrupt queue.  */
    122       1.1  christos struct frv_interrupt_queue_element *
    123       1.1  christos frv_queue_external_interrupt (
    124       1.1  christos   SIM_CPU *current_cpu, enum frv_interrupt_kind kind
    125       1.1  christos )
    126       1.1  christos {
    127       1.1  christos   if (! GET_H_PSR_ET ()
    128       1.1  christos       || (kind != FRV_INTERRUPT_LEVEL_15 && kind < GET_H_PSR_PIL ()))
    129       1.1  christos     return NULL; /* Leave it for later.  */
    130       1.1  christos 
    131       1.1  christos   return frv_queue_interrupt (current_cpu, kind);
    132       1.1  christos }
    133       1.1  christos 
    134       1.1  christos /* Add any interrupt to the interrupt queue. It will be added in reverse
    135       1.1  christos    priority order.  This makes it easy to find the highest priority interrupt
    136       1.1  christos    at the end of the queue and to remove it after processing.  */
    137       1.1  christos struct frv_interrupt_queue_element *
    138       1.1  christos frv_queue_interrupt (SIM_CPU *current_cpu, enum frv_interrupt_kind kind)
    139       1.1  christos {
    140       1.1  christos   int i;
    141       1.1  christos   int j;
    142       1.1  christos   int limit = frv_interrupt_state.queue_index;
    143       1.1  christos   struct frv_interrupt_queue_element *new_element;
    144       1.1  christos   enum frv_interrupt_class iclass;
    145       1.1  christos 
    146       1.1  christos   if (limit >= FRV_INTERRUPT_QUEUE_SIZE)
    147       1.1  christos     abort (); /* TODO: Make the queue dynamic */
    148       1.1  christos 
    149       1.1  christos   /* Find the right place in the queue.  */
    150       1.1  christos   for (i = 0; i < limit; ++i)
    151       1.1  christos     {
    152       1.1  christos       if (frv_interrupt_state.queue[i].kind >= kind)
    153       1.1  christos 	break;
    154       1.1  christos     }
    155       1.1  christos 
    156       1.1  christos   /* Don't queue two external interrupts of the same priority.  */
    157       1.1  christos   iclass = frv_interrupt_table[kind].iclass;
    158       1.1  christos   if (i < limit && iclass == FRV_EXTERNAL_INTERRUPT)
    159       1.1  christos     {
    160       1.1  christos       if (frv_interrupt_state.queue[i].kind == kind)
    161       1.1  christos 	return & frv_interrupt_state.queue[i];
    162       1.1  christos     }
    163       1.1  christos 
    164       1.1  christos   /* Make room for the new interrupt in this spot.  */
    165       1.1  christos   for (j = limit - 1; j >= i; --j)
    166       1.1  christos     frv_interrupt_state.queue[j + 1] = frv_interrupt_state.queue[j];
    167       1.1  christos 
    168       1.1  christos   /* Add the new interrupt.  */
    169       1.1  christos   frv_interrupt_state.queue_index++;
    170       1.1  christos   new_element = & frv_interrupt_state.queue[i];
    171       1.1  christos   new_element->kind = kind;
    172       1.1  christos   new_element->vpc = CPU_PC_GET (current_cpu);
    173       1.1  christos   new_element->u.data_written.length = 0;
    174       1.1  christos   frv_set_interrupt_queue_slot (current_cpu, new_element);
    175       1.1  christos 
    176       1.1  christos   return new_element;
    177       1.1  christos }
    178       1.1  christos 
    179       1.1  christos struct frv_interrupt_queue_element *
    180       1.1  christos frv_queue_register_exception_interrupt (SIM_CPU *current_cpu, enum frv_rec rec)
    181       1.1  christos {
    182       1.1  christos   struct frv_interrupt_queue_element *new_element =
    183       1.1  christos     frv_queue_program_interrupt (current_cpu, FRV_REGISTER_EXCEPTION);
    184       1.1  christos 
    185       1.1  christos   new_element->u.rec = rec;
    186       1.1  christos 
    187       1.1  christos   return new_element;
    188       1.1  christos }
    189       1.1  christos 
    190       1.1  christos struct frv_interrupt_queue_element *
    191       1.1  christos frv_queue_mem_address_not_aligned_interrupt (SIM_CPU *current_cpu, USI addr)
    192       1.1  christos {
    193       1.1  christos   struct frv_interrupt_queue_element *new_element;
    194       1.1  christos   USI isr = GET_ISR ();
    195       1.1  christos 
    196       1.1  christos   /* Make sure that this exception is not masked.  */
    197       1.1  christos   if (GET_ISR_EMAM (isr))
    198       1.1  christos     return NULL;
    199       1.1  christos 
    200       1.1  christos   /* Queue the interrupt.  */
    201       1.1  christos   new_element = frv_queue_program_interrupt (current_cpu,
    202       1.1  christos 					     FRV_MEM_ADDRESS_NOT_ALIGNED);
    203       1.1  christos   new_element->eaddress = addr;
    204       1.1  christos   new_element->u.data_written = frv_interrupt_state.data_written;
    205       1.1  christos   frv_interrupt_state.data_written.length = 0;
    206       1.1  christos 
    207       1.1  christos   return new_element;
    208       1.1  christos }
    209       1.1  christos 
    210       1.1  christos struct frv_interrupt_queue_element *
    211       1.1  christos frv_queue_data_access_error_interrupt (SIM_CPU *current_cpu, USI addr)
    212       1.1  christos {
    213       1.1  christos   struct frv_interrupt_queue_element *new_element;
    214       1.1  christos   new_element = frv_queue_program_interrupt (current_cpu,
    215       1.1  christos 					     FRV_DATA_ACCESS_ERROR);
    216       1.1  christos   new_element->eaddress = addr;
    217       1.1  christos   return new_element;
    218       1.1  christos }
    219       1.1  christos 
    220       1.1  christos struct frv_interrupt_queue_element *
    221       1.1  christos frv_queue_data_access_exception_interrupt (SIM_CPU *current_cpu)
    222       1.1  christos {
    223       1.1  christos   return frv_queue_program_interrupt (current_cpu, FRV_DATA_ACCESS_EXCEPTION);
    224       1.1  christos }
    225       1.1  christos 
    226       1.1  christos struct frv_interrupt_queue_element *
    227       1.1  christos frv_queue_instruction_access_error_interrupt (SIM_CPU *current_cpu)
    228       1.1  christos {
    229       1.1  christos   return frv_queue_program_interrupt (current_cpu, FRV_INSTRUCTION_ACCESS_ERROR);
    230       1.1  christos }
    231       1.1  christos 
    232       1.1  christos struct frv_interrupt_queue_element *
    233       1.1  christos frv_queue_instruction_access_exception_interrupt (SIM_CPU *current_cpu)
    234       1.1  christos {
    235       1.1  christos   return frv_queue_program_interrupt (current_cpu, FRV_INSTRUCTION_ACCESS_EXCEPTION);
    236       1.1  christos }
    237       1.1  christos 
    238       1.1  christos struct frv_interrupt_queue_element *
    239       1.1  christos frv_queue_illegal_instruction_interrupt (
    240       1.1  christos   SIM_CPU *current_cpu, const CGEN_INSN *insn
    241       1.1  christos )
    242       1.1  christos {
    243       1.1  christos   SIM_DESC sd = CPU_STATE (current_cpu);
    244       1.1  christos   switch (STATE_ARCHITECTURE (sd)->mach)
    245       1.1  christos     {
    246       1.1  christos     case bfd_mach_fr400:
    247       1.1  christos     case bfd_mach_fr450:
    248       1.1  christos     case bfd_mach_fr550:
    249       1.1  christos       break;
    250       1.1  christos     default:
    251       1.1  christos       /* Some machines generate fp_exception for this case.  */
    252       1.1  christos       if (frv_is_float_insn (insn) || frv_is_media_insn (insn))
    253       1.1  christos 	{
    254       1.1  christos 	  struct frv_fp_exception_info fp_info = {
    255       1.1  christos 	    FSR_NO_EXCEPTION, FTT_SEQUENCE_ERROR
    256       1.1  christos 	  };
    257       1.1  christos 	  return frv_queue_fp_exception_interrupt (current_cpu, & fp_info);
    258       1.1  christos 	}
    259       1.1  christos       break;
    260       1.1  christos     }
    261       1.1  christos 
    262       1.1  christos   return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
    263       1.1  christos }
    264       1.1  christos 
    265       1.1  christos struct frv_interrupt_queue_element *
    266       1.1  christos frv_queue_privileged_instruction_interrupt (SIM_CPU *current_cpu, const CGEN_INSN *insn)
    267       1.1  christos {
    268       1.1  christos   /* The fr550 has no privileged instruction interrupt. It uses
    269       1.1  christos      illegal_instruction.  */
    270       1.1  christos   SIM_DESC sd = CPU_STATE (current_cpu);
    271       1.1  christos   if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
    272       1.1  christos     return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
    273       1.1  christos 
    274       1.1  christos   return frv_queue_program_interrupt (current_cpu, FRV_PRIVILEGED_INSTRUCTION);
    275       1.1  christos }
    276       1.1  christos 
    277       1.1  christos struct frv_interrupt_queue_element *
    278       1.1  christos frv_queue_float_disabled_interrupt (SIM_CPU *current_cpu)
    279       1.1  christos {
    280       1.1  christos   /* The fr550 has no fp_disabled interrupt. It uses illegal_instruction.  */
    281       1.1  christos   SIM_DESC sd = CPU_STATE (current_cpu);
    282       1.1  christos   if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
    283       1.1  christos     return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
    284       1.1  christos 
    285       1.1  christos   return frv_queue_program_interrupt (current_cpu, FRV_FP_DISABLED);
    286       1.1  christos }
    287       1.1  christos 
    288       1.1  christos struct frv_interrupt_queue_element *
    289       1.1  christos frv_queue_media_disabled_interrupt (SIM_CPU *current_cpu)
    290       1.1  christos {
    291       1.1  christos   /* The fr550 has no mp_disabled interrupt. It uses illegal_instruction.  */
    292       1.1  christos   SIM_DESC sd = CPU_STATE (current_cpu);
    293       1.1  christos   if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
    294       1.1  christos     return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
    295       1.1  christos 
    296       1.1  christos   return frv_queue_program_interrupt (current_cpu, FRV_MP_DISABLED);
    297       1.1  christos }
    298       1.1  christos 
    299       1.1  christos struct frv_interrupt_queue_element *
    300       1.1  christos frv_queue_non_implemented_instruction_interrupt (
    301       1.1  christos   SIM_CPU *current_cpu, const CGEN_INSN *insn
    302       1.1  christos )
    303       1.1  christos {
    304       1.1  christos   SIM_DESC sd = CPU_STATE (current_cpu);
    305       1.1  christos   switch (STATE_ARCHITECTURE (sd)->mach)
    306       1.1  christos     {
    307       1.1  christos     case bfd_mach_fr400:
    308       1.1  christos     case bfd_mach_fr450:
    309       1.1  christos     case bfd_mach_fr550:
    310       1.1  christos       break;
    311       1.1  christos     default:
    312       1.1  christos       /* Some machines generate fp_exception or mp_exception for this case.  */
    313       1.1  christos       if (frv_is_float_insn (insn))
    314       1.1  christos 	{
    315       1.1  christos 	  struct frv_fp_exception_info fp_info = {
    316       1.1  christos 	    FSR_NO_EXCEPTION, FTT_UNIMPLEMENTED_FPOP
    317       1.1  christos 	  };
    318       1.1  christos 	  return frv_queue_fp_exception_interrupt (current_cpu, & fp_info);
    319       1.1  christos 	}
    320       1.1  christos       if (frv_is_media_insn (insn))
    321       1.1  christos 	{
    322       1.1  christos 	  frv_set_mp_exception_registers (current_cpu, MTT_UNIMPLEMENTED_MPOP,
    323       1.1  christos 					  0);
    324       1.1  christos 	  return NULL; /* no interrupt queued at this time.  */
    325       1.1  christos 	}
    326       1.1  christos       break;
    327       1.1  christos     }
    328       1.1  christos 
    329       1.1  christos   return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
    330       1.1  christos }
    331       1.1  christos 
    332       1.1  christos /* Queue the given fp_exception interrupt. Also update fp_info by removing
    333       1.1  christos    masked interrupts and updating the 'slot' flield.  */
    334       1.1  christos struct frv_interrupt_queue_element *
    335       1.1  christos frv_queue_fp_exception_interrupt (
    336       1.1  christos   SIM_CPU *current_cpu, struct frv_fp_exception_info *fp_info
    337       1.1  christos )
    338       1.1  christos {
    339       1.1  christos   SI fsr0 = GET_FSR (0);
    340       1.1  christos   int tem = GET_FSR_TEM (fsr0);
    341       1.1  christos   int aexc = GET_FSR_AEXC (fsr0);
    342       1.1  christos   struct frv_interrupt_queue_element *new_element = NULL;
    343       1.1  christos 
    344       1.1  christos   /* Update AEXC with the interrupts that are masked.  */
    345       1.1  christos   aexc |= fp_info->fsr_mask & ~tem;
    346       1.1  christos   SET_FSR_AEXC (fsr0, aexc);
    347       1.1  christos   SET_FSR (0, fsr0);
    348       1.1  christos 
    349       1.1  christos   /* update fsr_mask with the exceptions that are enabled.  */
    350       1.1  christos   fp_info->fsr_mask &= tem;
    351       1.1  christos 
    352       1.1  christos   /* If there is an unmasked interrupt then queue it, unless
    353       1.1  christos      this was a non-excepting insn, in which case simply set the NE
    354       1.1  christos      status registers.  */
    355       1.1  christos   if (frv_interrupt_state.ne_index != NE_NOFLAG
    356       1.1  christos       && fp_info->fsr_mask != FSR_NO_EXCEPTION)
    357       1.1  christos     {
    358       1.1  christos       SET_NE_FLAG (frv_interrupt_state.f_ne_flags,
    359       1.1  christos 		   frv_interrupt_state.ne_index);
    360       1.1  christos       /* TODO -- Set NESR for chips which support it.  */
    361       1.1  christos       new_element = NULL;
    362       1.1  christos     }
    363       1.1  christos   else if (fp_info->fsr_mask != FSR_NO_EXCEPTION
    364       1.1  christos 	   || fp_info->ftt == FTT_UNIMPLEMENTED_FPOP
    365       1.1  christos 	   || fp_info->ftt == FTT_SEQUENCE_ERROR
    366       1.1  christos 	   || fp_info->ftt == FTT_INVALID_FR)
    367       1.1  christos     {
    368       1.1  christos       new_element = frv_queue_program_interrupt (current_cpu, FRV_FP_EXCEPTION);
    369       1.1  christos       new_element->u.fp_info = *fp_info;
    370       1.1  christos     }
    371       1.1  christos 
    372       1.1  christos   return new_element;
    373       1.1  christos }
    374       1.1  christos 
    375       1.1  christos struct frv_interrupt_queue_element *
    376       1.1  christos frv_queue_division_exception_interrupt (SIM_CPU *current_cpu, enum frv_dtt dtt)
    377       1.1  christos {
    378       1.1  christos   struct frv_interrupt_queue_element *new_element =
    379       1.1  christos     frv_queue_program_interrupt (current_cpu, FRV_DIVISION_EXCEPTION);
    380       1.1  christos 
    381       1.1  christos   new_element->u.dtt = dtt;
    382       1.1  christos 
    383       1.1  christos   return new_element;
    384       1.1  christos }
    385       1.1  christos 
    386       1.1  christos /* Check for interrupts caused by illegal insn access.  These conditions are
    387       1.1  christos    checked in the order specified by the fr400 and fr500 LSI specs.  */
    388       1.1  christos void
    389       1.1  christos frv_detect_insn_access_interrupts (SIM_CPU *current_cpu, SCACHE *sc)
    390       1.1  christos {
    391       1.1  christos 
    392       1.1  christos   const CGEN_INSN *insn = sc->argbuf.idesc->idata;
    393       1.1  christos   FRV_VLIW *vliw = CPU_VLIW (current_cpu);
    394       1.1  christos 
    395       1.1  christos   /* Check for vliw constraints.  */
    396       1.1  christos   if (vliw->constraint_violation)
    397       1.1  christos     frv_queue_illegal_instruction_interrupt (current_cpu, insn);
    398       1.1  christos   /* Check for non-excepting insns.  */
    399       1.1  christos   else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_NON_EXCEPTING)
    400       1.1  christos       && ! GET_H_PSR_NEM ())
    401       1.1  christos     frv_queue_non_implemented_instruction_interrupt (current_cpu, insn);
    402       1.1  christos   /* Check for conditional insns.  */
    403       1.1  christos   else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONDITIONAL)
    404       1.1  christos       && ! GET_H_PSR_CM ())
    405       1.1  christos     frv_queue_non_implemented_instruction_interrupt (current_cpu, insn);
    406       1.1  christos   /* Make sure floating point support is enabled.  */
    407       1.1  christos   else if (! GET_H_PSR_EF ())
    408       1.1  christos     {
    409       1.1  christos       /* Generate fp_disabled if it is a floating point insn or if PSR.EM is
    410       1.1  christos 	 off and the insns accesses a fp register.  */
    411       1.1  christos       if (frv_is_float_insn (insn)
    412       1.1  christos 	  || (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR_ACCESS)
    413       1.1  christos 	      && ! GET_H_PSR_EM ()))
    414       1.1  christos 	frv_queue_float_disabled_interrupt (current_cpu);
    415       1.1  christos     }
    416       1.1  christos   /* Make sure media support is enabled.  */
    417       1.1  christos   else if (! GET_H_PSR_EM ())
    418       1.1  christos     {
    419       1.1  christos       /* Generate mp_disabled if it is a media insn.  */
    420       1.1  christos       if (frv_is_media_insn (insn) || CGEN_INSN_NUM (insn) == FRV_INSN_MTRAP)
    421       1.1  christos 	frv_queue_media_disabled_interrupt (current_cpu);
    422       1.1  christos     }
    423       1.1  christos   /* Check for privileged insns.  */
    424       1.1  christos   else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_PRIVILEGED) &&
    425       1.1  christos 	   ! GET_H_PSR_S ())
    426       1.1  christos     frv_queue_privileged_instruction_interrupt (current_cpu, insn);
    427       1.1  christos #if 0 /* disable for now until we find out how FSR0.QNE gets reset.  */
    428       1.1  christos   else
    429       1.1  christos     {
    430       1.1  christos       /* Enter the halt state if FSR0.QNE is set and we are executing a
    431       1.1  christos 	 floating point insn, a media insn or an insn which access a FR
    432       1.1  christos 	 register.  */
    433  1.1.1.10  christos       SIM_DESC sd = CPU_STATE (current_cpu);
    434       1.1  christos       SI fsr0 = GET_FSR (0);
    435       1.1  christos       if (GET_FSR_QNE (fsr0)
    436       1.1  christos 	  && (frv_is_float_insn (insn) || frv_is_media_insn (insn)
    437       1.1  christos 	      || CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR_ACCESS)))
    438       1.1  christos 	{
    439       1.1  christos 	  sim_engine_halt (sd, current_cpu, NULL, GET_H_PC (), sim_stopped,
    440       1.1  christos 			   SIM_SIGINT);
    441       1.1  christos 	}
    442       1.1  christos     }
    443       1.1  christos #endif
    444       1.1  christos }
    445       1.1  christos 
    446       1.1  christos /* Record the current VLIW slot in the given interrupt queue element.  */
    447       1.1  christos void
    448       1.1  christos frv_set_interrupt_queue_slot (
    449       1.1  christos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
    450       1.1  christos )
    451       1.1  christos {
    452       1.1  christos   FRV_VLIW *vliw = CPU_VLIW (current_cpu);
    453       1.1  christos   int slot = vliw->next_slot - 1;
    454       1.1  christos   item->slot = (*vliw->current_vliw)[slot];
    455       1.1  christos }
    456       1.1  christos 
    457       1.1  christos /* Handle an individual interrupt.  */
    458       1.1  christos static void
    459       1.1  christos handle_interrupt (SIM_CPU *current_cpu, IADDR pc)
    460       1.1  christos {
    461       1.1  christos   struct frv_interrupt *interrupt;
    462       1.1  christos   int writeback_done = 0;
    463       1.1  christos   while (1)
    464       1.1  christos     {
    465       1.1  christos       /* Interrupts are queued in priority order with the highest priority
    466       1.1  christos 	 last.  */
    467       1.1  christos       int index = frv_interrupt_state.queue_index - 1;
    468       1.1  christos       struct frv_interrupt_queue_element *item
    469       1.1  christos 	= & frv_interrupt_state.queue[index];
    470       1.1  christos       interrupt = & frv_interrupt_table[item->kind];
    471       1.1  christos 
    472       1.1  christos       switch (interrupt->iclass)
    473       1.1  christos 	{
    474       1.1  christos 	case FRV_EXTERNAL_INTERRUPT:
    475       1.1  christos 	  /* Perform writeback first. This may cause a higher priority
    476       1.1  christos 	     interrupt.  */
    477       1.1  christos 	  if (! writeback_done)
    478       1.1  christos 	    {
    479       1.1  christos 	      frvbf_perform_writeback (current_cpu);
    480       1.1  christos 	      writeback_done = 1;
    481       1.1  christos 	      continue;
    482       1.1  christos 	    }
    483       1.1  christos 	  frv_external_interrupt (current_cpu, item, pc);
    484       1.1  christos 	  return;
    485       1.1  christos 	case FRV_SOFTWARE_INTERRUPT:
    486       1.1  christos 	  frv_interrupt_state.queue_index = index;
    487       1.1  christos 	  frv_software_interrupt (current_cpu, item, pc);
    488       1.1  christos 	  return;
    489       1.1  christos 	case FRV_PROGRAM_INTERRUPT:
    490       1.1  christos 	  /* If the program interrupt is not strict (imprecise), then perform
    491       1.1  christos 	     writeback first. This may, in turn, cause a higher priority
    492       1.1  christos 	     interrupt.  */
    493       1.1  christos 	  if (! interrupt->precise && ! writeback_done)
    494       1.1  christos 	    {
    495       1.1  christos 	      frv_interrupt_state.imprecise_interrupt = item;
    496       1.1  christos 	      frvbf_perform_writeback (current_cpu);
    497       1.1  christos 	      writeback_done = 1;
    498       1.1  christos 	      continue;
    499       1.1  christos 	    }
    500       1.1  christos 	  frv_interrupt_state.queue_index = index;
    501       1.1  christos 	  frv_program_interrupt (current_cpu, item, pc);
    502       1.1  christos 	  return;
    503       1.1  christos 	case FRV_BREAK_INTERRUPT:
    504       1.1  christos 	  frv_interrupt_state.queue_index = index;
    505       1.1  christos 	  frv_break_interrupt (current_cpu, interrupt, pc);
    506       1.1  christos 	  return;
    507       1.1  christos 	case FRV_RESET_INTERRUPT:
    508       1.1  christos 	  break;
    509       1.1  christos 	default:
    510       1.1  christos 	  break;
    511       1.1  christos 	}
    512       1.1  christos       frv_interrupt_state.queue_index = index;
    513       1.1  christos       break; /* out of loop.  */
    514       1.1  christos     }
    515       1.1  christos 
    516       1.1  christos   /* We should never get here.  */
    517       1.1  christos   {
    518       1.1  christos     SIM_DESC sd = CPU_STATE (current_cpu);
    519       1.1  christos     sim_engine_abort (sd, current_cpu, pc,
    520       1.1  christos 		      "interrupt class not supported %d\n",
    521       1.1  christos 		      interrupt->iclass);
    522       1.1  christos   }
    523       1.1  christos }
    524       1.1  christos 
    525       1.1  christos /* Check to see the if the RSTR.HR or RSTR.SR bits have been set.  If so, handle
    526       1.1  christos    the appropriate reset interrupt.  */
    527       1.1  christos static int
    528       1.1  christos check_reset (SIM_CPU *current_cpu, IADDR pc)
    529       1.1  christos {
    530       1.1  christos   int hsr0;
    531       1.1  christos   int hr;
    532       1.1  christos   int sr;
    533       1.1  christos   SI rstr;
    534       1.1  christos   FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
    535       1.1  christos   IADDR address = RSTR_ADDRESS;
    536       1.1  christos 
    537       1.1  christos   /* We don't want this to show up in the cache statistics, so read the
    538       1.1  christos      cache passively.  */
    539       1.1  christos   if (! frv_cache_read_passive_SI (cache, address, & rstr))
    540       1.1  christos     rstr = sim_core_read_unaligned_4 (current_cpu, pc, read_map, address);
    541       1.1  christos 
    542       1.1  christos   hr = GET_RSTR_HR (rstr);
    543       1.1  christos   sr = GET_RSTR_SR (rstr);
    544       1.1  christos 
    545       1.1  christos   if (! hr && ! sr)
    546       1.1  christos     return 0; /* no reset.  */
    547       1.1  christos 
    548       1.1  christos   /* Reinitialize the machine state.  */
    549       1.1  christos   if (hr)
    550       1.1  christos     frv_hardware_reset (current_cpu);
    551       1.1  christos   else
    552       1.1  christos     frv_software_reset (current_cpu);
    553       1.1  christos 
    554       1.1  christos   /* Branch to the reset address.  */
    555       1.1  christos   hsr0 = GET_HSR0 ();
    556       1.1  christos   if (GET_HSR0_SA (hsr0))
    557       1.1  christos     SET_H_PC (0xff000000);
    558       1.1  christos   else
    559       1.1  christos     SET_H_PC (0);
    560       1.1  christos 
    561       1.1  christos   return 1; /* reset */
    562       1.1  christos }
    563       1.1  christos 
    564       1.1  christos /* Process any pending interrupt(s) after a group of parallel insns.  */
    565       1.1  christos void
    566       1.1  christos frv_process_interrupts (SIM_CPU *current_cpu)
    567       1.1  christos {
    568       1.1  christos   SI NE_flags[2];
    569       1.1  christos   /* Need to save the pc here because writeback may change it (due to a
    570       1.1  christos      branch).  */
    571       1.1  christos   IADDR pc = CPU_PC_GET (current_cpu);
    572       1.1  christos 
    573       1.1  christos   /* Check for a reset before anything else.  */
    574       1.1  christos   if (check_reset (current_cpu, pc))
    575       1.1  christos     return;
    576       1.1  christos 
    577       1.1  christos   /* First queue the writes for any accumulated NE flags.  */
    578       1.1  christos   if (frv_interrupt_state.f_ne_flags[0] != 0
    579       1.1  christos       || frv_interrupt_state.f_ne_flags[1] != 0)
    580       1.1  christos     {
    581       1.1  christos       GET_NE_FLAGS (NE_flags, H_SPR_FNER0);
    582       1.1  christos       NE_flags[0] |= frv_interrupt_state.f_ne_flags[0];
    583       1.1  christos       NE_flags[1] |= frv_interrupt_state.f_ne_flags[1];
    584       1.1  christos       SET_NE_FLAGS (H_SPR_FNER0, NE_flags);
    585       1.1  christos     }
    586       1.1  christos 
    587       1.1  christos   /* If there is no interrupt pending, then perform parallel writeback.  This
    588       1.1  christos      may cause an interrupt.  */
    589       1.1  christos   if (frv_interrupt_state.queue_index <= 0)
    590       1.1  christos     frvbf_perform_writeback (current_cpu);
    591       1.1  christos 
    592       1.1  christos   /* If there is an interrupt pending, then process it.  */
    593       1.1  christos   if (frv_interrupt_state.queue_index > 0)
    594       1.1  christos     handle_interrupt (current_cpu, pc);
    595       1.1  christos }
    596       1.1  christos 
    597       1.1  christos /* Find the next available ESR and return its index */
    598       1.1  christos static int
    599       1.1  christos esr_for_data_access_exception (
    600       1.1  christos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
    601       1.1  christos )
    602       1.1  christos {
    603       1.1  christos   SIM_DESC sd = CPU_STATE (current_cpu);
    604       1.1  christos   if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
    605       1.1  christos     return 8; /* Use ESR8, EPCR8.  */
    606       1.1  christos 
    607       1.1  christos   if (item->slot == UNIT_I0)
    608       1.1  christos     return 8; /* Use ESR8, EPCR8, EAR8, EDR8.  */
    609       1.1  christos 
    610       1.1  christos   return 9; /* Use ESR9, EPCR9, EAR9.  */
    611       1.1  christos }
    612       1.1  christos 
    613       1.1  christos /* Set the next available EDR register with the data which was to be stored
    614       1.1  christos    and return the index of the register.  */
    615       1.1  christos static int
    616       1.1  christos set_edr_register (
    617       1.1  christos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, int edr_index
    618       1.1  christos )
    619       1.1  christos {
    620       1.1  christos   /* EDR0, EDR4 and EDR8 are available as blocks of 4.
    621       1.1  christos        SI data uses EDR3, EDR7 and EDR11
    622       1.1  christos        DI data uses EDR2, EDR6 and EDR10
    623       1.1  christos        XI data uses EDR0, EDR4 and EDR8.  */
    624       1.1  christos   int i;
    625       1.1  christos   edr_index += 4 - item->u.data_written.length;
    626       1.1  christos   for (i = 0; i < item->u.data_written.length; ++i)
    627       1.1  christos     SET_EDR (edr_index + i, item->u.data_written.words[i]);
    628       1.1  christos 
    629       1.1  christos   return edr_index;
    630       1.1  christos };
    631       1.1  christos 
    632       1.1  christos /* Clear ESFR0, EPCRx, ESRx, EARx and EDRx.  */
    633       1.1  christos static void
    634       1.1  christos clear_exception_status_registers (SIM_CPU *current_cpu)
    635       1.1  christos {
    636       1.1  christos   int i;
    637       1.1  christos   /* It is only necessary to clear the flag bits indicating which registers
    638       1.1  christos      are valid.  */
    639       1.1  christos   SET_ESFR (0, 0);
    640       1.1  christos   SET_ESFR (1, 0);
    641       1.1  christos 
    642       1.1  christos   for (i = 0; i <= 2; ++i)
    643       1.1  christos     {
    644       1.1  christos       SI esr = GET_ESR (i);
    645       1.1  christos       CLEAR_ESR_VALID (esr);
    646       1.1  christos       SET_ESR (i, esr);
    647       1.1  christos     }
    648       1.1  christos   for (i = 8; i <= 15; ++i)
    649       1.1  christos     {
    650       1.1  christos       SI esr = GET_ESR (i);
    651       1.1  christos       CLEAR_ESR_VALID (esr);
    652       1.1  christos       SET_ESR (i, esr);
    653       1.1  christos     }
    654       1.1  christos }
    655       1.1  christos 
    656       1.1  christos /* Record state for media exception.  */
    657       1.1  christos void
    658       1.1  christos frv_set_mp_exception_registers (
    659       1.1  christos   SIM_CPU *current_cpu, enum frv_msr_mtt mtt, int sie
    660       1.1  christos )
    661       1.1  christos {
    662       1.1  christos   /* Record the interrupt factor in MSR0.  */
    663       1.1  christos   SI msr0 = GET_MSR (0);
    664       1.1  christos   if (GET_MSR_MTT (msr0) == MTT_NONE)
    665       1.1  christos     SET_MSR_MTT (msr0, mtt);
    666       1.1  christos 
    667       1.1  christos   /* Also set the OVF bit in the appropriate MSR as well as MSR0.AOVF.  */
    668       1.1  christos   if (mtt == MTT_OVERFLOW)
    669       1.1  christos     {
    670       1.1  christos       FRV_VLIW *vliw = CPU_VLIW (current_cpu);
    671       1.1  christos       int slot = vliw->next_slot - 1;
    672       1.1  christos       SIM_DESC sd = CPU_STATE (current_cpu);
    673       1.1  christos 
    674       1.1  christos       /* If this insn is in the M2 slot, then set MSR1.OVF and MSR1.SIE,
    675       1.1  christos 	 otherwise set MSR0.OVF and MSR0.SIE.  */
    676       1.1  christos       if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550 && (*vliw->current_vliw)[slot] == UNIT_FM1)
    677       1.1  christos 	{
    678       1.1  christos 	  SI msr = GET_MSR (1);
    679       1.1  christos 	  OR_MSR_SIE (msr, sie);
    680       1.1  christos 	  SET_MSR_OVF (msr);
    681       1.1  christos 	  SET_MSR (1, msr);
    682       1.1  christos 	}
    683       1.1  christos       else
    684       1.1  christos 	{
    685       1.1  christos 	  OR_MSR_SIE (msr0, sie);
    686       1.1  christos 	  SET_MSR_OVF (msr0);
    687       1.1  christos 	}
    688       1.1  christos 
    689       1.1  christos       /* Generate the interrupt now if MSR0.MPEM is set on fr550 */
    690       1.1  christos       if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550 && GET_MSR_MPEM (msr0))
    691       1.1  christos 	frv_queue_program_interrupt (current_cpu, FRV_MP_EXCEPTION);
    692       1.1  christos       else
    693       1.1  christos 	{
    694       1.1  christos 	  /* Regardless of the slot, set MSR0.AOVF.  */
    695       1.1  christos 	  SET_MSR_AOVF (msr0);
    696       1.1  christos 	}
    697       1.1  christos     }
    698       1.1  christos 
    699       1.1  christos   SET_MSR (0, msr0);
    700       1.1  christos }
    701       1.1  christos 
    702       1.1  christos /* Determine the correct FQ register to use for the given exception.
    703       1.1  christos    Return -1 if a register is not available.  */
    704       1.1  christos static int
    705       1.1  christos fq_for_exception (
    706       1.1  christos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
    707       1.1  christos )
    708       1.1  christos {
    709       1.1  christos   SI fq;
    710       1.1  christos   struct frv_fp_exception_info *fp_info = & item->u.fp_info;
    711       1.1  christos 
    712       1.1  christos   /* For fp_exception overflow, underflow or inexact, use FQ0 or FQ1.  */
    713       1.1  christos   if (fp_info->ftt == FTT_IEEE_754_EXCEPTION
    714       1.1  christos       && (fp_info->fsr_mask & (FSR_OVERFLOW | FSR_UNDERFLOW | FSR_INEXACT)))
    715       1.1  christos     {
    716       1.1  christos       fq = GET_FQ (0);
    717       1.1  christos       if (! GET_FQ_VALID (fq))
    718       1.1  christos 	return 0; /* FQ0 is available.  */
    719       1.1  christos       fq = GET_FQ (1);
    720       1.1  christos       if (! GET_FQ_VALID (fq))
    721       1.1  christos 	return 1; /* FQ1 is available.  */
    722       1.1  christos 
    723       1.1  christos       /* No FQ register is available */
    724       1.1  christos       {
    725       1.1  christos 	SIM_DESC sd = CPU_STATE (current_cpu);
    726       1.1  christos 	IADDR pc = CPU_PC_GET (current_cpu);
    727       1.1  christos 	sim_engine_abort (sd, current_cpu, pc, "No FQ register available\n");
    728       1.1  christos       }
    729       1.1  christos       return -1;
    730       1.1  christos     }
    731       1.1  christos   /* For other exceptions, use FQ2 if the insn was in slot F0/I0 and FQ3
    732       1.1  christos      otherwise.  */
    733       1.1  christos   if (item->slot == UNIT_FM0 || item->slot == UNIT_I0)
    734       1.1  christos     return 2;
    735       1.1  christos 
    736       1.1  christos   return 3;
    737       1.1  christos }
    738       1.1  christos 
    739       1.1  christos /* Set FSR0, FQ0-FQ9, depending on the interrupt.  */
    740       1.1  christos static void
    741       1.1  christos set_fp_exception_registers (
    742       1.1  christos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
    743       1.1  christos )
    744       1.1  christos {
    745       1.1  christos   int fq_index;
    746       1.1  christos   SI fq;
    747       1.1  christos   SI insn;
    748       1.1  christos   SI fsr0;
    749       1.1  christos   IADDR pc;
    750       1.1  christos   struct frv_fp_exception_info *fp_info;
    751       1.1  christos   SIM_DESC sd = CPU_STATE (current_cpu);
    752       1.1  christos 
    753       1.1  christos   /* No FQ registers on fr550 */
    754       1.1  christos   if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
    755       1.1  christos     {
    756       1.1  christos       /* Update the fsr.  */
    757       1.1  christos       fp_info = & item->u.fp_info;
    758       1.1  christos       fsr0 = GET_FSR (0);
    759       1.1  christos       SET_FSR_FTT (fsr0, fp_info->ftt);
    760       1.1  christos       SET_FSR (0, fsr0);
    761       1.1  christos       return;
    762       1.1  christos     }
    763       1.1  christos 
    764       1.1  christos   /* Select an FQ and update it with the exception information.  */
    765       1.1  christos   fq_index = fq_for_exception (current_cpu, item);
    766       1.1  christos   if (fq_index == -1)
    767       1.1  christos     return;
    768       1.1  christos 
    769       1.1  christos   fp_info = & item->u.fp_info;
    770       1.1  christos   fq = GET_FQ (fq_index);
    771       1.1  christos   SET_FQ_MIV (fq, MIV_FLOAT);
    772       1.1  christos   SET_FQ_SIE (fq, SIE_NIL);
    773       1.1  christos   SET_FQ_FTT (fq, fp_info->ftt);
    774       1.1  christos   SET_FQ_CEXC (fq, fp_info->fsr_mask);
    775       1.1  christos   SET_FQ_VALID (fq);
    776       1.1  christos   SET_FQ (fq_index, fq);
    777       1.1  christos 
    778       1.1  christos   /* Write the failing insn into FQx.OPC.  */
    779       1.1  christos   pc = item->vpc;
    780       1.1  christos   insn = GETMEMSI (current_cpu, pc, pc);
    781       1.1  christos   SET_FQ_OPC (fq_index, insn);
    782       1.1  christos 
    783       1.1  christos   /* Update the fsr.  */
    784       1.1  christos   fsr0 = GET_FSR (0);
    785       1.1  christos   SET_FSR_QNE (fsr0); /* FQ not empty */
    786       1.1  christos   SET_FSR_FTT (fsr0, fp_info->ftt);
    787       1.1  christos   SET_FSR (0, fsr0);
    788       1.1  christos }
    789       1.1  christos 
    790       1.1  christos /* Record the state of a division exception in the ISR.  */
    791       1.1  christos static void
    792       1.1  christos set_isr_exception_fields (
    793       1.1  christos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
    794       1.1  christos )
    795       1.1  christos {
    796       1.1  christos   USI isr = GET_ISR ();
    797       1.1  christos   int dtt = GET_ISR_DTT (isr);
    798       1.1  christos   dtt |= item->u.dtt;
    799       1.1  christos   SET_ISR_DTT (isr, dtt);
    800       1.1  christos   SET_ISR (isr);
    801       1.1  christos }
    802       1.1  christos 
    803       1.1  christos /* Set ESFR0, EPCRx, ESRx, EARx and EDRx, according to the given program
    804       1.1  christos    interrupt.  */
    805       1.1  christos static void
    806       1.1  christos set_exception_status_registers (
    807       1.1  christos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
    808       1.1  christos )
    809       1.1  christos {
    810       1.1  christos   struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind];
    811       1.1  christos   int reg_index = -1;
    812       1.1  christos   int set_ear = 0;
    813       1.1  christos   int set_edr = 0;
    814       1.1  christos   int set_daec = 0;
    815       1.1  christos   int set_epcr = 0;
    816       1.1  christos   SI esr = 0;
    817       1.1  christos   SIM_DESC sd = CPU_STATE (current_cpu);
    818       1.1  christos 
    819       1.1  christos   /* If the interrupt is strict (precise) or the interrupt is on the insns
    820       1.1  christos      in the I0 pipe, then set the 0 registers.  */
    821       1.1  christos   if (interrupt->precise)
    822       1.1  christos     {
    823       1.1  christos       reg_index = 0;
    824       1.1  christos       if (interrupt->kind == FRV_REGISTER_EXCEPTION)
    825       1.1  christos 	SET_ESR_REC (esr, item->u.rec);
    826       1.1  christos       else if (interrupt->kind == FRV_INSTRUCTION_ACCESS_EXCEPTION)
    827       1.1  christos 	SET_ESR_IAEC (esr, item->u.iaec);
    828       1.1  christos       /* For fr550, don't set epcr for precise interrupts.  */
    829       1.1  christos       if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550)
    830       1.1  christos 	set_epcr = 1;
    831       1.1  christos     }
    832       1.1  christos   else
    833       1.1  christos     {
    834       1.1  christos       switch (interrupt->kind)
    835       1.1  christos 	{
    836       1.1  christos 	case FRV_DIVISION_EXCEPTION:
    837       1.1  christos 	  set_isr_exception_fields (current_cpu, item);
    838  1.1.1.10  christos 	  ATTRIBUTE_FALLTHROUGH;  /* To set reg_index.  */
    839       1.1  christos 	case FRV_COMMIT_EXCEPTION:
    840       1.1  christos 	  /* For fr550, always use ESR0.  */
    841       1.1  christos 	  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
    842       1.1  christos 	    reg_index = 0;
    843       1.1  christos 	  else if (item->slot == UNIT_I0)
    844       1.1  christos 	    reg_index = 0;
    845       1.1  christos 	  else if (item->slot == UNIT_I1)
    846       1.1  christos 	    reg_index = 1;
    847       1.1  christos 	  set_epcr = 1;
    848       1.1  christos 	  break;
    849       1.1  christos 	case FRV_DATA_STORE_ERROR:
    850       1.1  christos 	  reg_index = 14; /* Use ESR14.  */
    851       1.1  christos 	  break;
    852       1.1  christos 	case FRV_DATA_ACCESS_ERROR:
    853       1.1  christos 	  reg_index = 15; /* Use ESR15, EPCR15.  */
    854       1.1  christos 	  set_ear = 1;
    855       1.1  christos 	  break;
    856       1.1  christos 	case FRV_DATA_ACCESS_EXCEPTION:
    857       1.1  christos 	  set_daec = 1;
    858  1.1.1.10  christos 	  ATTRIBUTE_FALLTHROUGH;
    859       1.1  christos 	case FRV_DATA_ACCESS_MMU_MISS:
    860       1.1  christos 	case FRV_MEM_ADDRESS_NOT_ALIGNED:
    861       1.1  christos 	  /* Get the appropriate ESR, EPCR, EAR and EDR.
    862       1.1  christos 	     EAR will be set. EDR will not be set if this is a store insn.  */
    863       1.1  christos 	  set_ear = 1;
    864       1.1  christos 	  /* For fr550, never use EDRx.  */
    865       1.1  christos 	  if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550)
    866       1.1  christos 	    if (item->u.data_written.length != 0)
    867       1.1  christos 	      set_edr = 1;
    868       1.1  christos 	  reg_index = esr_for_data_access_exception (current_cpu, item);
    869       1.1  christos 	  set_epcr = 1;
    870       1.1  christos 	  break;
    871       1.1  christos 	case FRV_MP_EXCEPTION:
    872       1.1  christos 	  /* For fr550, use EPCR2 and ESR2.  */
    873       1.1  christos 	  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
    874       1.1  christos 	    {
    875       1.1  christos 	      reg_index = 2;
    876       1.1  christos 	      set_epcr = 1;
    877       1.1  christos 	    }
    878       1.1  christos 	  break; /* MSR0-1, FQ0-9 are already set.  */
    879       1.1  christos 	case FRV_FP_EXCEPTION:
    880       1.1  christos 	  set_fp_exception_registers (current_cpu, item);
    881       1.1  christos 	  /* For fr550, use EPCR2 and ESR2.  */
    882       1.1  christos 	  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
    883       1.1  christos 	    {
    884       1.1  christos 	      reg_index = 2;
    885       1.1  christos 	      set_epcr = 1;
    886       1.1  christos 	    }
    887       1.1  christos 	  break;
    888       1.1  christos 	default:
    889       1.1  christos 	  {
    890       1.1  christos 	    IADDR pc = CPU_PC_GET (current_cpu);
    891       1.1  christos 	    sim_engine_abort (sd, current_cpu, pc,
    892       1.1  christos 			      "invalid non-strict program interrupt kind: %d\n",
    893       1.1  christos 			      interrupt->kind);
    894       1.1  christos 	    break;
    895       1.1  christos 	  }
    896       1.1  christos 	}
    897       1.1  christos     } /* non-strict (imprecise) interrupt */
    898       1.1  christos 
    899       1.1  christos   /* Now fill in the selected exception status registers.  */
    900       1.1  christos   if (reg_index != -1)
    901       1.1  christos     {
    902       1.1  christos       /* Now set the exception status registers.  */
    903       1.1  christos       SET_ESFR_FLAG (reg_index);
    904       1.1  christos       SET_ESR_EC (esr, interrupt->ec);
    905       1.1  christos 
    906       1.1  christos       if (set_epcr)
    907       1.1  christos 	{
    908       1.1  christos 	  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400)
    909       1.1  christos 	    SET_EPCR (reg_index, previous_vliw_pc);
    910       1.1  christos 	  else
    911       1.1  christos 	    SET_EPCR (reg_index, item->vpc);
    912       1.1  christos 	}
    913       1.1  christos 
    914       1.1  christos       if (set_ear)
    915       1.1  christos 	{
    916       1.1  christos 	  SET_EAR (reg_index, item->eaddress);
    917       1.1  christos 	  SET_ESR_EAV (esr);
    918       1.1  christos 	}
    919       1.1  christos       else
    920       1.1  christos 	CLEAR_ESR_EAV (esr);
    921       1.1  christos 
    922       1.1  christos       if (set_edr)
    923       1.1  christos 	{
    924       1.1  christos 	  int edn = set_edr_register (current_cpu, item, 0/* EDR0-3 */);
    925       1.1  christos 	  SET_ESR_EDN (esr, edn);
    926       1.1  christos 	  SET_ESR_EDV (esr);
    927       1.1  christos 	}
    928       1.1  christos       else
    929       1.1  christos 	CLEAR_ESR_EDV (esr);
    930       1.1  christos 
    931       1.1  christos       if (set_daec)
    932       1.1  christos 	SET_ESR_DAEC (esr, item->u.daec);
    933       1.1  christos 
    934       1.1  christos       SET_ESR_VALID (esr);
    935       1.1  christos       SET_ESR (reg_index, esr);
    936       1.1  christos     }
    937       1.1  christos }
    938       1.1  christos 
    939       1.1  christos /* Check for compound interrupts.
    940       1.1  christos    Returns NULL if no interrupt is to be processed.  */
    941       1.1  christos static struct frv_interrupt *
    942       1.1  christos check_for_compound_interrupt (
    943       1.1  christos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
    944       1.1  christos )
    945       1.1  christos {
    946       1.1  christos   struct frv_interrupt *interrupt;
    947       1.1  christos 
    948       1.1  christos   /* Set the exception status registers for the original interrupt.  */
    949       1.1  christos   set_exception_status_registers (current_cpu, item);
    950       1.1  christos   interrupt = & frv_interrupt_table[item->kind];
    951       1.1  christos 
    952       1.1  christos   if (! interrupt->precise)
    953       1.1  christos     {
    954       1.1  christos       IADDR vpc = 0;
    955       1.1  christos       int mask = 0;
    956       1.1  christos 
    957       1.1  christos       vpc = item->vpc;
    958       1.1  christos       mask = (1 << item->kind);
    959       1.1  christos 
    960       1.1  christos       /* Look for more queued program interrupts which are non-deferred
    961       1.1  christos 	 (pending inhibit), imprecise (non-strict) different than an interrupt
    962       1.1  christos 	 already found and caused by a different insn.  A bit mask is used
    963       1.1  christos 	 to keep track of interrupts which have already been detected.  */
    964       1.1  christos       while (item != frv_interrupt_state.queue)
    965       1.1  christos 	{
    966       1.1  christos 	  enum frv_interrupt_kind kind;
    967       1.1  christos 	  struct frv_interrupt *next_interrupt;
    968       1.1  christos 	  --item;
    969       1.1  christos 	  kind = item->kind;
    970       1.1  christos 	  next_interrupt = & frv_interrupt_table[kind];
    971       1.1  christos 
    972       1.1  christos 	  if (next_interrupt->iclass != FRV_PROGRAM_INTERRUPT)
    973       1.1  christos 	    break; /* no program interrupts left.  */
    974       1.1  christos 
    975       1.1  christos 	  if (item->vpc == vpc)
    976       1.1  christos 	    continue; /* caused by the same insn.  */
    977       1.1  christos 
    978       1.1  christos 	  vpc = item->vpc;
    979       1.1  christos 	  if (! next_interrupt->precise && ! next_interrupt->deferred)
    980       1.1  christos 	    {
    981       1.1  christos 	      if (! (mask & (1 << kind)))
    982       1.1  christos 		{
    983       1.1  christos 		  /* Set the exception status registers for the additional
    984       1.1  christos 		     interrupt.  */
    985       1.1  christos 		  set_exception_status_registers (current_cpu, item);
    986       1.1  christos 		  mask |= (1 << kind);
    987       1.1  christos 		  interrupt = & frv_interrupt_table[FRV_COMPOUND_EXCEPTION];
    988       1.1  christos 		}
    989       1.1  christos 	    }
    990       1.1  christos 	}
    991       1.1  christos     }
    992       1.1  christos 
    993       1.1  christos   /* Return with either the original interrupt, a compound_exception,
    994       1.1  christos      or no exception.  */
    995       1.1  christos   return interrupt;
    996       1.1  christos }
    997       1.1  christos 
    998       1.1  christos /* Handle a program interrupt.  */
    999       1.1  christos void
   1000       1.1  christos frv_program_interrupt (
   1001       1.1  christos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc
   1002       1.1  christos )
   1003       1.1  christos {
   1004       1.1  christos   struct frv_interrupt *interrupt;
   1005       1.1  christos 
   1006       1.1  christos   clear_exception_status_registers (current_cpu);
   1007       1.1  christos   /* If two or more non-deferred imprecise (non-strict) interrupts occur
   1008       1.1  christos      on two or more insns, then generate a compound_exception.  */
   1009       1.1  christos   interrupt = check_for_compound_interrupt (current_cpu, item);
   1010       1.1  christos   if (interrupt != NULL)
   1011       1.1  christos     {
   1012       1.1  christos       frv_program_or_software_interrupt (current_cpu, interrupt, pc);
   1013       1.1  christos       frv_clear_interrupt_classes (FRV_SOFTWARE_INTERRUPT,
   1014       1.1  christos 				   FRV_PROGRAM_INTERRUPT);
   1015       1.1  christos     }
   1016       1.1  christos }
   1017       1.1  christos 
   1018       1.1  christos /* Handle a software interrupt.  */
   1019       1.1  christos void
   1020       1.1  christos frv_software_interrupt (
   1021       1.1  christos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc
   1022       1.1  christos )
   1023       1.1  christos {
   1024       1.1  christos   struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind];
   1025       1.1  christos   frv_program_or_software_interrupt (current_cpu, interrupt, pc);
   1026       1.1  christos }
   1027       1.1  christos 
   1028       1.1  christos /* Handle a program interrupt or a software interrupt in non-operating mode.  */
   1029       1.1  christos void
   1030       1.1  christos frv_non_operating_interrupt (
   1031       1.1  christos   SIM_CPU *current_cpu, enum frv_interrupt_kind kind, IADDR pc
   1032       1.1  christos )
   1033       1.1  christos {
   1034       1.1  christos   SIM_DESC sd = CPU_STATE (current_cpu);
   1035       1.1  christos   switch (kind)
   1036       1.1  christos     {
   1037       1.1  christos     case FRV_INTERRUPT_LEVEL_1:
   1038       1.1  christos     case FRV_INTERRUPT_LEVEL_2:
   1039       1.1  christos     case FRV_INTERRUPT_LEVEL_3:
   1040       1.1  christos     case FRV_INTERRUPT_LEVEL_4:
   1041       1.1  christos     case FRV_INTERRUPT_LEVEL_5:
   1042       1.1  christos     case FRV_INTERRUPT_LEVEL_6:
   1043       1.1  christos     case FRV_INTERRUPT_LEVEL_7:
   1044       1.1  christos     case FRV_INTERRUPT_LEVEL_8:
   1045       1.1  christos     case FRV_INTERRUPT_LEVEL_9:
   1046       1.1  christos     case FRV_INTERRUPT_LEVEL_10:
   1047       1.1  christos     case FRV_INTERRUPT_LEVEL_11:
   1048       1.1  christos     case FRV_INTERRUPT_LEVEL_12:
   1049       1.1  christos     case FRV_INTERRUPT_LEVEL_13:
   1050       1.1  christos     case FRV_INTERRUPT_LEVEL_14:
   1051       1.1  christos     case FRV_INTERRUPT_LEVEL_15:
   1052       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1053       1.1  christos 			"interrupt: external %d\n", kind + 1);
   1054       1.1  christos       break;
   1055       1.1  christos     case FRV_TRAP_INSTRUCTION:
   1056       1.1  christos       break; /* handle as in operating mode.  */
   1057       1.1  christos     case FRV_COMMIT_EXCEPTION:
   1058       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1059       1.1  christos 			"interrupt: commit_exception\n");
   1060       1.1  christos       break;
   1061       1.1  christos     case FRV_DIVISION_EXCEPTION:
   1062       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1063       1.1  christos 			"interrupt: division_exception\n");
   1064       1.1  christos       break;
   1065       1.1  christos     case FRV_DATA_STORE_ERROR:
   1066       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1067       1.1  christos 			"interrupt: data_store_error\n");
   1068       1.1  christos       break;
   1069       1.1  christos     case FRV_DATA_ACCESS_EXCEPTION:
   1070       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1071       1.1  christos 			"interrupt: data_access_exception\n");
   1072       1.1  christos       break;
   1073       1.1  christos     case FRV_DATA_ACCESS_MMU_MISS:
   1074       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1075       1.1  christos 			"interrupt: data_access_mmu_miss\n");
   1076       1.1  christos       break;
   1077       1.1  christos     case FRV_DATA_ACCESS_ERROR:
   1078       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1079       1.1  christos 			"interrupt: data_access_error\n");
   1080       1.1  christos       break;
   1081       1.1  christos     case FRV_MP_EXCEPTION:
   1082       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1083       1.1  christos 			"interrupt: mp_exception\n");
   1084       1.1  christos       break;
   1085       1.1  christos     case FRV_FP_EXCEPTION:
   1086       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1087       1.1  christos 			"interrupt: fp_exception\n");
   1088       1.1  christos       break;
   1089       1.1  christos     case FRV_MEM_ADDRESS_NOT_ALIGNED:
   1090       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1091       1.1  christos 			"interrupt: mem_address_not_aligned\n");
   1092       1.1  christos       break;
   1093       1.1  christos     case FRV_REGISTER_EXCEPTION:
   1094       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1095       1.1  christos 			"interrupt: register_exception\n");
   1096       1.1  christos       break;
   1097       1.1  christos     case FRV_MP_DISABLED:
   1098       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1099       1.1  christos 			"interrupt: mp_disabled\n");
   1100       1.1  christos       break;
   1101       1.1  christos     case FRV_FP_DISABLED:
   1102       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1103       1.1  christos 			"interrupt: fp_disabled\n");
   1104       1.1  christos       break;
   1105       1.1  christos     case FRV_PRIVILEGED_INSTRUCTION:
   1106       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1107       1.1  christos 			"interrupt: privileged_instruction\n");
   1108       1.1  christos       break;
   1109       1.1  christos     case FRV_ILLEGAL_INSTRUCTION:
   1110       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1111       1.1  christos 			"interrupt: illegal_instruction\n");
   1112       1.1  christos       break;
   1113       1.1  christos     case FRV_INSTRUCTION_ACCESS_EXCEPTION:
   1114       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1115       1.1  christos 			"interrupt: instruction_access_exception\n");
   1116       1.1  christos       break;
   1117       1.1  christos     case FRV_INSTRUCTION_ACCESS_MMU_MISS:
   1118       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1119       1.1  christos 			"interrupt: instruction_access_mmu_miss\n");
   1120       1.1  christos       break;
   1121       1.1  christos     case FRV_INSTRUCTION_ACCESS_ERROR:
   1122       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1123       1.1  christos 			"interrupt: insn_access_error\n");
   1124       1.1  christos       break;
   1125       1.1  christos     case FRV_COMPOUND_EXCEPTION:
   1126       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1127       1.1  christos 			"interrupt: compound_exception\n");
   1128       1.1  christos       break;
   1129       1.1  christos     case FRV_BREAK_EXCEPTION:
   1130       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1131       1.1  christos 			"interrupt: break_exception\n");
   1132       1.1  christos       break;
   1133       1.1  christos     case FRV_RESET:
   1134       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1135       1.1  christos 			"interrupt: reset\n");
   1136       1.1  christos       break;
   1137       1.1  christos     default:
   1138       1.1  christos       sim_engine_abort (sd, current_cpu, pc,
   1139       1.1  christos 			"unhandled interrupt kind: %d\n", kind);
   1140       1.1  christos       break;
   1141       1.1  christos     }
   1142       1.1  christos }
   1143       1.1  christos 
   1144       1.1  christos /* Handle a break interrupt.  */
   1145       1.1  christos void
   1146       1.1  christos frv_break_interrupt (
   1147       1.1  christos   SIM_CPU *current_cpu, struct frv_interrupt *interrupt, IADDR current_pc
   1148       1.1  christos )
   1149       1.1  christos {
   1150       1.1  christos   IADDR new_pc;
   1151       1.1  christos 
   1152       1.1  christos   /* BPCSR=PC
   1153       1.1  christos      BPSR.BS=PSR.S
   1154       1.1  christos      BPSR.BET=PSR.ET
   1155       1.1  christos      PSR.S=1
   1156       1.1  christos      PSR.ET=0
   1157       1.1  christos      TBR.TT=0xff
   1158       1.1  christos      PC=TBR
   1159       1.1  christos   */
   1160       1.1  christos   /* Must set PSR.S first to allow access to supervisor-only spr registers.  */
   1161       1.1  christos   SET_H_BPSR_BS (GET_H_PSR_S ());
   1162       1.1  christos   SET_H_BPSR_BET (GET_H_PSR_ET ());
   1163       1.1  christos   SET_H_PSR_S (1);
   1164       1.1  christos   SET_H_PSR_ET (0);
   1165       1.1  christos   /* Must set PSR.S first to allow access to supervisor-only spr registers.  */
   1166       1.1  christos   SET_H_SPR (H_SPR_BPCSR, current_pc);
   1167       1.1  christos 
   1168       1.1  christos   /* Set the new PC in the TBR.  */
   1169       1.1  christos   SET_H_TBR_TT (interrupt->handler_offset);
   1170       1.1  christos   new_pc = GET_H_SPR (H_SPR_TBR);
   1171       1.1  christos   SET_H_PC (new_pc);
   1172       1.1  christos 
   1173       1.1  christos   CPU_DEBUG_STATE (current_cpu) = 1;
   1174       1.1  christos }
   1175       1.1  christos 
   1176       1.1  christos /* Handle a program interrupt or a software interrupt.  */
   1177       1.1  christos void
   1178       1.1  christos frv_program_or_software_interrupt (
   1179       1.1  christos   SIM_CPU *current_cpu, struct frv_interrupt *interrupt, IADDR current_pc
   1180       1.1  christos )
   1181       1.1  christos {
   1182       1.1  christos   USI new_pc;
   1183       1.1  christos   int original_psr_et;
   1184       1.1  christos 
   1185       1.1  christos   /* PCSR=PC
   1186       1.1  christos      PSR.PS=PSR.S
   1187       1.1  christos      PSR.ET=0
   1188       1.1  christos      PSR.S=1
   1189       1.1  christos      if PSR.ESR==1
   1190       1.1  christos        SR0 through SR3=GR4 through GR7
   1191       1.1  christos        TBR.TT=interrupt handler offset
   1192       1.1  christos        PC=TBR
   1193       1.1  christos   */
   1194       1.1  christos   original_psr_et = GET_H_PSR_ET ();
   1195       1.1  christos 
   1196       1.1  christos   SET_H_PSR_PS (GET_H_PSR_S ());
   1197       1.1  christos   SET_H_PSR_ET (0);
   1198       1.1  christos   SET_H_PSR_S (1);
   1199       1.1  christos 
   1200       1.1  christos   /* Must set PSR.S first to allow access to supervisor-only spr registers.  */
   1201       1.1  christos   /* The PCSR depends on the precision of the interrupt.  */
   1202       1.1  christos   if (interrupt->precise)
   1203       1.1  christos     SET_H_SPR (H_SPR_PCSR, previous_vliw_pc);
   1204       1.1  christos   else
   1205       1.1  christos     SET_H_SPR (H_SPR_PCSR, current_pc);
   1206       1.1  christos 
   1207       1.1  christos   /* Set the new PC in the TBR.  */
   1208       1.1  christos   SET_H_TBR_TT (interrupt->handler_offset);
   1209       1.1  christos   new_pc = GET_H_SPR (H_SPR_TBR);
   1210       1.1  christos   SET_H_PC (new_pc);
   1211       1.1  christos 
   1212       1.1  christos   /* If PSR.ET was not originally set, then enter the stopped state.  */
   1213       1.1  christos   if (! original_psr_et)
   1214       1.1  christos     {
   1215       1.1  christos       SIM_DESC sd = CPU_STATE (current_cpu);
   1216       1.1  christos       frv_non_operating_interrupt (current_cpu, interrupt->kind, current_pc);
   1217       1.1  christos       sim_engine_halt (sd, current_cpu, NULL, new_pc, sim_stopped, SIM_SIGINT);
   1218       1.1  christos     }
   1219       1.1  christos }
   1220       1.1  christos 
   1221       1.1  christos /* Handle a program interrupt or a software interrupt.  */
   1222       1.1  christos void
   1223       1.1  christos frv_external_interrupt (
   1224       1.1  christos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc
   1225       1.1  christos )
   1226       1.1  christos {
   1227       1.1  christos   USI new_pc;
   1228       1.1  christos   struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind];
   1229       1.1  christos 
   1230       1.1  christos   /* Don't process the interrupt if PSR.ET is not set or if it is masked.
   1231       1.1  christos      Interrupt 15 is processed even if it appears to be masked.  */
   1232       1.1  christos   if (! GET_H_PSR_ET ()
   1233       1.1  christos       || (interrupt->kind != FRV_INTERRUPT_LEVEL_15
   1234       1.1  christos 	  && interrupt->kind < GET_H_PSR_PIL ()))
   1235       1.1  christos     return; /* Leave it for later.  */
   1236       1.1  christos 
   1237       1.1  christos   /* Remove the interrupt from the queue.  */
   1238       1.1  christos   --frv_interrupt_state.queue_index;
   1239       1.1  christos 
   1240       1.1  christos   /* PCSR=PC
   1241       1.1  christos      PSR.PS=PSR.S
   1242       1.1  christos      PSR.ET=0
   1243       1.1  christos      PSR.S=1
   1244       1.1  christos      if PSR.ESR==1
   1245       1.1  christos        SR0 through SR3=GR4 through GR7
   1246       1.1  christos        TBR.TT=interrupt handler offset
   1247       1.1  christos        PC=TBR
   1248       1.1  christos   */
   1249       1.1  christos   SET_H_PSR_PS (GET_H_PSR_S ());
   1250       1.1  christos   SET_H_PSR_ET (0);
   1251       1.1  christos   SET_H_PSR_S (1);
   1252       1.1  christos   /* Must set PSR.S first to allow access to supervisor-only spr registers.  */
   1253       1.1  christos   SET_H_SPR (H_SPR_PCSR, GET_H_PC ());
   1254       1.1  christos 
   1255       1.1  christos   /* Set the new PC in the TBR.  */
   1256       1.1  christos   SET_H_TBR_TT (interrupt->handler_offset);
   1257       1.1  christos   new_pc = GET_H_SPR (H_SPR_TBR);
   1258       1.1  christos   SET_H_PC (new_pc);
   1259       1.1  christos }
   1260       1.1  christos 
   1261       1.1  christos /* Clear interrupts which fall within the range of classes given.  */
   1262       1.1  christos void
   1263       1.1  christos frv_clear_interrupt_classes (
   1264       1.1  christos   enum frv_interrupt_class low_class, enum frv_interrupt_class high_class
   1265       1.1  christos )
   1266       1.1  christos {
   1267       1.1  christos   int i;
   1268       1.1  christos   int j;
   1269       1.1  christos   int limit = frv_interrupt_state.queue_index;
   1270       1.1  christos 
   1271       1.1  christos   /* Find the lowest priority interrupt to be removed.  */
   1272       1.1  christos   for (i = 0; i < limit; ++i)
   1273       1.1  christos     {
   1274       1.1  christos       enum frv_interrupt_kind kind = frv_interrupt_state.queue[i].kind;
   1275       1.1  christos       struct frv_interrupt* interrupt = & frv_interrupt_table[kind];
   1276       1.1  christos       if (interrupt->iclass >= low_class)
   1277       1.1  christos 	break;
   1278       1.1  christos     }
   1279       1.1  christos 
   1280       1.1  christos   /* Find the highest priority interrupt to be removed.  */
   1281       1.1  christos   for (j = limit - 1; j >= i; --j)
   1282       1.1  christos     {
   1283       1.1  christos       enum frv_interrupt_kind kind = frv_interrupt_state.queue[j].kind;
   1284       1.1  christos       struct frv_interrupt* interrupt = & frv_interrupt_table[kind];
   1285       1.1  christos       if (interrupt->iclass <= high_class)
   1286       1.1  christos 	break;
   1287       1.1  christos     }
   1288       1.1  christos 
   1289       1.1  christos   /* Shuffle the remaining high priority interrupts down into the empty space
   1290       1.1  christos      left by the deleted interrupts.  */
   1291       1.1  christos   if (j >= i)
   1292       1.1  christos     {
   1293       1.1  christos       for (++j; j < limit; ++j)
   1294       1.1  christos 	frv_interrupt_state.queue[i++] = frv_interrupt_state.queue[j];
   1295       1.1  christos       frv_interrupt_state.queue_index -= (j - i);
   1296       1.1  christos     }
   1297       1.1  christos }
   1298       1.1  christos 
   1299       1.1  christos /* Save data written to memory into the interrupt state so that it can be
   1300       1.1  christos    copied to the appropriate EDR register, if necessary, in the event of an
   1301       1.1  christos    interrupt.  */
   1302       1.1  christos void
   1303       1.1  christos frv_save_data_written_for_interrupts (
   1304       1.1  christos   SIM_CPU *current_cpu, CGEN_WRITE_QUEUE_ELEMENT *item
   1305       1.1  christos )
   1306       1.1  christos {
   1307       1.1  christos   /* Record the slot containing the insn doing the write in the
   1308       1.1  christos      interrupt state.  */
   1309       1.1  christos   frv_interrupt_state.slot = CGEN_WRITE_QUEUE_ELEMENT_PIPE (item);
   1310       1.1  christos 
   1311       1.1  christos   /* Now record any data written to memory in the interrupt state.  */
   1312       1.1  christos   switch (CGEN_WRITE_QUEUE_ELEMENT_KIND (item))
   1313       1.1  christos     {
   1314       1.1  christos     case CGEN_BI_WRITE:
   1315       1.1  christos     case CGEN_QI_WRITE:
   1316       1.1  christos     case CGEN_SI_WRITE:
   1317       1.1  christos     case CGEN_SF_WRITE:
   1318       1.1  christos     case CGEN_PC_WRITE:
   1319       1.1  christos     case CGEN_FN_HI_WRITE:
   1320       1.1  christos     case CGEN_FN_SI_WRITE:
   1321       1.1  christos     case CGEN_FN_SF_WRITE:
   1322       1.1  christos     case CGEN_FN_DI_WRITE:
   1323       1.1  christos     case CGEN_FN_DF_WRITE:
   1324       1.1  christos     case CGEN_FN_XI_WRITE:
   1325       1.1  christos     case CGEN_FN_PC_WRITE:
   1326       1.1  christos       break; /* Ignore writes to registers.  */
   1327       1.1  christos     case CGEN_MEM_QI_WRITE:
   1328       1.1  christos       frv_interrupt_state.data_written.length = 1;
   1329       1.1  christos       frv_interrupt_state.data_written.words[0]
   1330       1.1  christos 	= item->kinds.mem_qi_write.value;
   1331       1.1  christos       break;
   1332       1.1  christos     case CGEN_MEM_HI_WRITE:
   1333       1.1  christos       frv_interrupt_state.data_written.length = 1;
   1334       1.1  christos       frv_interrupt_state.data_written.words[0]
   1335       1.1  christos 	= item->kinds.mem_hi_write.value;
   1336       1.1  christos       break;
   1337       1.1  christos     case CGEN_MEM_SI_WRITE:
   1338       1.1  christos       frv_interrupt_state.data_written.length = 1;
   1339       1.1  christos       frv_interrupt_state.data_written.words[0]
   1340       1.1  christos 	= item->kinds.mem_si_write.value;
   1341       1.1  christos       break;
   1342       1.1  christos     case CGEN_MEM_DI_WRITE:
   1343       1.1  christos       frv_interrupt_state.data_written.length = 2;
   1344       1.1  christos       frv_interrupt_state.data_written.words[0]
   1345       1.1  christos 	= item->kinds.mem_di_write.value >> 32;
   1346       1.1  christos       frv_interrupt_state.data_written.words[1]
   1347       1.1  christos 	= item->kinds.mem_di_write.value;
   1348       1.1  christos       break;
   1349       1.1  christos     case CGEN_MEM_DF_WRITE:
   1350       1.1  christos       frv_interrupt_state.data_written.length = 2;
   1351       1.1  christos       frv_interrupt_state.data_written.words[0]
   1352       1.1  christos 	= item->kinds.mem_df_write.value >> 32;
   1353       1.1  christos       frv_interrupt_state.data_written.words[1]
   1354       1.1  christos 	= item->kinds.mem_df_write.value;
   1355       1.1  christos       break;
   1356       1.1  christos     case CGEN_MEM_XI_WRITE:
   1357       1.1  christos       frv_interrupt_state.data_written.length = 4;
   1358       1.1  christos       frv_interrupt_state.data_written.words[0]
   1359       1.1  christos 	= item->kinds.mem_xi_write.value[0];
   1360       1.1  christos       frv_interrupt_state.data_written.words[1]
   1361       1.1  christos 	= item->kinds.mem_xi_write.value[1];
   1362       1.1  christos       frv_interrupt_state.data_written.words[2]
   1363       1.1  christos 	= item->kinds.mem_xi_write.value[2];
   1364       1.1  christos       frv_interrupt_state.data_written.words[3]
   1365       1.1  christos 	= item->kinds.mem_xi_write.value[3];
   1366       1.1  christos       break;
   1367       1.1  christos     case CGEN_FN_MEM_QI_WRITE:
   1368       1.1  christos       frv_interrupt_state.data_written.length = 1;
   1369       1.1  christos       frv_interrupt_state.data_written.words[0]
   1370       1.1  christos 	= item->kinds.fn_mem_qi_write.value;
   1371       1.1  christos       break;
   1372       1.1  christos     case CGEN_FN_MEM_HI_WRITE:
   1373       1.1  christos       frv_interrupt_state.data_written.length = 1;
   1374       1.1  christos       frv_interrupt_state.data_written.words[0]
   1375       1.1  christos 	= item->kinds.fn_mem_hi_write.value;
   1376       1.1  christos       break;
   1377       1.1  christos     case CGEN_FN_MEM_SI_WRITE:
   1378       1.1  christos       frv_interrupt_state.data_written.length = 1;
   1379       1.1  christos       frv_interrupt_state.data_written.words[0]
   1380       1.1  christos 	= item->kinds.fn_mem_si_write.value;
   1381       1.1  christos       break;
   1382       1.1  christos     case CGEN_FN_MEM_DI_WRITE:
   1383       1.1  christos       frv_interrupt_state.data_written.length = 2;
   1384       1.1  christos       frv_interrupt_state.data_written.words[0]
   1385       1.1  christos 	= item->kinds.fn_mem_di_write.value >> 32;
   1386       1.1  christos       frv_interrupt_state.data_written.words[1]
   1387       1.1  christos 	= item->kinds.fn_mem_di_write.value;
   1388       1.1  christos       break;
   1389       1.1  christos     case CGEN_FN_MEM_DF_WRITE:
   1390       1.1  christos       frv_interrupt_state.data_written.length = 2;
   1391       1.1  christos       frv_interrupt_state.data_written.words[0]
   1392       1.1  christos 	= item->kinds.fn_mem_df_write.value >> 32;
   1393       1.1  christos       frv_interrupt_state.data_written.words[1]
   1394       1.1  christos 	= item->kinds.fn_mem_df_write.value;
   1395       1.1  christos       break;
   1396       1.1  christos     case CGEN_FN_MEM_XI_WRITE:
   1397       1.1  christos       frv_interrupt_state.data_written.length = 4;
   1398       1.1  christos       frv_interrupt_state.data_written.words[0]
   1399       1.1  christos 	= item->kinds.fn_mem_xi_write.value[0];
   1400       1.1  christos       frv_interrupt_state.data_written.words[1]
   1401       1.1  christos 	= item->kinds.fn_mem_xi_write.value[1];
   1402       1.1  christos       frv_interrupt_state.data_written.words[2]
   1403       1.1  christos 	= item->kinds.fn_mem_xi_write.value[2];
   1404       1.1  christos       frv_interrupt_state.data_written.words[3]
   1405       1.1  christos 	= item->kinds.fn_mem_xi_write.value[3];
   1406       1.1  christos       break;
   1407       1.1  christos     default:
   1408       1.1  christos       {
   1409       1.1  christos 	SIM_DESC sd = CPU_STATE (current_cpu);
   1410       1.1  christos 	IADDR pc = CPU_PC_GET (current_cpu);
   1411       1.1  christos 	sim_engine_abort (sd, current_cpu, pc,
   1412       1.1  christos 			  "unknown write kind during save for interrupt\n");
   1413       1.1  christos       }
   1414       1.1  christos       break;
   1415       1.1  christos     }
   1416       1.1  christos }
   1417