1 1.1 christos /* The CRIS interrupt framework for GDB, the GNU Debugger. 2 1.1 christos 3 1.11 christos Copyright 2006-2024 Free Software Foundation, Inc. 4 1.1 christos 5 1.1 christos This file is part of GDB. 6 1.1 christos 7 1.1 christos This program is free software; you can redistribute it and/or modify 8 1.1 christos it under the terms of the GNU General Public License as published by 9 1.1 christos the Free Software Foundation; either version 3 of the License, or 10 1.1 christos (at your option) any later version. 11 1.1 christos 12 1.1 christos This program is distributed in the hope that it will be useful, 13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 1.1 christos GNU General Public License for more details. 16 1.1 christos 17 1.1 christos You should have received a copy of the GNU General Public License 18 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 1.1 christos 20 1.10 christos /* This must come before any other includes. */ 21 1.10 christos #include "defs.h" 22 1.10 christos 23 1.1 christos #include "sim-main.h" 24 1.1 christos #include "hw-main.h" 25 1.1 christos 26 1.1 christos /* DEVICE 27 1.1 christos 28 1.1 christos CRIS cpu virtual device (very rudimental; generic enough for all 29 1.1 christos currently used CRIS versions). 30 1.1 christos 31 1.1 christos 32 1.1 christos DESCRIPTION 33 1.1 christos 34 1.1 christos Implements the external CRIS functionality. This includes the 35 1.1 christos delivery of interrupts generated from other devices. 36 1.1 christos 37 1.1 christos 38 1.1 christos PROPERTIES 39 1.1 christos 40 1.1 christos vec-for-int = <int-a> <vec-a> <int-b> <vec-b> ... 41 1.1 christos These are the translations to interrupt vector for values appearing 42 1.1 christos on the "int" port, as pairs of the value and the corresponding 43 1.1 christos vector. Defaults to no translation. All values that may appear on 44 1.1 christos the "int" port must be defined, or the device aborts. 45 1.1 christos 46 1.1 christos multiple-int = ("abort" | "ignore_previous" | <vector>) 47 1.1 christos If multiple interrupt values are dispatched, this property decides 48 1.1 christos what to do. The value is either a number corresponding to the 49 1.1 christos vector to use, or the string "abort" to cause a hard abort, or the 50 1.1 christos string "ignore_previous", to silently use the new vector instead. 51 1.1 christos The default is "abort". 52 1.1 christos 53 1.1 christos 54 1.1 christos PORTS 55 1.1 christos 56 1.1 christos int (input) 57 1.1 christos Interrupt port. An event with a non-zero value on this port causes 58 1.1 christos an interrupt. If, after an event but before the interrupt has been 59 1.1 christos properly dispatched, a non-zero value appears that is different 60 1.1 christos after mapping than the previous, then the property multiple_int 61 1.1 christos decides what to do. 62 1.1 christos 63 1.1 christos FIXME: reg port so internal registers can be read. Requires 64 1.1 christos chip-specific versions, though. Ports "nmi" and "reset". 65 1.1 christos 66 1.1 christos 67 1.1 christos BUGS 68 1.1 christos When delivering an interrupt, this code assumes that there is only 69 1.1 christos one processor (number 0). 70 1.1 christos 71 1.1 christos This code does not attempt to be efficient at handling pending 72 1.1 christos interrupts. It simply schedules the interrupt delivery handler 73 1.1 christos every instruction cycle until all pending interrupts go away. 74 1.1 christos It also works around a bug in sim_events_process when doing so. 75 1.1 christos */ 76 1.1 christos 77 1.1 christos /* Keep this an enum for simple addition of "reset" and "nmi". */ 78 1.1 christos enum 79 1.1 christos { 80 1.1 christos INT_PORT, 81 1.1 christos }; 82 1.1 christos 83 1.1 christos static const struct hw_port_descriptor cris_ports[] = 84 1.1 christos { 85 1.1 christos { "int", INT_PORT, 0, input_port }, 86 1.1 christos { NULL, 0, 0, 0 } 87 1.1 christos }; 88 1.1 christos 89 1.1 christos struct cris_vec_tr 90 1.1 christos { 91 1.10 christos uint32_t portval, vec; 92 1.1 christos }; 93 1.1 christos 94 1.1 christos enum cris_multiple_ints 95 1.1 christos { 96 1.1 christos cris_multint_abort, 97 1.1 christos cris_multint_ignore_previous, 98 1.1 christos cris_multint_vector 99 1.1 christos }; 100 1.1 christos 101 1.1 christos struct cris_hw 102 1.1 christos { 103 1.1 christos struct hw_event *pending_handler; 104 1.10 christos uint32_t pending_vector; 105 1.1 christos struct cris_vec_tr *int_to_vec; 106 1.1 christos enum cris_multiple_ints multi_int_action; 107 1.10 christos uint32_t multiple_int_vector; 108 1.1 christos }; 109 1.1 christos 110 1.1 christos /* An event function, calling the actual CPU-model-specific 111 1.1 christos interrupt-delivery function. */ 112 1.1 christos 113 1.1 christos static void 114 1.1 christos deliver_cris_interrupt (struct hw *me, void *data) 115 1.1 christos { 116 1.1 christos struct cris_hw *crishw = hw_data (me); 117 1.1 christos SIM_DESC simulator = hw_system (me); 118 1.1 christos sim_cpu *cpu = STATE_CPU (simulator, 0); 119 1.1 christos unsigned int intno = crishw->pending_vector; 120 1.1 christos 121 1.1 christos if (CPU_CRIS_DELIVER_INTERRUPT (cpu) (cpu, CRIS_INT_INT, intno)) 122 1.1 christos { 123 1.1 christos crishw->pending_vector = 0; 124 1.1 christos crishw->pending_handler = NULL; 125 1.1 christos return; 126 1.1 christos } 127 1.1 christos 128 1.1 christos { 129 1.1 christos /* Bug workaround: at time T with a pending number of cycles N to 130 1.1 christos process, if re-scheduling an event at time T+M, M < N, 131 1.1 christos sim_events_process gets stuck at T (updating the "time" to 132 1.1 christos before the event rather than after the event, or somesuch). 133 1.1 christos 134 1.1 christos Hacking this locally is thankfully easy: if we see the same 135 1.1 christos simulation time, increase the number of cycles. Do this every 136 1.1 christos time we get here, until a new time is seen (supposedly unstuck 137 1.1 christos re-delivery). (Fixing in SIM/GDB source will hopefully then 138 1.1 christos also be easier, having a tangible test-case.) */ 139 1.10 christos static int64_t last_events_time = 0; 140 1.10 christos static int64_t delta = 1; 141 1.10 christos int64_t this_events_time = hw_event_queue_time (me); 142 1.1 christos 143 1.1 christos if (this_events_time == last_events_time) 144 1.1 christos delta++; 145 1.1 christos else 146 1.1 christos { 147 1.1 christos delta = 1; 148 1.1 christos last_events_time = this_events_time; 149 1.1 christos } 150 1.1 christos 151 1.1 christos crishw->pending_handler 152 1.1 christos = hw_event_queue_schedule (me, delta, deliver_cris_interrupt, NULL); 153 1.1 christos } 154 1.1 christos } 155 1.1 christos 156 1.1 christos 157 1.1 christos /* A port-event function for events arriving to an interrupt port. */ 158 1.1 christos 159 1.1 christos static void 160 1.1 christos cris_port_event (struct hw *me, 161 1.1 christos int my_port, 162 1.1 christos struct hw *source, 163 1.1 christos int source_port, 164 1.1 christos int intparam) 165 1.1 christos { 166 1.1 christos struct cris_hw *crishw = hw_data (me); 167 1.10 christos uint32_t vec; 168 1.1 christos 169 1.1 christos /* A few placeholders; only the INT port is implemented. */ 170 1.1 christos switch (my_port) 171 1.1 christos { 172 1.1 christos case INT_PORT: 173 1.1 christos HW_TRACE ((me, "INT value=0x%x", intparam)); 174 1.1 christos break; 175 1.1 christos 176 1.1 christos default: 177 1.1 christos hw_abort (me, "bad switch"); 178 1.1 christos break; 179 1.1 christos } 180 1.1 christos 181 1.1 christos if (intparam == 0) 182 1.1 christos return; 183 1.1 christos 184 1.1 christos if (crishw->int_to_vec != NULL) 185 1.1 christos { 186 1.1 christos unsigned int i; 187 1.1 christos for (i = 0; crishw->int_to_vec[i].portval != 0; i++) 188 1.1 christos if (crishw->int_to_vec[i].portval == intparam) 189 1.1 christos break; 190 1.1 christos 191 1.1 christos if (crishw->int_to_vec[i].portval == 0) 192 1.1 christos hw_abort (me, "unsupported value for int port: 0x%x", intparam); 193 1.1 christos 194 1.1 christos vec = crishw->int_to_vec[i].vec; 195 1.1 christos } 196 1.1 christos else 197 1.10 christos vec = (uint32_t) intparam; 198 1.1 christos 199 1.1 christos if (crishw->pending_vector != 0) 200 1.1 christos { 201 1.1 christos if (vec == crishw->pending_vector) 202 1.1 christos return; 203 1.1 christos 204 1.1 christos switch (crishw->multi_int_action) 205 1.1 christos { 206 1.1 christos case cris_multint_abort: 207 1.1 christos hw_abort (me, "int 0x%x (0x%x) while int 0x%x hasn't been delivered", 208 1.1 christos vec, intparam, crishw->pending_vector); 209 1.1 christos break; 210 1.1 christos 211 1.1 christos case cris_multint_ignore_previous: 212 1.1 christos break; 213 1.1 christos 214 1.1 christos case cris_multint_vector: 215 1.1 christos vec = crishw->multiple_int_vector; 216 1.1 christos break; 217 1.1 christos 218 1.1 christos default: 219 1.1 christos hw_abort (me, "bad switch"); 220 1.1 christos } 221 1.1 christos } 222 1.1 christos 223 1.1 christos crishw->pending_vector = vec; 224 1.1 christos 225 1.1 christos /* Schedule our event handler *now*. */ 226 1.1 christos if (crishw->pending_handler == NULL) 227 1.1 christos crishw->pending_handler 228 1.1 christos = hw_event_queue_schedule (me, 0, deliver_cris_interrupt, NULL); 229 1.1 christos } 230 1.1 christos 231 1.1 christos /* Instance initializer function. */ 232 1.1 christos 233 1.1 christos static void 234 1.1 christos cris_finish (struct hw *me) 235 1.1 christos { 236 1.1 christos struct cris_hw *crishw; 237 1.1 christos const struct hw_property *vec_for_int; 238 1.1 christos const struct hw_property *multiple_int; 239 1.1 christos 240 1.1 christos crishw = HW_ZALLOC (me, struct cris_hw); 241 1.1 christos set_hw_data (me, crishw); 242 1.1 christos set_hw_ports (me, cris_ports); 243 1.1 christos set_hw_port_event (me, cris_port_event); 244 1.1 christos 245 1.1 christos vec_for_int = hw_find_property (me, "vec-for-int"); 246 1.1 christos if (vec_for_int != NULL) 247 1.1 christos { 248 1.10 christos uint32_t vecsize; 249 1.10 christos uint32_t i; 250 1.1 christos 251 1.1 christos if (hw_property_type (vec_for_int) != array_property) 252 1.1 christos hw_abort (me, "property \"vec-for-int\" has the wrong type"); 253 1.1 christos 254 1.1 christos vecsize = hw_property_sizeof_array (vec_for_int) / sizeof (signed_cell); 255 1.1 christos 256 1.1 christos if ((vecsize % 2) != 0) 257 1.1 christos hw_abort (me, "translation vector does not consist of even pairs"); 258 1.1 christos 259 1.1 christos crishw->int_to_vec 260 1.1 christos = hw_malloc (me, (vecsize/2 + 1) * sizeof (crishw->int_to_vec[0])); 261 1.1 christos 262 1.1 christos for (i = 0; i < vecsize/2; i++) 263 1.1 christos { 264 1.1 christos signed_cell portval_sc; 265 1.1 christos signed_cell vec_sc; 266 1.1 christos 267 1.1 christos if (!hw_find_integer_array_property (me, "vec-for-int", i*2, 268 1.1 christos &portval_sc) 269 1.1 christos || !hw_find_integer_array_property (me, "vec-for-int", i*2 + 1, 270 1.1 christos &vec_sc) 271 1.1 christos || portval_sc < 0 272 1.1 christos || vec_sc < 0) 273 1.1 christos hw_abort (me, "no valid vector translation pair %u", i); 274 1.1 christos 275 1.10 christos crishw->int_to_vec[i].portval = (uint32_t) portval_sc; 276 1.10 christos crishw->int_to_vec[i].vec = (uint32_t) vec_sc; 277 1.1 christos } 278 1.1 christos 279 1.1 christos crishw->int_to_vec[i].portval = 0; 280 1.1 christos crishw->int_to_vec[i].vec = 0; 281 1.1 christos } 282 1.1 christos 283 1.1 christos multiple_int = hw_find_property (me, "multiple-int"); 284 1.1 christos if (multiple_int != NULL) 285 1.1 christos { 286 1.1 christos if (hw_property_type (multiple_int) == integer_property) 287 1.1 christos { 288 1.1 christos crishw->multiple_int_vector 289 1.1 christos = hw_find_integer_property (me, "multiple-int"); 290 1.1 christos crishw->multi_int_action = cris_multint_vector; 291 1.1 christos } 292 1.1 christos else 293 1.1 christos { 294 1.1 christos const char *action = hw_find_string_property (me, "multiple-int"); 295 1.1 christos 296 1.1 christos if (action == NULL) 297 1.1 christos hw_abort (me, "property \"multiple-int\" has the wrong type"); 298 1.1 christos 299 1.1 christos if (strcmp (action, "abort") == 0) 300 1.1 christos crishw->multi_int_action = cris_multint_abort; 301 1.1 christos else if (strcmp (action, "ignore_previous") == 0) 302 1.1 christos crishw->multi_int_action = cris_multint_ignore_previous; 303 1.1 christos else 304 1.1 christos hw_abort (me, "property \"multiple-int\" must be one of <vector number>\n" 305 1.1 christos "\"abort\" and \"ignore_previous\", not \"%s\"", action); 306 1.1 christos } 307 1.1 christos } 308 1.1 christos else 309 1.1 christos crishw->multi_int_action = cris_multint_abort; 310 1.1 christos } 311 1.1 christos 312 1.1 christos const struct hw_descriptor dv_cris_descriptor[] = { 313 1.1 christos { "cris", cris_finish, }, 314 1.1 christos { NULL }, 315 1.1 christos }; 316