x86: fold narrowing VCVT* templates
[external/binutils.git] / sim / common / hw-base.c
1 /* The common simulator framework for GDB, the GNU Debugger.
2
3    Copyright 2002-2018 Free Software Foundation, Inc.
4
5    Contributed by Andrew Cagney and Red Hat.
6
7    This file is part of GDB.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21
22
23 #include "hw-main.h"
24 #include "hw-base.h"
25
26
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #else
30 #ifdef HAVE_STRINGS_H
31 #include <strings.h>
32 #endif
33 #endif
34
35 #if HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif
38
39 #include <ctype.h>
40
41 #include "hw-config.h"
42
43 struct hw_base_data
44 {
45   int finished_p;
46   const struct hw_descriptor *descriptor;
47   hw_delete_callback *to_delete;
48 };
49
50 static int
51 generic_hw_unit_decode (struct hw *bus,
52                         const char *unit,
53                         hw_unit *phys)
54 {
55   memset (phys, 0, sizeof (*phys));
56   if (unit == NULL)
57     return 0;
58   else
59     {
60       int nr_cells = 0;
61       const int max_nr_cells = hw_unit_nr_address_cells (bus);
62       while (1)
63         {
64           char *end = NULL;
65           unsigned long val;
66           val = strtoul (unit, &end, 0);
67           /* parse error? */
68           if (unit == end)
69             return -1;
70           /* two many cells? */
71           if (nr_cells >= max_nr_cells)
72             return -1;
73           /* save it */
74           phys->cells[nr_cells] = val;
75           nr_cells++;
76           unit = end;
77           /* more to follow? */
78           if (isspace (*unit) || *unit == '\0')
79             break;
80           if (*unit != ',')
81             return -1;
82           unit++;
83         }
84       if (nr_cells < max_nr_cells)
85         {
86           /* shift everything to correct position */
87           int i;
88
89           for (i = 1; i <= nr_cells; i++)
90             phys->cells[max_nr_cells - i] = phys->cells[nr_cells - i];
91           for (i = 0; i < (max_nr_cells - nr_cells); i++)
92             phys->cells[i] = 0;
93         }
94       phys->nr_cells = max_nr_cells;
95       return max_nr_cells;
96   }
97 }
98
99 static int
100 generic_hw_unit_encode (struct hw *bus,
101                         const hw_unit *phys,
102                         char *buf,
103                         int sizeof_buf)
104 {
105   int i;
106   int len;
107   char *pos = buf;
108   /* skip leading zero's */
109   for (i = 0; i < phys->nr_cells; i++)
110     {
111       if (phys->cells[i] != 0)
112         break;
113     }
114   /* don't output anything if empty */
115   if (phys->nr_cells == 0)
116     {
117       strcpy (pos, "");
118       len = 0;
119     }
120   else if (i == phys->nr_cells)
121     {
122       /* all zero */
123       strcpy (pos, "0");
124       len = 1;
125     }
126   else
127     {
128       for (; i < phys->nr_cells; i++)
129         {
130           if (pos != buf)
131             {
132               strcat (pos, ",");
133               pos = strchr (pos, '\0');
134             }
135           if (phys->cells[i] < 10)
136             sprintf (pos, "%ld", (unsigned long)phys->cells[i]);
137           else
138             sprintf (pos, "0x%lx", (unsigned long)phys->cells[i]);
139           pos = strchr (pos, '\0');
140         }
141       len = pos - buf;
142     }
143   if (len >= sizeof_buf)
144     hw_abort (NULL, "generic_unit_encode - buffer overflow\n");
145   return len;
146 }
147
148 static int
149 generic_hw_unit_address_to_attach_address (struct hw *me,
150                                            const hw_unit *address,
151                                            int *attach_space,
152                                            unsigned_word *attach_address,
153                                            struct hw *client)
154 {
155   int i;
156   for (i = 0; i < address->nr_cells - 2; i++)
157     {
158       if (address->cells[i] != 0)
159         hw_abort (me, "Only 32bit addresses supported");
160     }
161   if (address->nr_cells >= 2)
162     *attach_space = address->cells[address->nr_cells - 2];
163   else
164     *attach_space = 0;
165   *attach_address = address->cells[address->nr_cells - 1];
166   return 1;
167 }
168
169 static int
170 generic_hw_unit_size_to_attach_size (struct hw *me,
171                                      const hw_unit *size,
172                                      unsigned *nr_bytes,
173                                      struct hw *client)
174 {
175   int i;
176   for (i = 0; i < size->nr_cells - 1; i++)
177     {
178       if (size->cells[i] != 0)
179         hw_abort (me, "Only 32bit sizes supported");
180     }
181   *nr_bytes = size->cells[0];
182   return *nr_bytes;
183 }
184
185
186 /* ignore/passthrough versions of each function */
187
188 static void
189 passthrough_hw_attach_address (struct hw *me,
190                                int level,
191                                int space,
192                                address_word addr,
193                                address_word nr_bytes,
194                                struct hw *client) /*callback/default*/
195 {
196   if (hw_parent (me) == NULL)
197     hw_abort (client, "hw_attach_address: no parent attach method");
198   hw_attach_address (hw_parent (me), level,
199                      space, addr, nr_bytes,
200                      client);
201 }
202
203 static void
204 passthrough_hw_detach_address (struct hw *me,
205                                int level,
206                                int space,
207                                address_word addr,
208                                address_word nr_bytes,
209                                struct hw *client) /*callback/default*/
210 {
211   if (hw_parent (me) == NULL)
212     hw_abort (client, "hw_attach_address: no parent attach method");
213   hw_detach_address (hw_parent (me), level,
214                      space, addr, nr_bytes,
215                      client);
216 }
217
218 static unsigned
219 panic_hw_io_read_buffer (struct hw *me,
220                          void *dest,
221                          int space,
222                          unsigned_word addr,
223                          unsigned nr_bytes)
224 {
225   hw_abort (me, "no io-read method");
226   return 0;
227 }
228
229 static unsigned
230 panic_hw_io_write_buffer (struct hw *me,
231                           const void *source,
232                           int space,
233                           unsigned_word addr,
234                           unsigned nr_bytes)
235 {
236   hw_abort (me, "no io-write method");
237   return 0;
238 }
239
240 static unsigned
241 passthrough_hw_dma_read_buffer (struct hw *me,
242                                 void *dest,
243                                 int space,
244                                 unsigned_word addr,
245                                 unsigned nr_bytes)
246 {
247   if (hw_parent (me) == NULL)
248     hw_abort (me, "no parent dma-read method");
249   return hw_dma_read_buffer (hw_parent (me), dest,
250                              space, addr, nr_bytes);
251 }
252
253 static unsigned
254 passthrough_hw_dma_write_buffer (struct hw *me,
255                                  const void *source,
256                                  int space,
257                                  unsigned_word addr,
258                                  unsigned nr_bytes,
259                                  int violate_read_only_section)
260 {
261   if (hw_parent (me) == NULL)
262     hw_abort (me, "no parent dma-write method");
263   return hw_dma_write_buffer (hw_parent (me), source,
264                               space, addr,
265                               nr_bytes,
266                               violate_read_only_section);
267 }
268
269 static void
270 ignore_hw_delete (struct hw *me)
271 {
272   /* NOP */
273 }
274
275
276
277
278 static const char *
279 full_name_of_hw (struct hw *leaf,
280                  char *buf,
281                  unsigned sizeof_buf)
282 {
283   /* get a buffer */
284   char full_name[1024];
285   if (buf == (char*)0)
286     {
287       buf = full_name;
288       sizeof_buf = sizeof (full_name);
289     }
290
291   /* use head recursion to construct the path */
292
293   if (hw_parent (leaf) == NULL)
294     /* root */
295     {
296       if (sizeof_buf < 1)
297         hw_abort (leaf, "buffer overflow");
298       *buf = '\0';
299     }
300   else
301     /* sub node */
302     {
303       char unit[1024];
304       full_name_of_hw (hw_parent (leaf), buf, sizeof_buf);
305       if (hw_unit_encode (hw_parent (leaf),
306                           hw_unit_address (leaf),
307                           unit + 1,
308                           sizeof (unit) - 1)
309           > 0)
310         unit[0] = '@';
311       else
312         unit[0] = '\0';
313       if (strlen (buf) + strlen ("/") + strlen (hw_name (leaf)) + strlen (unit)
314           >= sizeof_buf)
315         hw_abort (leaf, "buffer overflow");
316       strcat (buf, "/");
317       strcat (buf, hw_name (leaf));
318       strcat (buf, unit);
319     }
320
321   /* return it usefully */
322   if (buf == full_name)
323     buf = hw_strdup (leaf, full_name);
324   return buf;
325 }
326
327 struct hw *
328 hw_create (struct sim_state *sd,
329            struct hw *parent,
330            const char *family,
331            const char *name,
332            const char *unit,
333            const char *args)
334 {
335  /* NOTE: HW must be allocated using ZALLOC, others use HW_ZALLOC */
336   struct hw *hw = ZALLOC (struct hw);
337
338   /* our identity */
339   hw->family_of_hw = hw_strdup (hw, family);
340   hw->name_of_hw = hw_strdup (hw, name);
341   hw->args_of_hw = hw_strdup (hw, args);
342
343   /* a hook into the system */
344   if (sd != NULL)
345     hw->system_of_hw = sd;
346   else if (parent != NULL)
347     hw->system_of_hw = hw_system (parent);
348   else
349     hw_abort (parent, "No system found");
350
351   /* in a tree */
352   if (parent != NULL)
353     {
354       struct hw **sibling = &parent->child_of_hw;
355       while ((*sibling) != NULL)
356         sibling = &(*sibling)->sibling_of_hw;
357       *sibling = hw;
358       hw->parent_of_hw = parent;
359     }
360
361   /* top of tree */
362   if (parent != NULL)
363     {
364       struct hw *root = parent;
365       while (root->parent_of_hw != NULL)
366         root = root->parent_of_hw;
367       hw->root_of_hw = root;
368     }
369
370   /* a unique identifier for the device on the parents bus */
371   if (parent != NULL)
372     {
373       hw_unit_decode (parent, unit, &hw->unit_address_of_hw);
374     }
375
376   /* Determine our path */
377   if (parent != NULL)
378     hw->path_of_hw = full_name_of_hw (hw, NULL, 0);
379   else
380     hw->path_of_hw = "/";
381
382   /* create our base type */
383   hw->base_of_hw = HW_ZALLOC (hw, struct hw_base_data);
384   hw->base_of_hw->finished_p = 0;
385
386   /* our callbacks */
387   set_hw_io_read_buffer (hw, panic_hw_io_read_buffer);
388   set_hw_io_write_buffer (hw, panic_hw_io_write_buffer);
389   set_hw_dma_read_buffer (hw, passthrough_hw_dma_read_buffer);
390   set_hw_dma_write_buffer (hw, passthrough_hw_dma_write_buffer);
391   set_hw_unit_decode (hw, generic_hw_unit_decode);
392   set_hw_unit_encode (hw, generic_hw_unit_encode);
393   set_hw_unit_address_to_attach_address (hw, generic_hw_unit_address_to_attach_address);
394   set_hw_unit_size_to_attach_size (hw, generic_hw_unit_size_to_attach_size);
395   set_hw_attach_address (hw, passthrough_hw_attach_address);
396   set_hw_detach_address (hw, passthrough_hw_detach_address);
397   set_hw_delete (hw, ignore_hw_delete);
398
399   /* locate a descriptor */
400   {
401     const struct hw_descriptor **table;
402     for (table = hw_descriptors;
403          *table != NULL;
404          table++)
405       {
406         const struct hw_descriptor *entry;
407         for (entry = *table;
408              entry->family != NULL;
409              entry++)
410           {
411             if (strcmp (family, entry->family) == 0)
412               {
413                 hw->base_of_hw->descriptor = entry;
414                 break;
415               }
416           }
417       }
418     if (hw->base_of_hw->descriptor == NULL)
419       {
420         hw_abort (parent, "Unknown device `%s'", family);
421       }
422   }
423
424   /* Attach dummy ports */
425   create_hw_alloc_data (hw);
426   create_hw_property_data (hw);
427   create_hw_port_data (hw);
428   create_hw_event_data (hw);
429   create_hw_handle_data (hw);
430   create_hw_instance_data (hw);
431
432   return hw;
433 }
434
435
436 int
437 hw_finished_p (struct hw *me)
438 {
439   return (me->base_of_hw->finished_p);
440 }
441
442 void
443 hw_finish (struct hw *me)
444 {
445   if (hw_finished_p (me))
446     hw_abort (me, "Attempt to finish finished device");
447
448   /* Fill in the (hopefully) defined address/size cells values */
449   if (hw_find_property (me, "#address-cells") != NULL)
450     me->nr_address_cells_of_hw_unit =
451       hw_find_integer_property (me, "#address-cells");
452   else
453     me->nr_address_cells_of_hw_unit = 2;
454   if (hw_find_property (me, "#size-cells") != NULL)
455     me->nr_size_cells_of_hw_unit =
456       hw_find_integer_property (me, "#size-cells");
457   else
458     me->nr_size_cells_of_hw_unit = 1;
459
460   /* Fill in the (hopefully) defined trace variable */
461   if (hw_find_property (me, "trace?") != NULL)
462     me->trace_of_hw_p = hw_find_boolean_property (me, "trace?");
463   /* allow global variable to define default tracing */
464   else if (! hw_trace_p (me)
465            && hw_find_property (hw_root (me), "global-trace?") != NULL
466            && hw_find_boolean_property (hw_root (me), "global-trace?"))
467     me->trace_of_hw_p = 1;
468
469
470   /* Allow the real device to override any methods */
471   me->base_of_hw->descriptor->to_finish (me);
472   me->base_of_hw->finished_p = 1;
473 }
474
475
476 void
477 hw_delete (struct hw *me)
478 {
479   /* give the object a chance to tidy up */
480   me->base_of_hw->to_delete (me);
481
482   delete_hw_instance_data (me);
483   delete_hw_handle_data (me);
484   delete_hw_event_data (me);
485   delete_hw_port_data (me);
486   delete_hw_property_data (me);
487
488   /* now unlink us from the tree */
489   if (hw_parent (me))
490     {
491       struct hw **sibling = &hw_parent (me)->child_of_hw;
492       while (*sibling != NULL)
493         {
494           if (*sibling == me)
495             {
496               *sibling = me->sibling_of_hw;
497               me->sibling_of_hw = NULL;
498               me->parent_of_hw = NULL;
499               break;
500             }
501         }
502     }
503
504   /* some sanity checks */
505   if (hw_child (me) != NULL)
506     {
507       hw_abort (me, "attempt to delete device with children");
508     }
509   if (hw_sibling (me) != NULL)
510     {
511       hw_abort (me, "attempt to delete device with siblings");
512     }
513
514   /* blow away all memory belonging to the device */
515   delete_hw_alloc_data (me);
516
517   /* finally */
518   free (me);
519 }
520
521 void
522 set_hw_delete (struct hw *hw, hw_delete_callback method)
523 {
524   hw->base_of_hw->to_delete = method;
525 }
526
527
528 /* Go through the devices various reg properties for those that
529    specify attach addresses */
530
531
532 void
533 do_hw_attach_regs (struct hw *hw)
534 {
535   static const char *(reg_property_names[]) = {
536     "attach-addresses",
537     "assigned-addresses",
538     "reg",
539     "alternate-reg" ,
540     NULL
541   };
542   const char **reg_property_name;
543   int nr_valid_reg_properties = 0;
544   for (reg_property_name = reg_property_names;
545        *reg_property_name != NULL;
546        reg_property_name++)
547     {
548       if (hw_find_property (hw, *reg_property_name) != NULL)
549         {
550           reg_property_spec reg;
551           int reg_entry;
552           for (reg_entry = 0;
553                hw_find_reg_array_property (hw, *reg_property_name, reg_entry,
554                                            &reg);
555                reg_entry++)
556             {
557               unsigned_word attach_address;
558               int attach_space;
559               unsigned attach_size;
560               if (!hw_unit_address_to_attach_address (hw_parent (hw),
561                                                       &reg.address,
562                                                       &attach_space,
563                                                       &attach_address,
564                                                       hw))
565                 continue;
566               if (!hw_unit_size_to_attach_size (hw_parent (hw),
567                                                 &reg.size,
568                                                 &attach_size, hw))
569                 continue;
570               hw_attach_address (hw_parent (hw),
571                                  0,
572                                  attach_space, attach_address, attach_size,
573                                  hw);
574               nr_valid_reg_properties++;
575             }
576           /* if first option matches don't try for any others */
577           if (reg_property_name == reg_property_names)
578             break;
579         }
580     }
581 }