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