Home | History | Annotate | Line # | Download | only in cris
      1 /* The CRIS interrupt framework for GDB, the GNU Debugger.
      2 
      3    Copyright 2006-2024 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 /* This must come before any other includes.  */
     21 #include "defs.h"
     22 
     23 #include "sim-main.h"
     24 #include "hw-main.h"
     25 
     26 /* DEVICE
     27 
     28    CRIS cpu virtual device (very rudimental; generic enough for all
     29    currently used CRIS versions).
     30 
     31 
     32    DESCRIPTION
     33 
     34    Implements the external CRIS functionality.  This includes the
     35    delivery of interrupts generated from other devices.
     36 
     37 
     38    PROPERTIES
     39 
     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.
     45 
     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".
     52 
     53 
     54    PORTS
     55 
     56    int (input)
     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
     61    decides what to do.
     62 
     63    FIXME: reg port so internal registers can be read.  Requires
     64    chip-specific versions, though.  Ports "nmi" and "reset".
     65 
     66 
     67    BUGS
     68    When delivering an interrupt, this code assumes that there is only
     69    one processor (number 0).
     70 
     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.
     75    */
     76 
     77 /* Keep this an enum for simple addition of "reset" and "nmi".  */
     78 enum
     79  {
     80    INT_PORT,
     81  };
     82 
     83 static const struct hw_port_descriptor cris_ports[] =
     84  {
     85    { "int", INT_PORT, 0, input_port },
     86    { NULL, 0, 0, 0 }
     87  };
     88 
     89 struct cris_vec_tr
     90  {
     91    uint32_t portval, vec;
     92  };
     93 
     94 enum cris_multiple_ints
     95   {
     96     cris_multint_abort,
     97     cris_multint_ignore_previous,
     98     cris_multint_vector
     99   };
    100 
    101 struct cris_hw
    102  {
    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;
    108  };
    109 
    110 /* An event function, calling the actual CPU-model-specific
    111    interrupt-delivery function.  */
    112 
    113 static void
    114 deliver_cris_interrupt (struct hw *me, void *data)
    115 {
    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;
    120 
    121  if (CPU_CRIS_DELIVER_INTERRUPT (cpu) (cpu, CRIS_INT_INT, intno))
    122     {
    123       crishw->pending_vector = 0;
    124       crishw->pending_handler = NULL;
    125       return;
    126     }
    127 
    128  {
    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).
    133 
    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);
    142 
    143    if (this_events_time == last_events_time)
    144      delta++;
    145    else
    146      {
    147        delta = 1;
    148        last_events_time = this_events_time;
    149      }
    150 
    151    crishw->pending_handler
    152      = hw_event_queue_schedule (me, delta, deliver_cris_interrupt, NULL);
    153  }
    154 }
    155 
    156 
    157 /* A port-event function for events arriving to an interrupt port.  */
    158 
    159 static void
    160 cris_port_event (struct hw *me,
    161 		 int my_port,
    162 		 struct hw *source,
    163 		 int source_port,
    164 		 int intparam)
    165 {
    166   struct cris_hw *crishw = hw_data (me);
    167   uint32_t vec;
    168 
    169   /* A few placeholders; only the INT port is implemented.  */
    170   switch (my_port)
    171     {
    172     case INT_PORT:
    173       HW_TRACE ((me, "INT value=0x%x", intparam));
    174       break;
    175 
    176     default:
    177       hw_abort (me, "bad switch");
    178       break;
    179     }
    180 
    181   if (intparam == 0)
    182     return;
    183 
    184   if (crishw->int_to_vec != NULL)
    185     {
    186       unsigned int i;
    187       for (i = 0; crishw->int_to_vec[i].portval != 0; i++)
    188 	if (crishw->int_to_vec[i].portval == intparam)
    189 	  break;
    190 
    191       if (crishw->int_to_vec[i].portval == 0)
    192 	hw_abort (me, "unsupported value for int port: 0x%x", intparam);
    193 
    194       vec = crishw->int_to_vec[i].vec;
    195     }
    196   else
    197     vec = (uint32_t) intparam;
    198 
    199   if (crishw->pending_vector != 0)
    200     {
    201       if (vec == crishw->pending_vector)
    202 	return;
    203 
    204       switch (crishw->multi_int_action)
    205 	{
    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);
    209 	  break;
    210 
    211 	case cris_multint_ignore_previous:
    212 	  break;
    213 
    214 	case cris_multint_vector:
    215 	  vec = crishw->multiple_int_vector;
    216 	  break;
    217 
    218 	default:
    219 	  hw_abort (me, "bad switch");
    220 	}
    221     }
    222 
    223   crishw->pending_vector = vec;
    224 
    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);
    229 }
    230 
    231 /* Instance initializer function.  */
    232 
    233 static void
    234 cris_finish (struct hw *me)
    235 {
    236   struct cris_hw *crishw;
    237   const struct hw_property *vec_for_int;
    238   const struct hw_property *multiple_int;
    239 
    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);
    244 
    245   vec_for_int = hw_find_property (me, "vec-for-int");
    246   if (vec_for_int != NULL)
    247     {
    248       uint32_t vecsize;
    249       uint32_t i;
    250 
    251       if (hw_property_type (vec_for_int) != array_property)
    252 	hw_abort (me, "property \"vec-for-int\" has the wrong type");
    253 
    254       vecsize = hw_property_sizeof_array (vec_for_int) / sizeof (signed_cell);
    255 
    256       if ((vecsize % 2) != 0)
    257 	hw_abort (me, "translation vector does not consist of even pairs");
    258 
    259       crishw->int_to_vec
    260 	= hw_malloc (me, (vecsize/2 + 1) * sizeof (crishw->int_to_vec[0]));
    261 
    262       for (i = 0; i < vecsize/2; i++)
    263 	{
    264 	  signed_cell portval_sc;
    265 	  signed_cell vec_sc;
    266 
    267 	  if (!hw_find_integer_array_property (me, "vec-for-int", i*2,
    268 					       &portval_sc)
    269 	      || !hw_find_integer_array_property (me, "vec-for-int", i*2 + 1,
    270 						  &vec_sc)
    271 	      || portval_sc < 0
    272 	      || vec_sc < 0)
    273 	    hw_abort (me, "no valid vector translation pair %u", i);
    274 
    275 	  crishw->int_to_vec[i].portval = (uint32_t) portval_sc;
    276 	  crishw->int_to_vec[i].vec = (uint32_t) vec_sc;
    277 	}
    278 
    279       crishw->int_to_vec[i].portval = 0;
    280       crishw->int_to_vec[i].vec = 0;
    281     }
    282 
    283   multiple_int = hw_find_property (me, "multiple-int");
    284   if (multiple_int != NULL)
    285     {
    286       if (hw_property_type (multiple_int) == integer_property)
    287 	{
    288 	  crishw->multiple_int_vector
    289 	    = hw_find_integer_property (me, "multiple-int");
    290 	  crishw->multi_int_action = cris_multint_vector;
    291 	}
    292       else
    293 	{
    294 	  const char *action = hw_find_string_property (me, "multiple-int");
    295 
    296 	  if (action == NULL)
    297 	    hw_abort (me, "property \"multiple-int\" has the wrong type");
    298 
    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;
    303 	  else
    304 	    hw_abort (me, "property \"multiple-int\" must be one of <vector number>\n"
    305 		      "\"abort\" and \"ignore_previous\", not \"%s\"", action);
    306 	}
    307     }
    308   else
    309     crishw->multi_int_action = cris_multint_abort;
    310 }
    311 
    312 const struct hw_descriptor dv_cris_descriptor[] = {
    313   { "cris", cris_finish, },
    314   { NULL },
    315 };
    316