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