* sim-main.h: Define cycle_to_string.
[deliverable/binutils-gdb.git] / sim / m68hc11 / interrupts.c
CommitLineData
e0709f50
AC
1/* interrupts.c -- 68HC11 Interrupts Emulation
2 Copyright 1999, 2000 Free Software Foundation, Inc.
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"
22
23struct interrupt_def idefs[] = {
24 /* Serial interrupts. */
25 { M6811_INT_SCI, M6811_SCSR, M6811_TDRE, M6811_SCCR2, M6811_TIE },
26 { M6811_INT_SCI, M6811_SCSR, M6811_TC, M6811_SCCR2, M6811_TCIE },
27 { M6811_INT_SCI, M6811_SCSR, M6811_RDRF, M6811_SCCR2, M6811_RIE },
28 { M6811_INT_SCI, M6811_SCSR, M6811_IDLE, M6811_SCCR2, M6811_ILIE },
29
30 /* SPI interrupts. */
31 { M6811_INT_SPI, M6811_SPSR, M6811_SPIF, M6811_SPCR, M6811_SPIE },
32
33 /* Realtime interrupts. */
34 { M6811_INT_TCTN, M6811_TFLG2, M6811_TOF, M6811_TMSK2, M6811_TOI },
35 { M6811_INT_RT, M6811_TFLG2, M6811_RTIF, M6811_TMSK2, M6811_RTII },
36
37 /* Output compare interrupts. */
38 { M6811_INT_OUTCMP1, M6811_TFLG1, M6811_OC1F, M6811_TMSK1, M6811_OC1I },
39 { M6811_INT_OUTCMP2, M6811_TFLG1, M6811_OC2F, M6811_TMSK1, M6811_OC2I },
40 { M6811_INT_OUTCMP3, M6811_TFLG1, M6811_OC3F, M6811_TMSK1, M6811_OC3I },
41 { M6811_INT_OUTCMP4, M6811_TFLG1, M6811_OC4F, M6811_TMSK1, M6811_OC4I },
42 { M6811_INT_OUTCMP5, M6811_TFLG1, M6811_OC5F, M6811_TMSK1, M6811_OC5I },
43
44 /* Input compare interrupts. */
45 { M6811_INT_INCMP1, M6811_TFLG1, M6811_IC1F, M6811_TMSK1, M6811_IC1I },
46 { M6811_INT_INCMP2, M6811_TFLG1, M6811_IC2F, M6811_TMSK1, M6811_IC2I },
47 { M6811_INT_INCMP3, M6811_TFLG1, M6811_IC3F, M6811_TMSK1, M6811_IC3I },
48#if 0
49 { M6811_INT_COPRESET, M6811_CONFIG, M6811_NOCOP, 0, 0 },
50 { M6811_INT_COPFAIL, M6811_CONFIG, M6811_NOCOP, 0, 0 }
51#endif
52};
53
54#define TableSize(X) (sizeof X / sizeof(X[0]))
55#define CYCLES_MAX ((((signed64) 1) << 62) - 1)
56
57/* Initialize the interrupts of the processor. */
58int
59interrupts_initialize (struct _sim_cpu *proc)
60{
61 struct interrupts *interrupts = &proc->cpu_interrupts;
62 int i;
63
64 interrupts->cpu = proc;
65 interrupts->pending_mask = 0;
66 interrupts->vectors_addr = 0xffc0;
67 interrupts->nb_interrupts_raised = 0;
68 interrupts->min_mask_cycles = CYCLES_MAX;
69 interrupts->max_mask_cycles = 0;
70 interrupts->start_mask_cycle = -1;
71 interrupts->xirq_start_mask_cycle = -1;
72 interrupts->xirq_max_mask_cycles = 0;
73 interrupts->xirq_min_mask_cycles = CYCLES_MAX;
74
75 for (i = 0; i < M6811_INT_NUMBER; i++)
76 {
77 interrupts->interrupt_order[i] = i;
78 }
79 return 0;
80}
81
82
83/* Update the mask of pending interrupts. This operation must be called
84 when the state of some 68HC11 IO registers changes. It looks the
85 different registers that indicate a pending interrupt (timer, SCI, SPI,
86 ...) and records the interrupt if it's there and enabled. */
87void
88interrupts_update_pending (struct interrupts *interrupts)
89{
90 int i;
91 uint8 *ioregs;
92
93 ioregs = &interrupts->cpu->ios[0];
94
95 for (i = 0; i < TableSize(idefs); i++)
96 {
97 struct interrupt_def *idef = &idefs[i];
98 uint8 data;
99
100 /* Look if the interrupt is enabled. */
101 if (idef->enable_paddr)
102 {
103 data = ioregs[idef->enable_paddr];
104 if (!(data & idef->enabled_mask))
105 continue;
106 }
107
108 /* Interrupt is enabled, see if it's there. */
109 data = ioregs[idef->int_paddr];
110 if (!(data & idef->int_mask))
111 continue;
112
113 /* Ok, raise it. */
114 interrupts->pending_mask |= (1 << idef->int_number);
115 }
116}
117
118
119/* Finds the current active and non-masked interrupt.
120 Returns the interrupt number (index in the vector table) or -1
121 if no interrupt can be serviced. */
122int
123interrupts_get_current (struct interrupts *interrupts)
124{
125 int i;
126
127 if (interrupts->pending_mask == 0)
128 return -1;
129
130 /* SWI and illegal instructions are simulated by an interrupt.
131 They are not maskable. */
132 if (interrupts->pending_mask & (1 << M6811_INT_SWI))
133 {
134 interrupts->pending_mask &= ~(1 << M6811_INT_SWI);
135 return M6811_INT_SWI;
136 }
137 if (interrupts->pending_mask & (1 << M6811_INT_ILLEGAL))
138 {
139 interrupts->pending_mask &= ~(1 << M6811_INT_ILLEGAL);
140 return M6811_INT_ILLEGAL;
141 }
142
143 /* If there is a non maskable interrupt, go for it (unless we are masked
144 by the X-bit. */
145 if (interrupts->pending_mask & (1 << M6811_INT_XIRQ))
146 {
147 if (cpu_get_ccr_X (interrupts->cpu) == 0)
148 {
149 interrupts->pending_mask &= ~(1 << M6811_INT_XIRQ);
150 return M6811_INT_XIRQ;
151 }
152 return -1;
153 }
154
155 /* Interrupts are masked, do nothing. */
156 if (cpu_get_ccr_I (interrupts->cpu) == 1)
157 {
158 return -1;
159 }
160
161 /* Returns the first interrupt number which is pending.
162 The interrupt priority is specified by the table `interrupt_order'. */
163 for (i = 0; i < M6811_INT_NUMBER; i++)
164 {
165 enum M6811_INT int_number = interrupts->interrupt_order[i];
166
167 if (interrupts->pending_mask & (1 << int_number))
168 {
169 interrupts->pending_mask &= ~(1 << int_number);
170 return int_number;
171 }
172 }
173 return -1;
174}
175
176
177/* Process the current interrupt if there is one. This operation must
178 be called after each instruction to handle the interrupts. If interrupts
179 are masked, it does nothing. */
180int
181interrupts_process (struct interrupts *interrupts)
182{
183 int id;
184 uint8 ccr;
185
186 /* See if interrupts are enabled/disabled and keep track of the
187 number of cycles the interrupts are masked. Such information is
188 then reported by the info command. */
189 ccr = cpu_get_ccr (interrupts->cpu);
190 if (ccr & M6811_I_BIT)
191 {
192 if (interrupts->start_mask_cycle < 0)
193 interrupts->start_mask_cycle = cpu_current_cycle (interrupts->cpu);
194 }
195 else if (interrupts->start_mask_cycle >= 0
196 && (ccr & M6811_I_BIT) == 0)
197 {
198 signed64 t = cpu_current_cycle (interrupts->cpu);
199
200 t -= interrupts->start_mask_cycle;
201 if (t < interrupts->min_mask_cycles)
202 interrupts->min_mask_cycles = t;
203 if (t > interrupts->max_mask_cycles)
204 interrupts->max_mask_cycles = t;
205 interrupts->start_mask_cycle = -1;
206 }
207 if (ccr & M6811_X_BIT)
208 {
209 if (interrupts->xirq_start_mask_cycle < 0)
210 interrupts->xirq_start_mask_cycle
211 = cpu_current_cycle (interrupts->cpu);
212 }
213 else if (interrupts->xirq_start_mask_cycle >= 0
214 && (ccr & M6811_X_BIT) == 0)
215 {
216 signed64 t = cpu_current_cycle (interrupts->cpu);
217
218 t -= interrupts->xirq_start_mask_cycle;
219 if (t < interrupts->xirq_min_mask_cycles)
220 interrupts->xirq_min_mask_cycles = t;
221 if (t > interrupts->xirq_max_mask_cycles)
222 interrupts->xirq_max_mask_cycles = t;
223 interrupts->xirq_start_mask_cycle = -1;
224 }
225
226 id = interrupts_get_current (interrupts);
227 if (id >= 0)
228 {
229 uint16 addr;
230
231 cpu_push_all (interrupts->cpu);
232 addr = memory_read16 (interrupts->cpu,
233 interrupts->vectors_addr + id * 2);
234 cpu_call (interrupts->cpu, addr);
235
236 /* Now, protect from nested interrupts. */
237 if (id == M6811_INT_XIRQ)
238 {
239 cpu_set_ccr_X (interrupts->cpu, 1);
240 }
241 else
242 {
243 cpu_set_ccr_I (interrupts->cpu, 1);
244 }
245
246 interrupts->nb_interrupts_raised++;
247 cpu_add_cycles (interrupts->cpu, 14);
248 return 1;
249 }
250 return 0;
251}
252
253void
254interrupts_raise (struct interrupts *interrupts, enum M6811_INT number)
255{
256 interrupts->pending_mask |= (1 << number);
257 interrupts->nb_interrupts_raised ++;
258}
259
260
261
262void
263interrupts_info (SIM_DESC sd, struct interrupts *interrupts)
264{
2990a9f4
SC
265 signed64 t;
266
e0709f50
AC
267 if (interrupts->start_mask_cycle >= 0)
268 {
2990a9f4 269 t = cpu_current_cycle (interrupts->cpu);
e0709f50
AC
270
271 t -= interrupts->start_mask_cycle;
272 if (t > interrupts->max_mask_cycles)
273 interrupts->max_mask_cycles = t;
274 }
275 if (interrupts->xirq_start_mask_cycle >= 0)
276 {
2990a9f4 277 t = cpu_current_cycle (interrupts->cpu);
e0709f50
AC
278
279 t -= interrupts->xirq_start_mask_cycle;
280 if (t > interrupts->xirq_max_mask_cycles)
281 interrupts->xirq_max_mask_cycles = t;
282 }
283
284 sim_io_printf (sd, "Interrupts Info:\n");
285 sim_io_printf (sd, " Interrupts raised: %lu\n",
286 interrupts->nb_interrupts_raised);
2990a9f4
SC
287
288 t = interrupts->min_mask_cycles == CYCLES_MAX ?
289 interrupts->max_mask_cycles :
290 interrupts->min_mask_cycles;
291 sim_io_printf (sd, " Shortest interrupts masked sequence: %s\n",
292 cycle_to_string (interrupts->cpu, t));
293
294 t = interrupts->max_mask_cycles;
295 sim_io_printf (sd, " Longest interrupts masked sequence: %s\n",
296 cycle_to_string (interrupts->cpu, t));
297
298 t = interrupts->xirq_min_mask_cycles == CYCLES_MAX ?
299 interrupts->xirq_max_mask_cycles :
300 interrupts->xirq_min_mask_cycles;
301 sim_io_printf (sd, " XIRQ Min interrupts masked sequence: %s\n",
302 cycle_to_string (interrupts->cpu, t));
303
304 t = interrupts->xirq_max_mask_cycles;
305 sim_io_printf (sd, " XIRQ Max interrupts masked sequence: %s\n",
306 cycle_to_string (interrupts->cpu, t));
e0709f50 307}
This page took 0.045287 seconds and 4 git commands to generate.