1/* The CRIS interrupt framework for GDB, the GNU Debugger. 2 3 Copyright 2006, 2007 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 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. 11 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. 16 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/>. */ 19 20#include "sim-main.h" 21#include "hw-main.h" 22 23/* DEVICE 24 25 CRIS cpu virtual device (very rudimental; generic enough for all 26 currently used CRIS versions). 27 28 29 DESCRIPTION 30 31 Implements the external CRIS functionality. This includes the 32 delivery of interrupts generated from other devices. 33 34 35 PROPERTIES 36 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. 42 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". 49 50 51 PORTS 52 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. 59 60 FIXME: reg port so internal registers can be read. Requires 61 chip-specific versions, though. Ports "nmi" and "reset". 62 63 64 BUGS 65 When delivering an interrupt, this code assumes that there is only 66 one processor (number 0). 67 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. 72 */ 73 74/* Keep this an enum for simple addition of "reset" and "nmi". */ 75enum 76 { 77 INT_PORT, 78 }; 79 80static const struct hw_port_descriptor cris_ports[] = 81 { 82 { "int", INT_PORT, 0, input_port }, 83 { NULL, 0, 0, 0 } 84 }; 85 86struct cris_vec_tr 87 { 88 unsigned32 portval, vec; 89 }; 90 91enum cris_multiple_ints 92 { 93 cris_multint_abort, 94 cris_multint_ignore_previous, 95 cris_multint_vector 96 }; 97 98struct cris_hw 99 { 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; 105 }; 106 107/* An event function, calling the actual CPU-model-specific 108 interrupt-delivery function. */ 109 110static void 111deliver_cris_interrupt (struct hw *me, void *data) 112{ 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; 117 118 if (CPU_CRIS_DELIVER_INTERRUPT (cpu) (cpu, CRIS_INT_INT, intno)) 119 { 120 crishw->pending_vector = 0; 121 crishw->pending_handler = NULL; 122 return; 123 } 124 125 { 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). 130 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); 139 140 if (this_events_time == last_events_time) 141 delta++; 142 else 143 { 144 delta = 1; 145 last_events_time = this_events_time; 146 } 147 148 crishw->pending_handler 149 = hw_event_queue_schedule (me, delta, deliver_cris_interrupt, NULL); 150 } 151} 152 153 154/* A port-event function for events arriving to an interrupt port. */ 155 156static void 157cris_port_event (struct hw *me, 158 int my_port, 159 struct hw *source, 160 int source_port, 161 int intparam) 162{ 163 struct cris_hw *crishw = hw_data (me); 164 unsigned32 vec; 165 166 /* A few placeholders; only the INT port is implemented. */ 167 switch (my_port) 168 { 169 case INT_PORT: 170 HW_TRACE ((me, "INT value=0x%x", intparam)); 171 break; 172 173 default: 174 hw_abort (me, "bad switch"); 175 break; 176 } 177 178 if (intparam == 0) 179 return; 180 181 if (crishw->int_to_vec != NULL) 182 { 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; 187 188 if (crishw->int_to_vec[i].portval == 0) 189 hw_abort (me, "unsupported value for int port: 0x%x", intparam); 190 191 vec = crishw->int_to_vec[i].vec; 192 } 193 else 194 vec = (unsigned32) intparam; 195 196 if (crishw->pending_vector != 0) 197 { 198 if (vec == crishw->pending_vector) 199 return; 200 201 switch (crishw->multi_int_action) 202 { 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; 207 208 case cris_multint_ignore_previous: 209 break; 210 211 case cris_multint_vector: 212 vec = crishw->multiple_int_vector; 213 break; 214 215 default: 216 hw_abort (me, "bad switch"); 217 } 218 } 219 220 crishw->pending_vector = vec; 221 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); 226} 227 228/* Instance initializer function. */ 229 230static void 231cris_finish (struct hw *me) 232{ 233 struct cris_hw *crishw; 234 const struct hw_property *vec_for_int; 235 const struct hw_property *multiple_int; 236 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); 241 242 vec_for_int = hw_find_property (me, "vec-for-int"); 243 if (vec_for_int != NULL) 244 { 245 unsigned32 vecsize; 246 unsigned32 i; 247 248 if (hw_property_type (vec_for_int) != array_property) 249 hw_abort (me, "property \"vec-for-int\" has the wrong type"); 250 251 vecsize = hw_property_sizeof_array (vec_for_int) / sizeof (signed_cell); 252 253 if ((vecsize % 2) != 0) 254 hw_abort (me, "translation vector does not consist of even pairs"); 255 256 crishw->int_to_vec 257 = hw_malloc (me, (vecsize/2 + 1) * sizeof (crishw->int_to_vec[0])); 258 259 for (i = 0; i < vecsize/2; i++) 260 { 261 signed_cell portval_sc; 262 signed_cell vec_sc; 263 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); 271 272 crishw->int_to_vec[i].portval = (unsigned32) portval_sc; 273 crishw->int_to_vec[i].vec = (unsigned32) vec_sc; 274 } 275 276 crishw->int_to_vec[i].portval = 0; 277 crishw->int_to_vec[i].vec = 0; 278 } 279 280 multiple_int = hw_find_property (me, "multiple-int"); 281 if (multiple_int != NULL) 282 { 283 if (hw_property_type (multiple_int) == integer_property) 284 { 285 crishw->multiple_int_vector 286 = hw_find_integer_property (me, "multiple-int"); 287 crishw->multi_int_action = cris_multint_vector; 288 } 289 else 290 { 291 const char *action = hw_find_string_property (me, "multiple-int"); 292 293 if (action == NULL) 294 hw_abort (me, "property \"multiple-int\" has the wrong type"); 295 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); 303 } 304 } 305 else 306 crishw->multi_int_action = cris_multint_abort; 307} 308 309const struct hw_descriptor dv_cris_descriptor[] = { 310 { "cris", cris_finish, }, 311 { NULL }, 312}; 313