xref: /netbsd-src/external/gpl3/gdb/dist/sim/frv/interrupts.c (revision 854b025f2fdbc2b8be5b6915e0337cc556c8c54d)
14e98e3e1Schristos /* frv exception and interrupt support
2*854b025fSchristos    Copyright (C) 1999-2024 Free Software Foundation, Inc.
34e98e3e1Schristos    Contributed by Red Hat.
44e98e3e1Schristos 
54e98e3e1Schristos This file is part of the GNU simulators.
64e98e3e1Schristos 
74e98e3e1Schristos This program is free software; you can redistribute it and/or modify
84e98e3e1Schristos it under the terms of the GNU General Public License as published by
94e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or
104e98e3e1Schristos (at your option) any later version.
114e98e3e1Schristos 
124e98e3e1Schristos This program is distributed in the hope that it will be useful,
134e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
144e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
154e98e3e1Schristos GNU General Public License for more details.
164e98e3e1Schristos 
174e98e3e1Schristos You should have received a copy of the GNU General Public License
184e98e3e1Schristos along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
194e98e3e1Schristos 
204b169a6bSchristos /* This must come before any other includes.  */
214b169a6bSchristos #include "defs.h"
224b169a6bSchristos 
234e98e3e1Schristos #define WANT_CPU frvbf
244e98e3e1Schristos #define WANT_CPU_FRVBF
254e98e3e1Schristos 
264e98e3e1Schristos #include "sim-main.h"
274b169a6bSchristos #include "sim-signal.h"
284e98e3e1Schristos #include "bfd.h"
294b169a6bSchristos #include <stdlib.h>
304b169a6bSchristos #include "cgen-mem.h"
314e98e3e1Schristos 
324e98e3e1Schristos /* FR-V Interrupt table.
334e98e3e1Schristos    Describes the interrupts supported by the FR-V.
344e98e3e1Schristos    This table *must* be maintained in order of interrupt priority as defined by
354e98e3e1Schristos    frv_interrupt_kind.  */
364e98e3e1Schristos #define DEFERRED 1
374e98e3e1Schristos #define PRECISE  1
384e98e3e1Schristos #define ITABLE_ENTRY(name, class, deferral, precision, offset) \
394e98e3e1Schristos   {FRV_##name, FRV_EC_##name, class, deferral, precision, offset}
404e98e3e1Schristos 
414e98e3e1Schristos struct frv_interrupt frv_interrupt_table[NUM_FRV_INTERRUPT_KINDS] =
424e98e3e1Schristos {
434e98e3e1Schristos   /* External interrupts */
444e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_1,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x21),
454e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_2,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x22),
464e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_3,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x23),
474e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_4,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x24),
484e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_5,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x25),
494e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_6,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x26),
504e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_7,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x27),
514e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_8,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x28),
524e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_9,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x29),
534e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_10,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2a),
544e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_11,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2b),
554e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_12,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2c),
564e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_13,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2d),
574e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_14,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2e),
584e98e3e1Schristos   ITABLE_ENTRY(INTERRUPT_LEVEL_15,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2f),
594e98e3e1Schristos   /* Software interrupt */
604e98e3e1Schristos   ITABLE_ENTRY(TRAP_INSTRUCTION,             FRV_SOFTWARE_INTERRUPT, !DEFERRED, !PRECISE, 0x80),
614e98e3e1Schristos   /* Program interrupts */
624e98e3e1Schristos   ITABLE_ENTRY(COMMIT_EXCEPTION,             FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x19),
634e98e3e1Schristos   ITABLE_ENTRY(DIVISION_EXCEPTION,           FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x17),
644e98e3e1Schristos   ITABLE_ENTRY(DATA_STORE_ERROR,             FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x14),
654e98e3e1Schristos   ITABLE_ENTRY(DATA_ACCESS_EXCEPTION,        FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x13),
664e98e3e1Schristos   ITABLE_ENTRY(DATA_ACCESS_MMU_MISS,         FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x12),
674e98e3e1Schristos   ITABLE_ENTRY(DATA_ACCESS_ERROR,            FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x11),
684e98e3e1Schristos   ITABLE_ENTRY(MP_EXCEPTION,                 FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x0e),
694e98e3e1Schristos   ITABLE_ENTRY(FP_EXCEPTION,                 FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x0d),
704e98e3e1Schristos   ITABLE_ENTRY(MEM_ADDRESS_NOT_ALIGNED,      FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x10),
714e98e3e1Schristos   ITABLE_ENTRY(REGISTER_EXCEPTION,           FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x08),
724e98e3e1Schristos   ITABLE_ENTRY(MP_DISABLED,                  FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x0b),
734e98e3e1Schristos   ITABLE_ENTRY(FP_DISABLED,                  FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x0a),
744e98e3e1Schristos   ITABLE_ENTRY(PRIVILEGED_INSTRUCTION,       FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x06),
754e98e3e1Schristos   ITABLE_ENTRY(ILLEGAL_INSTRUCTION,          FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x07),
764e98e3e1Schristos   ITABLE_ENTRY(INSTRUCTION_ACCESS_EXCEPTION, FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x03),
774e98e3e1Schristos   ITABLE_ENTRY(INSTRUCTION_ACCESS_ERROR,     FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x02),
784e98e3e1Schristos   ITABLE_ENTRY(INSTRUCTION_ACCESS_MMU_MISS,  FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x01),
794e98e3e1Schristos   ITABLE_ENTRY(COMPOUND_EXCEPTION,           FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x20),
804e98e3e1Schristos   /* Break interrupt */
814e98e3e1Schristos   ITABLE_ENTRY(BREAK_EXCEPTION,              FRV_BREAK_INTERRUPT,    !DEFERRED, !PRECISE, 0xff),
824e98e3e1Schristos   /* Reset interrupt */
834e98e3e1Schristos   ITABLE_ENTRY(RESET,                        FRV_RESET_INTERRUPT,    !DEFERRED, !PRECISE, 0x00)
844e98e3e1Schristos };
854e98e3e1Schristos 
864e98e3e1Schristos /* The current interrupt state.  */
874e98e3e1Schristos struct frv_interrupt_state frv_interrupt_state;
884e98e3e1Schristos 
894e98e3e1Schristos /* maintain the address of the start of the previous VLIW insn sequence.  */
904e98e3e1Schristos IADDR previous_vliw_pc;
914e98e3e1Schristos 
924e98e3e1Schristos /* Add a break interrupt to the interrupt queue.  */
934e98e3e1Schristos struct frv_interrupt_queue_element *
944e98e3e1Schristos frv_queue_break_interrupt (SIM_CPU *current_cpu)
954e98e3e1Schristos {
964e98e3e1Schristos   return frv_queue_interrupt (current_cpu, FRV_BREAK_EXCEPTION);
974e98e3e1Schristos }
984e98e3e1Schristos 
994e98e3e1Schristos /* Add a software interrupt to the interrupt queue.  */
1004e98e3e1Schristos struct frv_interrupt_queue_element *
1014e98e3e1Schristos frv_queue_software_interrupt (SIM_CPU *current_cpu, SI offset)
1024e98e3e1Schristos {
1034e98e3e1Schristos   struct frv_interrupt_queue_element *new_element
1044e98e3e1Schristos     = frv_queue_interrupt (current_cpu, FRV_TRAP_INSTRUCTION);
1054e98e3e1Schristos 
1064e98e3e1Schristos   struct frv_interrupt *interrupt = & frv_interrupt_table[new_element->kind];
1074e98e3e1Schristos   interrupt->handler_offset = offset;
1084e98e3e1Schristos 
1094e98e3e1Schristos   return new_element;
1104e98e3e1Schristos }
1114e98e3e1Schristos 
1124e98e3e1Schristos /* Add a program interrupt to the interrupt queue.  */
1134e98e3e1Schristos struct frv_interrupt_queue_element *
1144e98e3e1Schristos frv_queue_program_interrupt (
1154e98e3e1Schristos   SIM_CPU *current_cpu, enum frv_interrupt_kind kind
1164e98e3e1Schristos )
1174e98e3e1Schristos {
1184e98e3e1Schristos   return frv_queue_interrupt (current_cpu, kind);
1194e98e3e1Schristos }
1204e98e3e1Schristos 
1214e98e3e1Schristos /* Add an external interrupt to the interrupt queue.  */
1224e98e3e1Schristos struct frv_interrupt_queue_element *
1234e98e3e1Schristos frv_queue_external_interrupt (
1244e98e3e1Schristos   SIM_CPU *current_cpu, enum frv_interrupt_kind kind
1254e98e3e1Schristos )
1264e98e3e1Schristos {
1274e98e3e1Schristos   if (! GET_H_PSR_ET ()
1284e98e3e1Schristos       || (kind != FRV_INTERRUPT_LEVEL_15 && kind < GET_H_PSR_PIL ()))
1294e98e3e1Schristos     return NULL; /* Leave it for later.  */
1304e98e3e1Schristos 
1314e98e3e1Schristos   return frv_queue_interrupt (current_cpu, kind);
1324e98e3e1Schristos }
1334e98e3e1Schristos 
1344e98e3e1Schristos /* Add any interrupt to the interrupt queue. It will be added in reverse
1354e98e3e1Schristos    priority order.  This makes it easy to find the highest priority interrupt
1364e98e3e1Schristos    at the end of the queue and to remove it after processing.  */
1374e98e3e1Schristos struct frv_interrupt_queue_element *
1384e98e3e1Schristos frv_queue_interrupt (SIM_CPU *current_cpu, enum frv_interrupt_kind kind)
1394e98e3e1Schristos {
1404e98e3e1Schristos   int i;
1414e98e3e1Schristos   int j;
1424e98e3e1Schristos   int limit = frv_interrupt_state.queue_index;
1434e98e3e1Schristos   struct frv_interrupt_queue_element *new_element;
1444e98e3e1Schristos   enum frv_interrupt_class iclass;
1454e98e3e1Schristos 
1464e98e3e1Schristos   if (limit >= FRV_INTERRUPT_QUEUE_SIZE)
1474e98e3e1Schristos     abort (); /* TODO: Make the queue dynamic */
1484e98e3e1Schristos 
1494e98e3e1Schristos   /* Find the right place in the queue.  */
1504e98e3e1Schristos   for (i = 0; i < limit; ++i)
1514e98e3e1Schristos     {
1524e98e3e1Schristos       if (frv_interrupt_state.queue[i].kind >= kind)
1534e98e3e1Schristos 	break;
1544e98e3e1Schristos     }
1554e98e3e1Schristos 
1564e98e3e1Schristos   /* Don't queue two external interrupts of the same priority.  */
1574e98e3e1Schristos   iclass = frv_interrupt_table[kind].iclass;
1584e98e3e1Schristos   if (i < limit && iclass == FRV_EXTERNAL_INTERRUPT)
1594e98e3e1Schristos     {
1604e98e3e1Schristos       if (frv_interrupt_state.queue[i].kind == kind)
1614e98e3e1Schristos 	return & frv_interrupt_state.queue[i];
1624e98e3e1Schristos     }
1634e98e3e1Schristos 
1644e98e3e1Schristos   /* Make room for the new interrupt in this spot.  */
1654e98e3e1Schristos   for (j = limit - 1; j >= i; --j)
1664e98e3e1Schristos     frv_interrupt_state.queue[j + 1] = frv_interrupt_state.queue[j];
1674e98e3e1Schristos 
1684e98e3e1Schristos   /* Add the new interrupt.  */
1694e98e3e1Schristos   frv_interrupt_state.queue_index++;
1704e98e3e1Schristos   new_element = & frv_interrupt_state.queue[i];
1714e98e3e1Schristos   new_element->kind = kind;
1724e98e3e1Schristos   new_element->vpc = CPU_PC_GET (current_cpu);
1734e98e3e1Schristos   new_element->u.data_written.length = 0;
1744e98e3e1Schristos   frv_set_interrupt_queue_slot (current_cpu, new_element);
1754e98e3e1Schristos 
1764e98e3e1Schristos   return new_element;
1774e98e3e1Schristos }
1784e98e3e1Schristos 
1794e98e3e1Schristos struct frv_interrupt_queue_element *
1804e98e3e1Schristos frv_queue_register_exception_interrupt (SIM_CPU *current_cpu, enum frv_rec rec)
1814e98e3e1Schristos {
1824e98e3e1Schristos   struct frv_interrupt_queue_element *new_element =
1834e98e3e1Schristos     frv_queue_program_interrupt (current_cpu, FRV_REGISTER_EXCEPTION);
1844e98e3e1Schristos 
1854e98e3e1Schristos   new_element->u.rec = rec;
1864e98e3e1Schristos 
1874e98e3e1Schristos   return new_element;
1884e98e3e1Schristos }
1894e98e3e1Schristos 
1904e98e3e1Schristos struct frv_interrupt_queue_element *
1914e98e3e1Schristos frv_queue_mem_address_not_aligned_interrupt (SIM_CPU *current_cpu, USI addr)
1924e98e3e1Schristos {
1934e98e3e1Schristos   struct frv_interrupt_queue_element *new_element;
1944e98e3e1Schristos   USI isr = GET_ISR ();
1954e98e3e1Schristos 
1964e98e3e1Schristos   /* Make sure that this exception is not masked.  */
1974e98e3e1Schristos   if (GET_ISR_EMAM (isr))
1984e98e3e1Schristos     return NULL;
1994e98e3e1Schristos 
2004e98e3e1Schristos   /* Queue the interrupt.  */
2014e98e3e1Schristos   new_element = frv_queue_program_interrupt (current_cpu,
2024e98e3e1Schristos 					     FRV_MEM_ADDRESS_NOT_ALIGNED);
2034e98e3e1Schristos   new_element->eaddress = addr;
2044e98e3e1Schristos   new_element->u.data_written = frv_interrupt_state.data_written;
2054e98e3e1Schristos   frv_interrupt_state.data_written.length = 0;
2064e98e3e1Schristos 
2074e98e3e1Schristos   return new_element;
2084e98e3e1Schristos }
2094e98e3e1Schristos 
2104e98e3e1Schristos struct frv_interrupt_queue_element *
2114e98e3e1Schristos frv_queue_data_access_error_interrupt (SIM_CPU *current_cpu, USI addr)
2124e98e3e1Schristos {
2134e98e3e1Schristos   struct frv_interrupt_queue_element *new_element;
2144e98e3e1Schristos   new_element = frv_queue_program_interrupt (current_cpu,
2154e98e3e1Schristos 					     FRV_DATA_ACCESS_ERROR);
2164e98e3e1Schristos   new_element->eaddress = addr;
2174e98e3e1Schristos   return new_element;
2184e98e3e1Schristos }
2194e98e3e1Schristos 
2204e98e3e1Schristos struct frv_interrupt_queue_element *
2214e98e3e1Schristos frv_queue_data_access_exception_interrupt (SIM_CPU *current_cpu)
2224e98e3e1Schristos {
2234e98e3e1Schristos   return frv_queue_program_interrupt (current_cpu, FRV_DATA_ACCESS_EXCEPTION);
2244e98e3e1Schristos }
2254e98e3e1Schristos 
2264e98e3e1Schristos struct frv_interrupt_queue_element *
2274e98e3e1Schristos frv_queue_instruction_access_error_interrupt (SIM_CPU *current_cpu)
2284e98e3e1Schristos {
2294e98e3e1Schristos   return frv_queue_program_interrupt (current_cpu, FRV_INSTRUCTION_ACCESS_ERROR);
2304e98e3e1Schristos }
2314e98e3e1Schristos 
2324e98e3e1Schristos struct frv_interrupt_queue_element *
2334e98e3e1Schristos frv_queue_instruction_access_exception_interrupt (SIM_CPU *current_cpu)
2344e98e3e1Schristos {
2354e98e3e1Schristos   return frv_queue_program_interrupt (current_cpu, FRV_INSTRUCTION_ACCESS_EXCEPTION);
2364e98e3e1Schristos }
2374e98e3e1Schristos 
2384e98e3e1Schristos struct frv_interrupt_queue_element *
2394e98e3e1Schristos frv_queue_illegal_instruction_interrupt (
2404e98e3e1Schristos   SIM_CPU *current_cpu, const CGEN_INSN *insn
2414e98e3e1Schristos )
2424e98e3e1Schristos {
2434e98e3e1Schristos   SIM_DESC sd = CPU_STATE (current_cpu);
2444e98e3e1Schristos   switch (STATE_ARCHITECTURE (sd)->mach)
2454e98e3e1Schristos     {
2464e98e3e1Schristos     case bfd_mach_fr400:
2474e98e3e1Schristos     case bfd_mach_fr450:
2484e98e3e1Schristos     case bfd_mach_fr550:
2494e98e3e1Schristos       break;
2504e98e3e1Schristos     default:
2514e98e3e1Schristos       /* Some machines generate fp_exception for this case.  */
2524e98e3e1Schristos       if (frv_is_float_insn (insn) || frv_is_media_insn (insn))
2534e98e3e1Schristos 	{
2544e98e3e1Schristos 	  struct frv_fp_exception_info fp_info = {
2554e98e3e1Schristos 	    FSR_NO_EXCEPTION, FTT_SEQUENCE_ERROR
2564e98e3e1Schristos 	  };
2574e98e3e1Schristos 	  return frv_queue_fp_exception_interrupt (current_cpu, & fp_info);
2584e98e3e1Schristos 	}
2594e98e3e1Schristos       break;
2604e98e3e1Schristos     }
2614e98e3e1Schristos 
2624e98e3e1Schristos   return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
2634e98e3e1Schristos }
2644e98e3e1Schristos 
2654e98e3e1Schristos struct frv_interrupt_queue_element *
2664e98e3e1Schristos frv_queue_privileged_instruction_interrupt (SIM_CPU *current_cpu, const CGEN_INSN *insn)
2674e98e3e1Schristos {
2684e98e3e1Schristos   /* The fr550 has no privileged instruction interrupt. It uses
2694e98e3e1Schristos      illegal_instruction.  */
2704e98e3e1Schristos   SIM_DESC sd = CPU_STATE (current_cpu);
2714e98e3e1Schristos   if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
2724e98e3e1Schristos     return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
2734e98e3e1Schristos 
2744e98e3e1Schristos   return frv_queue_program_interrupt (current_cpu, FRV_PRIVILEGED_INSTRUCTION);
2754e98e3e1Schristos }
2764e98e3e1Schristos 
2774e98e3e1Schristos struct frv_interrupt_queue_element *
2784e98e3e1Schristos frv_queue_float_disabled_interrupt (SIM_CPU *current_cpu)
2794e98e3e1Schristos {
2804e98e3e1Schristos   /* The fr550 has no fp_disabled interrupt. It uses illegal_instruction.  */
2814e98e3e1Schristos   SIM_DESC sd = CPU_STATE (current_cpu);
2824e98e3e1Schristos   if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
2834e98e3e1Schristos     return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
2844e98e3e1Schristos 
2854e98e3e1Schristos   return frv_queue_program_interrupt (current_cpu, FRV_FP_DISABLED);
2864e98e3e1Schristos }
2874e98e3e1Schristos 
2884e98e3e1Schristos struct frv_interrupt_queue_element *
2894e98e3e1Schristos frv_queue_media_disabled_interrupt (SIM_CPU *current_cpu)
2904e98e3e1Schristos {
2914e98e3e1Schristos   /* The fr550 has no mp_disabled interrupt. It uses illegal_instruction.  */
2924e98e3e1Schristos   SIM_DESC sd = CPU_STATE (current_cpu);
2934e98e3e1Schristos   if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
2944e98e3e1Schristos     return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
2954e98e3e1Schristos 
2964e98e3e1Schristos   return frv_queue_program_interrupt (current_cpu, FRV_MP_DISABLED);
2974e98e3e1Schristos }
2984e98e3e1Schristos 
2994e98e3e1Schristos struct frv_interrupt_queue_element *
3004e98e3e1Schristos frv_queue_non_implemented_instruction_interrupt (
3014e98e3e1Schristos   SIM_CPU *current_cpu, const CGEN_INSN *insn
3024e98e3e1Schristos )
3034e98e3e1Schristos {
3044e98e3e1Schristos   SIM_DESC sd = CPU_STATE (current_cpu);
3054e98e3e1Schristos   switch (STATE_ARCHITECTURE (sd)->mach)
3064e98e3e1Schristos     {
3074e98e3e1Schristos     case bfd_mach_fr400:
3084e98e3e1Schristos     case bfd_mach_fr450:
3094e98e3e1Schristos     case bfd_mach_fr550:
3104e98e3e1Schristos       break;
3114e98e3e1Schristos     default:
3124e98e3e1Schristos       /* Some machines generate fp_exception or mp_exception for this case.  */
3134e98e3e1Schristos       if (frv_is_float_insn (insn))
3144e98e3e1Schristos 	{
3154e98e3e1Schristos 	  struct frv_fp_exception_info fp_info = {
3164e98e3e1Schristos 	    FSR_NO_EXCEPTION, FTT_UNIMPLEMENTED_FPOP
3174e98e3e1Schristos 	  };
3184e98e3e1Schristos 	  return frv_queue_fp_exception_interrupt (current_cpu, & fp_info);
3194e98e3e1Schristos 	}
3204e98e3e1Schristos       if (frv_is_media_insn (insn))
3214e98e3e1Schristos 	{
3224e98e3e1Schristos 	  frv_set_mp_exception_registers (current_cpu, MTT_UNIMPLEMENTED_MPOP,
3234e98e3e1Schristos 					  0);
3244e98e3e1Schristos 	  return NULL; /* no interrupt queued at this time.  */
3254e98e3e1Schristos 	}
3264e98e3e1Schristos       break;
3274e98e3e1Schristos     }
3284e98e3e1Schristos 
3294e98e3e1Schristos   return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
3304e98e3e1Schristos }
3314e98e3e1Schristos 
3324e98e3e1Schristos /* Queue the given fp_exception interrupt. Also update fp_info by removing
3334e98e3e1Schristos    masked interrupts and updating the 'slot' flield.  */
3344e98e3e1Schristos struct frv_interrupt_queue_element *
3354e98e3e1Schristos frv_queue_fp_exception_interrupt (
3364e98e3e1Schristos   SIM_CPU *current_cpu, struct frv_fp_exception_info *fp_info
3374e98e3e1Schristos )
3384e98e3e1Schristos {
3394e98e3e1Schristos   SI fsr0 = GET_FSR (0);
3404e98e3e1Schristos   int tem = GET_FSR_TEM (fsr0);
3414e98e3e1Schristos   int aexc = GET_FSR_AEXC (fsr0);
3424e98e3e1Schristos   struct frv_interrupt_queue_element *new_element = NULL;
3434e98e3e1Schristos 
3444e98e3e1Schristos   /* Update AEXC with the interrupts that are masked.  */
3454e98e3e1Schristos   aexc |= fp_info->fsr_mask & ~tem;
3464e98e3e1Schristos   SET_FSR_AEXC (fsr0, aexc);
3474e98e3e1Schristos   SET_FSR (0, fsr0);
3484e98e3e1Schristos 
3494e98e3e1Schristos   /* update fsr_mask with the exceptions that are enabled.  */
3504e98e3e1Schristos   fp_info->fsr_mask &= tem;
3514e98e3e1Schristos 
3524e98e3e1Schristos   /* If there is an unmasked interrupt then queue it, unless
3534e98e3e1Schristos      this was a non-excepting insn, in which case simply set the NE
3544e98e3e1Schristos      status registers.  */
3554e98e3e1Schristos   if (frv_interrupt_state.ne_index != NE_NOFLAG
3564e98e3e1Schristos       && fp_info->fsr_mask != FSR_NO_EXCEPTION)
3574e98e3e1Schristos     {
3584e98e3e1Schristos       SET_NE_FLAG (frv_interrupt_state.f_ne_flags,
3594e98e3e1Schristos 		   frv_interrupt_state.ne_index);
3604e98e3e1Schristos       /* TODO -- Set NESR for chips which support it.  */
3614e98e3e1Schristos       new_element = NULL;
3624e98e3e1Schristos     }
3634e98e3e1Schristos   else if (fp_info->fsr_mask != FSR_NO_EXCEPTION
3644e98e3e1Schristos 	   || fp_info->ftt == FTT_UNIMPLEMENTED_FPOP
3654e98e3e1Schristos 	   || fp_info->ftt == FTT_SEQUENCE_ERROR
3664e98e3e1Schristos 	   || fp_info->ftt == FTT_INVALID_FR)
3674e98e3e1Schristos     {
3684e98e3e1Schristos       new_element = frv_queue_program_interrupt (current_cpu, FRV_FP_EXCEPTION);
3694e98e3e1Schristos       new_element->u.fp_info = *fp_info;
3704e98e3e1Schristos     }
3714e98e3e1Schristos 
3724e98e3e1Schristos   return new_element;
3734e98e3e1Schristos }
3744e98e3e1Schristos 
3754e98e3e1Schristos struct frv_interrupt_queue_element *
3764e98e3e1Schristos frv_queue_division_exception_interrupt (SIM_CPU *current_cpu, enum frv_dtt dtt)
3774e98e3e1Schristos {
3784e98e3e1Schristos   struct frv_interrupt_queue_element *new_element =
3794e98e3e1Schristos     frv_queue_program_interrupt (current_cpu, FRV_DIVISION_EXCEPTION);
3804e98e3e1Schristos 
3814e98e3e1Schristos   new_element->u.dtt = dtt;
3824e98e3e1Schristos 
3834e98e3e1Schristos   return new_element;
3844e98e3e1Schristos }
3854e98e3e1Schristos 
3864e98e3e1Schristos /* Check for interrupts caused by illegal insn access.  These conditions are
3874e98e3e1Schristos    checked in the order specified by the fr400 and fr500 LSI specs.  */
3884e98e3e1Schristos void
3894e98e3e1Schristos frv_detect_insn_access_interrupts (SIM_CPU *current_cpu, SCACHE *sc)
3904e98e3e1Schristos {
3914e98e3e1Schristos 
3924e98e3e1Schristos   const CGEN_INSN *insn = sc->argbuf.idesc->idata;
3934e98e3e1Schristos   FRV_VLIW *vliw = CPU_VLIW (current_cpu);
3944e98e3e1Schristos 
3954e98e3e1Schristos   /* Check for vliw constraints.  */
3964e98e3e1Schristos   if (vliw->constraint_violation)
3974e98e3e1Schristos     frv_queue_illegal_instruction_interrupt (current_cpu, insn);
3984e98e3e1Schristos   /* Check for non-excepting insns.  */
3994e98e3e1Schristos   else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_NON_EXCEPTING)
4004e98e3e1Schristos       && ! GET_H_PSR_NEM ())
4014e98e3e1Schristos     frv_queue_non_implemented_instruction_interrupt (current_cpu, insn);
4024e98e3e1Schristos   /* Check for conditional insns.  */
4034e98e3e1Schristos   else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONDITIONAL)
4044e98e3e1Schristos       && ! GET_H_PSR_CM ())
4054e98e3e1Schristos     frv_queue_non_implemented_instruction_interrupt (current_cpu, insn);
4064e98e3e1Schristos   /* Make sure floating point support is enabled.  */
4074e98e3e1Schristos   else if (! GET_H_PSR_EF ())
4084e98e3e1Schristos     {
4094e98e3e1Schristos       /* Generate fp_disabled if it is a floating point insn or if PSR.EM is
4104e98e3e1Schristos 	 off and the insns accesses a fp register.  */
4114e98e3e1Schristos       if (frv_is_float_insn (insn)
4124e98e3e1Schristos 	  || (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR_ACCESS)
4134e98e3e1Schristos 	      && ! GET_H_PSR_EM ()))
4144e98e3e1Schristos 	frv_queue_float_disabled_interrupt (current_cpu);
4154e98e3e1Schristos     }
4164e98e3e1Schristos   /* Make sure media support is enabled.  */
4174e98e3e1Schristos   else if (! GET_H_PSR_EM ())
4184e98e3e1Schristos     {
4194e98e3e1Schristos       /* Generate mp_disabled if it is a media insn.  */
4204e98e3e1Schristos       if (frv_is_media_insn (insn) || CGEN_INSN_NUM (insn) == FRV_INSN_MTRAP)
4214e98e3e1Schristos 	frv_queue_media_disabled_interrupt (current_cpu);
4224e98e3e1Schristos     }
4234e98e3e1Schristos   /* Check for privileged insns.  */
4244e98e3e1Schristos   else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_PRIVILEGED) &&
4254e98e3e1Schristos 	   ! GET_H_PSR_S ())
4264e98e3e1Schristos     frv_queue_privileged_instruction_interrupt (current_cpu, insn);
4274e98e3e1Schristos #if 0 /* disable for now until we find out how FSR0.QNE gets reset.  */
4284e98e3e1Schristos   else
4294e98e3e1Schristos     {
4304e98e3e1Schristos       /* Enter the halt state if FSR0.QNE is set and we are executing a
4314e98e3e1Schristos 	 floating point insn, a media insn or an insn which access a FR
4324e98e3e1Schristos 	 register.  */
433*854b025fSchristos       SIM_DESC sd = CPU_STATE (current_cpu);
4344e98e3e1Schristos       SI fsr0 = GET_FSR (0);
4354e98e3e1Schristos       if (GET_FSR_QNE (fsr0)
4364e98e3e1Schristos 	  && (frv_is_float_insn (insn) || frv_is_media_insn (insn)
4374e98e3e1Schristos 	      || CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR_ACCESS)))
4384e98e3e1Schristos 	{
4394e98e3e1Schristos 	  sim_engine_halt (sd, current_cpu, NULL, GET_H_PC (), sim_stopped,
4404e98e3e1Schristos 			   SIM_SIGINT);
4414e98e3e1Schristos 	}
4424e98e3e1Schristos     }
4434e98e3e1Schristos #endif
4444e98e3e1Schristos }
4454e98e3e1Schristos 
4464e98e3e1Schristos /* Record the current VLIW slot in the given interrupt queue element.  */
4474e98e3e1Schristos void
4484e98e3e1Schristos frv_set_interrupt_queue_slot (
4494e98e3e1Schristos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
4504e98e3e1Schristos )
4514e98e3e1Schristos {
4524e98e3e1Schristos   FRV_VLIW *vliw = CPU_VLIW (current_cpu);
4534e98e3e1Schristos   int slot = vliw->next_slot - 1;
4544e98e3e1Schristos   item->slot = (*vliw->current_vliw)[slot];
4554e98e3e1Schristos }
4564e98e3e1Schristos 
4574e98e3e1Schristos /* Handle an individual interrupt.  */
4584e98e3e1Schristos static void
4594e98e3e1Schristos handle_interrupt (SIM_CPU *current_cpu, IADDR pc)
4604e98e3e1Schristos {
4614e98e3e1Schristos   struct frv_interrupt *interrupt;
4624e98e3e1Schristos   int writeback_done = 0;
4634e98e3e1Schristos   while (1)
4644e98e3e1Schristos     {
4654e98e3e1Schristos       /* Interrupts are queued in priority order with the highest priority
4664e98e3e1Schristos 	 last.  */
4674e98e3e1Schristos       int index = frv_interrupt_state.queue_index - 1;
4684e98e3e1Schristos       struct frv_interrupt_queue_element *item
4694e98e3e1Schristos 	= & frv_interrupt_state.queue[index];
4704e98e3e1Schristos       interrupt = & frv_interrupt_table[item->kind];
4714e98e3e1Schristos 
4724e98e3e1Schristos       switch (interrupt->iclass)
4734e98e3e1Schristos 	{
4744e98e3e1Schristos 	case FRV_EXTERNAL_INTERRUPT:
4754e98e3e1Schristos 	  /* Perform writeback first. This may cause a higher priority
4764e98e3e1Schristos 	     interrupt.  */
4774e98e3e1Schristos 	  if (! writeback_done)
4784e98e3e1Schristos 	    {
4794e98e3e1Schristos 	      frvbf_perform_writeback (current_cpu);
4804e98e3e1Schristos 	      writeback_done = 1;
4814e98e3e1Schristos 	      continue;
4824e98e3e1Schristos 	    }
4834e98e3e1Schristos 	  frv_external_interrupt (current_cpu, item, pc);
4844e98e3e1Schristos 	  return;
4854e98e3e1Schristos 	case FRV_SOFTWARE_INTERRUPT:
4864e98e3e1Schristos 	  frv_interrupt_state.queue_index = index;
4874e98e3e1Schristos 	  frv_software_interrupt (current_cpu, item, pc);
4884e98e3e1Schristos 	  return;
4894e98e3e1Schristos 	case FRV_PROGRAM_INTERRUPT:
4904e98e3e1Schristos 	  /* If the program interrupt is not strict (imprecise), then perform
4914e98e3e1Schristos 	     writeback first. This may, in turn, cause a higher priority
4924e98e3e1Schristos 	     interrupt.  */
4934e98e3e1Schristos 	  if (! interrupt->precise && ! writeback_done)
4944e98e3e1Schristos 	    {
4954e98e3e1Schristos 	      frv_interrupt_state.imprecise_interrupt = item;
4964e98e3e1Schristos 	      frvbf_perform_writeback (current_cpu);
4974e98e3e1Schristos 	      writeback_done = 1;
4984e98e3e1Schristos 	      continue;
4994e98e3e1Schristos 	    }
5004e98e3e1Schristos 	  frv_interrupt_state.queue_index = index;
5014e98e3e1Schristos 	  frv_program_interrupt (current_cpu, item, pc);
5024e98e3e1Schristos 	  return;
5034e98e3e1Schristos 	case FRV_BREAK_INTERRUPT:
5044e98e3e1Schristos 	  frv_interrupt_state.queue_index = index;
5054e98e3e1Schristos 	  frv_break_interrupt (current_cpu, interrupt, pc);
5064e98e3e1Schristos 	  return;
5074e98e3e1Schristos 	case FRV_RESET_INTERRUPT:
5084e98e3e1Schristos 	  break;
5094e98e3e1Schristos 	default:
5104e98e3e1Schristos 	  break;
5114e98e3e1Schristos 	}
5124e98e3e1Schristos       frv_interrupt_state.queue_index = index;
5134e98e3e1Schristos       break; /* out of loop.  */
5144e98e3e1Schristos     }
5154e98e3e1Schristos 
5164e98e3e1Schristos   /* We should never get here.  */
5174e98e3e1Schristos   {
5184e98e3e1Schristos     SIM_DESC sd = CPU_STATE (current_cpu);
5194e98e3e1Schristos     sim_engine_abort (sd, current_cpu, pc,
5204e98e3e1Schristos 		      "interrupt class not supported %d\n",
5214e98e3e1Schristos 		      interrupt->iclass);
5224e98e3e1Schristos   }
5234e98e3e1Schristos }
5244e98e3e1Schristos 
5254e98e3e1Schristos /* Check to see the if the RSTR.HR or RSTR.SR bits have been set.  If so, handle
5264e98e3e1Schristos    the appropriate reset interrupt.  */
5274e98e3e1Schristos static int
5284e98e3e1Schristos check_reset (SIM_CPU *current_cpu, IADDR pc)
5294e98e3e1Schristos {
5304e98e3e1Schristos   int hsr0;
5314e98e3e1Schristos   int hr;
5324e98e3e1Schristos   int sr;
5334e98e3e1Schristos   SI rstr;
5344e98e3e1Schristos   FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
5354e98e3e1Schristos   IADDR address = RSTR_ADDRESS;
5364e98e3e1Schristos 
5374e98e3e1Schristos   /* We don't want this to show up in the cache statistics, so read the
5384e98e3e1Schristos      cache passively.  */
5394e98e3e1Schristos   if (! frv_cache_read_passive_SI (cache, address, & rstr))
5404e98e3e1Schristos     rstr = sim_core_read_unaligned_4 (current_cpu, pc, read_map, address);
5414e98e3e1Schristos 
5424e98e3e1Schristos   hr = GET_RSTR_HR (rstr);
5434e98e3e1Schristos   sr = GET_RSTR_SR (rstr);
5444e98e3e1Schristos 
5454e98e3e1Schristos   if (! hr && ! sr)
5464e98e3e1Schristos     return 0; /* no reset.  */
5474e98e3e1Schristos 
5484e98e3e1Schristos   /* Reinitialize the machine state.  */
5494e98e3e1Schristos   if (hr)
5504e98e3e1Schristos     frv_hardware_reset (current_cpu);
5514e98e3e1Schristos   else
5524e98e3e1Schristos     frv_software_reset (current_cpu);
5534e98e3e1Schristos 
5544e98e3e1Schristos   /* Branch to the reset address.  */
5554e98e3e1Schristos   hsr0 = GET_HSR0 ();
5564e98e3e1Schristos   if (GET_HSR0_SA (hsr0))
5574e98e3e1Schristos     SET_H_PC (0xff000000);
5584e98e3e1Schristos   else
5594e98e3e1Schristos     SET_H_PC (0);
5604e98e3e1Schristos 
5614e98e3e1Schristos   return 1; /* reset */
5624e98e3e1Schristos }
5634e98e3e1Schristos 
5644e98e3e1Schristos /* Process any pending interrupt(s) after a group of parallel insns.  */
5654e98e3e1Schristos void
5664e98e3e1Schristos frv_process_interrupts (SIM_CPU *current_cpu)
5674e98e3e1Schristos {
5684e98e3e1Schristos   SI NE_flags[2];
5694e98e3e1Schristos   /* Need to save the pc here because writeback may change it (due to a
5704e98e3e1Schristos      branch).  */
5714e98e3e1Schristos   IADDR pc = CPU_PC_GET (current_cpu);
5724e98e3e1Schristos 
5734e98e3e1Schristos   /* Check for a reset before anything else.  */
5744e98e3e1Schristos   if (check_reset (current_cpu, pc))
5754e98e3e1Schristos     return;
5764e98e3e1Schristos 
5774e98e3e1Schristos   /* First queue the writes for any accumulated NE flags.  */
5784e98e3e1Schristos   if (frv_interrupt_state.f_ne_flags[0] != 0
5794e98e3e1Schristos       || frv_interrupt_state.f_ne_flags[1] != 0)
5804e98e3e1Schristos     {
5814e98e3e1Schristos       GET_NE_FLAGS (NE_flags, H_SPR_FNER0);
5824e98e3e1Schristos       NE_flags[0] |= frv_interrupt_state.f_ne_flags[0];
5834e98e3e1Schristos       NE_flags[1] |= frv_interrupt_state.f_ne_flags[1];
5844e98e3e1Schristos       SET_NE_FLAGS (H_SPR_FNER0, NE_flags);
5854e98e3e1Schristos     }
5864e98e3e1Schristos 
5874e98e3e1Schristos   /* If there is no interrupt pending, then perform parallel writeback.  This
5884e98e3e1Schristos      may cause an interrupt.  */
5894e98e3e1Schristos   if (frv_interrupt_state.queue_index <= 0)
5904e98e3e1Schristos     frvbf_perform_writeback (current_cpu);
5914e98e3e1Schristos 
5924e98e3e1Schristos   /* If there is an interrupt pending, then process it.  */
5934e98e3e1Schristos   if (frv_interrupt_state.queue_index > 0)
5944e98e3e1Schristos     handle_interrupt (current_cpu, pc);
5954e98e3e1Schristos }
5964e98e3e1Schristos 
5974e98e3e1Schristos /* Find the next available ESR and return its index */
5984e98e3e1Schristos static int
5994e98e3e1Schristos esr_for_data_access_exception (
6004e98e3e1Schristos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
6014e98e3e1Schristos )
6024e98e3e1Schristos {
6034e98e3e1Schristos   SIM_DESC sd = CPU_STATE (current_cpu);
6044e98e3e1Schristos   if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
6054e98e3e1Schristos     return 8; /* Use ESR8, EPCR8.  */
6064e98e3e1Schristos 
6074e98e3e1Schristos   if (item->slot == UNIT_I0)
6084e98e3e1Schristos     return 8; /* Use ESR8, EPCR8, EAR8, EDR8.  */
6094e98e3e1Schristos 
6104e98e3e1Schristos   return 9; /* Use ESR9, EPCR9, EAR9.  */
6114e98e3e1Schristos }
6124e98e3e1Schristos 
6134e98e3e1Schristos /* Set the next available EDR register with the data which was to be stored
6144e98e3e1Schristos    and return the index of the register.  */
6154e98e3e1Schristos static int
6164e98e3e1Schristos set_edr_register (
6174e98e3e1Schristos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, int edr_index
6184e98e3e1Schristos )
6194e98e3e1Schristos {
6204e98e3e1Schristos   /* EDR0, EDR4 and EDR8 are available as blocks of 4.
6214e98e3e1Schristos        SI data uses EDR3, EDR7 and EDR11
6224e98e3e1Schristos        DI data uses EDR2, EDR6 and EDR10
6234e98e3e1Schristos        XI data uses EDR0, EDR4 and EDR8.  */
6244e98e3e1Schristos   int i;
6254e98e3e1Schristos   edr_index += 4 - item->u.data_written.length;
6264e98e3e1Schristos   for (i = 0; i < item->u.data_written.length; ++i)
6274e98e3e1Schristos     SET_EDR (edr_index + i, item->u.data_written.words[i]);
6284e98e3e1Schristos 
6294e98e3e1Schristos   return edr_index;
6304e98e3e1Schristos };
6314e98e3e1Schristos 
6324e98e3e1Schristos /* Clear ESFR0, EPCRx, ESRx, EARx and EDRx.  */
6334e98e3e1Schristos static void
6344e98e3e1Schristos clear_exception_status_registers (SIM_CPU *current_cpu)
6354e98e3e1Schristos {
6364e98e3e1Schristos   int i;
6374e98e3e1Schristos   /* It is only necessary to clear the flag bits indicating which registers
6384e98e3e1Schristos      are valid.  */
6394e98e3e1Schristos   SET_ESFR (0, 0);
6404e98e3e1Schristos   SET_ESFR (1, 0);
6414e98e3e1Schristos 
6424e98e3e1Schristos   for (i = 0; i <= 2; ++i)
6434e98e3e1Schristos     {
6444e98e3e1Schristos       SI esr = GET_ESR (i);
6454e98e3e1Schristos       CLEAR_ESR_VALID (esr);
6464e98e3e1Schristos       SET_ESR (i, esr);
6474e98e3e1Schristos     }
6484e98e3e1Schristos   for (i = 8; i <= 15; ++i)
6494e98e3e1Schristos     {
6504e98e3e1Schristos       SI esr = GET_ESR (i);
6514e98e3e1Schristos       CLEAR_ESR_VALID (esr);
6524e98e3e1Schristos       SET_ESR (i, esr);
6534e98e3e1Schristos     }
6544e98e3e1Schristos }
6554e98e3e1Schristos 
6564e98e3e1Schristos /* Record state for media exception.  */
6574e98e3e1Schristos void
6584e98e3e1Schristos frv_set_mp_exception_registers (
6594e98e3e1Schristos   SIM_CPU *current_cpu, enum frv_msr_mtt mtt, int sie
6604e98e3e1Schristos )
6614e98e3e1Schristos {
6624e98e3e1Schristos   /* Record the interrupt factor in MSR0.  */
6634e98e3e1Schristos   SI msr0 = GET_MSR (0);
6644e98e3e1Schristos   if (GET_MSR_MTT (msr0) == MTT_NONE)
6654e98e3e1Schristos     SET_MSR_MTT (msr0, mtt);
6664e98e3e1Schristos 
6674e98e3e1Schristos   /* Also set the OVF bit in the appropriate MSR as well as MSR0.AOVF.  */
6684e98e3e1Schristos   if (mtt == MTT_OVERFLOW)
6694e98e3e1Schristos     {
6704e98e3e1Schristos       FRV_VLIW *vliw = CPU_VLIW (current_cpu);
6714e98e3e1Schristos       int slot = vliw->next_slot - 1;
6724e98e3e1Schristos       SIM_DESC sd = CPU_STATE (current_cpu);
6734e98e3e1Schristos 
6744e98e3e1Schristos       /* If this insn is in the M2 slot, then set MSR1.OVF and MSR1.SIE,
6754e98e3e1Schristos 	 otherwise set MSR0.OVF and MSR0.SIE.  */
6764e98e3e1Schristos       if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550 && (*vliw->current_vliw)[slot] == UNIT_FM1)
6774e98e3e1Schristos 	{
6784e98e3e1Schristos 	  SI msr = GET_MSR (1);
6794e98e3e1Schristos 	  OR_MSR_SIE (msr, sie);
6804e98e3e1Schristos 	  SET_MSR_OVF (msr);
6814e98e3e1Schristos 	  SET_MSR (1, msr);
6824e98e3e1Schristos 	}
6834e98e3e1Schristos       else
6844e98e3e1Schristos 	{
6854e98e3e1Schristos 	  OR_MSR_SIE (msr0, sie);
6864e98e3e1Schristos 	  SET_MSR_OVF (msr0);
6874e98e3e1Schristos 	}
6884e98e3e1Schristos 
6894e98e3e1Schristos       /* Generate the interrupt now if MSR0.MPEM is set on fr550 */
6904e98e3e1Schristos       if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550 && GET_MSR_MPEM (msr0))
6914e98e3e1Schristos 	frv_queue_program_interrupt (current_cpu, FRV_MP_EXCEPTION);
6924e98e3e1Schristos       else
6934e98e3e1Schristos 	{
6944e98e3e1Schristos 	  /* Regardless of the slot, set MSR0.AOVF.  */
6954e98e3e1Schristos 	  SET_MSR_AOVF (msr0);
6964e98e3e1Schristos 	}
6974e98e3e1Schristos     }
6984e98e3e1Schristos 
6994e98e3e1Schristos   SET_MSR (0, msr0);
7004e98e3e1Schristos }
7014e98e3e1Schristos 
7024e98e3e1Schristos /* Determine the correct FQ register to use for the given exception.
7034e98e3e1Schristos    Return -1 if a register is not available.  */
7044e98e3e1Schristos static int
7054e98e3e1Schristos fq_for_exception (
7064e98e3e1Schristos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
7074e98e3e1Schristos )
7084e98e3e1Schristos {
7094e98e3e1Schristos   SI fq;
7104e98e3e1Schristos   struct frv_fp_exception_info *fp_info = & item->u.fp_info;
7114e98e3e1Schristos 
7124e98e3e1Schristos   /* For fp_exception overflow, underflow or inexact, use FQ0 or FQ1.  */
7134e98e3e1Schristos   if (fp_info->ftt == FTT_IEEE_754_EXCEPTION
7144e98e3e1Schristos       && (fp_info->fsr_mask & (FSR_OVERFLOW | FSR_UNDERFLOW | FSR_INEXACT)))
7154e98e3e1Schristos     {
7164e98e3e1Schristos       fq = GET_FQ (0);
7174e98e3e1Schristos       if (! GET_FQ_VALID (fq))
7184e98e3e1Schristos 	return 0; /* FQ0 is available.  */
7194e98e3e1Schristos       fq = GET_FQ (1);
7204e98e3e1Schristos       if (! GET_FQ_VALID (fq))
7214e98e3e1Schristos 	return 1; /* FQ1 is available.  */
7224e98e3e1Schristos 
7234e98e3e1Schristos       /* No FQ register is available */
7244e98e3e1Schristos       {
7254e98e3e1Schristos 	SIM_DESC sd = CPU_STATE (current_cpu);
7264e98e3e1Schristos 	IADDR pc = CPU_PC_GET (current_cpu);
7274e98e3e1Schristos 	sim_engine_abort (sd, current_cpu, pc, "No FQ register available\n");
7284e98e3e1Schristos       }
7294e98e3e1Schristos       return -1;
7304e98e3e1Schristos     }
7314e98e3e1Schristos   /* For other exceptions, use FQ2 if the insn was in slot F0/I0 and FQ3
7324e98e3e1Schristos      otherwise.  */
7334e98e3e1Schristos   if (item->slot == UNIT_FM0 || item->slot == UNIT_I0)
7344e98e3e1Schristos     return 2;
7354e98e3e1Schristos 
7364e98e3e1Schristos   return 3;
7374e98e3e1Schristos }
7384e98e3e1Schristos 
7394e98e3e1Schristos /* Set FSR0, FQ0-FQ9, depending on the interrupt.  */
7404e98e3e1Schristos static void
7414e98e3e1Schristos set_fp_exception_registers (
7424e98e3e1Schristos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
7434e98e3e1Schristos )
7444e98e3e1Schristos {
7454e98e3e1Schristos   int fq_index;
7464e98e3e1Schristos   SI fq;
7474e98e3e1Schristos   SI insn;
7484e98e3e1Schristos   SI fsr0;
7494e98e3e1Schristos   IADDR pc;
7504e98e3e1Schristos   struct frv_fp_exception_info *fp_info;
7514e98e3e1Schristos   SIM_DESC sd = CPU_STATE (current_cpu);
7524e98e3e1Schristos 
7534e98e3e1Schristos   /* No FQ registers on fr550 */
7544e98e3e1Schristos   if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
7554e98e3e1Schristos     {
7564e98e3e1Schristos       /* Update the fsr.  */
7574e98e3e1Schristos       fp_info = & item->u.fp_info;
7584e98e3e1Schristos       fsr0 = GET_FSR (0);
7594e98e3e1Schristos       SET_FSR_FTT (fsr0, fp_info->ftt);
7604e98e3e1Schristos       SET_FSR (0, fsr0);
7614e98e3e1Schristos       return;
7624e98e3e1Schristos     }
7634e98e3e1Schristos 
7644e98e3e1Schristos   /* Select an FQ and update it with the exception information.  */
7654e98e3e1Schristos   fq_index = fq_for_exception (current_cpu, item);
7664e98e3e1Schristos   if (fq_index == -1)
7674e98e3e1Schristos     return;
7684e98e3e1Schristos 
7694e98e3e1Schristos   fp_info = & item->u.fp_info;
7704e98e3e1Schristos   fq = GET_FQ (fq_index);
7714e98e3e1Schristos   SET_FQ_MIV (fq, MIV_FLOAT);
7724e98e3e1Schristos   SET_FQ_SIE (fq, SIE_NIL);
7734e98e3e1Schristos   SET_FQ_FTT (fq, fp_info->ftt);
7744e98e3e1Schristos   SET_FQ_CEXC (fq, fp_info->fsr_mask);
7754e98e3e1Schristos   SET_FQ_VALID (fq);
7764e98e3e1Schristos   SET_FQ (fq_index, fq);
7774e98e3e1Schristos 
7784e98e3e1Schristos   /* Write the failing insn into FQx.OPC.  */
7794e98e3e1Schristos   pc = item->vpc;
7804e98e3e1Schristos   insn = GETMEMSI (current_cpu, pc, pc);
7814e98e3e1Schristos   SET_FQ_OPC (fq_index, insn);
7824e98e3e1Schristos 
7834e98e3e1Schristos   /* Update the fsr.  */
7844e98e3e1Schristos   fsr0 = GET_FSR (0);
7854e98e3e1Schristos   SET_FSR_QNE (fsr0); /* FQ not empty */
7864e98e3e1Schristos   SET_FSR_FTT (fsr0, fp_info->ftt);
7874e98e3e1Schristos   SET_FSR (0, fsr0);
7884e98e3e1Schristos }
7894e98e3e1Schristos 
7904e98e3e1Schristos /* Record the state of a division exception in the ISR.  */
7914e98e3e1Schristos static void
7924e98e3e1Schristos set_isr_exception_fields (
7934e98e3e1Schristos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
7944e98e3e1Schristos )
7954e98e3e1Schristos {
7964e98e3e1Schristos   USI isr = GET_ISR ();
7974e98e3e1Schristos   int dtt = GET_ISR_DTT (isr);
7984e98e3e1Schristos   dtt |= item->u.dtt;
7994e98e3e1Schristos   SET_ISR_DTT (isr, dtt);
8004e98e3e1Schristos   SET_ISR (isr);
8014e98e3e1Schristos }
8024e98e3e1Schristos 
8034e98e3e1Schristos /* Set ESFR0, EPCRx, ESRx, EARx and EDRx, according to the given program
8044e98e3e1Schristos    interrupt.  */
8054e98e3e1Schristos static void
8064e98e3e1Schristos set_exception_status_registers (
8074e98e3e1Schristos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
8084e98e3e1Schristos )
8094e98e3e1Schristos {
8104e98e3e1Schristos   struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind];
8114e98e3e1Schristos   int reg_index = -1;
8124e98e3e1Schristos   int set_ear = 0;
8134e98e3e1Schristos   int set_edr = 0;
8144e98e3e1Schristos   int set_daec = 0;
8154e98e3e1Schristos   int set_epcr = 0;
8164e98e3e1Schristos   SI esr = 0;
8174e98e3e1Schristos   SIM_DESC sd = CPU_STATE (current_cpu);
8184e98e3e1Schristos 
8194e98e3e1Schristos   /* If the interrupt is strict (precise) or the interrupt is on the insns
8204e98e3e1Schristos      in the I0 pipe, then set the 0 registers.  */
8214e98e3e1Schristos   if (interrupt->precise)
8224e98e3e1Schristos     {
8234e98e3e1Schristos       reg_index = 0;
8244e98e3e1Schristos       if (interrupt->kind == FRV_REGISTER_EXCEPTION)
8254e98e3e1Schristos 	SET_ESR_REC (esr, item->u.rec);
8264e98e3e1Schristos       else if (interrupt->kind == FRV_INSTRUCTION_ACCESS_EXCEPTION)
8274e98e3e1Schristos 	SET_ESR_IAEC (esr, item->u.iaec);
8284e98e3e1Schristos       /* For fr550, don't set epcr for precise interrupts.  */
8294e98e3e1Schristos       if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550)
8304e98e3e1Schristos 	set_epcr = 1;
8314e98e3e1Schristos     }
8324e98e3e1Schristos   else
8334e98e3e1Schristos     {
8344e98e3e1Schristos       switch (interrupt->kind)
8354e98e3e1Schristos 	{
8364e98e3e1Schristos 	case FRV_DIVISION_EXCEPTION:
8374e98e3e1Schristos 	  set_isr_exception_fields (current_cpu, item);
838*854b025fSchristos 	  ATTRIBUTE_FALLTHROUGH;  /* To set reg_index.  */
8394e98e3e1Schristos 	case FRV_COMMIT_EXCEPTION:
8404e98e3e1Schristos 	  /* For fr550, always use ESR0.  */
8414e98e3e1Schristos 	  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
8424e98e3e1Schristos 	    reg_index = 0;
8434e98e3e1Schristos 	  else if (item->slot == UNIT_I0)
8444e98e3e1Schristos 	    reg_index = 0;
8454e98e3e1Schristos 	  else if (item->slot == UNIT_I1)
8464e98e3e1Schristos 	    reg_index = 1;
8474e98e3e1Schristos 	  set_epcr = 1;
8484e98e3e1Schristos 	  break;
8494e98e3e1Schristos 	case FRV_DATA_STORE_ERROR:
8504e98e3e1Schristos 	  reg_index = 14; /* Use ESR14.  */
8514e98e3e1Schristos 	  break;
8524e98e3e1Schristos 	case FRV_DATA_ACCESS_ERROR:
8534e98e3e1Schristos 	  reg_index = 15; /* Use ESR15, EPCR15.  */
8544e98e3e1Schristos 	  set_ear = 1;
8554e98e3e1Schristos 	  break;
8564e98e3e1Schristos 	case FRV_DATA_ACCESS_EXCEPTION:
8574e98e3e1Schristos 	  set_daec = 1;
858*854b025fSchristos 	  ATTRIBUTE_FALLTHROUGH;
8594e98e3e1Schristos 	case FRV_DATA_ACCESS_MMU_MISS:
8604e98e3e1Schristos 	case FRV_MEM_ADDRESS_NOT_ALIGNED:
8614e98e3e1Schristos 	  /* Get the appropriate ESR, EPCR, EAR and EDR.
8624e98e3e1Schristos 	     EAR will be set. EDR will not be set if this is a store insn.  */
8634e98e3e1Schristos 	  set_ear = 1;
8644e98e3e1Schristos 	  /* For fr550, never use EDRx.  */
8654e98e3e1Schristos 	  if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550)
8664e98e3e1Schristos 	    if (item->u.data_written.length != 0)
8674e98e3e1Schristos 	      set_edr = 1;
8684e98e3e1Schristos 	  reg_index = esr_for_data_access_exception (current_cpu, item);
8694e98e3e1Schristos 	  set_epcr = 1;
8704e98e3e1Schristos 	  break;
8714e98e3e1Schristos 	case FRV_MP_EXCEPTION:
8724e98e3e1Schristos 	  /* For fr550, use EPCR2 and ESR2.  */
8734e98e3e1Schristos 	  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
8744e98e3e1Schristos 	    {
8754e98e3e1Schristos 	      reg_index = 2;
8764e98e3e1Schristos 	      set_epcr = 1;
8774e98e3e1Schristos 	    }
8784e98e3e1Schristos 	  break; /* MSR0-1, FQ0-9 are already set.  */
8794e98e3e1Schristos 	case FRV_FP_EXCEPTION:
8804e98e3e1Schristos 	  set_fp_exception_registers (current_cpu, item);
8814e98e3e1Schristos 	  /* For fr550, use EPCR2 and ESR2.  */
8824e98e3e1Schristos 	  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
8834e98e3e1Schristos 	    {
8844e98e3e1Schristos 	      reg_index = 2;
8854e98e3e1Schristos 	      set_epcr = 1;
8864e98e3e1Schristos 	    }
8874e98e3e1Schristos 	  break;
8884e98e3e1Schristos 	default:
8894e98e3e1Schristos 	  {
8904e98e3e1Schristos 	    IADDR pc = CPU_PC_GET (current_cpu);
8914e98e3e1Schristos 	    sim_engine_abort (sd, current_cpu, pc,
8924e98e3e1Schristos 			      "invalid non-strict program interrupt kind: %d\n",
8934e98e3e1Schristos 			      interrupt->kind);
8944e98e3e1Schristos 	    break;
8954e98e3e1Schristos 	  }
8964e98e3e1Schristos 	}
8974e98e3e1Schristos     } /* non-strict (imprecise) interrupt */
8984e98e3e1Schristos 
8994e98e3e1Schristos   /* Now fill in the selected exception status registers.  */
9004e98e3e1Schristos   if (reg_index != -1)
9014e98e3e1Schristos     {
9024e98e3e1Schristos       /* Now set the exception status registers.  */
9034e98e3e1Schristos       SET_ESFR_FLAG (reg_index);
9044e98e3e1Schristos       SET_ESR_EC (esr, interrupt->ec);
9054e98e3e1Schristos 
9064e98e3e1Schristos       if (set_epcr)
9074e98e3e1Schristos 	{
9084e98e3e1Schristos 	  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400)
9094e98e3e1Schristos 	    SET_EPCR (reg_index, previous_vliw_pc);
9104e98e3e1Schristos 	  else
9114e98e3e1Schristos 	    SET_EPCR (reg_index, item->vpc);
9124e98e3e1Schristos 	}
9134e98e3e1Schristos 
9144e98e3e1Schristos       if (set_ear)
9154e98e3e1Schristos 	{
9164e98e3e1Schristos 	  SET_EAR (reg_index, item->eaddress);
9174e98e3e1Schristos 	  SET_ESR_EAV (esr);
9184e98e3e1Schristos 	}
9194e98e3e1Schristos       else
9204e98e3e1Schristos 	CLEAR_ESR_EAV (esr);
9214e98e3e1Schristos 
9224e98e3e1Schristos       if (set_edr)
9234e98e3e1Schristos 	{
9244e98e3e1Schristos 	  int edn = set_edr_register (current_cpu, item, 0/* EDR0-3 */);
9254e98e3e1Schristos 	  SET_ESR_EDN (esr, edn);
9264e98e3e1Schristos 	  SET_ESR_EDV (esr);
9274e98e3e1Schristos 	}
9284e98e3e1Schristos       else
9294e98e3e1Schristos 	CLEAR_ESR_EDV (esr);
9304e98e3e1Schristos 
9314e98e3e1Schristos       if (set_daec)
9324e98e3e1Schristos 	SET_ESR_DAEC (esr, item->u.daec);
9334e98e3e1Schristos 
9344e98e3e1Schristos       SET_ESR_VALID (esr);
9354e98e3e1Schristos       SET_ESR (reg_index, esr);
9364e98e3e1Schristos     }
9374e98e3e1Schristos }
9384e98e3e1Schristos 
9394e98e3e1Schristos /* Check for compound interrupts.
9404e98e3e1Schristos    Returns NULL if no interrupt is to be processed.  */
9414e98e3e1Schristos static struct frv_interrupt *
9424e98e3e1Schristos check_for_compound_interrupt (
9434e98e3e1Schristos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
9444e98e3e1Schristos )
9454e98e3e1Schristos {
9464e98e3e1Schristos   struct frv_interrupt *interrupt;
9474e98e3e1Schristos 
9484e98e3e1Schristos   /* Set the exception status registers for the original interrupt.  */
9494e98e3e1Schristos   set_exception_status_registers (current_cpu, item);
9504e98e3e1Schristos   interrupt = & frv_interrupt_table[item->kind];
9514e98e3e1Schristos 
9524e98e3e1Schristos   if (! interrupt->precise)
9534e98e3e1Schristos     {
9544e98e3e1Schristos       IADDR vpc = 0;
9554e98e3e1Schristos       int mask = 0;
9564e98e3e1Schristos 
9574e98e3e1Schristos       vpc = item->vpc;
9584e98e3e1Schristos       mask = (1 << item->kind);
9594e98e3e1Schristos 
9604e98e3e1Schristos       /* Look for more queued program interrupts which are non-deferred
9614e98e3e1Schristos 	 (pending inhibit), imprecise (non-strict) different than an interrupt
9624e98e3e1Schristos 	 already found and caused by a different insn.  A bit mask is used
9634e98e3e1Schristos 	 to keep track of interrupts which have already been detected.  */
9644e98e3e1Schristos       while (item != frv_interrupt_state.queue)
9654e98e3e1Schristos 	{
9664e98e3e1Schristos 	  enum frv_interrupt_kind kind;
9674e98e3e1Schristos 	  struct frv_interrupt *next_interrupt;
9684e98e3e1Schristos 	  --item;
9694e98e3e1Schristos 	  kind = item->kind;
9704e98e3e1Schristos 	  next_interrupt = & frv_interrupt_table[kind];
9714e98e3e1Schristos 
9724e98e3e1Schristos 	  if (next_interrupt->iclass != FRV_PROGRAM_INTERRUPT)
9734e98e3e1Schristos 	    break; /* no program interrupts left.  */
9744e98e3e1Schristos 
9754e98e3e1Schristos 	  if (item->vpc == vpc)
9764e98e3e1Schristos 	    continue; /* caused by the same insn.  */
9774e98e3e1Schristos 
9784e98e3e1Schristos 	  vpc = item->vpc;
9794e98e3e1Schristos 	  if (! next_interrupt->precise && ! next_interrupt->deferred)
9804e98e3e1Schristos 	    {
9814e98e3e1Schristos 	      if (! (mask & (1 << kind)))
9824e98e3e1Schristos 		{
9834e98e3e1Schristos 		  /* Set the exception status registers for the additional
9844e98e3e1Schristos 		     interrupt.  */
9854e98e3e1Schristos 		  set_exception_status_registers (current_cpu, item);
9864e98e3e1Schristos 		  mask |= (1 << kind);
9874e98e3e1Schristos 		  interrupt = & frv_interrupt_table[FRV_COMPOUND_EXCEPTION];
9884e98e3e1Schristos 		}
9894e98e3e1Schristos 	    }
9904e98e3e1Schristos 	}
9914e98e3e1Schristos     }
9924e98e3e1Schristos 
9934e98e3e1Schristos   /* Return with either the original interrupt, a compound_exception,
9944e98e3e1Schristos      or no exception.  */
9954e98e3e1Schristos   return interrupt;
9964e98e3e1Schristos }
9974e98e3e1Schristos 
9984e98e3e1Schristos /* Handle a program interrupt.  */
9994e98e3e1Schristos void
10004e98e3e1Schristos frv_program_interrupt (
10014e98e3e1Schristos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc
10024e98e3e1Schristos )
10034e98e3e1Schristos {
10044e98e3e1Schristos   struct frv_interrupt *interrupt;
10054e98e3e1Schristos 
10064e98e3e1Schristos   clear_exception_status_registers (current_cpu);
10074e98e3e1Schristos   /* If two or more non-deferred imprecise (non-strict) interrupts occur
10084e98e3e1Schristos      on two or more insns, then generate a compound_exception.  */
10094e98e3e1Schristos   interrupt = check_for_compound_interrupt (current_cpu, item);
10104e98e3e1Schristos   if (interrupt != NULL)
10114e98e3e1Schristos     {
10124e98e3e1Schristos       frv_program_or_software_interrupt (current_cpu, interrupt, pc);
10134e98e3e1Schristos       frv_clear_interrupt_classes (FRV_SOFTWARE_INTERRUPT,
10144e98e3e1Schristos 				   FRV_PROGRAM_INTERRUPT);
10154e98e3e1Schristos     }
10164e98e3e1Schristos }
10174e98e3e1Schristos 
10184e98e3e1Schristos /* Handle a software interrupt.  */
10194e98e3e1Schristos void
10204e98e3e1Schristos frv_software_interrupt (
10214e98e3e1Schristos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc
10224e98e3e1Schristos )
10234e98e3e1Schristos {
10244e98e3e1Schristos   struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind];
10254e98e3e1Schristos   frv_program_or_software_interrupt (current_cpu, interrupt, pc);
10264e98e3e1Schristos }
10274e98e3e1Schristos 
10284e98e3e1Schristos /* Handle a program interrupt or a software interrupt in non-operating mode.  */
10294e98e3e1Schristos void
10304e98e3e1Schristos frv_non_operating_interrupt (
10314e98e3e1Schristos   SIM_CPU *current_cpu, enum frv_interrupt_kind kind, IADDR pc
10324e98e3e1Schristos )
10334e98e3e1Schristos {
10344e98e3e1Schristos   SIM_DESC sd = CPU_STATE (current_cpu);
10354e98e3e1Schristos   switch (kind)
10364e98e3e1Schristos     {
10374e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_1:
10384e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_2:
10394e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_3:
10404e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_4:
10414e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_5:
10424e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_6:
10434e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_7:
10444e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_8:
10454e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_9:
10464e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_10:
10474e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_11:
10484e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_12:
10494e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_13:
10504e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_14:
10514e98e3e1Schristos     case FRV_INTERRUPT_LEVEL_15:
10524e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
10534e98e3e1Schristos 			"interrupt: external %d\n", kind + 1);
10544e98e3e1Schristos       break;
10554e98e3e1Schristos     case FRV_TRAP_INSTRUCTION:
10564e98e3e1Schristos       break; /* handle as in operating mode.  */
10574e98e3e1Schristos     case FRV_COMMIT_EXCEPTION:
10584e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
10594e98e3e1Schristos 			"interrupt: commit_exception\n");
10604e98e3e1Schristos       break;
10614e98e3e1Schristos     case FRV_DIVISION_EXCEPTION:
10624e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
10634e98e3e1Schristos 			"interrupt: division_exception\n");
10644e98e3e1Schristos       break;
10654e98e3e1Schristos     case FRV_DATA_STORE_ERROR:
10664e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
10674e98e3e1Schristos 			"interrupt: data_store_error\n");
10684e98e3e1Schristos       break;
10694e98e3e1Schristos     case FRV_DATA_ACCESS_EXCEPTION:
10704e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
10714e98e3e1Schristos 			"interrupt: data_access_exception\n");
10724e98e3e1Schristos       break;
10734e98e3e1Schristos     case FRV_DATA_ACCESS_MMU_MISS:
10744e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
10754e98e3e1Schristos 			"interrupt: data_access_mmu_miss\n");
10764e98e3e1Schristos       break;
10774e98e3e1Schristos     case FRV_DATA_ACCESS_ERROR:
10784e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
10794e98e3e1Schristos 			"interrupt: data_access_error\n");
10804e98e3e1Schristos       break;
10814e98e3e1Schristos     case FRV_MP_EXCEPTION:
10824e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
10834e98e3e1Schristos 			"interrupt: mp_exception\n");
10844e98e3e1Schristos       break;
10854e98e3e1Schristos     case FRV_FP_EXCEPTION:
10864e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
10874e98e3e1Schristos 			"interrupt: fp_exception\n");
10884e98e3e1Schristos       break;
10894e98e3e1Schristos     case FRV_MEM_ADDRESS_NOT_ALIGNED:
10904e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
10914e98e3e1Schristos 			"interrupt: mem_address_not_aligned\n");
10924e98e3e1Schristos       break;
10934e98e3e1Schristos     case FRV_REGISTER_EXCEPTION:
10944e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
10954e98e3e1Schristos 			"interrupt: register_exception\n");
10964e98e3e1Schristos       break;
10974e98e3e1Schristos     case FRV_MP_DISABLED:
10984e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
10994e98e3e1Schristos 			"interrupt: mp_disabled\n");
11004e98e3e1Schristos       break;
11014e98e3e1Schristos     case FRV_FP_DISABLED:
11024e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
11034e98e3e1Schristos 			"interrupt: fp_disabled\n");
11044e98e3e1Schristos       break;
11054e98e3e1Schristos     case FRV_PRIVILEGED_INSTRUCTION:
11064e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
11074e98e3e1Schristos 			"interrupt: privileged_instruction\n");
11084e98e3e1Schristos       break;
11094e98e3e1Schristos     case FRV_ILLEGAL_INSTRUCTION:
11104e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
11114e98e3e1Schristos 			"interrupt: illegal_instruction\n");
11124e98e3e1Schristos       break;
11134e98e3e1Schristos     case FRV_INSTRUCTION_ACCESS_EXCEPTION:
11144e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
11154e98e3e1Schristos 			"interrupt: instruction_access_exception\n");
11164e98e3e1Schristos       break;
11174e98e3e1Schristos     case FRV_INSTRUCTION_ACCESS_MMU_MISS:
11184e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
11194e98e3e1Schristos 			"interrupt: instruction_access_mmu_miss\n");
11204e98e3e1Schristos       break;
11214e98e3e1Schristos     case FRV_INSTRUCTION_ACCESS_ERROR:
11224e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
11234e98e3e1Schristos 			"interrupt: insn_access_error\n");
11244e98e3e1Schristos       break;
11254e98e3e1Schristos     case FRV_COMPOUND_EXCEPTION:
11264e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
11274e98e3e1Schristos 			"interrupt: compound_exception\n");
11284e98e3e1Schristos       break;
11294e98e3e1Schristos     case FRV_BREAK_EXCEPTION:
11304e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
11314e98e3e1Schristos 			"interrupt: break_exception\n");
11324e98e3e1Schristos       break;
11334e98e3e1Schristos     case FRV_RESET:
11344e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
11354e98e3e1Schristos 			"interrupt: reset\n");
11364e98e3e1Schristos       break;
11374e98e3e1Schristos     default:
11384e98e3e1Schristos       sim_engine_abort (sd, current_cpu, pc,
11394e98e3e1Schristos 			"unhandled interrupt kind: %d\n", kind);
11404e98e3e1Schristos       break;
11414e98e3e1Schristos     }
11424e98e3e1Schristos }
11434e98e3e1Schristos 
11444e98e3e1Schristos /* Handle a break interrupt.  */
11454e98e3e1Schristos void
11464e98e3e1Schristos frv_break_interrupt (
11474e98e3e1Schristos   SIM_CPU *current_cpu, struct frv_interrupt *interrupt, IADDR current_pc
11484e98e3e1Schristos )
11494e98e3e1Schristos {
11504e98e3e1Schristos   IADDR new_pc;
11514e98e3e1Schristos 
11524e98e3e1Schristos   /* BPCSR=PC
11534e98e3e1Schristos      BPSR.BS=PSR.S
11544e98e3e1Schristos      BPSR.BET=PSR.ET
11554e98e3e1Schristos      PSR.S=1
11564e98e3e1Schristos      PSR.ET=0
11574e98e3e1Schristos      TBR.TT=0xff
11584e98e3e1Schristos      PC=TBR
11594e98e3e1Schristos   */
11604e98e3e1Schristos   /* Must set PSR.S first to allow access to supervisor-only spr registers.  */
11614e98e3e1Schristos   SET_H_BPSR_BS (GET_H_PSR_S ());
11624e98e3e1Schristos   SET_H_BPSR_BET (GET_H_PSR_ET ());
11634e98e3e1Schristos   SET_H_PSR_S (1);
11644e98e3e1Schristos   SET_H_PSR_ET (0);
11654e98e3e1Schristos   /* Must set PSR.S first to allow access to supervisor-only spr registers.  */
11664e98e3e1Schristos   SET_H_SPR (H_SPR_BPCSR, current_pc);
11674e98e3e1Schristos 
11684e98e3e1Schristos   /* Set the new PC in the TBR.  */
11694e98e3e1Schristos   SET_H_TBR_TT (interrupt->handler_offset);
11704e98e3e1Schristos   new_pc = GET_H_SPR (H_SPR_TBR);
11714e98e3e1Schristos   SET_H_PC (new_pc);
11724e98e3e1Schristos 
11734e98e3e1Schristos   CPU_DEBUG_STATE (current_cpu) = 1;
11744e98e3e1Schristos }
11754e98e3e1Schristos 
11764e98e3e1Schristos /* Handle a program interrupt or a software interrupt.  */
11774e98e3e1Schristos void
11784e98e3e1Schristos frv_program_or_software_interrupt (
11794e98e3e1Schristos   SIM_CPU *current_cpu, struct frv_interrupt *interrupt, IADDR current_pc
11804e98e3e1Schristos )
11814e98e3e1Schristos {
11824e98e3e1Schristos   USI new_pc;
11834e98e3e1Schristos   int original_psr_et;
11844e98e3e1Schristos 
11854e98e3e1Schristos   /* PCSR=PC
11864e98e3e1Schristos      PSR.PS=PSR.S
11874e98e3e1Schristos      PSR.ET=0
11884e98e3e1Schristos      PSR.S=1
11894e98e3e1Schristos      if PSR.ESR==1
11904e98e3e1Schristos        SR0 through SR3=GR4 through GR7
11914e98e3e1Schristos        TBR.TT=interrupt handler offset
11924e98e3e1Schristos        PC=TBR
11934e98e3e1Schristos   */
11944e98e3e1Schristos   original_psr_et = GET_H_PSR_ET ();
11954e98e3e1Schristos 
11964e98e3e1Schristos   SET_H_PSR_PS (GET_H_PSR_S ());
11974e98e3e1Schristos   SET_H_PSR_ET (0);
11984e98e3e1Schristos   SET_H_PSR_S (1);
11994e98e3e1Schristos 
12004e98e3e1Schristos   /* Must set PSR.S first to allow access to supervisor-only spr registers.  */
12014e98e3e1Schristos   /* The PCSR depends on the precision of the interrupt.  */
12024e98e3e1Schristos   if (interrupt->precise)
12034e98e3e1Schristos     SET_H_SPR (H_SPR_PCSR, previous_vliw_pc);
12044e98e3e1Schristos   else
12054e98e3e1Schristos     SET_H_SPR (H_SPR_PCSR, current_pc);
12064e98e3e1Schristos 
12074e98e3e1Schristos   /* Set the new PC in the TBR.  */
12084e98e3e1Schristos   SET_H_TBR_TT (interrupt->handler_offset);
12094e98e3e1Schristos   new_pc = GET_H_SPR (H_SPR_TBR);
12104e98e3e1Schristos   SET_H_PC (new_pc);
12114e98e3e1Schristos 
12124e98e3e1Schristos   /* If PSR.ET was not originally set, then enter the stopped state.  */
12134e98e3e1Schristos   if (! original_psr_et)
12144e98e3e1Schristos     {
12154e98e3e1Schristos       SIM_DESC sd = CPU_STATE (current_cpu);
12164e98e3e1Schristos       frv_non_operating_interrupt (current_cpu, interrupt->kind, current_pc);
12174e98e3e1Schristos       sim_engine_halt (sd, current_cpu, NULL, new_pc, sim_stopped, SIM_SIGINT);
12184e98e3e1Schristos     }
12194e98e3e1Schristos }
12204e98e3e1Schristos 
12214e98e3e1Schristos /* Handle a program interrupt or a software interrupt.  */
12224e98e3e1Schristos void
12234e98e3e1Schristos frv_external_interrupt (
12244e98e3e1Schristos   SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc
12254e98e3e1Schristos )
12264e98e3e1Schristos {
12274e98e3e1Schristos   USI new_pc;
12284e98e3e1Schristos   struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind];
12294e98e3e1Schristos 
12304e98e3e1Schristos   /* Don't process the interrupt if PSR.ET is not set or if it is masked.
12314e98e3e1Schristos      Interrupt 15 is processed even if it appears to be masked.  */
12324e98e3e1Schristos   if (! GET_H_PSR_ET ()
12334e98e3e1Schristos       || (interrupt->kind != FRV_INTERRUPT_LEVEL_15
12344e98e3e1Schristos 	  && interrupt->kind < GET_H_PSR_PIL ()))
12354e98e3e1Schristos     return; /* Leave it for later.  */
12364e98e3e1Schristos 
12374e98e3e1Schristos   /* Remove the interrupt from the queue.  */
12384e98e3e1Schristos   --frv_interrupt_state.queue_index;
12394e98e3e1Schristos 
12404e98e3e1Schristos   /* PCSR=PC
12414e98e3e1Schristos      PSR.PS=PSR.S
12424e98e3e1Schristos      PSR.ET=0
12434e98e3e1Schristos      PSR.S=1
12444e98e3e1Schristos      if PSR.ESR==1
12454e98e3e1Schristos        SR0 through SR3=GR4 through GR7
12464e98e3e1Schristos        TBR.TT=interrupt handler offset
12474e98e3e1Schristos        PC=TBR
12484e98e3e1Schristos   */
12494e98e3e1Schristos   SET_H_PSR_PS (GET_H_PSR_S ());
12504e98e3e1Schristos   SET_H_PSR_ET (0);
12514e98e3e1Schristos   SET_H_PSR_S (1);
12524e98e3e1Schristos   /* Must set PSR.S first to allow access to supervisor-only spr registers.  */
12534e98e3e1Schristos   SET_H_SPR (H_SPR_PCSR, GET_H_PC ());
12544e98e3e1Schristos 
12554e98e3e1Schristos   /* Set the new PC in the TBR.  */
12564e98e3e1Schristos   SET_H_TBR_TT (interrupt->handler_offset);
12574e98e3e1Schristos   new_pc = GET_H_SPR (H_SPR_TBR);
12584e98e3e1Schristos   SET_H_PC (new_pc);
12594e98e3e1Schristos }
12604e98e3e1Schristos 
12614e98e3e1Schristos /* Clear interrupts which fall within the range of classes given.  */
12624e98e3e1Schristos void
12634e98e3e1Schristos frv_clear_interrupt_classes (
12644e98e3e1Schristos   enum frv_interrupt_class low_class, enum frv_interrupt_class high_class
12654e98e3e1Schristos )
12664e98e3e1Schristos {
12674e98e3e1Schristos   int i;
12684e98e3e1Schristos   int j;
12694e98e3e1Schristos   int limit = frv_interrupt_state.queue_index;
12704e98e3e1Schristos 
12714e98e3e1Schristos   /* Find the lowest priority interrupt to be removed.  */
12724e98e3e1Schristos   for (i = 0; i < limit; ++i)
12734e98e3e1Schristos     {
12744e98e3e1Schristos       enum frv_interrupt_kind kind = frv_interrupt_state.queue[i].kind;
12754e98e3e1Schristos       struct frv_interrupt* interrupt = & frv_interrupt_table[kind];
12764e98e3e1Schristos       if (interrupt->iclass >= low_class)
12774e98e3e1Schristos 	break;
12784e98e3e1Schristos     }
12794e98e3e1Schristos 
12804e98e3e1Schristos   /* Find the highest priority interrupt to be removed.  */
12814e98e3e1Schristos   for (j = limit - 1; j >= i; --j)
12824e98e3e1Schristos     {
12834e98e3e1Schristos       enum frv_interrupt_kind kind = frv_interrupt_state.queue[j].kind;
12844e98e3e1Schristos       struct frv_interrupt* interrupt = & frv_interrupt_table[kind];
12854e98e3e1Schristos       if (interrupt->iclass <= high_class)
12864e98e3e1Schristos 	break;
12874e98e3e1Schristos     }
12884e98e3e1Schristos 
12894e98e3e1Schristos   /* Shuffle the remaining high priority interrupts down into the empty space
12904e98e3e1Schristos      left by the deleted interrupts.  */
12914e98e3e1Schristos   if (j >= i)
12924e98e3e1Schristos     {
12934e98e3e1Schristos       for (++j; j < limit; ++j)
12944e98e3e1Schristos 	frv_interrupt_state.queue[i++] = frv_interrupt_state.queue[j];
12954e98e3e1Schristos       frv_interrupt_state.queue_index -= (j - i);
12964e98e3e1Schristos     }
12974e98e3e1Schristos }
12984e98e3e1Schristos 
12994e98e3e1Schristos /* Save data written to memory into the interrupt state so that it can be
13004e98e3e1Schristos    copied to the appropriate EDR register, if necessary, in the event of an
13014e98e3e1Schristos    interrupt.  */
13024e98e3e1Schristos void
13034e98e3e1Schristos frv_save_data_written_for_interrupts (
13044e98e3e1Schristos   SIM_CPU *current_cpu, CGEN_WRITE_QUEUE_ELEMENT *item
13054e98e3e1Schristos )
13064e98e3e1Schristos {
13074e98e3e1Schristos   /* Record the slot containing the insn doing the write in the
13084e98e3e1Schristos      interrupt state.  */
13094e98e3e1Schristos   frv_interrupt_state.slot = CGEN_WRITE_QUEUE_ELEMENT_PIPE (item);
13104e98e3e1Schristos 
13114e98e3e1Schristos   /* Now record any data written to memory in the interrupt state.  */
13124e98e3e1Schristos   switch (CGEN_WRITE_QUEUE_ELEMENT_KIND (item))
13134e98e3e1Schristos     {
13144e98e3e1Schristos     case CGEN_BI_WRITE:
13154e98e3e1Schristos     case CGEN_QI_WRITE:
13164e98e3e1Schristos     case CGEN_SI_WRITE:
13174e98e3e1Schristos     case CGEN_SF_WRITE:
13184e98e3e1Schristos     case CGEN_PC_WRITE:
13194e98e3e1Schristos     case CGEN_FN_HI_WRITE:
13204e98e3e1Schristos     case CGEN_FN_SI_WRITE:
13214e98e3e1Schristos     case CGEN_FN_SF_WRITE:
13224e98e3e1Schristos     case CGEN_FN_DI_WRITE:
13234e98e3e1Schristos     case CGEN_FN_DF_WRITE:
13244e98e3e1Schristos     case CGEN_FN_XI_WRITE:
13254e98e3e1Schristos     case CGEN_FN_PC_WRITE:
13264e98e3e1Schristos       break; /* Ignore writes to registers.  */
13274e98e3e1Schristos     case CGEN_MEM_QI_WRITE:
13284e98e3e1Schristos       frv_interrupt_state.data_written.length = 1;
13294e98e3e1Schristos       frv_interrupt_state.data_written.words[0]
13304e98e3e1Schristos 	= item->kinds.mem_qi_write.value;
13314e98e3e1Schristos       break;
13324e98e3e1Schristos     case CGEN_MEM_HI_WRITE:
13334e98e3e1Schristos       frv_interrupt_state.data_written.length = 1;
13344e98e3e1Schristos       frv_interrupt_state.data_written.words[0]
13354e98e3e1Schristos 	= item->kinds.mem_hi_write.value;
13364e98e3e1Schristos       break;
13374e98e3e1Schristos     case CGEN_MEM_SI_WRITE:
13384e98e3e1Schristos       frv_interrupt_state.data_written.length = 1;
13394e98e3e1Schristos       frv_interrupt_state.data_written.words[0]
13404e98e3e1Schristos 	= item->kinds.mem_si_write.value;
13414e98e3e1Schristos       break;
13424e98e3e1Schristos     case CGEN_MEM_DI_WRITE:
13434e98e3e1Schristos       frv_interrupt_state.data_written.length = 2;
13444e98e3e1Schristos       frv_interrupt_state.data_written.words[0]
13454e98e3e1Schristos 	= item->kinds.mem_di_write.value >> 32;
13464e98e3e1Schristos       frv_interrupt_state.data_written.words[1]
13474e98e3e1Schristos 	= item->kinds.mem_di_write.value;
13484e98e3e1Schristos       break;
13494e98e3e1Schristos     case CGEN_MEM_DF_WRITE:
13504e98e3e1Schristos       frv_interrupt_state.data_written.length = 2;
13514e98e3e1Schristos       frv_interrupt_state.data_written.words[0]
13524e98e3e1Schristos 	= item->kinds.mem_df_write.value >> 32;
13534e98e3e1Schristos       frv_interrupt_state.data_written.words[1]
13544e98e3e1Schristos 	= item->kinds.mem_df_write.value;
13554e98e3e1Schristos       break;
13564e98e3e1Schristos     case CGEN_MEM_XI_WRITE:
13574e98e3e1Schristos       frv_interrupt_state.data_written.length = 4;
13584e98e3e1Schristos       frv_interrupt_state.data_written.words[0]
13594e98e3e1Schristos 	= item->kinds.mem_xi_write.value[0];
13604e98e3e1Schristos       frv_interrupt_state.data_written.words[1]
13614e98e3e1Schristos 	= item->kinds.mem_xi_write.value[1];
13624e98e3e1Schristos       frv_interrupt_state.data_written.words[2]
13634e98e3e1Schristos 	= item->kinds.mem_xi_write.value[2];
13644e98e3e1Schristos       frv_interrupt_state.data_written.words[3]
13654e98e3e1Schristos 	= item->kinds.mem_xi_write.value[3];
13664e98e3e1Schristos       break;
13674e98e3e1Schristos     case CGEN_FN_MEM_QI_WRITE:
13684e98e3e1Schristos       frv_interrupt_state.data_written.length = 1;
13694e98e3e1Schristos       frv_interrupt_state.data_written.words[0]
13704e98e3e1Schristos 	= item->kinds.fn_mem_qi_write.value;
13714e98e3e1Schristos       break;
13724e98e3e1Schristos     case CGEN_FN_MEM_HI_WRITE:
13734e98e3e1Schristos       frv_interrupt_state.data_written.length = 1;
13744e98e3e1Schristos       frv_interrupt_state.data_written.words[0]
13754e98e3e1Schristos 	= item->kinds.fn_mem_hi_write.value;
13764e98e3e1Schristos       break;
13774e98e3e1Schristos     case CGEN_FN_MEM_SI_WRITE:
13784e98e3e1Schristos       frv_interrupt_state.data_written.length = 1;
13794e98e3e1Schristos       frv_interrupt_state.data_written.words[0]
13804e98e3e1Schristos 	= item->kinds.fn_mem_si_write.value;
13814e98e3e1Schristos       break;
13824e98e3e1Schristos     case CGEN_FN_MEM_DI_WRITE:
13834e98e3e1Schristos       frv_interrupt_state.data_written.length = 2;
13844e98e3e1Schristos       frv_interrupt_state.data_written.words[0]
13854e98e3e1Schristos 	= item->kinds.fn_mem_di_write.value >> 32;
13864e98e3e1Schristos       frv_interrupt_state.data_written.words[1]
13874e98e3e1Schristos 	= item->kinds.fn_mem_di_write.value;
13884e98e3e1Schristos       break;
13894e98e3e1Schristos     case CGEN_FN_MEM_DF_WRITE:
13904e98e3e1Schristos       frv_interrupt_state.data_written.length = 2;
13914e98e3e1Schristos       frv_interrupt_state.data_written.words[0]
13924e98e3e1Schristos 	= item->kinds.fn_mem_df_write.value >> 32;
13934e98e3e1Schristos       frv_interrupt_state.data_written.words[1]
13944e98e3e1Schristos 	= item->kinds.fn_mem_df_write.value;
13954e98e3e1Schristos       break;
13964e98e3e1Schristos     case CGEN_FN_MEM_XI_WRITE:
13974e98e3e1Schristos       frv_interrupt_state.data_written.length = 4;
13984e98e3e1Schristos       frv_interrupt_state.data_written.words[0]
13994e98e3e1Schristos 	= item->kinds.fn_mem_xi_write.value[0];
14004e98e3e1Schristos       frv_interrupt_state.data_written.words[1]
14014e98e3e1Schristos 	= item->kinds.fn_mem_xi_write.value[1];
14024e98e3e1Schristos       frv_interrupt_state.data_written.words[2]
14034e98e3e1Schristos 	= item->kinds.fn_mem_xi_write.value[2];
14044e98e3e1Schristos       frv_interrupt_state.data_written.words[3]
14054e98e3e1Schristos 	= item->kinds.fn_mem_xi_write.value[3];
14064e98e3e1Schristos       break;
14074e98e3e1Schristos     default:
14084e98e3e1Schristos       {
14094e98e3e1Schristos 	SIM_DESC sd = CPU_STATE (current_cpu);
14104e98e3e1Schristos 	IADDR pc = CPU_PC_GET (current_cpu);
14114e98e3e1Schristos 	sim_engine_abort (sd, current_cpu, pc,
14124e98e3e1Schristos 			  "unknown write kind during save for interrupt\n");
14134e98e3e1Schristos       }
14144e98e3e1Schristos       break;
14154e98e3e1Schristos     }
14164e98e3e1Schristos }
1417