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