1 /* interrupts.c -- 68HC11 Interrupts Emulation
2 Copyright 1999-2023 Free Software Foundation, Inc.
3 Written by Stephane Carrez (stcarrez@nerim.fr)
5 This file is part of GDB, GAS, and the GNU binutils.
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.
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.
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/>. */
20 /* This must come before any other includes. */
26 #include "sim-options.h"
27 #include "sim-signal.h"
29 #include "m68hc11-sim.h"
31 static const char *interrupt_names
[] = {
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
},
75 { M6811_INT_SPI
, M6811_SPSR
, M6811_SPIF
, M6811_SPCR
, M6811_SPIE
},
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
},
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
},
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
},
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
},
97 { M6811_INT_COPRESET
, M6811_CONFIG
, M6811_NOCOP
, 0, 0 },
98 { M6811_INT_COPFAIL
, M6811_CONFIG
, M6811_NOCOP
, 0, 0 }
102 #define CYCLES_MAX ((((int64_t) 1) << 62) - 1)
106 OPTION_INTERRUPT_INFO
= OPTION_START
,
107 OPTION_INTERRUPT_CATCH
,
108 OPTION_INTERRUPT_CLEAR
111 static DECLARE_OPTION_HANDLER (interrupt_option_handler
);
113 static const OPTION interrupt_options
[] =
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
},
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
},
128 { {NULL
, no_argument
, NULL
, 0}, '\0', NULL
, NULL
, NULL
}
131 /* Initialize the interrupts module. */
133 interrupts_initialize (SIM_DESC sd
, sim_cpu
*cpu
)
135 struct interrupts
*interrupts
= &M68HC11_SIM_CPU (cpu
)->cpu_interrupts
;
137 interrupts
->cpu
= cpu
;
139 sim_add_option_table (sd
, 0, interrupt_options
);
142 /* Initialize the interrupts of the processor. */
144 interrupts_reset (struct interrupts
*interrupts
)
146 sim_cpu
*cpu
= interrupts
->cpu
;
147 struct m68hc11_sim_cpu
*m68hc11_cpu
= M68HC11_SIM_CPU (cpu
);
150 interrupts
->pending_mask
= 0;
151 if (m68hc11_cpu
->cpu_mode
& M6811_SMOD
)
152 interrupts
->vectors_addr
= 0xbfc0;
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;
165 for (i
= 0; i
< M6811_INT_NUMBER
; i
++)
167 interrupts
->interrupt_order
[i
] = i
;
170 /* Clear the interrupt history table. */
171 interrupts
->history_index
= 0;
172 memset (interrupts
->interrupts_history
, 0,
173 sizeof (interrupts
->interrupts_history
));
175 memset (interrupts
->interrupts
, 0,
176 sizeof (interrupts
->interrupts
));
178 /* In bootstrap mode, initialize the vector table to point
179 to the RAM location. */
180 if (m68hc11_cpu
->cpu_mode
== M6811_SMOD
)
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
++)
186 memory_write16 (cpu
, addr
, vector
);
194 find_interrupt (const char *name
)
199 for (i
= 0; i
< M6811_INT_NUMBER
; i
++)
200 if (strcasecmp (name
, interrupt_names
[i
]) == 0)
207 interrupt_option_handler (SIM_DESC sd
, sim_cpu
*cpu
,
208 int opt
, char *arg
, int is_command
)
213 struct interrupts
*interrupts
;
216 cpu
= STATE_CPU (sd
, 0);
218 interrupts
= &M68HC11_SIM_CPU (cpu
)->cpu_interrupts
;
221 case OPTION_INTERRUPT_INFO
:
222 for (id
= 0; id
< M6811_INT_NUMBER
; id
++)
224 sim_io_eprintf (sd
, "%-10.10s ", interrupt_names
[id
]);
225 switch (interrupts
->interrupts
[id
].stop_mode
)
227 case SIM_STOP_WHEN_RAISED
:
228 sim_io_eprintf (sd
, "catch raised ");
231 case SIM_STOP_WHEN_TAKEN
:
232 sim_io_eprintf (sd
, "catch taken ");
235 case SIM_STOP_WHEN_RAISED
| SIM_STOP_WHEN_TAKEN
:
236 sim_io_eprintf (sd
, "catch all ");
240 sim_io_eprintf (sd
, " ");
243 sim_io_eprintf (sd
, "%ld\n",
244 interrupts
->interrupts
[id
].raised_count
);
248 case OPTION_INTERRUPT_CATCH
:
249 p
= strchr (arg
, ',');
253 mode
= SIM_STOP_WHEN_RAISED
;
254 id
= find_interrupt (arg
);
256 sim_io_eprintf (sd
, "Interrupt name not recognized: %s\n", arg
);
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
;
266 sim_io_eprintf (sd
, "Invalid argument: %s\n", p
);
270 interrupts
->interrupts
[id
].stop_mode
= mode
;
273 case OPTION_INTERRUPT_CLEAR
:
274 mode
= SIM_STOP_WHEN_RAISED
;
275 id
= find_interrupt (arg
);
277 sim_io_eprintf (sd
, "Interrupt name not recognized: %s\n", arg
);
279 interrupts
->interrupts
[id
].stop_mode
= 0;
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. */
291 interrupts_update_pending (struct interrupts
*interrupts
)
295 unsigned long clear_mask
;
296 unsigned long set_mask
;
300 ioregs
= &M68HC11_SIM_CPU (interrupts
->cpu
)->ios
[0];
302 for (i
= 0; i
< ARRAY_SIZE (idefs
); i
++)
304 struct interrupt_def
*idef
= &idefs
[i
];
307 /* Look if the interrupt is enabled. */
308 if (idef
->enable_paddr
)
310 data
= ioregs
[idef
->enable_paddr
];
311 if (!(data
& idef
->enabled_mask
))
314 clear_mask
|= (1 << idef
->int_number
);
319 /* Interrupt is enabled, see if it's there. */
320 data
= ioregs
[idef
->int_paddr
];
321 if (!(data
& idef
->int_mask
))
324 clear_mask
|= (1 << idef
->int_number
);
329 set_mask
|= (1 << idef
->int_number
);
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
;
337 /* Keep track of when the interrupt is raised by the device.
338 Also implements the breakpoint-on-interrupt. */
341 int64_t cycle
= cpu_current_cycle (interrupts
->cpu
);
344 for (i
= 0; i
< M6811_INT_NUMBER
; i
++)
346 if (!(set_mask
& (1 << i
)))
349 interrupts
->interrupts
[i
].cpu_cycle
= cycle
;
350 if (interrupts
->interrupts
[i
].stop_mode
& SIM_STOP_WHEN_RAISED
)
353 sim_io_printf (CPU_STATE (interrupts
->cpu
),
354 "Interrupt %s raised\n",
359 sim_engine_halt (CPU_STATE (interrupts
->cpu
),
361 0, cpu_get_pc (interrupts
->cpu
),
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. */
372 interrupts_get_current (struct interrupts
*interrupts
)
376 if (interrupts
->pending_mask
== 0)
379 /* SWI and illegal instructions are simulated by an interrupt.
380 They are not maskable. */
381 if (interrupts
->pending_mask
& (1 << M6811_INT_SWI
))
383 interrupts
->pending_mask
&= ~(1 << M6811_INT_SWI
);
384 return M6811_INT_SWI
;
386 if (interrupts
->pending_mask
& (1 << M6811_INT_ILLEGAL
))
388 interrupts
->pending_mask
&= ~(1 << M6811_INT_ILLEGAL
);
389 return M6811_INT_ILLEGAL
;
392 /* If there is a non maskable interrupt, go for it (unless we are masked
394 if (interrupts
->pending_mask
& (1 << M6811_INT_XIRQ
))
396 if (cpu_get_ccr_X (interrupts
->cpu
) == 0)
398 interrupts
->pending_mask
&= ~(1 << M6811_INT_XIRQ
);
399 return M6811_INT_XIRQ
;
404 /* Interrupts are masked, do nothing. */
405 if (cpu_get_ccr_I (interrupts
->cpu
) == 1)
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
++)
418 enum M6811_INT int_number
= interrupts
->interrupt_order
[i
];
420 if (interrupts
->pending_mask
& (1 << int_number
))
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. */
433 interrupts_process (struct interrupts
*interrupts
)
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
)
444 if (interrupts
->start_mask_cycle
< 0)
445 interrupts
->start_mask_cycle
= cpu_current_cycle (interrupts
->cpu
);
447 else if (interrupts
->start_mask_cycle
>= 0
448 && (ccr
& M6811_I_BIT
) == 0)
450 int64_t t
= cpu_current_cycle (interrupts
->cpu
);
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
;
460 if (ccr
& M6811_X_BIT
)
462 if (interrupts
->xirq_start_mask_cycle
< 0)
463 interrupts
->xirq_start_mask_cycle
464 = cpu_current_cycle (interrupts
->cpu
);
466 else if (interrupts
->xirq_start_mask_cycle
>= 0
467 && (ccr
& M6811_X_BIT
) == 0)
469 int64_t t
= cpu_current_cycle (interrupts
->cpu
);
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
;
480 id
= interrupts_get_current (interrupts
);
484 struct interrupt_history
*h
;
486 /* Implement the breakpoint-on-interrupt. */
487 if (interrupts
->interrupts
[id
].stop_mode
& SIM_STOP_WHEN_TAKEN
)
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
),
494 0, cpu_get_pc (interrupts
->cpu
),
499 cpu_push_all (interrupts
->cpu
);
500 addr
= memory_read16 (interrupts
->cpu
,
501 interrupts
->vectors_addr
+ id
* 2);
502 cpu_call (interrupts
->cpu
, addr
);
504 /* Now, protect from nested interrupts. */
505 if (id
== M6811_INT_XIRQ
)
507 cpu_set_ccr_X (interrupts
->cpu
, 1);
511 cpu_set_ccr_I (interrupts
->cpu
, 1);
514 /* Update the interrupt history table. */
515 h
= &interrupts
->interrupts_history
[interrupts
->history_index
];
517 h
->taken_cycle
= cpu_current_cycle (interrupts
->cpu
);
518 h
->raised_cycle
= interrupts
->interrupts
[id
].cpu_cycle
;
520 if (interrupts
->history_index
>= MAX_INT_HISTORY
-1)
521 interrupts
->history_index
= 0;
523 interrupts
->history_index
++;
525 interrupts
->nb_interrupts_raised
++;
526 cpu_add_cycles (interrupts
->cpu
, 14);
533 interrupts_raise (struct interrupts
*interrupts
, enum M6811_INT number
)
535 interrupts
->pending_mask
|= (1 << number
);
536 interrupts
->nb_interrupts_raised
++;
540 interrupts_info (SIM_DESC sd
, struct interrupts
*interrupts
)
542 int64_t t
, prev_interrupt
;
545 sim_io_printf (sd
, "Interrupts Info:\n");
546 sim_io_printf (sd
, " Interrupts raised: %lu\n",
547 interrupts
->nb_interrupts_raised
);
549 if (interrupts
->start_mask_cycle
>= 0)
551 t
= cpu_current_cycle (interrupts
->cpu
);
553 t
-= interrupts
->start_mask_cycle
;
554 if (t
> interrupts
->max_mask_cycles
)
555 interrupts
->max_mask_cycles
= t
;
557 sim_io_printf (sd
, " Current interrupts masked sequence: %s\n",
558 cycle_to_string (interrupts
->cpu
, t
,
559 PRINT_TIME
| PRINT_CYCLE
));
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
));
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
));
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
));
578 if (interrupts
->xirq_start_mask_cycle
>= 0)
580 t
= cpu_current_cycle (interrupts
->cpu
);
582 t
-= interrupts
->xirq_start_mask_cycle
;
583 if (t
> interrupts
->xirq_max_mask_cycles
)
584 interrupts
->xirq_max_mask_cycles
= t
;
586 sim_io_printf (sd
, " XIRQ Current interrupts masked sequence: %s\n",
587 cycle_to_string (interrupts
->cpu
, t
,
588 PRINT_TIME
| PRINT_CYCLE
));
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
));
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
));
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
));
608 if (interrupts
->pending_mask
)
610 sim_io_printf (sd
, " Pending interrupts : ");
611 for (i
= 0; i
< M6811_INT_NUMBER
; i
++)
613 enum M6811_INT int_number
= interrupts
->interrupt_order
[i
];
615 if (interrupts
->pending_mask
& (1 << int_number
))
617 sim_io_printf (sd
, "%s ", interrupt_names
[int_number
]);
620 sim_io_printf (sd
, "\n");
624 sim_io_printf (sd
, "N Interrupt Cycle Taken Latency"
625 " Delta between interrupts\n");
626 for (i
= 0; i
< MAX_INT_HISTORY
; i
++)
629 struct interrupt_history
*h
;
632 which
= interrupts
->history_index
- i
- 1;
634 which
+= MAX_INT_HISTORY
;
635 h
= &interrupts
->interrupts_history
[which
];
636 if (h
->taken_cycle
== 0)
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));
647 dt
= prev_interrupt
- h
->taken_cycle
;
648 sim_io_printf (sd
, " %s",
649 cycle_to_string (interrupts
->cpu
, dt
, PRINT_TIME
));
651 sim_io_printf (sd
, "\n");
652 prev_interrupt
= h
->taken_cycle
;