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