Fix clearing of interrupts in 68hc11 simulator
[deliverable/binutils-gdb.git] / sim / m68hc11 / interrupts.c
1 /* interrupts.c -- 68HC11 Interrupts Emulation
2 Copyright 1999, 2000 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
23 struct 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. */
58 int
59 interrupts_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. */
87 void
88 interrupts_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 {
106 /* Disable it. */
107 interrupts->pending_mask &= ~(1 << idef->int_number);
108 continue;
109 }
110 }
111
112 /* Interrupt is enabled, see if it's there. */
113 data = ioregs[idef->int_paddr];
114 if (!(data & idef->int_mask))
115 {
116 /* Disable it. */
117 interrupts->pending_mask &= ~(1 << idef->int_number);
118 continue;
119 }
120
121 /* Ok, raise it. */
122 interrupts->pending_mask |= (1 << idef->int_number);
123 }
124 }
125
126
127 /* Finds the current active and non-masked interrupt.
128 Returns the interrupt number (index in the vector table) or -1
129 if no interrupt can be serviced. */
130 int
131 interrupts_get_current (struct interrupts *interrupts)
132 {
133 int i;
134
135 if (interrupts->pending_mask == 0)
136 return -1;
137
138 /* SWI and illegal instructions are simulated by an interrupt.
139 They are not maskable. */
140 if (interrupts->pending_mask & (1 << M6811_INT_SWI))
141 {
142 interrupts->pending_mask &= ~(1 << M6811_INT_SWI);
143 return M6811_INT_SWI;
144 }
145 if (interrupts->pending_mask & (1 << M6811_INT_ILLEGAL))
146 {
147 interrupts->pending_mask &= ~(1 << M6811_INT_ILLEGAL);
148 return M6811_INT_ILLEGAL;
149 }
150
151 /* If there is a non maskable interrupt, go for it (unless we are masked
152 by the X-bit. */
153 if (interrupts->pending_mask & (1 << M6811_INT_XIRQ))
154 {
155 if (cpu_get_ccr_X (interrupts->cpu) == 0)
156 {
157 interrupts->pending_mask &= ~(1 << M6811_INT_XIRQ);
158 return M6811_INT_XIRQ;
159 }
160 return -1;
161 }
162
163 /* Interrupts are masked, do nothing. */
164 if (cpu_get_ccr_I (interrupts->cpu) == 1)
165 {
166 return -1;
167 }
168
169 /* Returns the first interrupt number which is pending.
170 The interrupt priority is specified by the table `interrupt_order'.
171 For these interrupts, the pending mask is cleared when the program
172 performs some actions on the corresponding device. If the device
173 is not reset, the interrupt remains and will be re-raised when
174 we return from the interrupt (see 68HC11 pink book). */
175 for (i = 0; i < M6811_INT_NUMBER; i++)
176 {
177 enum M6811_INT int_number = interrupts->interrupt_order[i];
178
179 if (interrupts->pending_mask & (1 << int_number))
180 {
181 return int_number;
182 }
183 }
184 return -1;
185 }
186
187
188 /* Process the current interrupt if there is one. This operation must
189 be called after each instruction to handle the interrupts. If interrupts
190 are masked, it does nothing. */
191 int
192 interrupts_process (struct interrupts *interrupts)
193 {
194 int id;
195 uint8 ccr;
196
197 /* See if interrupts are enabled/disabled and keep track of the
198 number of cycles the interrupts are masked. Such information is
199 then reported by the info command. */
200 ccr = cpu_get_ccr (interrupts->cpu);
201 if (ccr & M6811_I_BIT)
202 {
203 if (interrupts->start_mask_cycle < 0)
204 interrupts->start_mask_cycle = cpu_current_cycle (interrupts->cpu);
205 }
206 else if (interrupts->start_mask_cycle >= 0
207 && (ccr & M6811_I_BIT) == 0)
208 {
209 signed64 t = cpu_current_cycle (interrupts->cpu);
210
211 t -= interrupts->start_mask_cycle;
212 if (t < interrupts->min_mask_cycles)
213 interrupts->min_mask_cycles = t;
214 if (t > interrupts->max_mask_cycles)
215 interrupts->max_mask_cycles = t;
216 interrupts->start_mask_cycle = -1;
217 }
218 if (ccr & M6811_X_BIT)
219 {
220 if (interrupts->xirq_start_mask_cycle < 0)
221 interrupts->xirq_start_mask_cycle
222 = cpu_current_cycle (interrupts->cpu);
223 }
224 else if (interrupts->xirq_start_mask_cycle >= 0
225 && (ccr & M6811_X_BIT) == 0)
226 {
227 signed64 t = cpu_current_cycle (interrupts->cpu);
228
229 t -= interrupts->xirq_start_mask_cycle;
230 if (t < interrupts->xirq_min_mask_cycles)
231 interrupts->xirq_min_mask_cycles = t;
232 if (t > interrupts->xirq_max_mask_cycles)
233 interrupts->xirq_max_mask_cycles = t;
234 interrupts->xirq_start_mask_cycle = -1;
235 }
236
237 id = interrupts_get_current (interrupts);
238 if (id >= 0)
239 {
240 uint16 addr;
241
242 cpu_push_all (interrupts->cpu);
243 addr = memory_read16 (interrupts->cpu,
244 interrupts->vectors_addr + id * 2);
245 cpu_call (interrupts->cpu, addr);
246
247 /* Now, protect from nested interrupts. */
248 if (id == M6811_INT_XIRQ)
249 {
250 cpu_set_ccr_X (interrupts->cpu, 1);
251 }
252 else
253 {
254 cpu_set_ccr_I (interrupts->cpu, 1);
255 }
256
257 interrupts->nb_interrupts_raised++;
258 cpu_add_cycles (interrupts->cpu, 14);
259 return 1;
260 }
261 return 0;
262 }
263
264 void
265 interrupts_raise (struct interrupts *interrupts, enum M6811_INT number)
266 {
267 interrupts->pending_mask |= (1 << number);
268 interrupts->nb_interrupts_raised ++;
269 }
270
271
272
273 void
274 interrupts_info (SIM_DESC sd, struct interrupts *interrupts)
275 {
276 signed64 t;
277
278 if (interrupts->start_mask_cycle >= 0)
279 {
280 t = cpu_current_cycle (interrupts->cpu);
281
282 t -= interrupts->start_mask_cycle;
283 if (t > interrupts->max_mask_cycles)
284 interrupts->max_mask_cycles = t;
285 }
286 if (interrupts->xirq_start_mask_cycle >= 0)
287 {
288 t = cpu_current_cycle (interrupts->cpu);
289
290 t -= interrupts->xirq_start_mask_cycle;
291 if (t > interrupts->xirq_max_mask_cycles)
292 interrupts->xirq_max_mask_cycles = t;
293 }
294
295 sim_io_printf (sd, "Interrupts Info:\n");
296 sim_io_printf (sd, " Interrupts raised: %lu\n",
297 interrupts->nb_interrupts_raised);
298
299 t = interrupts->min_mask_cycles == CYCLES_MAX ?
300 interrupts->max_mask_cycles :
301 interrupts->min_mask_cycles;
302 sim_io_printf (sd, " Shortest interrupts masked sequence: %s\n",
303 cycle_to_string (interrupts->cpu, t));
304
305 t = interrupts->max_mask_cycles;
306 sim_io_printf (sd, " Longest interrupts masked sequence: %s\n",
307 cycle_to_string (interrupts->cpu, t));
308
309 t = interrupts->xirq_min_mask_cycles == CYCLES_MAX ?
310 interrupts->xirq_max_mask_cycles :
311 interrupts->xirq_min_mask_cycles;
312 sim_io_printf (sd, " XIRQ Min interrupts masked sequence: %s\n",
313 cycle_to_string (interrupts->cpu, t));
314
315 t = interrupts->xirq_max_mask_cycles;
316 sim_io_printf (sd, " XIRQ Max interrupts masked sequence: %s\n",
317 cycle_to_string (interrupts->cpu, t));
318 }
This page took 0.036297 seconds and 4 git commands to generate.