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