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. */
28 CRIS cpu virtual device (very rudimental; generic enough for all
29 currently used CRIS versions).
34 Implements the external CRIS functionality. This includes the
35 delivery of interrupts generated from other devices.
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".
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
63 FIXME: reg port so internal registers can be read. Requires
64 chip-specific versions, though. Ports "nmi" and "reset".
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". */
83 static const struct hw_port_descriptor cris_ports
[] =
85 { "int", INT_PORT
, 0, input_port
},
91 uint32_t portval
, vec
;
94 enum cris_multiple_ints
97 cris_multint_ignore_previous
,
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. */
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
;
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
)
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. */
160 cris_port_event (struct hw
*me
,
166 struct cris_hw
*crishw
= hw_data (me
);
169 /* A few placeholders; only the INT port is implemented. */
173 HW_TRACE ((me
, "INT value=0x%x", intparam
));
177 hw_abort (me
, "bad switch");
184 if (crishw
->int_to_vec
!= NULL
)
187 for (i
= 0; crishw
->int_to_vec
[i
].portval
!= 0; i
++)
188 if (crishw
->int_to_vec
[i
].portval
== intparam
)
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
;
197 vec
= (uint32_t) intparam
;
199 if (crishw
->pending_vector
!= 0)
201 if (vec
== crishw
->pending_vector
)
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
);
211 case cris_multint_ignore_previous
:
214 case cris_multint_vector
:
215 vec
= crishw
->multiple_int_vector
;
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. */
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
)
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");
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
;
267 if (!hw_find_integer_array_property (me
, "vec-for-int", i
*2,
269 || !hw_find_integer_array_property (me
, "vec-for-int", i
*2 + 1,
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
;
294 const char *action
= hw_find_string_property (me
, "multiple-int");
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
;
304 hw_abort (me
, "property \"multiple-int\" must be one of <vector number>\n"
305 "\"abort\" and \"ignore_previous\", not \"%s\"", action
);
309 crishw
->multi_int_action
= cris_multint_abort
;
312 const struct hw_descriptor dv_cris_descriptor
[] = {
313 { "cris", cris_finish
, },