sim: syscall: unify memory helpers
[external/binutils.git] / sim / cris / dv-cris.c
1 /* The CRIS interrupt framework for GDB, the GNU Debugger.
2
3    Copyright 2006-2015 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".  */
75 enum
76  {
77    INT_PORT,
78  };
79
80 static const struct hw_port_descriptor cris_ports[] =
81  {
82    { "int", INT_PORT, 0, input_port },
83    { NULL, 0, 0, 0 }
84  };
85
86 struct cris_vec_tr
87  {
88    unsigned32 portval, vec;
89  };
90
91 enum cris_multiple_ints
92   {
93     cris_multint_abort,
94     cris_multint_ignore_previous,
95     cris_multint_vector
96   };
97
98 struct 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
110 static void
111 deliver_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
156 static void
157 cris_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
230 static void
231 cris_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
309 const struct hw_descriptor dv_cris_descriptor[] = {
310   { "cris", cris_finish, },
311   { NULL },
312 };