1 /* The CRIS interrupt framework for GDB, the GNU Debugger.
3 Copyright 2006, 2007, 2008, 2009 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/>. */
25 CRIS cpu virtual device (very rudimental; generic enough for all
26 currently used CRIS versions).
31 Implements the external CRIS functionality. This includes the
32 delivery of interrupts generated from other devices.
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".
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
60 FIXME: reg port so internal registers can be read. Requires
61 chip-specific versions, though. Ports "nmi" and "reset".
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". */
80 static const struct hw_port_descriptor cris_ports
[] =
82 { "int", INT_PORT
, 0, input_port
},
88 unsigned32 portval
, vec
;
91 enum cris_multiple_ints
94 cris_multint_ignore_previous
,
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. */
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
;
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
)
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. */
157 cris_port_event (struct hw
*me
,
163 struct cris_hw
*crishw
= hw_data (me
);
166 /* A few placeholders; only the INT port is implemented. */
170 HW_TRACE ((me
, "INT value=0x%x", intparam
));
174 hw_abort (me
, "bad switch");
181 if (crishw
->int_to_vec
!= NULL
)
184 for (i
= 0; crishw
->int_to_vec
[i
].portval
!= 0; i
++)
185 if (crishw
->int_to_vec
[i
].portval
== intparam
)
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
;
194 vec
= (unsigned32
) intparam
;
196 if (crishw
->pending_vector
!= 0)
198 if (vec
== crishw
->pending_vector
)
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
);
208 case cris_multint_ignore_previous
:
211 case cris_multint_vector
:
212 vec
= crishw
->multiple_int_vector
;
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. */
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
)
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");
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
;
264 if (!hw_find_integer_array_property (me
, "vec-for-int", i
*2,
266 || !hw_find_integer_array_property (me
, "vec-for-int", i
*2 + 1,
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
;
291 const char *action
= hw_find_string_property (me
, "multiple-int");
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
;
301 hw_abort (me
, "property \"multiple-int\" must be one of <vector number>\n"
302 "\"abort\" and \"ignore_previous\", not \"%s\"", action
);
306 crishw
->multi_int_action
= cris_multint_abort
;
309 const struct hw_descriptor dv_cris_descriptor
[] = {
310 { "cris", cris_finish
, },