OSDN Git Service

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