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