Home | History | Annotate | Line # | Download | only in m68hc11
      1 /* interrupts.c -- 68HC11 Interrupts Emulation
      2    Copyright 1999-2024 Free Software Foundation, Inc.
      3    Written by Stephane Carrez (stcarrez (at) nerim.fr)
      4 
      5 This file is part of GDB, GAS, and the GNU binutils.
      6 
      7 This program is free software; you can redistribute it and/or modify
      8 it under the terms of the GNU General Public License as published by
      9 the Free Software Foundation; either version 3 of the License, or
     10 (at your option) any later version.
     11 
     12 This program is distributed in the hope that it will be useful,
     13 but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 /* This must come before any other includes.  */
     21 #include "defs.h"
     22 
     23 #include "bfd.h"
     24 
     25 #include "sim-main.h"
     26 #include "sim-options.h"
     27 #include "sim-signal.h"
     28 
     29 #include "m68hc11-sim.h"
     30 
     31 static const char *interrupt_names[] = {
     32   "R1",
     33   "R2",
     34   "R3",
     35   "R4",
     36   "R5",
     37   "R6",
     38   "R7",
     39   "R8",
     40   "R9",
     41   "R10",
     42   "R11",
     43 
     44   "SCI",
     45   "SPI",
     46   "AINPUT",
     47   "AOVERFLOW",
     48   "TOVERFLOW",
     49   "OUT5",
     50   "OUT4",
     51   "OUT3",
     52   "OUT2",
     53   "OUT1",
     54   "INC3",
     55   "INC2",
     56   "INC1",
     57   "RT",
     58   "IRQ",
     59   "XIRQ",
     60   "SWI",
     61   "ILL",
     62   "COPRESET",
     63   "COPFAIL",
     64   "RESET"
     65 };
     66 
     67 struct interrupt_def idefs[] = {
     68   /* Serial interrupts.  */
     69   { M6811_INT_SCI,      M6811_SCSR,   M6811_TDRE,  M6811_SCCR2,  M6811_TIE },
     70   { M6811_INT_SCI,      M6811_SCSR,   M6811_TC,    M6811_SCCR2,  M6811_TCIE },
     71   { M6811_INT_SCI,      M6811_SCSR,   M6811_RDRF,  M6811_SCCR2,  M6811_RIE },
     72   { M6811_INT_SCI,      M6811_SCSR,   M6811_IDLE,  M6811_SCCR2,  M6811_ILIE },
     73 
     74   /* SPI interrupts.  */
     75   { M6811_INT_SPI,      M6811_SPSR,   M6811_SPIF,  M6811_SPCR,   M6811_SPIE },
     76 
     77   /* Realtime interrupts.  */
     78   { M6811_INT_TCTN,     M6811_TFLG2,  M6811_TOF,   M6811_TMSK2,  M6811_TOI },
     79   { M6811_INT_RT,       M6811_TFLG2,  M6811_RTIF,  M6811_TMSK2,  M6811_RTII },
     80 
     81   /* Output compare interrupts.  */
     82   { M6811_INT_OUTCMP1,  M6811_TFLG1,  M6811_OC1F,  M6811_TMSK1,  M6811_OC1I },
     83   { M6811_INT_OUTCMP2,  M6811_TFLG1,  M6811_OC2F,  M6811_TMSK1,  M6811_OC2I },
     84   { M6811_INT_OUTCMP3,  M6811_TFLG1,  M6811_OC3F,  M6811_TMSK1,  M6811_OC3I },
     85   { M6811_INT_OUTCMP4,  M6811_TFLG1,  M6811_OC4F,  M6811_TMSK1,  M6811_OC4I },
     86   { M6811_INT_OUTCMP5,  M6811_TFLG1,  M6811_OC5F,  M6811_TMSK1,  M6811_OC5I },
     87 
     88   /* Input compare interrupts.  */
     89   { M6811_INT_INCMP1,   M6811_TFLG1,  M6811_IC1F,  M6811_TMSK1,  M6811_IC1I },
     90   { M6811_INT_INCMP2,   M6811_TFLG1,  M6811_IC2F,  M6811_TMSK1,  M6811_IC2I },
     91   { M6811_INT_INCMP3,   M6811_TFLG1,  M6811_IC3F,  M6811_TMSK1,  M6811_IC3I },
     92 
     93   /* Pulse accumulator.  */
     94   { M6811_INT_AINPUT,   M6811_TFLG2,  M6811_PAIF,  M6811_TMSK2,  M6811_PAII },
     95   { M6811_INT_AOVERFLOW,M6811_TFLG2,  M6811_PAOVF, M6811_TMSK2,  M6811_PAOVI},
     96 #if 0
     97   { M6811_INT_COPRESET, M6811_CONFIG, M6811_NOCOP, 0,            0 },
     98   { M6811_INT_COPFAIL,  M6811_CONFIG, M6811_NOCOP, 0,            0 }
     99 #endif
    100 };
    101 
    102 #define CYCLES_MAX ((((int64_t) 1) << 62) - 1)
    103 
    104 enum
    105 {
    106   OPTION_INTERRUPT_INFO = OPTION_START,
    107   OPTION_INTERRUPT_CATCH,
    108   OPTION_INTERRUPT_CLEAR
    109 };
    110 
    111 static DECLARE_OPTION_HANDLER (interrupt_option_handler);
    112 
    113 static const OPTION interrupt_options[] =
    114 {
    115   { {"interrupt-info", no_argument, NULL, OPTION_INTERRUPT_INFO },
    116       '\0', NULL, "Print information about interrupts",
    117       interrupt_option_handler },
    118   { {"interrupt-catch", required_argument, NULL, OPTION_INTERRUPT_CATCH },
    119       '\0', "NAME[,MODE]",
    120     "Catch interrupts when they are raised or taken\n"
    121     "NAME   Name of the interrupt\n"
    122     "MODE   Optional mode (`taken' or `raised')",
    123       interrupt_option_handler },
    124   { {"interrupt-clear", required_argument, NULL, OPTION_INTERRUPT_CLEAR },
    125       '\0', "NAME", "No longer catch the interrupt",
    126       interrupt_option_handler },
    127 
    128   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
    129 };
    130 
    131 /* Initialize the interrupts module.  */
    132 void
    133 interrupts_initialize (SIM_DESC sd, sim_cpu *cpu)
    134 {
    135   struct interrupts *interrupts = &M68HC11_SIM_CPU (cpu)->cpu_interrupts;
    136 
    137   interrupts->cpu          = cpu;
    138 
    139   sim_add_option_table (sd, 0, interrupt_options);
    140 }
    141 
    142 /* Initialize the interrupts of the processor.  */
    143 void
    144 interrupts_reset (struct interrupts *interrupts)
    145 {
    146   sim_cpu *cpu = interrupts->cpu;
    147   struct m68hc11_sim_cpu *m68hc11_cpu = M68HC11_SIM_CPU (cpu);
    148   int i;
    149 
    150   interrupts->pending_mask = 0;
    151   if (m68hc11_cpu->cpu_mode & M6811_SMOD)
    152     interrupts->vectors_addr = 0xbfc0;
    153   else
    154     interrupts->vectors_addr = 0xffc0;
    155   interrupts->nb_interrupts_raised = 0;
    156   interrupts->min_mask_cycles = CYCLES_MAX;
    157   interrupts->max_mask_cycles = 0;
    158   interrupts->last_mask_cycles = 0;
    159   interrupts->start_mask_cycle = -1;
    160   interrupts->xirq_start_mask_cycle = -1;
    161   interrupts->xirq_max_mask_cycles = 0;
    162   interrupts->xirq_min_mask_cycles = CYCLES_MAX;
    163   interrupts->xirq_last_mask_cycles = 0;
    164 
    165   for (i = 0; i < M6811_INT_NUMBER; i++)
    166     {
    167       interrupts->interrupt_order[i] = i;
    168     }
    169 
    170   /* Clear the interrupt history table.  */
    171   interrupts->history_index = 0;
    172   memset (interrupts->interrupts_history, 0,
    173           sizeof (interrupts->interrupts_history));
    174 
    175   memset (interrupts->interrupts, 0,
    176           sizeof (interrupts->interrupts));
    177 
    178   /* In bootstrap mode, initialize the vector table to point
    179      to the RAM location.  */
    180   if (m68hc11_cpu->cpu_mode == M6811_SMOD)
    181     {
    182       bfd_vma addr = interrupts->vectors_addr;
    183       uint16_t vector = 0x0100 - 3 * (M6811_INT_NUMBER - 1);
    184       for (i = 0; i < M6811_INT_NUMBER; i++)
    185         {
    186           memory_write16 (cpu, addr, vector);
    187           addr += 2;
    188           vector += 3;
    189         }
    190     }
    191 }
    192 
    193 static int
    194 find_interrupt (const char *name)
    195 {
    196   int i;
    197 
    198   if (name)
    199     for (i = 0; i < M6811_INT_NUMBER; i++)
    200       if (strcasecmp (name, interrupt_names[i]) == 0)
    201         return i;
    202 
    203   return -1;
    204 }
    205 
    206 static SIM_RC
    207 interrupt_option_handler (SIM_DESC sd, sim_cpu *cpu,
    208                           int opt, char *arg, int is_command)
    209 {
    210   char *p;
    211   int mode;
    212   int id;
    213   struct interrupts *interrupts;
    214 
    215   if (cpu == 0)
    216     cpu = STATE_CPU (sd, 0);
    217 
    218   interrupts = &M68HC11_SIM_CPU (cpu)->cpu_interrupts;
    219   switch (opt)
    220     {
    221     case OPTION_INTERRUPT_INFO:
    222       for (id = 0; id < M6811_INT_NUMBER; id++)
    223         {
    224           sim_io_eprintf (sd, "%-10.10s ", interrupt_names[id]);
    225           switch (interrupts->interrupts[id].stop_mode)
    226             {
    227             case SIM_STOP_WHEN_RAISED:
    228               sim_io_eprintf (sd, "catch raised ");
    229               break;
    230 
    231             case SIM_STOP_WHEN_TAKEN:
    232               sim_io_eprintf (sd, "catch taken  ");
    233               break;
    234 
    235             case SIM_STOP_WHEN_RAISED | SIM_STOP_WHEN_TAKEN:
    236               sim_io_eprintf (sd, "catch all    ");
    237               break;
    238 
    239             default:
    240               sim_io_eprintf (sd, "             ");
    241               break;
    242             }
    243           sim_io_eprintf (sd, "%ld\n",
    244                           interrupts->interrupts[id].raised_count);
    245         }
    246       break;
    247 
    248     case OPTION_INTERRUPT_CATCH:
    249       p = strchr (arg, ',');
    250       if (p)
    251         *p++ = 0;
    252 
    253       mode = SIM_STOP_WHEN_RAISED;
    254       id = find_interrupt (arg);
    255       if (id < 0)
    256         sim_io_eprintf (sd, "Interrupt name not recognized: %s\n", arg);
    257 
    258       if (p && strcasecmp (p, "raised") == 0)
    259         mode = SIM_STOP_WHEN_RAISED;
    260       else if (p && strcasecmp (p, "taken") == 0)
    261         mode = SIM_STOP_WHEN_TAKEN;
    262       else if (p && strcasecmp (p, "all") == 0)
    263         mode = SIM_STOP_WHEN_RAISED | SIM_STOP_WHEN_TAKEN;
    264       else if (p)
    265         {
    266           sim_io_eprintf (sd, "Invalid argument: %s\n", p);
    267           break;
    268         }
    269       if (id >= 0)
    270         interrupts->interrupts[id].stop_mode = mode;
    271       break;
    272 
    273     case OPTION_INTERRUPT_CLEAR:
    274       mode = SIM_STOP_WHEN_RAISED;
    275       id = find_interrupt (arg);
    276       if (id < 0)
    277         sim_io_eprintf (sd, "Interrupt name not recognized: %s\n", arg);
    278       else
    279         interrupts->interrupts[id].stop_mode = 0;
    280       break;
    281     }
    282 
    283   return SIM_RC_OK;
    284 }
    285 
    286 /* Update the mask of pending interrupts.  This operation must be called
    287    when the state of some 68HC11 IO register changes.  It looks the
    288    different registers that indicate a pending interrupt (timer, SCI, SPI,
    289    ...) and records the interrupt if it's there and enabled.  */
    290 void
    291 interrupts_update_pending (struct interrupts *interrupts)
    292 {
    293   int i;
    294   uint8_t *ioregs;
    295   unsigned long clear_mask;
    296   unsigned long set_mask;
    297 
    298   clear_mask = 0;
    299   set_mask = 0;
    300   ioregs = &M68HC11_SIM_CPU (interrupts->cpu)->ios[0];
    301 
    302   for (i = 0; i < ARRAY_SIZE (idefs); i++)
    303     {
    304       struct interrupt_def *idef = &idefs[i];
    305       uint8_t data;
    306 
    307       /* Look if the interrupt is enabled.  */
    308       if (idef->enable_paddr)
    309 	{
    310 	  data = ioregs[idef->enable_paddr];
    311 	  if (!(data & idef->enabled_mask))
    312             {
    313               /* Disable it.  */
    314               clear_mask |= (1 << idef->int_number);
    315               continue;
    316             }
    317 	}
    318 
    319       /* Interrupt is enabled, see if it's there.  */
    320       data = ioregs[idef->int_paddr];
    321       if (!(data & idef->int_mask))
    322         {
    323           /* Disable it.  */
    324           clear_mask |= (1 << idef->int_number);
    325           continue;
    326         }
    327 
    328       /* Ok, raise it.  */
    329       set_mask |= (1 << idef->int_number);
    330     }
    331 
    332   /* Some interrupts are shared (M6811_INT_SCI) so clear
    333      the interrupts before setting the new ones.  */
    334   interrupts->pending_mask &= ~clear_mask;
    335   interrupts->pending_mask |= set_mask;
    336 
    337   /* Keep track of when the interrupt is raised by the device.
    338      Also implements the breakpoint-on-interrupt.  */
    339   if (set_mask)
    340     {
    341       int64_t cycle = cpu_current_cycle (interrupts->cpu);
    342       int must_stop = 0;
    343 
    344       for (i = 0; i < M6811_INT_NUMBER; i++)
    345         {
    346           if (!(set_mask & (1 << i)))
    347             continue;
    348 
    349           interrupts->interrupts[i].cpu_cycle = cycle;
    350           if (interrupts->interrupts[i].stop_mode & SIM_STOP_WHEN_RAISED)
    351             {
    352               must_stop = 1;
    353               sim_io_printf (CPU_STATE (interrupts->cpu),
    354                              "Interrupt %s raised\n",
    355                              interrupt_names[i]);
    356             }
    357         }
    358       if (must_stop)
    359         sim_engine_halt (CPU_STATE (interrupts->cpu),
    360                          interrupts->cpu,
    361                          0, cpu_get_pc (interrupts->cpu),
    362                          sim_stopped,
    363                          SIM_SIGTRAP);
    364     }
    365 }
    366 
    367 
    368 /* Finds the current active and non-masked interrupt.
    369    Returns the interrupt number (index in the vector table) or -1
    370    if no interrupt can be serviced.  */
    371 int
    372 interrupts_get_current (struct interrupts *interrupts)
    373 {
    374   int i;
    375 
    376   if (interrupts->pending_mask == 0)
    377     return -1;
    378 
    379   /* SWI and illegal instructions are simulated by an interrupt.
    380      They are not maskable.  */
    381   if (interrupts->pending_mask & (1 << M6811_INT_SWI))
    382     {
    383       interrupts->pending_mask &= ~(1 << M6811_INT_SWI);
    384       return M6811_INT_SWI;
    385     }
    386   if (interrupts->pending_mask & (1 << M6811_INT_ILLEGAL))
    387     {
    388       interrupts->pending_mask &= ~(1 << M6811_INT_ILLEGAL);
    389       return M6811_INT_ILLEGAL;
    390     }
    391 
    392   /* If there is a non maskable interrupt, go for it (unless we are masked
    393      by the X-bit.  */
    394   if (interrupts->pending_mask & (1 << M6811_INT_XIRQ))
    395     {
    396       if (cpu_get_ccr_X (interrupts->cpu) == 0)
    397 	{
    398 	  interrupts->pending_mask &= ~(1 << M6811_INT_XIRQ);
    399 	  return M6811_INT_XIRQ;
    400 	}
    401       return -1;
    402     }
    403 
    404   /* Interrupts are masked, do nothing.  */
    405   if (cpu_get_ccr_I (interrupts->cpu) == 1)
    406     {
    407       return -1;
    408     }
    409 
    410   /* Returns the first interrupt number which is pending.
    411      The interrupt priority is specified by the table `interrupt_order'.
    412      For these interrupts, the pending mask is cleared when the program
    413      performs some actions on the corresponding device.  If the device
    414      is not reset, the interrupt remains and will be re-raised when
    415      we return from the interrupt (see 68HC11 pink book).  */
    416   for (i = 0; i < M6811_INT_NUMBER; i++)
    417     {
    418       enum M6811_INT int_number = interrupts->interrupt_order[i];
    419 
    420       if (interrupts->pending_mask & (1 << int_number))
    421 	{
    422 	  return int_number;
    423 	}
    424     }
    425   return -1;
    426 }
    427 
    428 
    429 /* Process the current interrupt if there is one.  This operation must
    430    be called after each instruction to handle the interrupts.  If interrupts
    431    are masked, it does nothing.  */
    432 int
    433 interrupts_process (struct interrupts *interrupts)
    434 {
    435   int id;
    436   uint8_t ccr;
    437 
    438   /* See if interrupts are enabled/disabled and keep track of the
    439      number of cycles the interrupts are masked.  Such information is
    440      then reported by the info command.  */
    441   ccr = cpu_get_ccr (interrupts->cpu);
    442   if (ccr & M6811_I_BIT)
    443     {
    444       if (interrupts->start_mask_cycle < 0)
    445         interrupts->start_mask_cycle = cpu_current_cycle (interrupts->cpu);
    446     }
    447   else if (interrupts->start_mask_cycle >= 0
    448            && (ccr & M6811_I_BIT) == 0)
    449     {
    450       int64_t t = cpu_current_cycle (interrupts->cpu);
    451 
    452       t -= interrupts->start_mask_cycle;
    453       if (t < interrupts->min_mask_cycles)
    454         interrupts->min_mask_cycles = t;
    455       if (t > interrupts->max_mask_cycles)
    456         interrupts->max_mask_cycles = t;
    457       interrupts->start_mask_cycle = -1;
    458       interrupts->last_mask_cycles = t;
    459     }
    460   if (ccr & M6811_X_BIT)
    461     {
    462       if (interrupts->xirq_start_mask_cycle < 0)
    463         interrupts->xirq_start_mask_cycle
    464 	  = cpu_current_cycle (interrupts->cpu);
    465     }
    466   else if (interrupts->xirq_start_mask_cycle >= 0
    467            && (ccr & M6811_X_BIT) == 0)
    468     {
    469       int64_t t = cpu_current_cycle (interrupts->cpu);
    470 
    471       t -= interrupts->xirq_start_mask_cycle;
    472       if (t < interrupts->xirq_min_mask_cycles)
    473         interrupts->xirq_min_mask_cycles = t;
    474       if (t > interrupts->xirq_max_mask_cycles)
    475         interrupts->xirq_max_mask_cycles = t;
    476       interrupts->xirq_start_mask_cycle = -1;
    477       interrupts->xirq_last_mask_cycles = t;
    478     }
    479 
    480   id = interrupts_get_current (interrupts);
    481   if (id >= 0)
    482     {
    483       uint16_t addr;
    484       struct interrupt_history *h;
    485 
    486       /* Implement the breakpoint-on-interrupt.  */
    487       if (interrupts->interrupts[id].stop_mode & SIM_STOP_WHEN_TAKEN)
    488         {
    489           sim_io_printf (CPU_STATE (interrupts->cpu),
    490                          "Interrupt %s will be handled\n",
    491                          interrupt_names[id]);
    492           sim_engine_halt (CPU_STATE (interrupts->cpu),
    493                            interrupts->cpu,
    494                            0, cpu_get_pc (interrupts->cpu),
    495                            sim_stopped,
    496                            SIM_SIGTRAP);
    497         }
    498 
    499       cpu_push_all (interrupts->cpu);
    500       addr = memory_read16 (interrupts->cpu,
    501                             interrupts->vectors_addr + id * 2);
    502       cpu_call (interrupts->cpu, addr);
    503 
    504       /* Now, protect from nested interrupts.  */
    505       if (id == M6811_INT_XIRQ)
    506 	{
    507 	  cpu_set_ccr_X (interrupts->cpu, 1);
    508 	}
    509       else
    510 	{
    511 	  cpu_set_ccr_I (interrupts->cpu, 1);
    512 	}
    513 
    514       /* Update the interrupt history table.  */
    515       h = &interrupts->interrupts_history[interrupts->history_index];
    516       h->type = id;
    517       h->taken_cycle = cpu_current_cycle (interrupts->cpu);
    518       h->raised_cycle = interrupts->interrupts[id].cpu_cycle;
    519 
    520       if (interrupts->history_index >= MAX_INT_HISTORY-1)
    521         interrupts->history_index = 0;
    522       else
    523         interrupts->history_index++;
    524 
    525       interrupts->nb_interrupts_raised++;
    526       cpu_add_cycles (interrupts->cpu, 14);
    527       return 1;
    528     }
    529   return 0;
    530 }
    531 
    532 void
    533 interrupts_raise (struct interrupts *interrupts, enum M6811_INT number)
    534 {
    535   interrupts->pending_mask |= (1 << number);
    536   interrupts->nb_interrupts_raised ++;
    537 }
    538 
    539 void
    540 interrupts_info (SIM_DESC sd, struct interrupts *interrupts)
    541 {
    542   int64_t t, prev_interrupt;
    543   int i;
    544 
    545   sim_io_printf (sd, "Interrupts Info:\n");
    546   sim_io_printf (sd, "  Interrupts raised: %lu\n",
    547                  interrupts->nb_interrupts_raised);
    548 
    549   if (interrupts->start_mask_cycle >= 0)
    550     {
    551       t = cpu_current_cycle (interrupts->cpu);
    552 
    553       t -= interrupts->start_mask_cycle;
    554       if (t > interrupts->max_mask_cycles)
    555         interrupts->max_mask_cycles = t;
    556 
    557       sim_io_printf (sd, "  Current interrupts masked sequence:   %s\n",
    558                      cycle_to_string (interrupts->cpu, t,
    559                                       PRINT_TIME | PRINT_CYCLE));
    560     }
    561   t = interrupts->min_mask_cycles == CYCLES_MAX ?
    562     interrupts->max_mask_cycles :
    563     interrupts->min_mask_cycles;
    564   sim_io_printf (sd, "  Shortest interrupts masked sequence:  %s\n",
    565                  cycle_to_string (interrupts->cpu, t,
    566                                   PRINT_TIME | PRINT_CYCLE));
    567 
    568   t = interrupts->max_mask_cycles;
    569   sim_io_printf (sd, "  Longest interrupts masked sequence:   %s\n",
    570                  cycle_to_string (interrupts->cpu, t,
    571                                   PRINT_TIME | PRINT_CYCLE));
    572 
    573   t = interrupts->last_mask_cycles;
    574   sim_io_printf (sd, "  Last interrupts masked sequence:      %s\n",
    575                  cycle_to_string (interrupts->cpu, t,
    576                                   PRINT_TIME | PRINT_CYCLE));
    577 
    578   if (interrupts->xirq_start_mask_cycle >= 0)
    579     {
    580       t = cpu_current_cycle (interrupts->cpu);
    581 
    582       t -= interrupts->xirq_start_mask_cycle;
    583       if (t > interrupts->xirq_max_mask_cycles)
    584         interrupts->xirq_max_mask_cycles = t;
    585 
    586       sim_io_printf (sd, "  XIRQ Current interrupts masked sequence: %s\n",
    587                      cycle_to_string (interrupts->cpu, t,
    588                                       PRINT_TIME | PRINT_CYCLE));
    589     }
    590 
    591   t = interrupts->xirq_min_mask_cycles == CYCLES_MAX ?
    592     interrupts->xirq_max_mask_cycles :
    593     interrupts->xirq_min_mask_cycles;
    594   sim_io_printf (sd, "  XIRQ Min interrupts masked sequence:  %s\n",
    595                  cycle_to_string (interrupts->cpu, t,
    596                                   PRINT_TIME | PRINT_CYCLE));
    597 
    598   t = interrupts->xirq_max_mask_cycles;
    599   sim_io_printf (sd, "  XIRQ Max interrupts masked sequence:  %s\n",
    600                  cycle_to_string (interrupts->cpu, t,
    601                                   PRINT_TIME | PRINT_CYCLE));
    602 
    603   t = interrupts->xirq_last_mask_cycles;
    604   sim_io_printf (sd, "  XIRQ Last interrupts masked sequence: %s\n",
    605                  cycle_to_string (interrupts->cpu, t,
    606                                   PRINT_TIME | PRINT_CYCLE));
    607 
    608   if (interrupts->pending_mask)
    609     {
    610       sim_io_printf (sd, "  Pending interrupts : ");
    611       for (i = 0; i < M6811_INT_NUMBER; i++)
    612         {
    613           enum M6811_INT int_number = interrupts->interrupt_order[i];
    614 
    615           if (interrupts->pending_mask & (1 << int_number))
    616             {
    617               sim_io_printf (sd, "%s ", interrupt_names[int_number]);
    618             }
    619         }
    620       sim_io_printf (sd, "\n");
    621     }
    622 
    623   prev_interrupt = 0;
    624   sim_io_printf (sd, "N  Interrupt     Cycle Taken         Latency"
    625                  "   Delta between interrupts\n");
    626   for (i = 0; i < MAX_INT_HISTORY; i++)
    627     {
    628       int which;
    629       struct interrupt_history *h;
    630       int64_t dt;
    631 
    632       which = interrupts->history_index - i - 1;
    633       if (which < 0)
    634         which += MAX_INT_HISTORY;
    635       h = &interrupts->interrupts_history[which];
    636       if (h->taken_cycle == 0)
    637         break;
    638 
    639       dt = h->taken_cycle - h->raised_cycle;
    640       sim_io_printf (sd, "%2d %-9.9s %15.15s ", i,
    641                      interrupt_names[h->type],
    642                      cycle_to_string (interrupts->cpu, h->taken_cycle, 0));
    643       sim_io_printf (sd, "%15.15s",
    644                      cycle_to_string (interrupts->cpu, dt, 0));
    645       if (prev_interrupt)
    646         {
    647           dt = prev_interrupt - h->taken_cycle;
    648           sim_io_printf (sd, " %s",
    649                          cycle_to_string (interrupts->cpu, dt, PRINT_TIME));
    650         }
    651       sim_io_printf (sd, "\n");
    652       prev_interrupt = h->taken_cycle;
    653     }
    654 }
    655