Update copyright year range in header of all files managed by GDB
[binutils-gdb.git] / sim / cris / dv-cris.c
blob5f910043d71907c4dfc055f7e2f32a399143b8c2
1 /* The CRIS interrupt framework for GDB, the GNU Debugger.
3 Copyright 2006-2023 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
20 /* This must come before any other includes. */
21 #include "defs.h"
23 #include "sim-main.h"
24 #include "hw-main.h"
26 /* DEVICE
28 CRIS cpu virtual device (very rudimental; generic enough for all
29 currently used CRIS versions).
32 DESCRIPTION
34 Implements the external CRIS functionality. This includes the
35 delivery of interrupts generated from other devices.
38 PROPERTIES
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.
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".
54 PORTS
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.
63 FIXME: reg port so internal registers can be read. Requires
64 chip-specific versions, though. Ports "nmi" and "reset".
67 BUGS
68 When delivering an interrupt, this code assumes that there is only
69 one processor (number 0).
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.
77 /* Keep this an enum for simple addition of "reset" and "nmi". */
78 enum
80 INT_PORT,
83 static const struct hw_port_descriptor cris_ports[] =
85 { "int", INT_PORT, 0, input_port },
86 { NULL, 0, 0, 0 }
89 struct cris_vec_tr
91 uint32_t portval, vec;
94 enum cris_multiple_ints
96 cris_multint_abort,
97 cris_multint_ignore_previous,
98 cris_multint_vector
101 struct cris_hw
103 struct hw_event *pending_handler;
104 uint32_t pending_vector;
105 struct cris_vec_tr *int_to_vec;
106 enum cris_multiple_ints multi_int_action;
107 uint32_t multiple_int_vector;
110 /* An event function, calling the actual CPU-model-specific
111 interrupt-delivery function. */
113 static void
114 deliver_cris_interrupt (struct hw *me, void *data)
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;
121 if (CPU_CRIS_DELIVER_INTERRUPT (cpu) (cpu, CRIS_INT_INT, intno))
123 crishw->pending_vector = 0;
124 crishw->pending_handler = NULL;
125 return;
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).
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 int64_t last_events_time = 0;
140 static int64_t delta = 1;
141 int64_t this_events_time = hw_event_queue_time (me);
143 if (this_events_time == last_events_time)
144 delta++;
145 else
147 delta = 1;
148 last_events_time = this_events_time;
151 crishw->pending_handler
152 = hw_event_queue_schedule (me, delta, deliver_cris_interrupt, NULL);
157 /* A port-event function for events arriving to an interrupt port. */
159 static void
160 cris_port_event (struct hw *me,
161 int my_port,
162 struct hw *source,
163 int source_port,
164 int intparam)
166 struct cris_hw *crishw = hw_data (me);
167 uint32_t vec;
169 /* A few placeholders; only the INT port is implemented. */
170 switch (my_port)
172 case INT_PORT:
173 HW_TRACE ((me, "INT value=0x%x", intparam));
174 break;
176 default:
177 hw_abort (me, "bad switch");
178 break;
181 if (intparam == 0)
182 return;
184 if (crishw->int_to_vec != NULL)
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;
191 if (crishw->int_to_vec[i].portval == 0)
192 hw_abort (me, "unsupported value for int port: 0x%x", intparam);
194 vec = crishw->int_to_vec[i].vec;
196 else
197 vec = (uint32_t) intparam;
199 if (crishw->pending_vector != 0)
201 if (vec == crishw->pending_vector)
202 return;
204 switch (crishw->multi_int_action)
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;
211 case cris_multint_ignore_previous:
212 break;
214 case cris_multint_vector:
215 vec = crishw->multiple_int_vector;
216 break;
218 default:
219 hw_abort (me, "bad switch");
223 crishw->pending_vector = vec;
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);
231 /* Instance initializer function. */
233 static void
234 cris_finish (struct hw *me)
236 struct cris_hw *crishw;
237 const struct hw_property *vec_for_int;
238 const struct hw_property *multiple_int;
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);
245 vec_for_int = hw_find_property (me, "vec-for-int");
246 if (vec_for_int != NULL)
248 uint32_t vecsize;
249 uint32_t i;
251 if (hw_property_type (vec_for_int) != array_property)
252 hw_abort (me, "property \"vec-for-int\" has the wrong type");
254 vecsize = hw_property_sizeof_array (vec_for_int) / sizeof (signed_cell);
256 if ((vecsize % 2) != 0)
257 hw_abort (me, "translation vector does not consist of even pairs");
259 crishw->int_to_vec
260 = hw_malloc (me, (vecsize/2 + 1) * sizeof (crishw->int_to_vec[0]));
262 for (i = 0; i < vecsize/2; i++)
264 signed_cell portval_sc;
265 signed_cell vec_sc;
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);
275 crishw->int_to_vec[i].portval = (uint32_t) portval_sc;
276 crishw->int_to_vec[i].vec = (uint32_t) vec_sc;
279 crishw->int_to_vec[i].portval = 0;
280 crishw->int_to_vec[i].vec = 0;
283 multiple_int = hw_find_property (me, "multiple-int");
284 if (multiple_int != NULL)
286 if (hw_property_type (multiple_int) == integer_property)
288 crishw->multiple_int_vector
289 = hw_find_integer_property (me, "multiple-int");
290 crishw->multi_int_action = cris_multint_vector;
292 else
294 const char *action = hw_find_string_property (me, "multiple-int");
296 if (action == NULL)
297 hw_abort (me, "property \"multiple-int\" has the wrong type");
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);
308 else
309 crishw->multi_int_action = cris_multint_abort;
312 const struct hw_descriptor dv_cris_descriptor[] = {
313 { "cris", cris_finish, },
314 { NULL },