]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/cris/dv-cris.c
b98a6b734256550182faad7d896da6785cda1cf6
[thirdparty/binutils-gdb.git] / sim / cris / dv-cris.c
1 /* The CRIS interrupt framework for GDB, the GNU Debugger.
2
3 Copyright 2006 Free Software Foundation, Inc.
4
5 This file is part of GDB.
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 2 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, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #include "sim-main.h"
23 #include "hw-main.h"
24
25 /* DEVICE
26
27 CRIS cpu virtual device (very rudimental; generic enough for all
28 currently used CRIS versions).
29
30
31 DESCRIPTION
32
33 Implements the external CRIS functionality. This includes the
34 delivery of interrupts generated from other devices.
35
36
37 PROPERTIES
38
39 vec-for-int = <int-a> <vec-a> <int-b> <vec-b> ...
40 These are the translations to interrupt vector for values appearing
41 on the "int" port, as pairs of the value and the corresponding
42 vector. Defaults to no translation. All values that may appear on
43 the "int" port must be defined, or the device aborts.
44
45 multiple-int = ("abort" | "ignore_previous" | <vector>)
46 If multiple interrupt values are dispatched, this property decides
47 what to do. The value is either a number corresponding to the
48 vector to use, or the string "abort" to cause a hard abort, or the
49 string "ignore_previous", to silently use the new vector instead.
50 The default is "abort".
51
52
53 PORTS
54
55 int (input)
56 Interrupt port. An event with a non-zero value on this port causes
57 an interrupt. If, after an event but before the interrupt has been
58 properly dispatched, a non-zero value appears that is different
59 after mapping than the previous, then the property multiple_int
60 decides what to do.
61
62 FIXME: reg port so internal registers can be read. Requires
63 chip-specific versions, though. Ports "nmi" and "reset".
64
65
66 BUGS
67 When delivering an interrupt, this code assumes that there is only
68 one processor (number 0).
69
70 This code does not attempt to be efficient at handling pending
71 interrupts. It simply schedules the interrupt delivery handler
72 every instruction cycle until all pending interrupts go away.
73 It also works around a bug in sim_events_process when doing so.
74 */
75
76 /* Keep this an enum for simple addition of "reset" and "nmi". */
77 enum
78 {
79 INT_PORT,
80 };
81
82 static const struct hw_port_descriptor cris_ports[] =
83 {
84 { "int", INT_PORT, 0, input_port },
85 { NULL, 0, 0, 0 }
86 };
87
88 struct cris_vec_tr
89 {
90 unsigned32 portval, vec;
91 };
92
93 enum cris_multiple_ints
94 {
95 cris_multint_abort,
96 cris_multint_ignore_previous,
97 cris_multint_vector
98 };
99
100 struct cris_hw
101 {
102 struct hw_event *pending_handler;
103 unsigned32 pending_vector;
104 struct cris_vec_tr *int_to_vec;
105 enum cris_multiple_ints multi_int_action;
106 unsigned32 multiple_int_vector;
107 };
108
109 /* An event function, calling the actual CPU-model-specific
110 interrupt-delivery function. */
111
112 static void
113 deliver_cris_interrupt (struct hw *me, void *data)
114 {
115 struct cris_hw *crishw = hw_data (me);
116 SIM_DESC simulator = hw_system (me);
117 sim_cpu *cpu = STATE_CPU (simulator, 0);
118 unsigned int intno = crishw->pending_vector;
119
120 if (CPU_CRIS_DELIVER_INTERRUPT (cpu) (cpu, CRIS_INT_INT, intno))
121 {
122 crishw->pending_vector = 0;
123 crishw->pending_handler = NULL;
124 return;
125 }
126
127 {
128 /* Bug workaround: at time T with a pending number of cycles N to
129 process, if re-scheduling an event at time T+M, M < N,
130 sim_events_process gets stuck at T (updating the "time" to
131 before the event rather than after the event, or somesuch).
132
133 Hacking this locally is thankfully easy: if we see the same
134 simulation time, increase the number of cycles. Do this every
135 time we get here, until a new time is seen (supposedly unstuck
136 re-delivery). (Fixing in SIM/GDB source will hopefully then
137 also be easier, having a tangible test-case.) */
138 static signed64 last_events_time = 0;
139 static signed64 delta = 1;
140 signed64 this_events_time = hw_event_queue_time (me);
141
142 if (this_events_time == last_events_time)
143 delta++;
144 else
145 {
146 delta = 1;
147 last_events_time = this_events_time;
148 }
149
150 crishw->pending_handler
151 = hw_event_queue_schedule (me, delta, deliver_cris_interrupt, NULL);
152 }
153 }
154
155
156 /* A port-event function for events arriving to an interrupt port. */
157
158 static void
159 cris_port_event (struct hw *me,
160 int my_port,
161 struct hw *source,
162 int source_port,
163 int intparam)
164 {
165 struct cris_hw *crishw = hw_data (me);
166 unsigned32 vec;
167
168 /* A few placeholders; only the INT port is implemented. */
169 switch (my_port)
170 {
171 case INT_PORT:
172 HW_TRACE ((me, "INT value=0x%x", intparam));
173 break;
174
175 default:
176 hw_abort (me, "bad switch");
177 break;
178 }
179
180 if (intparam == 0)
181 return;
182
183 if (crishw->int_to_vec != NULL)
184 {
185 unsigned int i;
186 for (i = 0; crishw->int_to_vec[i].portval != 0; i++)
187 if (crishw->int_to_vec[i].portval == intparam)
188 break;
189
190 if (crishw->int_to_vec[i].portval == 0)
191 hw_abort (me, "unsupported value for int port: 0x%x", intparam);
192
193 vec = crishw->int_to_vec[i].vec;
194 }
195 else
196 vec = (unsigned32) intparam;
197
198 if (crishw->pending_vector != 0)
199 {
200 if (vec == crishw->pending_vector)
201 return;
202
203 switch (crishw->multi_int_action)
204 {
205 case cris_multint_abort:
206 hw_abort (me, "int 0x%x (0x%x) while int 0x%x hasn't been delivered",
207 vec, intparam, crishw->pending_vector);
208 break;
209
210 case cris_multint_ignore_previous:
211 break;
212
213 case cris_multint_vector:
214 vec = crishw->multiple_int_vector;
215 break;
216
217 default:
218 hw_abort (me, "bad switch");
219 }
220 }
221
222 crishw->pending_vector = vec;
223
224 /* Schedule our event handler *now*. */
225 if (crishw->pending_handler == NULL)
226 crishw->pending_handler
227 = hw_event_queue_schedule (me, 0, deliver_cris_interrupt, NULL);
228 }
229
230 /* Instance initializer function. */
231
232 static void
233 cris_finish (struct hw *me)
234 {
235 struct cris_hw *crishw;
236 const struct hw_property *vec_for_int;
237 const struct hw_property *multiple_int;
238
239 crishw = HW_ZALLOC (me, struct cris_hw);
240 set_hw_data (me, crishw);
241 set_hw_ports (me, cris_ports);
242 set_hw_port_event (me, cris_port_event);
243
244 vec_for_int = hw_find_property (me, "vec-for-int");
245 if (vec_for_int != NULL)
246 {
247 unsigned32 vecsize;
248 unsigned32 i;
249
250 if (hw_property_type (vec_for_int) != array_property)
251 hw_abort (me, "property \"vec-for-int\" has the wrong type");
252
253 vecsize = hw_property_sizeof_array (vec_for_int) / sizeof (signed_cell);
254
255 if ((vecsize % 2) != 0)
256 hw_abort (me, "translation vector does not consist of even pairs");
257
258 crishw->int_to_vec
259 = hw_malloc (me, (vecsize/2 + 1) * sizeof (crishw->int_to_vec[0]));
260
261 for (i = 0; i < vecsize/2; i++)
262 {
263 signed_cell portval_sc;
264 signed_cell vec_sc;
265
266 if (!hw_find_integer_array_property (me, "vec-for-int", i*2,
267 &portval_sc)
268 || !hw_find_integer_array_property (me, "vec-for-int", i*2 + 1,
269 &vec_sc)
270 || portval_sc < 0
271 || vec_sc < 0)
272 hw_abort (me, "no valid vector translation pair %u", i);
273
274 crishw->int_to_vec[i].portval = (unsigned32) portval_sc;
275 crishw->int_to_vec[i].vec = (unsigned32) vec_sc;
276 }
277
278 crishw->int_to_vec[i].portval = 0;
279 crishw->int_to_vec[i].vec = 0;
280 }
281
282 multiple_int = hw_find_property (me, "multiple-int");
283 if (multiple_int != NULL)
284 {
285 if (hw_property_type (multiple_int) == integer_property)
286 {
287 crishw->multiple_int_vector
288 = hw_find_integer_property (me, "multiple-int");
289 crishw->multi_int_action = cris_multint_vector;
290 }
291 else
292 {
293 const char *action = hw_find_string_property (me, "multiple-int");
294
295 if (action == NULL)
296 hw_abort (me, "property \"multiple-int\" has the wrong type");
297
298 if (strcmp (action, "abort") == 0)
299 crishw->multi_int_action = cris_multint_abort;
300 else if (strcmp (action, "ignore_previous") == 0)
301 crishw->multi_int_action = cris_multint_ignore_previous;
302 else
303 hw_abort (me, "property \"multiple-int\" must be one of <vector number>\n"
304 "\"abort\" and \"ignore_previous\", not \"%s\"", action);
305 }
306 }
307 else
308 crishw->multi_int_action = cris_multint_abort;
309 }
310
311 const struct hw_descriptor dv_cris_descriptor[] = {
312 { "cris", cris_finish, },
313 { NULL },
314 };