xref: /netbsd-src/external/gpl3/gdb/dist/sim/m68hc11/interrupts.c (revision 9b2a9e00295c5af9c57a466f299054d5910e47d6)
14e98e3e1Schristos /* interrupts.c -- 68HC11 Interrupts Emulation
2*9b2a9e00Schristos    Copyright 1999-2024 Free Software Foundation, Inc.
34e98e3e1Schristos    Written by Stephane Carrez (stcarrez@nerim.fr)
44e98e3e1Schristos 
54e98e3e1Schristos This file is part of GDB, GAS, and the GNU binutils.
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 
23*9b2a9e00Schristos #include "bfd.h"
24*9b2a9e00Schristos 
254e98e3e1Schristos #include "sim-main.h"
264e98e3e1Schristos #include "sim-options.h"
274b169a6bSchristos #include "sim-signal.h"
284e98e3e1Schristos 
29*9b2a9e00Schristos #include "m68hc11-sim.h"
30*9b2a9e00Schristos 
314e98e3e1Schristos static const char *interrupt_names[] = {
324e98e3e1Schristos   "R1",
334e98e3e1Schristos   "R2",
344e98e3e1Schristos   "R3",
354e98e3e1Schristos   "R4",
364e98e3e1Schristos   "R5",
374e98e3e1Schristos   "R6",
384e98e3e1Schristos   "R7",
394e98e3e1Schristos   "R8",
404e98e3e1Schristos   "R9",
414e98e3e1Schristos   "R10",
424e98e3e1Schristos   "R11",
434e98e3e1Schristos 
444e98e3e1Schristos   "SCI",
454e98e3e1Schristos   "SPI",
464e98e3e1Schristos   "AINPUT",
474e98e3e1Schristos   "AOVERFLOW",
484e98e3e1Schristos   "TOVERFLOW",
494e98e3e1Schristos   "OUT5",
504e98e3e1Schristos   "OUT4",
514e98e3e1Schristos   "OUT3",
524e98e3e1Schristos   "OUT2",
534e98e3e1Schristos   "OUT1",
544e98e3e1Schristos   "INC3",
554e98e3e1Schristos   "INC2",
564e98e3e1Schristos   "INC1",
574e98e3e1Schristos   "RT",
584e98e3e1Schristos   "IRQ",
594e98e3e1Schristos   "XIRQ",
604e98e3e1Schristos   "SWI",
614e98e3e1Schristos   "ILL",
624e98e3e1Schristos   "COPRESET",
634e98e3e1Schristos   "COPFAIL",
644e98e3e1Schristos   "RESET"
654e98e3e1Schristos };
664e98e3e1Schristos 
674e98e3e1Schristos struct interrupt_def idefs[] = {
684e98e3e1Schristos   /* Serial interrupts.  */
694e98e3e1Schristos   { M6811_INT_SCI,      M6811_SCSR,   M6811_TDRE,  M6811_SCCR2,  M6811_TIE },
704e98e3e1Schristos   { M6811_INT_SCI,      M6811_SCSR,   M6811_TC,    M6811_SCCR2,  M6811_TCIE },
714e98e3e1Schristos   { M6811_INT_SCI,      M6811_SCSR,   M6811_RDRF,  M6811_SCCR2,  M6811_RIE },
724e98e3e1Schristos   { M6811_INT_SCI,      M6811_SCSR,   M6811_IDLE,  M6811_SCCR2,  M6811_ILIE },
734e98e3e1Schristos 
744e98e3e1Schristos   /* SPI interrupts.  */
754e98e3e1Schristos   { M6811_INT_SPI,      M6811_SPSR,   M6811_SPIF,  M6811_SPCR,   M6811_SPIE },
764e98e3e1Schristos 
774e98e3e1Schristos   /* Realtime interrupts.  */
784e98e3e1Schristos   { M6811_INT_TCTN,     M6811_TFLG2,  M6811_TOF,   M6811_TMSK2,  M6811_TOI },
794e98e3e1Schristos   { M6811_INT_RT,       M6811_TFLG2,  M6811_RTIF,  M6811_TMSK2,  M6811_RTII },
804e98e3e1Schristos 
814e98e3e1Schristos   /* Output compare interrupts.  */
824e98e3e1Schristos   { M6811_INT_OUTCMP1,  M6811_TFLG1,  M6811_OC1F,  M6811_TMSK1,  M6811_OC1I },
834e98e3e1Schristos   { M6811_INT_OUTCMP2,  M6811_TFLG1,  M6811_OC2F,  M6811_TMSK1,  M6811_OC2I },
844e98e3e1Schristos   { M6811_INT_OUTCMP3,  M6811_TFLG1,  M6811_OC3F,  M6811_TMSK1,  M6811_OC3I },
854e98e3e1Schristos   { M6811_INT_OUTCMP4,  M6811_TFLG1,  M6811_OC4F,  M6811_TMSK1,  M6811_OC4I },
864e98e3e1Schristos   { M6811_INT_OUTCMP5,  M6811_TFLG1,  M6811_OC5F,  M6811_TMSK1,  M6811_OC5I },
874e98e3e1Schristos 
884e98e3e1Schristos   /* Input compare interrupts.  */
894e98e3e1Schristos   { M6811_INT_INCMP1,   M6811_TFLG1,  M6811_IC1F,  M6811_TMSK1,  M6811_IC1I },
904e98e3e1Schristos   { M6811_INT_INCMP2,   M6811_TFLG1,  M6811_IC2F,  M6811_TMSK1,  M6811_IC2I },
914e98e3e1Schristos   { M6811_INT_INCMP3,   M6811_TFLG1,  M6811_IC3F,  M6811_TMSK1,  M6811_IC3I },
924e98e3e1Schristos 
934e98e3e1Schristos   /* Pulse accumulator.  */
944e98e3e1Schristos   { M6811_INT_AINPUT,   M6811_TFLG2,  M6811_PAIF,  M6811_TMSK2,  M6811_PAII },
954e98e3e1Schristos   { M6811_INT_AOVERFLOW,M6811_TFLG2,  M6811_PAOVF, M6811_TMSK2,  M6811_PAOVI},
964e98e3e1Schristos #if 0
974e98e3e1Schristos   { M6811_INT_COPRESET, M6811_CONFIG, M6811_NOCOP, 0,            0 },
984e98e3e1Schristos   { M6811_INT_COPFAIL,  M6811_CONFIG, M6811_NOCOP, 0,            0 }
994e98e3e1Schristos #endif
1004e98e3e1Schristos };
1014e98e3e1Schristos 
1024b169a6bSchristos #define CYCLES_MAX ((((int64_t) 1) << 62) - 1)
1034e98e3e1Schristos 
1044e98e3e1Schristos enum
1054e98e3e1Schristos {
1064e98e3e1Schristos   OPTION_INTERRUPT_INFO = OPTION_START,
1074e98e3e1Schristos   OPTION_INTERRUPT_CATCH,
1084e98e3e1Schristos   OPTION_INTERRUPT_CLEAR
1094e98e3e1Schristos };
1104e98e3e1Schristos 
1114e98e3e1Schristos static DECLARE_OPTION_HANDLER (interrupt_option_handler);
1124e98e3e1Schristos 
1134e98e3e1Schristos static const OPTION interrupt_options[] =
1144e98e3e1Schristos {
1154e98e3e1Schristos   { {"interrupt-info", no_argument, NULL, OPTION_INTERRUPT_INFO },
1164e98e3e1Schristos       '\0', NULL, "Print information about interrupts",
1174e98e3e1Schristos       interrupt_option_handler },
1184e98e3e1Schristos   { {"interrupt-catch", required_argument, NULL, OPTION_INTERRUPT_CATCH },
1194e98e3e1Schristos       '\0', "NAME[,MODE]",
1204e98e3e1Schristos     "Catch interrupts when they are raised or taken\n"
1214e98e3e1Schristos     "NAME   Name of the interrupt\n"
1224e98e3e1Schristos     "MODE   Optional mode (`taken' or `raised')",
1234e98e3e1Schristos       interrupt_option_handler },
1244e98e3e1Schristos   { {"interrupt-clear", required_argument, NULL, OPTION_INTERRUPT_CLEAR },
1254e98e3e1Schristos       '\0', "NAME", "No longer catch the interrupt",
1264e98e3e1Schristos       interrupt_option_handler },
1274e98e3e1Schristos 
1284e98e3e1Schristos   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
1294e98e3e1Schristos };
1304e98e3e1Schristos 
1314e98e3e1Schristos /* Initialize the interrupts module.  */
1324e98e3e1Schristos void
133796c32c9Schristos interrupts_initialize (SIM_DESC sd, sim_cpu *cpu)
1344e98e3e1Schristos {
135*9b2a9e00Schristos   struct interrupts *interrupts = &M68HC11_SIM_CPU (cpu)->cpu_interrupts;
1364e98e3e1Schristos 
137796c32c9Schristos   interrupts->cpu          = cpu;
1384e98e3e1Schristos 
1394e98e3e1Schristos   sim_add_option_table (sd, 0, interrupt_options);
1404e98e3e1Schristos }
1414e98e3e1Schristos 
1424e98e3e1Schristos /* Initialize the interrupts of the processor.  */
1434e98e3e1Schristos void
1444e98e3e1Schristos interrupts_reset (struct interrupts *interrupts)
1454e98e3e1Schristos {
146*9b2a9e00Schristos   sim_cpu *cpu = interrupts->cpu;
147*9b2a9e00Schristos   struct m68hc11_sim_cpu *m68hc11_cpu = M68HC11_SIM_CPU (cpu);
1484e98e3e1Schristos   int i;
1494e98e3e1Schristos 
1504e98e3e1Schristos   interrupts->pending_mask = 0;
151*9b2a9e00Schristos   if (m68hc11_cpu->cpu_mode & M6811_SMOD)
1524e98e3e1Schristos     interrupts->vectors_addr = 0xbfc0;
1534e98e3e1Schristos   else
1544e98e3e1Schristos     interrupts->vectors_addr = 0xffc0;
1554e98e3e1Schristos   interrupts->nb_interrupts_raised = 0;
1564e98e3e1Schristos   interrupts->min_mask_cycles = CYCLES_MAX;
1574e98e3e1Schristos   interrupts->max_mask_cycles = 0;
1584e98e3e1Schristos   interrupts->last_mask_cycles = 0;
1594e98e3e1Schristos   interrupts->start_mask_cycle = -1;
1604e98e3e1Schristos   interrupts->xirq_start_mask_cycle = -1;
1614e98e3e1Schristos   interrupts->xirq_max_mask_cycles = 0;
1624e98e3e1Schristos   interrupts->xirq_min_mask_cycles = CYCLES_MAX;
1634e98e3e1Schristos   interrupts->xirq_last_mask_cycles = 0;
1644e98e3e1Schristos 
1654e98e3e1Schristos   for (i = 0; i < M6811_INT_NUMBER; i++)
1664e98e3e1Schristos     {
1674e98e3e1Schristos       interrupts->interrupt_order[i] = i;
1684e98e3e1Schristos     }
1694e98e3e1Schristos 
1704e98e3e1Schristos   /* Clear the interrupt history table.  */
1714e98e3e1Schristos   interrupts->history_index = 0;
1724e98e3e1Schristos   memset (interrupts->interrupts_history, 0,
1734e98e3e1Schristos           sizeof (interrupts->interrupts_history));
1744e98e3e1Schristos 
1754e98e3e1Schristos   memset (interrupts->interrupts, 0,
1764e98e3e1Schristos           sizeof (interrupts->interrupts));
1774e98e3e1Schristos 
1784e98e3e1Schristos   /* In bootstrap mode, initialize the vector table to point
1794e98e3e1Schristos      to the RAM location.  */
180*9b2a9e00Schristos   if (m68hc11_cpu->cpu_mode == M6811_SMOD)
1814e98e3e1Schristos     {
1824e98e3e1Schristos       bfd_vma addr = interrupts->vectors_addr;
1834b169a6bSchristos       uint16_t vector = 0x0100 - 3 * (M6811_INT_NUMBER - 1);
1844e98e3e1Schristos       for (i = 0; i < M6811_INT_NUMBER; i++)
1854e98e3e1Schristos         {
186*9b2a9e00Schristos           memory_write16 (cpu, addr, vector);
1874e98e3e1Schristos           addr += 2;
1884e98e3e1Schristos           vector += 3;
1894e98e3e1Schristos         }
1904e98e3e1Schristos     }
1914e98e3e1Schristos }
1924e98e3e1Schristos 
1934e98e3e1Schristos static int
1944e98e3e1Schristos find_interrupt (const char *name)
1954e98e3e1Schristos {
1964e98e3e1Schristos   int i;
1974e98e3e1Schristos 
1984e98e3e1Schristos   if (name)
1994e98e3e1Schristos     for (i = 0; i < M6811_INT_NUMBER; i++)
2004e98e3e1Schristos       if (strcasecmp (name, interrupt_names[i]) == 0)
2014e98e3e1Schristos         return i;
2024e98e3e1Schristos 
2034e98e3e1Schristos   return -1;
2044e98e3e1Schristos }
2054e98e3e1Schristos 
2064e98e3e1Schristos static SIM_RC
2074e98e3e1Schristos interrupt_option_handler (SIM_DESC sd, sim_cpu *cpu,
2084e98e3e1Schristos                           int opt, char *arg, int is_command)
2094e98e3e1Schristos {
2104e98e3e1Schristos   char *p;
2114e98e3e1Schristos   int mode;
2124e98e3e1Schristos   int id;
2134e98e3e1Schristos   struct interrupts *interrupts;
2144e98e3e1Schristos 
2154e98e3e1Schristos   if (cpu == 0)
2164e98e3e1Schristos     cpu = STATE_CPU (sd, 0);
2174e98e3e1Schristos 
218*9b2a9e00Schristos   interrupts = &M68HC11_SIM_CPU (cpu)->cpu_interrupts;
2194e98e3e1Schristos   switch (opt)
2204e98e3e1Schristos     {
2214e98e3e1Schristos     case OPTION_INTERRUPT_INFO:
2224e98e3e1Schristos       for (id = 0; id < M6811_INT_NUMBER; id++)
2234e98e3e1Schristos         {
2244e98e3e1Schristos           sim_io_eprintf (sd, "%-10.10s ", interrupt_names[id]);
2254e98e3e1Schristos           switch (interrupts->interrupts[id].stop_mode)
2264e98e3e1Schristos             {
2274e98e3e1Schristos             case SIM_STOP_WHEN_RAISED:
2284e98e3e1Schristos               sim_io_eprintf (sd, "catch raised ");
2294e98e3e1Schristos               break;
2304e98e3e1Schristos 
2314e98e3e1Schristos             case SIM_STOP_WHEN_TAKEN:
2324e98e3e1Schristos               sim_io_eprintf (sd, "catch taken  ");
2334e98e3e1Schristos               break;
2344e98e3e1Schristos 
2354e98e3e1Schristos             case SIM_STOP_WHEN_RAISED | SIM_STOP_WHEN_TAKEN:
2364e98e3e1Schristos               sim_io_eprintf (sd, "catch all    ");
2374e98e3e1Schristos               break;
2384e98e3e1Schristos 
2394e98e3e1Schristos             default:
2404e98e3e1Schristos               sim_io_eprintf (sd, "             ");
2414e98e3e1Schristos               break;
2424e98e3e1Schristos             }
2434e98e3e1Schristos           sim_io_eprintf (sd, "%ld\n",
2444e98e3e1Schristos                           interrupts->interrupts[id].raised_count);
2454e98e3e1Schristos         }
2464e98e3e1Schristos       break;
2474e98e3e1Schristos 
2484e98e3e1Schristos     case OPTION_INTERRUPT_CATCH:
2494e98e3e1Schristos       p = strchr (arg, ',');
2504e98e3e1Schristos       if (p)
2514e98e3e1Schristos         *p++ = 0;
2524e98e3e1Schristos 
2534e98e3e1Schristos       mode = SIM_STOP_WHEN_RAISED;
2544e98e3e1Schristos       id = find_interrupt (arg);
2554e98e3e1Schristos       if (id < 0)
2564e98e3e1Schristos         sim_io_eprintf (sd, "Interrupt name not recognized: %s\n", arg);
2574e98e3e1Schristos 
2584e98e3e1Schristos       if (p && strcasecmp (p, "raised") == 0)
2594e98e3e1Schristos         mode = SIM_STOP_WHEN_RAISED;
2604e98e3e1Schristos       else if (p && strcasecmp (p, "taken") == 0)
2614e98e3e1Schristos         mode = SIM_STOP_WHEN_TAKEN;
2624e98e3e1Schristos       else if (p && strcasecmp (p, "all") == 0)
2634e98e3e1Schristos         mode = SIM_STOP_WHEN_RAISED | SIM_STOP_WHEN_TAKEN;
2644e98e3e1Schristos       else if (p)
2654e98e3e1Schristos         {
2664e98e3e1Schristos           sim_io_eprintf (sd, "Invalid argument: %s\n", p);
2674e98e3e1Schristos           break;
2684e98e3e1Schristos         }
2694e98e3e1Schristos       if (id >= 0)
2704e98e3e1Schristos         interrupts->interrupts[id].stop_mode = mode;
2714e98e3e1Schristos       break;
2724e98e3e1Schristos 
2734e98e3e1Schristos     case OPTION_INTERRUPT_CLEAR:
2744e98e3e1Schristos       mode = SIM_STOP_WHEN_RAISED;
2754e98e3e1Schristos       id = find_interrupt (arg);
2764e98e3e1Schristos       if (id < 0)
2774e98e3e1Schristos         sim_io_eprintf (sd, "Interrupt name not recognized: %s\n", arg);
2784e98e3e1Schristos       else
2794e98e3e1Schristos         interrupts->interrupts[id].stop_mode = 0;
2804e98e3e1Schristos       break;
2814e98e3e1Schristos     }
2824e98e3e1Schristos 
2834e98e3e1Schristos   return SIM_RC_OK;
2844e98e3e1Schristos }
2854e98e3e1Schristos 
2864e98e3e1Schristos /* Update the mask of pending interrupts.  This operation must be called
2874e98e3e1Schristos    when the state of some 68HC11 IO register changes.  It looks the
2884e98e3e1Schristos    different registers that indicate a pending interrupt (timer, SCI, SPI,
2894e98e3e1Schristos    ...) and records the interrupt if it's there and enabled.  */
2904e98e3e1Schristos void
2914e98e3e1Schristos interrupts_update_pending (struct interrupts *interrupts)
2924e98e3e1Schristos {
2934e98e3e1Schristos   int i;
2944b169a6bSchristos   uint8_t *ioregs;
2954e98e3e1Schristos   unsigned long clear_mask;
2964e98e3e1Schristos   unsigned long set_mask;
2974e98e3e1Schristos 
2984e98e3e1Schristos   clear_mask = 0;
2994e98e3e1Schristos   set_mask = 0;
300*9b2a9e00Schristos   ioregs = &M68HC11_SIM_CPU (interrupts->cpu)->ios[0];
3014e98e3e1Schristos 
302796c32c9Schristos   for (i = 0; i < ARRAY_SIZE (idefs); i++)
3034e98e3e1Schristos     {
3044e98e3e1Schristos       struct interrupt_def *idef = &idefs[i];
3054b169a6bSchristos       uint8_t data;
3064e98e3e1Schristos 
3074e98e3e1Schristos       /* Look if the interrupt is enabled.  */
3084e98e3e1Schristos       if (idef->enable_paddr)
3094e98e3e1Schristos 	{
3104e98e3e1Schristos 	  data = ioregs[idef->enable_paddr];
3114e98e3e1Schristos 	  if (!(data & idef->enabled_mask))
3124e98e3e1Schristos             {
3134e98e3e1Schristos               /* Disable it.  */
3144e98e3e1Schristos               clear_mask |= (1 << idef->int_number);
3154e98e3e1Schristos               continue;
3164e98e3e1Schristos             }
3174e98e3e1Schristos 	}
3184e98e3e1Schristos 
3194e98e3e1Schristos       /* Interrupt is enabled, see if it's there.  */
3204e98e3e1Schristos       data = ioregs[idef->int_paddr];
3214e98e3e1Schristos       if (!(data & idef->int_mask))
3224e98e3e1Schristos         {
3234e98e3e1Schristos           /* Disable it.  */
3244e98e3e1Schristos           clear_mask |= (1 << idef->int_number);
3254e98e3e1Schristos           continue;
3264e98e3e1Schristos         }
3274e98e3e1Schristos 
3284e98e3e1Schristos       /* Ok, raise it.  */
3294e98e3e1Schristos       set_mask |= (1 << idef->int_number);
3304e98e3e1Schristos     }
3314e98e3e1Schristos 
3324e98e3e1Schristos   /* Some interrupts are shared (M6811_INT_SCI) so clear
3334e98e3e1Schristos      the interrupts before setting the new ones.  */
3344e98e3e1Schristos   interrupts->pending_mask &= ~clear_mask;
3354e98e3e1Schristos   interrupts->pending_mask |= set_mask;
3364e98e3e1Schristos 
3374e98e3e1Schristos   /* Keep track of when the interrupt is raised by the device.
3384e98e3e1Schristos      Also implements the breakpoint-on-interrupt.  */
3394e98e3e1Schristos   if (set_mask)
3404e98e3e1Schristos     {
3414b169a6bSchristos       int64_t cycle = cpu_current_cycle (interrupts->cpu);
3424e98e3e1Schristos       int must_stop = 0;
3434e98e3e1Schristos 
3444e98e3e1Schristos       for (i = 0; i < M6811_INT_NUMBER; i++)
3454e98e3e1Schristos         {
3464e98e3e1Schristos           if (!(set_mask & (1 << i)))
3474e98e3e1Schristos             continue;
3484e98e3e1Schristos 
3494e98e3e1Schristos           interrupts->interrupts[i].cpu_cycle = cycle;
3504e98e3e1Schristos           if (interrupts->interrupts[i].stop_mode & SIM_STOP_WHEN_RAISED)
3514e98e3e1Schristos             {
3524e98e3e1Schristos               must_stop = 1;
3534e98e3e1Schristos               sim_io_printf (CPU_STATE (interrupts->cpu),
3544e98e3e1Schristos                              "Interrupt %s raised\n",
3554e98e3e1Schristos                              interrupt_names[i]);
3564e98e3e1Schristos             }
3574e98e3e1Schristos         }
3584e98e3e1Schristos       if (must_stop)
3594e98e3e1Schristos         sim_engine_halt (CPU_STATE (interrupts->cpu),
3604e98e3e1Schristos                          interrupts->cpu,
3614e98e3e1Schristos                          0, cpu_get_pc (interrupts->cpu),
3624e98e3e1Schristos                          sim_stopped,
3634e98e3e1Schristos                          SIM_SIGTRAP);
3644e98e3e1Schristos     }
3654e98e3e1Schristos }
3664e98e3e1Schristos 
3674e98e3e1Schristos 
3684e98e3e1Schristos /* Finds the current active and non-masked interrupt.
3694e98e3e1Schristos    Returns the interrupt number (index in the vector table) or -1
3704e98e3e1Schristos    if no interrupt can be serviced.  */
3714e98e3e1Schristos int
3724e98e3e1Schristos interrupts_get_current (struct interrupts *interrupts)
3734e98e3e1Schristos {
3744e98e3e1Schristos   int i;
3754e98e3e1Schristos 
3764e98e3e1Schristos   if (interrupts->pending_mask == 0)
3774e98e3e1Schristos     return -1;
3784e98e3e1Schristos 
3794e98e3e1Schristos   /* SWI and illegal instructions are simulated by an interrupt.
3804e98e3e1Schristos      They are not maskable.  */
3814e98e3e1Schristos   if (interrupts->pending_mask & (1 << M6811_INT_SWI))
3824e98e3e1Schristos     {
3834e98e3e1Schristos       interrupts->pending_mask &= ~(1 << M6811_INT_SWI);
3844e98e3e1Schristos       return M6811_INT_SWI;
3854e98e3e1Schristos     }
3864e98e3e1Schristos   if (interrupts->pending_mask & (1 << M6811_INT_ILLEGAL))
3874e98e3e1Schristos     {
3884e98e3e1Schristos       interrupts->pending_mask &= ~(1 << M6811_INT_ILLEGAL);
3894e98e3e1Schristos       return M6811_INT_ILLEGAL;
3904e98e3e1Schristos     }
3914e98e3e1Schristos 
3924e98e3e1Schristos   /* If there is a non maskable interrupt, go for it (unless we are masked
3934e98e3e1Schristos      by the X-bit.  */
3944e98e3e1Schristos   if (interrupts->pending_mask & (1 << M6811_INT_XIRQ))
3954e98e3e1Schristos     {
3964e98e3e1Schristos       if (cpu_get_ccr_X (interrupts->cpu) == 0)
3974e98e3e1Schristos 	{
3984e98e3e1Schristos 	  interrupts->pending_mask &= ~(1 << M6811_INT_XIRQ);
3994e98e3e1Schristos 	  return M6811_INT_XIRQ;
4004e98e3e1Schristos 	}
4014e98e3e1Schristos       return -1;
4024e98e3e1Schristos     }
4034e98e3e1Schristos 
4044e98e3e1Schristos   /* Interrupts are masked, do nothing.  */
4054e98e3e1Schristos   if (cpu_get_ccr_I (interrupts->cpu) == 1)
4064e98e3e1Schristos     {
4074e98e3e1Schristos       return -1;
4084e98e3e1Schristos     }
4094e98e3e1Schristos 
4104e98e3e1Schristos   /* Returns the first interrupt number which is pending.
4114e98e3e1Schristos      The interrupt priority is specified by the table `interrupt_order'.
4124e98e3e1Schristos      For these interrupts, the pending mask is cleared when the program
4134e98e3e1Schristos      performs some actions on the corresponding device.  If the device
4144e98e3e1Schristos      is not reset, the interrupt remains and will be re-raised when
4154e98e3e1Schristos      we return from the interrupt (see 68HC11 pink book).  */
4164e98e3e1Schristos   for (i = 0; i < M6811_INT_NUMBER; i++)
4174e98e3e1Schristos     {
4184e98e3e1Schristos       enum M6811_INT int_number = interrupts->interrupt_order[i];
4194e98e3e1Schristos 
4204e98e3e1Schristos       if (interrupts->pending_mask & (1 << int_number))
4214e98e3e1Schristos 	{
4224e98e3e1Schristos 	  return int_number;
4234e98e3e1Schristos 	}
4244e98e3e1Schristos     }
4254e98e3e1Schristos   return -1;
4264e98e3e1Schristos }
4274e98e3e1Schristos 
4284e98e3e1Schristos 
4294e98e3e1Schristos /* Process the current interrupt if there is one.  This operation must
4304e98e3e1Schristos    be called after each instruction to handle the interrupts.  If interrupts
4314e98e3e1Schristos    are masked, it does nothing.  */
4324e98e3e1Schristos int
4334e98e3e1Schristos interrupts_process (struct interrupts *interrupts)
4344e98e3e1Schristos {
4354e98e3e1Schristos   int id;
4364b169a6bSchristos   uint8_t ccr;
4374e98e3e1Schristos 
4384e98e3e1Schristos   /* See if interrupts are enabled/disabled and keep track of the
4394e98e3e1Schristos      number of cycles the interrupts are masked.  Such information is
4404e98e3e1Schristos      then reported by the info command.  */
4414e98e3e1Schristos   ccr = cpu_get_ccr (interrupts->cpu);
4424e98e3e1Schristos   if (ccr & M6811_I_BIT)
4434e98e3e1Schristos     {
4444e98e3e1Schristos       if (interrupts->start_mask_cycle < 0)
4454e98e3e1Schristos         interrupts->start_mask_cycle = cpu_current_cycle (interrupts->cpu);
4464e98e3e1Schristos     }
4474e98e3e1Schristos   else if (interrupts->start_mask_cycle >= 0
4484e98e3e1Schristos            && (ccr & M6811_I_BIT) == 0)
4494e98e3e1Schristos     {
4504b169a6bSchristos       int64_t t = cpu_current_cycle (interrupts->cpu);
4514e98e3e1Schristos 
4524e98e3e1Schristos       t -= interrupts->start_mask_cycle;
4534e98e3e1Schristos       if (t < interrupts->min_mask_cycles)
4544e98e3e1Schristos         interrupts->min_mask_cycles = t;
4554e98e3e1Schristos       if (t > interrupts->max_mask_cycles)
4564e98e3e1Schristos         interrupts->max_mask_cycles = t;
4574e98e3e1Schristos       interrupts->start_mask_cycle = -1;
4584e98e3e1Schristos       interrupts->last_mask_cycles = t;
4594e98e3e1Schristos     }
4604e98e3e1Schristos   if (ccr & M6811_X_BIT)
4614e98e3e1Schristos     {
4624e98e3e1Schristos       if (interrupts->xirq_start_mask_cycle < 0)
4634e98e3e1Schristos         interrupts->xirq_start_mask_cycle
4644e98e3e1Schristos 	  = cpu_current_cycle (interrupts->cpu);
4654e98e3e1Schristos     }
4664e98e3e1Schristos   else if (interrupts->xirq_start_mask_cycle >= 0
4674e98e3e1Schristos            && (ccr & M6811_X_BIT) == 0)
4684e98e3e1Schristos     {
4694b169a6bSchristos       int64_t t = cpu_current_cycle (interrupts->cpu);
4704e98e3e1Schristos 
4714e98e3e1Schristos       t -= interrupts->xirq_start_mask_cycle;
4724e98e3e1Schristos       if (t < interrupts->xirq_min_mask_cycles)
4734e98e3e1Schristos         interrupts->xirq_min_mask_cycles = t;
4744e98e3e1Schristos       if (t > interrupts->xirq_max_mask_cycles)
4754e98e3e1Schristos         interrupts->xirq_max_mask_cycles = t;
4764e98e3e1Schristos       interrupts->xirq_start_mask_cycle = -1;
4774e98e3e1Schristos       interrupts->xirq_last_mask_cycles = t;
4784e98e3e1Schristos     }
4794e98e3e1Schristos 
4804e98e3e1Schristos   id = interrupts_get_current (interrupts);
4814e98e3e1Schristos   if (id >= 0)
4824e98e3e1Schristos     {
4834b169a6bSchristos       uint16_t addr;
4844e98e3e1Schristos       struct interrupt_history *h;
4854e98e3e1Schristos 
4864e98e3e1Schristos       /* Implement the breakpoint-on-interrupt.  */
4874e98e3e1Schristos       if (interrupts->interrupts[id].stop_mode & SIM_STOP_WHEN_TAKEN)
4884e98e3e1Schristos         {
4894e98e3e1Schristos           sim_io_printf (CPU_STATE (interrupts->cpu),
4904e98e3e1Schristos                          "Interrupt %s will be handled\n",
4914e98e3e1Schristos                          interrupt_names[id]);
4924e98e3e1Schristos           sim_engine_halt (CPU_STATE (interrupts->cpu),
4934e98e3e1Schristos                            interrupts->cpu,
4944e98e3e1Schristos                            0, cpu_get_pc (interrupts->cpu),
4954e98e3e1Schristos                            sim_stopped,
4964e98e3e1Schristos                            SIM_SIGTRAP);
4974e98e3e1Schristos         }
4984e98e3e1Schristos 
4994e98e3e1Schristos       cpu_push_all (interrupts->cpu);
5004e98e3e1Schristos       addr = memory_read16 (interrupts->cpu,
5014e98e3e1Schristos                             interrupts->vectors_addr + id * 2);
5024e98e3e1Schristos       cpu_call (interrupts->cpu, addr);
5034e98e3e1Schristos 
5044e98e3e1Schristos       /* Now, protect from nested interrupts.  */
5054e98e3e1Schristos       if (id == M6811_INT_XIRQ)
5064e98e3e1Schristos 	{
5074e98e3e1Schristos 	  cpu_set_ccr_X (interrupts->cpu, 1);
5084e98e3e1Schristos 	}
5094e98e3e1Schristos       else
5104e98e3e1Schristos 	{
5114e98e3e1Schristos 	  cpu_set_ccr_I (interrupts->cpu, 1);
5124e98e3e1Schristos 	}
5134e98e3e1Schristos 
5144e98e3e1Schristos       /* Update the interrupt history table.  */
5154e98e3e1Schristos       h = &interrupts->interrupts_history[interrupts->history_index];
5164e98e3e1Schristos       h->type = id;
5174e98e3e1Schristos       h->taken_cycle = cpu_current_cycle (interrupts->cpu);
5184e98e3e1Schristos       h->raised_cycle = interrupts->interrupts[id].cpu_cycle;
5194e98e3e1Schristos 
5204e98e3e1Schristos       if (interrupts->history_index >= MAX_INT_HISTORY-1)
5214e98e3e1Schristos         interrupts->history_index = 0;
5224e98e3e1Schristos       else
5234e98e3e1Schristos         interrupts->history_index++;
5244e98e3e1Schristos 
5254e98e3e1Schristos       interrupts->nb_interrupts_raised++;
5264e98e3e1Schristos       cpu_add_cycles (interrupts->cpu, 14);
5274e98e3e1Schristos       return 1;
5284e98e3e1Schristos     }
5294e98e3e1Schristos   return 0;
5304e98e3e1Schristos }
5314e98e3e1Schristos 
5324e98e3e1Schristos void
5334e98e3e1Schristos interrupts_raise (struct interrupts *interrupts, enum M6811_INT number)
5344e98e3e1Schristos {
5354e98e3e1Schristos   interrupts->pending_mask |= (1 << number);
5364e98e3e1Schristos   interrupts->nb_interrupts_raised ++;
5374e98e3e1Schristos }
5384e98e3e1Schristos 
5394e98e3e1Schristos void
5404e98e3e1Schristos interrupts_info (SIM_DESC sd, struct interrupts *interrupts)
5414e98e3e1Schristos {
5424b169a6bSchristos   int64_t t, prev_interrupt;
5434e98e3e1Schristos   int i;
5444e98e3e1Schristos 
5454e98e3e1Schristos   sim_io_printf (sd, "Interrupts Info:\n");
5464e98e3e1Schristos   sim_io_printf (sd, "  Interrupts raised: %lu\n",
5474e98e3e1Schristos                  interrupts->nb_interrupts_raised);
5484e98e3e1Schristos 
5494e98e3e1Schristos   if (interrupts->start_mask_cycle >= 0)
5504e98e3e1Schristos     {
5514e98e3e1Schristos       t = cpu_current_cycle (interrupts->cpu);
5524e98e3e1Schristos 
5534e98e3e1Schristos       t -= interrupts->start_mask_cycle;
5544e98e3e1Schristos       if (t > interrupts->max_mask_cycles)
5554e98e3e1Schristos         interrupts->max_mask_cycles = t;
5564e98e3e1Schristos 
5574e98e3e1Schristos       sim_io_printf (sd, "  Current interrupts masked sequence:   %s\n",
5584e98e3e1Schristos                      cycle_to_string (interrupts->cpu, t,
5594e98e3e1Schristos                                       PRINT_TIME | PRINT_CYCLE));
5604e98e3e1Schristos     }
5614e98e3e1Schristos   t = interrupts->min_mask_cycles == CYCLES_MAX ?
5624e98e3e1Schristos     interrupts->max_mask_cycles :
5634e98e3e1Schristos     interrupts->min_mask_cycles;
5644e98e3e1Schristos   sim_io_printf (sd, "  Shortest interrupts masked sequence:  %s\n",
5654e98e3e1Schristos                  cycle_to_string (interrupts->cpu, t,
5664e98e3e1Schristos                                   PRINT_TIME | PRINT_CYCLE));
5674e98e3e1Schristos 
5684e98e3e1Schristos   t = interrupts->max_mask_cycles;
5694e98e3e1Schristos   sim_io_printf (sd, "  Longest interrupts masked sequence:   %s\n",
5704e98e3e1Schristos                  cycle_to_string (interrupts->cpu, t,
5714e98e3e1Schristos                                   PRINT_TIME | PRINT_CYCLE));
5724e98e3e1Schristos 
5734e98e3e1Schristos   t = interrupts->last_mask_cycles;
5744e98e3e1Schristos   sim_io_printf (sd, "  Last interrupts masked sequence:      %s\n",
5754e98e3e1Schristos                  cycle_to_string (interrupts->cpu, t,
5764e98e3e1Schristos                                   PRINT_TIME | PRINT_CYCLE));
5774e98e3e1Schristos 
5784e98e3e1Schristos   if (interrupts->xirq_start_mask_cycle >= 0)
5794e98e3e1Schristos     {
5804e98e3e1Schristos       t = cpu_current_cycle (interrupts->cpu);
5814e98e3e1Schristos 
5824e98e3e1Schristos       t -= interrupts->xirq_start_mask_cycle;
5834e98e3e1Schristos       if (t > interrupts->xirq_max_mask_cycles)
5844e98e3e1Schristos         interrupts->xirq_max_mask_cycles = t;
5854e98e3e1Schristos 
5864e98e3e1Schristos       sim_io_printf (sd, "  XIRQ Current interrupts masked sequence: %s\n",
5874e98e3e1Schristos                      cycle_to_string (interrupts->cpu, t,
5884e98e3e1Schristos                                       PRINT_TIME | PRINT_CYCLE));
5894e98e3e1Schristos     }
5904e98e3e1Schristos 
5914e98e3e1Schristos   t = interrupts->xirq_min_mask_cycles == CYCLES_MAX ?
5924e98e3e1Schristos     interrupts->xirq_max_mask_cycles :
5934e98e3e1Schristos     interrupts->xirq_min_mask_cycles;
5944e98e3e1Schristos   sim_io_printf (sd, "  XIRQ Min interrupts masked sequence:  %s\n",
5954e98e3e1Schristos                  cycle_to_string (interrupts->cpu, t,
5964e98e3e1Schristos                                   PRINT_TIME | PRINT_CYCLE));
5974e98e3e1Schristos 
5984e98e3e1Schristos   t = interrupts->xirq_max_mask_cycles;
5994e98e3e1Schristos   sim_io_printf (sd, "  XIRQ Max interrupts masked sequence:  %s\n",
6004e98e3e1Schristos                  cycle_to_string (interrupts->cpu, t,
6014e98e3e1Schristos                                   PRINT_TIME | PRINT_CYCLE));
6024e98e3e1Schristos 
6034e98e3e1Schristos   t = interrupts->xirq_last_mask_cycles;
6044e98e3e1Schristos   sim_io_printf (sd, "  XIRQ Last interrupts masked sequence: %s\n",
6054e98e3e1Schristos                  cycle_to_string (interrupts->cpu, t,
6064e98e3e1Schristos                                   PRINT_TIME | PRINT_CYCLE));
6074e98e3e1Schristos 
6084e98e3e1Schristos   if (interrupts->pending_mask)
6094e98e3e1Schristos     {
6104e98e3e1Schristos       sim_io_printf (sd, "  Pending interrupts : ");
6114e98e3e1Schristos       for (i = 0; i < M6811_INT_NUMBER; i++)
6124e98e3e1Schristos         {
6134e98e3e1Schristos           enum M6811_INT int_number = interrupts->interrupt_order[i];
6144e98e3e1Schristos 
6154e98e3e1Schristos           if (interrupts->pending_mask & (1 << int_number))
6164e98e3e1Schristos             {
6174e98e3e1Schristos               sim_io_printf (sd, "%s ", interrupt_names[int_number]);
6184e98e3e1Schristos             }
6194e98e3e1Schristos         }
6204e98e3e1Schristos       sim_io_printf (sd, "\n");
6214e98e3e1Schristos     }
6224e98e3e1Schristos 
6234e98e3e1Schristos   prev_interrupt = 0;
6244e98e3e1Schristos   sim_io_printf (sd, "N  Interrupt     Cycle Taken         Latency"
6254e98e3e1Schristos                  "   Delta between interrupts\n");
6264e98e3e1Schristos   for (i = 0; i < MAX_INT_HISTORY; i++)
6274e98e3e1Schristos     {
6284e98e3e1Schristos       int which;
6294e98e3e1Schristos       struct interrupt_history *h;
6304b169a6bSchristos       int64_t dt;
6314e98e3e1Schristos 
6324e98e3e1Schristos       which = interrupts->history_index - i - 1;
6334e98e3e1Schristos       if (which < 0)
6344e98e3e1Schristos         which += MAX_INT_HISTORY;
6354e98e3e1Schristos       h = &interrupts->interrupts_history[which];
6364e98e3e1Schristos       if (h->taken_cycle == 0)
6374e98e3e1Schristos         break;
6384e98e3e1Schristos 
6394e98e3e1Schristos       dt = h->taken_cycle - h->raised_cycle;
6404e98e3e1Schristos       sim_io_printf (sd, "%2d %-9.9s %15.15s ", i,
6414e98e3e1Schristos                      interrupt_names[h->type],
6424e98e3e1Schristos                      cycle_to_string (interrupts->cpu, h->taken_cycle, 0));
6434e98e3e1Schristos       sim_io_printf (sd, "%15.15s",
6444e98e3e1Schristos                      cycle_to_string (interrupts->cpu, dt, 0));
6454e98e3e1Schristos       if (prev_interrupt)
6464e98e3e1Schristos         {
6474e98e3e1Schristos           dt = prev_interrupt - h->taken_cycle;
6484e98e3e1Schristos           sim_io_printf (sd, " %s",
6494e98e3e1Schristos                          cycle_to_string (interrupts->cpu, dt, PRINT_TIME));
6504e98e3e1Schristos         }
6514e98e3e1Schristos       sim_io_printf (sd, "\n");
6524e98e3e1Schristos       prev_interrupt = h->taken_cycle;
6534e98e3e1Schristos     }
6544e98e3e1Schristos }
655