OSDN Git Service

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