[binutils, ARM, 5/16] BF insns infrastructure with new global reloc R_ARM_THM_BF16
[binutils-gdb.git] / sim / cris / dv-cris.c
blob3347091ac76d73b4cfc1f73535aa417cdba65b8a
1 /* The CRIS interrupt framework for GDB, the GNU Debugger.
3 Copyright 2006-2019 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 #include "sim-main.h"
21 #include "hw-main.h"
23 /* DEVICE
25 CRIS cpu virtual device (very rudimental; generic enough for all
26 currently used CRIS versions).
29 DESCRIPTION
31 Implements the external CRIS functionality. This includes the
32 delivery of interrupts generated from other devices.
35 PROPERTIES
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.
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".
51 PORTS
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.
60 FIXME: reg port so internal registers can be read. Requires
61 chip-specific versions, though. Ports "nmi" and "reset".
64 BUGS
65 When delivering an interrupt, this code assumes that there is only
66 one processor (number 0).
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.
74 /* Keep this an enum for simple addition of "reset" and "nmi". */
75 enum
77 INT_PORT,
80 static const struct hw_port_descriptor cris_ports[] =
82 { "int", INT_PORT, 0, input_port },
83 { NULL, 0, 0, 0 }
86 struct cris_vec_tr
88 unsigned32 portval, vec;
91 enum cris_multiple_ints
93 cris_multint_abort,
94 cris_multint_ignore_previous,
95 cris_multint_vector
98 struct cris_hw
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;
107 /* An event function, calling the actual CPU-model-specific
108 interrupt-delivery function. */
110 static void
111 deliver_cris_interrupt (struct hw *me, void *data)
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;
118 if (CPU_CRIS_DELIVER_INTERRUPT (cpu) (cpu, CRIS_INT_INT, intno))
120 crishw->pending_vector = 0;
121 crishw->pending_handler = NULL;
122 return;
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).
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);
140 if (this_events_time == last_events_time)
141 delta++;
142 else
144 delta = 1;
145 last_events_time = this_events_time;
148 crishw->pending_handler
149 = hw_event_queue_schedule (me, delta, deliver_cris_interrupt, NULL);
154 /* A port-event function for events arriving to an interrupt port. */
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)
163 struct cris_hw *crishw = hw_data (me);
164 unsigned32 vec;
166 /* A few placeholders; only the INT port is implemented. */
167 switch (my_port)
169 case INT_PORT:
170 HW_TRACE ((me, "INT value=0x%x", intparam));
171 break;
173 default:
174 hw_abort (me, "bad switch");
175 break;
178 if (intparam == 0)
179 return;
181 if (crishw->int_to_vec != NULL)
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;
188 if (crishw->int_to_vec[i].portval == 0)
189 hw_abort (me, "unsupported value for int port: 0x%x", intparam);
191 vec = crishw->int_to_vec[i].vec;
193 else
194 vec = (unsigned32) intparam;
196 if (crishw->pending_vector != 0)
198 if (vec == crishw->pending_vector)
199 return;
201 switch (crishw->multi_int_action)
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;
208 case cris_multint_ignore_previous:
209 break;
211 case cris_multint_vector:
212 vec = crishw->multiple_int_vector;
213 break;
215 default:
216 hw_abort (me, "bad switch");
220 crishw->pending_vector = vec;
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);
228 /* Instance initializer function. */
230 static void
231 cris_finish (struct hw *me)
233 struct cris_hw *crishw;
234 const struct hw_property *vec_for_int;
235 const struct hw_property *multiple_int;
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);
242 vec_for_int = hw_find_property (me, "vec-for-int");
243 if (vec_for_int != NULL)
245 unsigned32 vecsize;
246 unsigned32 i;
248 if (hw_property_type (vec_for_int) != array_property)
249 hw_abort (me, "property \"vec-for-int\" has the wrong type");
251 vecsize = hw_property_sizeof_array (vec_for_int) / sizeof (signed_cell);
253 if ((vecsize % 2) != 0)
254 hw_abort (me, "translation vector does not consist of even pairs");
256 crishw->int_to_vec
257 = hw_malloc (me, (vecsize/2 + 1) * sizeof (crishw->int_to_vec[0]));
259 for (i = 0; i < vecsize/2; i++)
261 signed_cell portval_sc;
262 signed_cell vec_sc;
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);
272 crishw->int_to_vec[i].portval = (unsigned32) portval_sc;
273 crishw->int_to_vec[i].vec = (unsigned32) vec_sc;
276 crishw->int_to_vec[i].portval = 0;
277 crishw->int_to_vec[i].vec = 0;
280 multiple_int = hw_find_property (me, "multiple-int");
281 if (multiple_int != NULL)
283 if (hw_property_type (multiple_int) == integer_property)
285 crishw->multiple_int_vector
286 = hw_find_integer_property (me, "multiple-int");
287 crishw->multi_int_action = cris_multint_vector;
289 else
291 const char *action = hw_find_string_property (me, "multiple-int");
293 if (action == NULL)
294 hw_abort (me, "property \"multiple-int\" has the wrong type");
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);
305 else
306 crishw->multi_int_action = cris_multint_abort;
309 const struct hw_descriptor dv_cris_descriptor[] = {
310 { "cris", cris_finish, },
311 { NULL },