1 /* The CRIS interrupt framework for GDB, the GNU Debugger.
3 Copyright 2006 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 2 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, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
27 CRIS cpu virtual device (very rudimental; generic enough for all
28 currently used CRIS versions).
33 Implements the external CRIS functionality. This includes the
34 delivery of interrupts generated from other devices.
39 vec-for-int = <int-a> <vec-a> <int-b> <vec-b> ...
40 These are the translations to interrupt vector for values appearing
41 on the "int" port, as pairs of the value and the corresponding
42 vector. Defaults to no translation. All values that may appear on
43 the "int" port must be defined, or the device aborts.
45 multiple-int = ("abort" | "ignore_previous" | <vector>)
46 If multiple interrupt values are dispatched, this property decides
47 what to do. The value is either a number corresponding to the
48 vector to use, or the string "abort" to cause a hard abort, or the
49 string "ignore_previous", to silently use the new vector instead.
50 The default is "abort".
56 Interrupt port. An event with a non-zero value on this port causes
57 an interrupt. If, after an event but before the interrupt has been
58 properly dispatched, a non-zero value appears that is different
59 after mapping than the previous, then the property multiple_int
62 FIXME: reg port so internal registers can be read. Requires
63 chip-specific versions, though. Ports "nmi" and "reset".
67 When delivering an interrupt, this code assumes that there is only
68 one processor (number 0).
70 This code does not attempt to be efficient at handling pending
71 interrupts. It simply schedules the interrupt delivery handler
72 every instruction cycle until all pending interrupts go away.
73 It also works around a bug in sim_events_process when doing so.
76 /* Keep this an enum for simple addition of "reset" and "nmi". */
82 static const struct hw_port_descriptor cris_ports
[] =
84 { "int", INT_PORT
, 0, input_port
},
90 unsigned32 portval
, vec
;
93 enum cris_multiple_ints
96 cris_multint_ignore_previous
,
102 struct hw_event
*pending_handler
;
103 unsigned32 pending_vector
;
104 struct cris_vec_tr
*int_to_vec
;
105 enum cris_multiple_ints multi_int_action
;
106 unsigned32 multiple_int_vector
;
109 /* An event function, calling the actual CPU-model-specific
110 interrupt-delivery function. */
113 deliver_cris_interrupt (struct hw
*me
, void *data
)
115 struct cris_hw
*crishw
= hw_data (me
);
116 SIM_DESC simulator
= hw_system (me
);
117 sim_cpu
*cpu
= STATE_CPU (simulator
, 0);
118 unsigned int intno
= crishw
->pending_vector
;
120 if (CPU_CRIS_DELIVER_INTERRUPT (cpu
) (cpu
, CRIS_INT_INT
, intno
))
122 crishw
->pending_vector
= 0;
123 crishw
->pending_handler
= NULL
;
128 /* Bug workaround: at time T with a pending number of cycles N to
129 process, if re-scheduling an event at time T+M, M < N,
130 sim_events_process gets stuck at T (updating the "time" to
131 before the event rather than after the event, or somesuch).
133 Hacking this locally is thankfully easy: if we see the same
134 simulation time, increase the number of cycles. Do this every
135 time we get here, until a new time is seen (supposedly unstuck
136 re-delivery). (Fixing in SIM/GDB source will hopefully then
137 also be easier, having a tangible test-case.) */
138 static signed64 last_events_time
= 0;
139 static signed64 delta
= 1;
140 signed64 this_events_time
= hw_event_queue_time (me
);
142 if (this_events_time
== last_events_time
)
147 last_events_time
= this_events_time
;
150 crishw
->pending_handler
151 = hw_event_queue_schedule (me
, delta
, deliver_cris_interrupt
, NULL
);
156 /* A port-event function for events arriving to an interrupt port. */
159 cris_port_event (struct hw
*me
,
165 struct cris_hw
*crishw
= hw_data (me
);
168 /* A few placeholders; only the INT port is implemented. */
172 HW_TRACE ((me
, "INT value=0x%x", intparam
));
176 hw_abort (me
, "bad switch");
183 if (crishw
->int_to_vec
!= NULL
)
186 for (i
= 0; crishw
->int_to_vec
[i
].portval
!= 0; i
++)
187 if (crishw
->int_to_vec
[i
].portval
== intparam
)
190 if (crishw
->int_to_vec
[i
].portval
== 0)
191 hw_abort (me
, "unsupported value for int port: 0x%x", intparam
);
193 vec
= crishw
->int_to_vec
[i
].vec
;
196 vec
= (unsigned32
) intparam
;
198 if (crishw
->pending_vector
!= 0)
200 if (vec
== crishw
->pending_vector
)
203 switch (crishw
->multi_int_action
)
205 case cris_multint_abort
:
206 hw_abort (me
, "int 0x%x (0x%x) while int 0x%x hasn't been delivered",
207 vec
, intparam
, crishw
->pending_vector
);
210 case cris_multint_ignore_previous
:
213 case cris_multint_vector
:
214 vec
= crishw
->multiple_int_vector
;
218 hw_abort (me
, "bad switch");
222 crishw
->pending_vector
= vec
;
224 /* Schedule our event handler *now*. */
225 if (crishw
->pending_handler
== NULL
)
226 crishw
->pending_handler
227 = hw_event_queue_schedule (me
, 0, deliver_cris_interrupt
, NULL
);
230 /* Instance initializer function. */
233 cris_finish (struct hw
*me
)
235 struct cris_hw
*crishw
;
236 const struct hw_property
*vec_for_int
;
237 const struct hw_property
*multiple_int
;
239 crishw
= HW_ZALLOC (me
, struct cris_hw
);
240 set_hw_data (me
, crishw
);
241 set_hw_ports (me
, cris_ports
);
242 set_hw_port_event (me
, cris_port_event
);
244 vec_for_int
= hw_find_property (me
, "vec-for-int");
245 if (vec_for_int
!= NULL
)
250 if (hw_property_type (vec_for_int
) != array_property
)
251 hw_abort (me
, "property \"vec-for-int\" has the wrong type");
253 vecsize
= hw_property_sizeof_array (vec_for_int
) / sizeof (signed_cell
);
255 if ((vecsize
% 2) != 0)
256 hw_abort (me
, "translation vector does not consist of even pairs");
259 = hw_malloc (me
, (vecsize
/2 + 1) * sizeof (crishw
->int_to_vec
[0]));
261 for (i
= 0; i
< vecsize
/2; i
++)
263 signed_cell portval_sc
;
266 if (!hw_find_integer_array_property (me
, "vec-for-int", i
*2,
268 || !hw_find_integer_array_property (me
, "vec-for-int", i
*2 + 1,
272 hw_abort (me
, "no valid vector translation pair %u", i
);
274 crishw
->int_to_vec
[i
].portval
= (unsigned32
) portval_sc
;
275 crishw
->int_to_vec
[i
].vec
= (unsigned32
) vec_sc
;
278 crishw
->int_to_vec
[i
].portval
= 0;
279 crishw
->int_to_vec
[i
].vec
= 0;
282 multiple_int
= hw_find_property (me
, "multiple-int");
283 if (multiple_int
!= NULL
)
285 if (hw_property_type (multiple_int
) == integer_property
)
287 crishw
->multiple_int_vector
288 = hw_find_integer_property (me
, "multiple-int");
289 crishw
->multi_int_action
= cris_multint_vector
;
293 const char *action
= hw_find_string_property (me
, "multiple-int");
296 hw_abort (me
, "property \"multiple-int\" has the wrong type");
298 if (strcmp (action
, "abort") == 0)
299 crishw
->multi_int_action
= cris_multint_abort
;
300 else if (strcmp (action
, "ignore_previous") == 0)
301 crishw
->multi_int_action
= cris_multint_ignore_previous
;
303 hw_abort (me
, "property \"multiple-int\" must be one of <vector number>\n"
304 "\"abort\" and \"ignore_previous\", not \"%s\"", action
);
308 crishw
->multi_int_action
= cris_multint_abort
;
311 const struct hw_descriptor dv_cris_descriptor
[] = {
312 { "cris", cris_finish
, },