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