This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / sim / m68hc11 / interrupts.c
1 /* interrupts.c -- 68HC11 Interrupts Emulation
2    Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3    Written by Stephane Carrez (stcarrez@worldnet.fr)
4
5 This file is part of GDB, GAS, and the GNU binutils.
6
7 GDB, GAS, and the GNU binutils are free software; you can redistribute
8 them and/or modify them under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either version
10 1, or (at your option) any later version.
11
12 GDB, GAS, and the GNU binutils are distributed in the hope that they
13 will be useful, but WITHOUT ANY WARRANTY; without even the implied
14 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
15 the 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 file; see the file COPYING.  If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #include "sim-main.h"
22 #include "sim-options.h"
23
24 static 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 };
59
60 struct 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 },
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},
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
98 enum
99 {
100   OPTION_INTERRUPT_INFO = OPTION_START,
101   OPTION_INTERRUPT_CATCH,
102   OPTION_INTERRUPT_CLEAR
103 };
104
105 static DECLARE_OPTION_HANDLER (interrupt_option_handler);
106
107 static 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.  */
126 void
127 interrupts_initialize (SIM_DESC sd, struct _sim_cpu *proc)
128 {
129   struct interrupts *interrupts = &proc->cpu_interrupts;
130   
131   interrupts->cpu          = proc;
132
133   sim_add_option_table (sd, 0, interrupt_options);
134 }
135
136 /* Initialize the interrupts of the processor.  */
137 void
138 interrupts_reset (struct interrupts *interrupts)
139 {
140   int i;
141   
142   interrupts->pending_mask = 0;
143   if (interrupts->cpu->cpu_mode & M6811_SMOD)
144     interrupts->vectors_addr = 0xbfc0;
145   else
146     interrupts->vectors_addr = 0xffc0;
147   interrupts->nb_interrupts_raised = 0;
148   interrupts->min_mask_cycles = CYCLES_MAX;
149   interrupts->max_mask_cycles = 0;
150   interrupts->last_mask_cycles = 0;
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;
155   interrupts->xirq_last_mask_cycles = 0;
156   
157   for (i = 0; i < M6811_INT_NUMBER; i++)
158     {
159       interrupts->interrupt_order[i] = i;
160     }
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
171 static int
172 find_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;
182 }
183
184 static SIM_RC
185 interrupt_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 }
263
264 /* Update the mask of pending interrupts.  This operation must be called
265    when the state of some 68HC11 IO register changes.  It looks the
266    different registers that indicate a pending interrupt (timer, SCI, SPI,
267    ...) and records the interrupt if it's there and enabled.  */
268 void
269 interrupts_update_pending (struct interrupts *interrupts)
270 {
271   int i;
272   uint8 *ioregs;
273   unsigned long clear_mask;
274   unsigned long set_mask;
275
276   clear_mask = 0;
277   set_mask = 0;
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))
290             {
291               /* Disable it.  */
292               clear_mask |= (1 << idef->int_number);
293               continue;
294             }
295         }
296
297       /* Interrupt is enabled, see if it's there.  */
298       data = ioregs[idef->int_paddr];
299       if (!(data & idef->int_mask))
300         {
301           /* Disable it.  */
302           clear_mask |= (1 << idef->int_number);
303           continue;
304         }
305
306       /* Ok, raise it.  */
307       set_mask |= (1 << idef->int_number);
308     }
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;
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     }
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.  */
349 int
350 interrupts_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.
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).  */
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         {
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.  */
410 int
411 interrupts_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;
436       interrupts->last_mask_cycles = t;
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;
455       interrupts->xirq_last_mask_cycles = t;
456     }
457
458   id = interrupts_get_current (interrupts);
459   if (id >= 0)
460     {
461       uint16 addr;
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
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
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
503       interrupts->nb_interrupts_raised++;
504       cpu_add_cycles (interrupts->cpu, 14);
505       return 1;
506     }
507   return 0;
508 }
509
510 void
511 interrupts_raise (struct interrupts *interrupts, enum M6811_INT number)
512 {
513   interrupts->pending_mask |= (1 << number);
514   interrupts->nb_interrupts_raised ++;
515 }
516
517 void
518 interrupts_info (SIM_DESC sd, struct interrupts *interrupts)
519 {
520   signed64 t;
521   int i;
522   
523   sim_io_printf (sd, "Interrupts Info:\n");
524   sim_io_printf (sd, "  Interrupts raised: %lu\n",
525                  interrupts->nb_interrupts_raised);
526
527   if (interrupts->start_mask_cycle >= 0)
528     {
529       t = cpu_current_cycle (interrupts->cpu);
530
531       t -= interrupts->start_mask_cycle;
532       if (t > interrupts->max_mask_cycles)
533         interrupts->max_mask_cycles = t;
534
535       sim_io_printf (sd, "  Current interrupts masked sequence:   %s\n",
536                      cycle_to_string (interrupts->cpu, t));
537     }
538   t = interrupts->min_mask_cycles == CYCLES_MAX ?
539     interrupts->max_mask_cycles :
540     interrupts->min_mask_cycles;
541   sim_io_printf (sd, "  Shortest interrupts masked sequence:  %s\n",
542                  cycle_to_string (interrupts->cpu, t));
543
544   t = interrupts->max_mask_cycles;
545   sim_io_printf (sd, "  Longest interrupts masked sequence:   %s\n",
546                  cycle_to_string (interrupts->cpu, t));
547
548   t = interrupts->last_mask_cycles;
549   sim_io_printf (sd, "  Last interrupts masked sequence:      %s\n",
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
564   t = interrupts->xirq_min_mask_cycles == CYCLES_MAX ?
565     interrupts->xirq_max_mask_cycles :
566     interrupts->xirq_min_mask_cycles;
567   sim_io_printf (sd, "  XIRQ Min interrupts masked sequence:  %s\n",
568                  cycle_to_string (interrupts->cpu, t));
569
570   t = interrupts->xirq_max_mask_cycles;
571   sim_io_printf (sd, "  XIRQ Max interrupts masked sequence:  %s\n",
572                  cycle_to_string (interrupts->cpu, t));
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));
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     }
613 }