Copy function ../ppc/device_table.c:generic_device_init_address() to
authorAndrew Cagney <cagney@redhat.com>
Sun, 22 Mar 1998 05:49:30 +0000 (05:49 +0000)
committerAndrew Cagney <cagney@redhat.com>
Sun, 22 Mar 1998 05:49:30 +0000 (05:49 +0000)
hw-base.c:do_hw_attach_regs().  Use in dv-pal.
Add hw_tree_delete to hw-tree.c.

sim/common/ChangeLog
sim/common/dv-pal.c
sim/common/hw-base.c
sim/common/hw-tree.c [new file with mode: 0644]

index 9ecbe0436a6b43eea9ff813b0a8372d10013de28..e454601b1328d470037c2ce2e2795efaab3a9905 100644 (file)
@@ -1,3 +1,13 @@
+Sun Mar 22 16:45:54 1998  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * hw-base.h, hw-base.c (do_hw_attach_regs): Copy function from
+       ../ppc/device_table.c.
+
+       * dv-pal.c (hw_pal_finish): Attach PAL device to parent bus.
+
+       * hw-tree.c (print_properties): Supress path when printing
+       properties of root node.
+
 Sun Mar 22 16:21:15 1998  Andrew Cagney  <cagney@b1.cygnus.com>
 
        * hw-device.h (HW_TRACE): Define.
@@ -32,6 +42,8 @@ Sun Mar 22 15:23:35 1998  Andrew Cagney  <cagney@b1.cygnus.com>
        (hw_create): Allocate the base type using HW_ZALLOC before setting
        any methods.
 
+       * hw-tree.h, hw-tree.c (hw_tree_delete): New function.
+       
        * hw-properties.c: Replace zalloc/zfree with hw_zalloc/hw_free.
        
        * hw-ports.c: Replace zalloc/zfree with hw_zalloc/hw_free.
index 2e00c3bddee7c94198f753311f2f03f2a37843dd..c98ff6860f10336b389a1c0e8494d66fedfaeb74 100644 (file)
@@ -385,6 +385,8 @@ hw_pal_finish (struct hw *hw)
   set_hw_io_read_buffer (hw, hw_pal_io_read_buffer);
   set_hw_io_write_buffer (hw, hw_pal_io_write_buffer);
   set_hw_ports (hw, hw_pal_ports);
+  /* attach ourselves */
+  do_hw_attach_regs (me);
 }
 
 
index ad17df43865f6121819c6b52626a397410e40234..2057e904bd8d4f3bb0d9d661d42fd170dba38175 100644 (file)
@@ -442,10 +442,6 @@ hw_create (SIM_DESC sd,
       }
   }
 
-  /* Fill in the (hopefully) defined trace variable */
-  if (hw_find_property (hw, "trace?") != NULL)
-    hw->trace_of_hw_p = hw_find_boolean_property (hw, "trace?");
-
   /* Attach dummy ports */
   set_hw_ports (hw, empty_hw_ports);
   set_hw_port_event (hw, panic_hw_port_event);
@@ -478,6 +474,10 @@ hw_finish (struct hw *me)
   else
     me->nr_size_cells_of_hw_unit = 1;
 
+  /* Fill in the (hopefully) defined trace variable */
+  if (hw_find_property (hw, "trace?") != NULL)
+    hw->trace_of_hw_p = hw_find_boolean_property (hw, "trace?");
+
   /* Allow the real device to override any methods */
   me->base_of_hw->descriptor->to_finish (me);
   me->base_of_hw->finished_p = 1;
@@ -523,3 +523,59 @@ hw_delete (struct hw *me)
   zfree (me->base_of_hw);
   zfree (me);
 }
+
+
+/* Go through the devices various reg properties for those that
+   specify attach addresses */
+
+
+void
+do_hw_attach_regs (struct hw *hw)
+{
+  static const char *(reg_property_names[]) = {
+    "attach-addresses",
+    "assigned-addresses",
+    "reg",
+    "alternate-reg" ,
+    NULL
+  };
+  const char **reg_property_name;
+  int nr_valid_reg_properties = 0;
+  for (reg_property_name = reg_property_names;
+       *reg_property_name != NULL;
+       reg_property_name++)
+    {
+      if (hw_find_property (hw, *reg_property_name) != NULL)
+       {
+         reg_property_spec reg;
+         int reg_entry;
+         for (reg_entry = 0;
+              hw_find_reg_array_property (hw, *reg_property_name, reg_entry,
+                                          &reg);
+              reg_entry++)
+           {
+             unsigned_word attach_address;
+             int attach_space;
+             unsigned attach_size;
+             if (!hw_unit_address_to_attach_address (hw_parent (hw),
+                                                     &reg.address,
+                                                     &attach_space,
+                                                     &attach_address,
+                                                     hw))
+               continue;
+             if (!hw_unit_size_to_attach_size (hw_parent (hw),
+                                               &reg.size,
+                                               &attach_size, hw))
+               continue;
+             hw_attach_address (hw_parent (hw),
+                                0,
+                                attach_space, attach_address, attach_size,
+                                hw);
+             nr_valid_reg_properties++;
+           }
+         /* if first option matches don't try for any others */
+         if (reg_property_name == reg_property_names)
+           break;
+       }
+    }
+}
diff --git a/sim/common/hw-tree.c b/sim/common/hw-tree.c
new file mode 100644 (file)
index 0000000..219b75b
--- /dev/null
@@ -0,0 +1,1316 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+    */
+
+#include "sim-main.h"
+
+#include "hw-base.h"
+#include "hw-tree.h"
+
+#include "sim-assert.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+
+#include <ctype.h>
+
+/* manipulate/lookup device names */
+
+typedef struct _name_specifier {
+  
+  /* components in the full length name */
+  char *path;
+  char *property;
+  char *value;
+  
+  /* current device */
+  char *family;
+  char *name;
+  char *unit;
+  char *args;
+  
+  /* previous device */
+  char *last_name;
+  char *last_family;
+  char *last_unit;
+  char *last_args;
+  
+  /* work area */
+  char buf[1024];
+  
+} name_specifier;
+
+
+
+/* Given a device specifier, break it up into its main components:
+   path (and if present) property name and property value. */
+
+static int
+split_device_specifier (struct hw *current,
+                       const char *device_specifier,
+                       name_specifier *spec)
+{
+  char *chp = NULL;
+  
+  /* expand any leading alias if present */
+  if (current != NULL
+      && *device_specifier != '\0'
+      && *device_specifier != '.'
+      && *device_specifier != '/')
+    {
+      struct hw *aliases = hw_tree_find_device (current, "/aliases");
+      char alias[32];
+      int len = 0;
+      while (device_specifier[len] != '\0'
+            && device_specifier[len] != '/'
+            && device_specifier[len] != ':'
+            && !isspace (device_specifier[len]))
+       {
+         alias[len] = device_specifier[len];
+         len++;
+         if (len >= sizeof(alias))
+           hw_abort (NULL, "split_device_specifier: buffer overflow");
+       }
+      alias[len] = '\0';
+      if (aliases != NULL
+         && hw_find_property (aliases, alias))
+       {
+         strcpy (spec->buf, hw_find_string_property(aliases, alias));
+         strcat (spec->buf, device_specifier + len);
+       }
+      else
+       {
+         strcpy (spec->buf, device_specifier);
+       }
+    }
+  else
+    {
+      strcpy(spec->buf, device_specifier);
+    }
+  
+  /* check no overflow */
+  if (strlen(spec->buf) >= sizeof(spec->buf))
+    hw_abort (NULL, "split_device_specifier: buffer overflow\n");
+  
+  /* strip leading spaces */
+  chp = spec->buf;
+  while (*chp != '\0' && isspace(*chp))
+    chp++;
+  if (*chp == '\0')
+    return 0;
+  
+  /* find the path and terminate it with null */
+  spec->path = chp;
+  while (*chp != '\0' && !isspace(*chp))
+    chp++;
+  if (*chp != '\0')
+    {
+      *chp = '\0';
+      chp++;
+    }
+  
+  /* and any value */
+  while (*chp != '\0' && isspace(*chp))
+    chp++;
+  spec->value = chp;
+  
+  /* now go back and chop the property off of the path */
+  if (spec->value[0] == '\0')
+    {
+      spec->property = NULL; /*not a property*/
+      spec->value = NULL;
+    }
+  else if (spec->value[0] == '>'
+          || spec->value[0] == '<')
+    {
+      /* an interrupt spec */
+      spec->property = NULL;
+    }
+  else {
+    chp = strrchr(spec->path, '/');
+    if (chp == NULL)
+      {
+       spec->property = spec->path;
+       spec->path = strchr(spec->property, '\0');
+      }
+    else {
+      *chp = '\0';
+      spec->property = chp+1;
+    }
+  }
+  
+  /* and mark the rest as invalid */
+  spec->name = NULL;
+  spec->family = NULL;
+  spec->unit = NULL;
+  spec->args = NULL;
+  spec->last_name = NULL;
+  spec->last_family = NULL;
+  spec->last_unit = NULL;
+  spec->last_args = NULL;
+  
+  return 1;
+}
+
+
+/* given a device specifier break it up into its main components -
+   path and property name - assuming that the last `device' is a
+   property name. */
+
+static int
+split_property_specifier (struct hw *current,
+                         const char *property_specifier,
+                         name_specifier *spec)
+{
+  if (split_device_specifier (current, property_specifier, spec))
+    {
+      if (spec->property == NULL)
+       {
+         /* force the last name to be a property name */
+         char *chp = strrchr (spec->path, '/');
+         if (chp == NULL)
+           {
+             spec->property = spec->path;
+             spec->path = strrchr (spec->property, '\0');;
+           }
+         else
+           {
+             *chp = '\0';
+             spec->property = chp + 1;
+           }
+       }
+      return 1;
+    }
+  else
+    return 0;
+}
+
+
+/* device the next device name and split it up, return 0 when no more
+   names to struct hw */
+
+static int
+split_device_name (name_specifier *spec)
+{
+  char *chp;
+  /* remember what came before */
+  spec->last_name = spec->name;
+  spec->last_family = spec->family;
+  spec->last_unit = spec->unit;
+  spec->last_args = spec->args;
+  /* finished? */
+  if (spec->path[0] == '\0')
+    {
+      spec->name = NULL;
+      spec->family = NULL;
+      spec->unit = NULL;
+      spec->args = NULL;
+      return 0;
+    }
+  /* break the current device spec from the path */
+  spec->name = spec->path;
+  chp = strchr (spec->name, '/');
+  if (chp == NULL)
+    spec->path = strchr (spec->name, '\0');
+  else 
+    {
+      spec->path = chp+1;
+      *chp = '\0';
+    }
+  /* break out the base */
+  if (spec->name[0] == '(')
+    {
+      chp = strchr(spec->name, ')');
+      if (chp == NULL)
+       {
+         spec->family = spec->name;
+       }
+      else
+       {
+         *chp = '\0';
+         spec->family = spec->name + 1;
+         spec->name = chp + 1;
+       }
+    }
+  else
+    {
+      spec->family = spec->name;
+    }
+  /* now break out the unit */
+  chp = strchr(spec->name, '@');
+  if (chp == NULL)
+    {
+      spec->unit = NULL;
+      chp = spec->name;
+    }
+  else
+    {
+      *chp = '\0';
+      chp += 1;
+      spec->unit = chp;
+    }
+  /* finally any args */
+  chp = strchr(chp, ':');
+  if (chp == NULL)
+    spec->args = NULL;
+  else
+    {
+      *chp = '\0';
+      spec->args = chp+1;
+    }
+  return 1;
+}
+
+
+/* device the value, returning the next non-space token */
+
+static char *
+split_value (name_specifier *spec)
+{
+  char *token;
+  if (spec->value == NULL)
+    return NULL;
+  /* skip leading white space */
+  while (isspace (spec->value[0]))
+    spec->value++;
+  if (spec->value[0] == '\0')
+    {
+      spec->value = NULL;
+      return NULL;
+    }
+  token = spec->value;
+  /* find trailing space */
+  while (spec->value[0] != '\0' && !isspace (spec->value[0]))
+    spec->value++;
+  /* chop this value out */
+  if (spec->value[0] != '\0')
+    {
+      spec->value[0] = '\0';
+      spec->value++;
+    }
+  return token;
+}
+
+
+
+/* traverse the path specified by spec starting at current */
+
+static struct hw *
+split_find_device (struct hw *current,
+                  name_specifier *spec)
+{
+  /* strip off (and process) any leading ., .., ./ and / */
+  while (1)
+    {
+      if (strncmp (spec->path, "/", strlen ("/")) == 0)
+       {
+         /* cd /... */
+         while (current != NULL && hw_parent (current) != NULL)
+           current = hw_parent (current);
+         spec->path += strlen ("/");
+       }
+      else if (strncmp (spec->path, "./", strlen ("./")) == 0)
+       {
+         /* cd ./... */
+         current = current;
+         spec->path += strlen ("./");
+       }
+      else if (strncmp (spec->path, "../", strlen ("../")) == 0)
+       {
+         /* cd ../... */
+         if (current != NULL && hw_parent (current) != NULL)
+           current = hw_parent (current);
+         spec->path += strlen ("../");
+       }
+      else if (strcmp (spec->path, ".") == 0)
+       {
+         /* cd . */
+         current = current;
+         spec->path += strlen (".");
+       }
+      else if (strcmp (spec->path, "..") == 0)
+       {
+         /* cd .. */
+         if (current != NULL && hw_parent (current) != NULL)
+           current = hw_parent (current);
+         spec->path += strlen ("..");
+       }
+      else
+       break;
+    }
+  
+  /* now go through the path proper */
+  
+  if (current == NULL)
+    {
+      split_device_name (spec);
+      return NULL;
+    }
+  
+  while (split_device_name (spec))
+    {
+      struct hw *child;
+      for (child = hw_child (current);
+          child != NULL; child = hw_sibling (child))
+       {
+         if (strcmp (spec->name, hw_name (child)) == 0)
+           {
+             if (spec->unit == NULL)
+               break;
+             else
+               {
+                 hw_unit phys;
+                 hw_unit_decode (current, spec->unit, &phys);
+                 if (memcmp (&phys, hw_unit_address (child),
+                             sizeof (hw_unit)) == 0)
+                   break;
+               }
+           }
+       }
+      if (child == NULL)
+       return current; /* search failed */
+      current = child;
+    }
+  
+  return current;
+}
+
+
+static struct hw *
+split_fill_path (struct hw *current,
+                const char *device_specifier,
+                name_specifier *spec)
+{
+  /* break it up */
+  if (!split_device_specifier (current, device_specifier, spec))
+    hw_abort (current, "error parsing %s\n", device_specifier);
+  
+  /* fill our tree with its contents */
+  current = split_find_device (current, spec);
+  
+  /* add any additional devices as needed */
+  if (spec->name != NULL)
+    {
+      do
+       {
+         if (current != NULL && !hw_finished_p (current))
+           hw_finish (current);
+         current = hw_create (NULL,
+                              current,
+                              spec->family,
+                              spec->name,
+                              spec->unit,
+                              spec->args);
+       }
+      while (split_device_name (spec));
+    }
+  
+  return current;
+}
+
+\f
+/* <non-white-space> */
+
+static const char *
+skip_token(const char *chp)
+{
+  while (!isspace(*chp) && *chp != '\0')
+    chp++;
+  while (isspace(*chp) && *chp != '\0')
+    chp++;
+  return chp;
+}
+
+
+/* count the number of entries */
+
+static int
+count_entries (struct hw *current,
+              const char *property_name,
+              const char *property_value,
+              int modulo)
+{
+  const char *chp = property_value;
+  int nr_entries = 0;
+  while (*chp != '\0')
+    {
+      nr_entries += 1;
+      chp = skip_token (chp);
+    }
+  if ((nr_entries % modulo) != 0)
+    {
+      hw_abort (current, "incorrect number of entries for %s property %s, should be multiple of %d",
+               property_name, property_value, modulo);
+    }
+  return nr_entries / modulo;
+}
+
+
+
+/* parse: <address> ::= <token> ; device dependant */
+
+static const char *
+parse_address (struct hw *current,
+              struct hw *bus,
+              const char *chp,
+              hw_unit *address)
+{
+  if (hw_unit_decode (bus, chp, address) < 0)
+    hw_abort (current, "invalid unit address in %s", chp);
+  return skip_token (chp);
+}
+
+
+/* parse: <size> ::= <number> { "," <number> } ; */
+
+static const char *
+parse_size (struct hw *current,
+           struct hw *bus,
+           const char *chp,
+           hw_unit *size)
+{
+  int i;
+  int nr;
+  const char *curr = chp;
+  memset(size, 0, sizeof(*size));
+  /* parse the numeric list */
+  size->nr_cells = hw_unit_nr_size_cells (bus);
+  nr = 0;
+  while (1)
+    {
+      char *next;
+      size->cells[nr] = strtoul (curr, &next, 0);
+      if (curr == next)
+       hw_abort (current, "Problem parsing <size> %s", chp);
+      nr += 1;
+      if (next[0] != ',')
+       break;
+      if (nr == size->nr_cells)
+       hw_abort (current, "Too many values in <size> %s", chp);
+      curr = next + 1;
+    }
+  ASSERT (nr > 0 && nr <= size->nr_cells);
+  /* right align the numbers */
+  for (i = 1; i <= size->nr_cells; i++)
+    {
+      if (i <= nr)
+       size->cells[size->nr_cells - i] = size->cells[nr - i];
+      else
+       size->cells[size->nr_cells - i] = 0;
+    }
+  return skip_token (chp);
+}
+
+
+/* parse: <reg> ::= { <address> <size> } ; */
+
+static void
+parse_reg_property (struct hw *current,
+                   const char *property_name,
+                   const char *property_value)
+{
+  int nr_regs;
+  int reg_nr;
+  reg_property_spec *regs;
+  const char *chp;
+  
+  /* determine the number of reg entries by counting tokens */
+  nr_regs = count_entries (current, property_name, property_value, 2);
+  
+  /* create working space */
+  regs = zalloc (nr_regs * sizeof (*regs));
+  
+  /* fill it in */
+  chp = property_value;
+  for (reg_nr = 0; reg_nr < nr_regs; reg_nr++)
+    {
+      chp = parse_address (current, hw_parent(current),
+                          chp, &regs[reg_nr].address);
+      chp = parse_size (current, hw_parent(current),
+                       chp, &regs[reg_nr].size);
+    }
+  
+  /* create it */
+  hw_add_reg_array_property (current, property_name,
+                            regs, nr_regs);
+  
+  zfree (regs);
+}
+
+
+/* { <child-address> <parent-address> <child-size> }* */
+
+static void
+parse_ranges_property (struct hw *current,
+                      const char *property_name,
+                      const char *property_value)
+{
+  int nr_ranges;
+  int range_nr;
+  range_property_spec *ranges;
+  const char *chp;
+  
+  /* determine the number of ranges specified */
+  nr_ranges = count_entries (current, property_name, property_value, 3);
+  
+  /* create a property of that size */
+  ranges = zalloc (nr_ranges * sizeof(*ranges));
+  
+  /* fill it in */
+  chp = property_value;
+  for (range_nr = 0; range_nr < nr_ranges; range_nr++)
+    {
+      chp = parse_address (current, current,
+                          chp, &ranges[range_nr].child_address);
+      chp = parse_address (current, hw_parent(current),
+                          chp, &ranges[range_nr].parent_address);
+      chp = parse_size (current, current,
+                       chp, &ranges[range_nr].size);
+    }
+  
+  /* create it */
+  hw_add_range_array_property (current, property_name, ranges, nr_ranges);
+  
+  zfree (ranges);
+}
+
+
+/* <integer> ... */
+
+static void
+parse_integer_property (struct hw *current,
+                       const char *property_name,
+                       const char *property_value)
+{
+  int nr_entries;
+  unsigned_cell words[1024];
+  /* integer or integer array? */
+  nr_entries = 0;
+  while (1)
+    {
+      char *end;
+      words[nr_entries] = strtoul (property_value, &end, 0);
+      if (property_value == end)
+       break;
+      nr_entries += 1;
+      if (nr_entries * sizeof (words[0]) >= sizeof (words))
+       hw_abort (current, "buffer overflow");
+      property_value = end;
+    }
+  if (nr_entries == 0)
+    hw_abort (current, "error parsing integer property %s (%s)",
+             property_name, property_value);
+  else if (nr_entries == 1)
+    hw_add_integer_property (current, property_name, words[0]);
+  else
+    {
+      int i;
+      for (i = 0; i < nr_entries; i++)
+       {
+         H2BE (words[i]);
+       }
+      /* perhaphs integer array property is better */
+      hw_add_array_property (current, property_name, words,
+                            sizeof(words[0]) * nr_entries);
+    }
+}
+
+
+/* <string> ... */
+
+static void
+parse_string_property (struct hw *current,
+                      const char *property_name,
+                      const char *property_value)
+{
+  char **strings;
+  const char *chp;
+  int nr_strings;
+  int approx_nr_strings;
+  
+  /* get an estimate as to the number of strings by counting double
+     quotes */
+  approx_nr_strings = 2;
+  for (chp = property_value; *chp; chp++)
+    {
+      if (*chp == '"')
+       approx_nr_strings++;
+    }
+  approx_nr_strings = (approx_nr_strings) / 2;
+  
+  /* create a string buffer for that many (plus a null) */
+  strings = (char**) zalloc ((approx_nr_strings + 1) * sizeof(char*));
+  
+  /* now find all the strings */
+  chp = property_value;
+  nr_strings = 0;
+  while (1)
+    {
+      
+      /* skip leading space */
+      while (*chp != '\0' && isspace (*chp))
+       chp += 1;
+      if (*chp == '\0')
+       break;
+      
+      /* copy it in */
+      if (*chp == '"')
+       {
+         /* a quoted string - watch for '\' et.al. */
+         /* estimate the size and allocate space for it */
+         int pos;
+         chp++;
+         pos = 0;
+         while (chp[pos] != '\0' && chp[pos] != '"')
+           {
+             if (chp[pos] == '\\' && chp[pos+1] != '\0')
+               pos += 2;
+             else
+               pos += 1;
+           }
+         strings[nr_strings] = zalloc (pos + 1);
+         /* copy the string over */
+         pos = 0;
+         while (*chp != '\0' && *chp != '"')
+           {
+             if (*chp == '\\' && *(chp+1) != '\0') {
+               strings[nr_strings][pos] = *(chp+1);
+               chp += 2;
+               pos++;
+             }
+             else
+               {
+                 strings[nr_strings][pos] = *chp;
+                 chp += 1;
+                 pos++;
+               }
+           }
+         if (*chp != '\0')
+           chp++;
+         strings[nr_strings][pos] = '\0';
+       }
+      else
+       {
+         /* copy over a single unquoted token */
+         int len = 0;
+         while (chp[len] != '\0' && !isspace(chp[len]))
+           len++;
+         strings[nr_strings] = zalloc(len + 1);
+         strncpy(strings[nr_strings], chp, len);
+         strings[nr_strings][len] = '\0';
+         chp += len;
+       }
+      nr_strings++;
+      if (nr_strings > approx_nr_strings)
+       hw_abort (current, "String property %s badly formatted",
+                 property_name);
+    }
+  ASSERT (strings[nr_strings] == NULL); /* from zalloc */
+  
+  /* install it */
+  if (nr_strings == 0)
+    hw_add_string_property (current, property_name, "");
+  else if (nr_strings == 1)
+    hw_add_string_property (current, property_name, strings[0]);
+  else
+    {
+      const char **specs = (const char**) strings; /* stop a bogus error */
+      hw_add_string_array_property (current, property_name,
+                                   specs, nr_strings);
+    }
+  
+  /* flush the created string */
+  while (nr_strings > 0)
+    {
+      nr_strings--;
+      zfree (strings[nr_strings]);
+    }
+  zfree(strings);
+}
+
+
+/* <path-to-ihandle-device> */
+
+#if NOT_YET
+static void
+parse_ihandle_property (struct hw *current,
+                       const char *property,
+                       const char *value)
+{
+  ihandle_runtime_property_spec ihandle;
+  
+  /* pass the full path */
+  ihandle.full_path = value;
+  
+  /* save this ready for the ihandle create */
+  hw_add_ihandle_runtime_property (current, property,
+                                  &ihandle);
+}
+#endif
+
+
+struct hw *
+hw_tree_create (SIM_DESC sd,
+               const char *family)
+{
+  return hw_create (sd, NULL, family, family, NULL, NULL);
+}
+
+void
+hw_tree_delete (struct hw *me)
+{
+  /* Need to allow devices to disapear under our feet */
+  while (hw_child (me) != NULL)
+    {
+      hw_tree_delete (hw_child (me));
+    }
+  hw_delete (me);
+}
+
+
+struct hw *
+hw_tree_parse (struct hw *current,
+              const char *fmt,
+              ...)
+{
+  char device_specifier[1024];
+  name_specifier spec;
+  
+  /* format the path */
+  {
+    va_list ap;
+    va_start (ap, fmt);
+    vsprintf (device_specifier, fmt, ap);
+    va_end (ap);
+    if (strlen (device_specifier) >= sizeof (device_specifier))
+      hw_abort (NULL, "device_tree_add_deviced: buffer overflow\n");
+  }
+  
+  /* construct the tree down to the final struct hw */
+  current = split_fill_path (current, device_specifier, &spec);
+  
+  /* is there an interrupt spec */
+  if (spec.property == NULL
+      && spec.value != NULL)
+    {
+      char *op = split_value (&spec);
+      switch (op[0])
+       {
+       case '>':
+         {
+           char *my_port_name = split_value (&spec);
+           int my_port;
+           char *dest_port_name = split_value (&spec);
+           int dest_port;
+           name_specifier dest_spec;
+           char *dest_hw_name = split_value (&spec);
+           struct hw *dest;
+           /* find my name */
+           my_port = hw_port_decode (current, my_port_name,
+                                     output_port);
+           /* find the dest device and port */
+           dest = split_fill_path(current, dest_hw_name, &dest_spec);
+           dest_port = hw_port_decode (dest, dest_port_name,
+                                       input_port);
+           /* connect the two */
+           hw_port_attach (current,
+                           my_port,
+                           dest,
+                           dest_port,
+                           permenant_object);
+           break;
+         }
+       default:
+         hw_abort (current, "unreconised interrupt spec %s\n", spec.value);
+         break;
+       }
+    }
+  
+  /* is there a property */
+  if (spec.property != NULL)
+    {
+      if (strcmp (spec.value, "true") == 0)
+       hw_add_boolean_property (current, spec.property, 1);
+      else if (strcmp (spec.value, "false") == 0)
+       hw_add_boolean_property (current, spec.property, 0);
+      else
+       {
+         const struct hw_property *property;
+         switch (spec.value[0])
+           {
+#if NOT_YET
+           case '*':
+             {
+               parse_ihandle_property (current, spec.property, spec.value + 1);
+               break;
+             }
+#endif
+           case '[':
+             {
+               unsigned8 words[1024];
+               char *curr = spec.value + 1;
+               int nr_words = 0;
+               while (1)
+                 {
+                   char *next;
+                   words[nr_words] = H2BE_1 (strtoul (curr, &next, 0));
+                   if (curr == next)
+                     break;
+                   curr = next;
+                   nr_words += 1;
+                 }
+               hw_add_array_property (current, spec.property,
+                                      words, sizeof(words[0]) * nr_words);
+               break;
+             }
+           case '"':
+             {
+               parse_string_property (current, spec.property, spec.value);
+               break;
+             }
+           case '!':
+             {
+               spec.value++;
+               property = hw_tree_find_property (current, spec.value);
+               if (property == NULL)
+                 hw_abort (current, "property %s not found\n", spec.value);
+               hw_add_duplicate_property (current,
+                                          spec.property,
+                                          property);
+               break;
+             }
+           default:
+             {
+               if (strcmp (spec.property, "reg") == 0
+                   || strcmp (spec.property, "assigned-addresses") == 0
+                   || strcmp (spec.property, "alternate-reg") == 0)
+                 {
+                   parse_reg_property (current, spec.property, spec.value);
+                 }
+               else if (strcmp (spec.property, "ranges") == 0)
+                 {
+                   parse_ranges_property (current, spec.property, spec.value);
+                 }
+               else if (isdigit(spec.value[0])
+                        || (spec.value[0] == '-' && isdigit(spec.value[1]))
+                        || (spec.value[0] == '+' && isdigit(spec.value[1])))
+                 {
+                   parse_integer_property(current, spec.property, spec.value);
+                 }
+               else
+                 parse_string_property(current, spec.property, spec.value);
+               break;
+             }
+           }
+       }
+    }
+  return current;
+}
+
+
+static void
+finish_hw_tree (struct hw *me,
+               void *data)
+{
+  if (!hw_finished_p (me))
+    hw_finish (me);
+}
+
+void
+hw_tree_finish (struct hw *root)
+{
+  hw_tree_traverse (root, finish_hw_tree, NULL, NULL);
+}
+
+
+
+void
+hw_tree_traverse (struct hw *root,
+                 hw_tree_traverse_function *prefix,
+                 hw_tree_traverse_function *postfix,
+                 void *data)
+{
+  struct hw *child;
+  if (prefix != NULL)
+    prefix (root, data);
+  for (child = hw_child (root);
+       child != NULL;
+       child = hw_sibling (child))
+    {
+      hw_tree_traverse (child, prefix, postfix, data);
+    }
+  if (postfix != NULL)
+    postfix (root, data);
+}
+
+
+static void hw_printf
+(struct hw *,
+ const char *,
+ ...) __attribute__ ((format (printf, 2, 3)));
+
+static void
+hw_printf (struct hw *me,
+          const char *fmt,
+          ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  sim_io_vprintf (hw_system (me), fmt, ap);
+  va_end (ap);
+}
+
+
+static void
+print_address (struct hw *bus,
+              const hw_unit *phys)
+{
+  char unit[32];
+  hw_unit_encode (bus, phys, unit, sizeof(unit));
+  hw_printf (bus, " %s", unit);
+}
+
+static void
+print_size (struct hw *bus,
+           const hw_unit *size)
+{
+  int i;
+  for (i = 0; i < size->nr_cells; i++)
+    if (size->cells[i] != 0)
+      break;
+  if (i < size->nr_cells) {
+    hw_printf (bus, " 0x%lx", (unsigned long) size->cells[i]);
+    i++;
+    for (; i < size->nr_cells; i++)
+      hw_printf (bus, ",0x%lx", (unsigned long) size->cells[i]);
+  }
+  else
+    hw_printf (bus, " 0");
+}
+
+static void
+print_reg_property(struct hw *me,
+                  const struct hw_property *property)
+{
+  int reg_nr;
+  reg_property_spec reg;
+  for (reg_nr = 0;
+       hw_find_reg_array_property (me, property->name, reg_nr, &reg);
+       reg_nr++) {
+    print_address (hw_parent (me), &reg.address);
+    print_size (me, &reg.size);
+  }
+}
+
+static void
+print_ranges_property(struct hw *me,
+                     const struct hw_property *property)
+{
+  int range_nr;
+  range_property_spec range;
+  for (range_nr = 0;
+       hw_find_range_array_property (me, property->name, range_nr, &range);
+       range_nr++)
+    {
+      print_address (me, &range.child_address);
+      print_address (hw_parent (me), &range.parent_address);
+      print_size (me, &range.size);
+    }
+}
+
+static void
+print_string (struct hw *me,
+             const char *string)
+{
+  hw_printf (me, " \"");
+  while (*string != '\0') {
+    switch (*string) {
+    case '"':
+      hw_printf (me, "\\\"");
+      break;
+    case '\\':
+      hw_printf (me, "\\\\");
+      break;
+    default:
+      hw_printf (me, "%c", *string);
+      break;
+    }
+    string++;
+  }
+  hw_printf (me, "\"");
+}
+
+static void
+print_string_array_property (struct hw *me,
+                            const struct hw_property *property)
+{
+  int nr;
+  string_property_spec string;
+  for (nr = 0;
+       hw_find_string_array_property (me, property->name, nr, &string);
+       nr++)
+    {
+      print_string (me, string);
+    }
+}
+
+static void
+print_properties (struct hw *me)
+{
+  const struct hw_property *property;
+  for (property = hw_find_property (me, NULL);
+       property != NULL;
+       property = hw_next_property (property))
+    {
+      if (hw_parent (me) == NULL)
+       hw_printf (me, "/%s", property->name);
+      else
+       hw_printf (me, "%s/%s", hw_path (me), property->name);
+      if (property->original != NULL)
+       {
+         hw_printf (me, " !");
+         hw_printf (me, "%s/%s", 
+                    hw_path (property->original->owner),
+                    property->original->name);
+       }
+      else
+       {
+         switch (property->type)
+           {
+           case array_property:
+             {
+               if ((property->sizeof_array % sizeof (signed_cell)) == 0)
+                 {
+                   unsigned_cell *w = (unsigned_cell*) property->array;
+                   int cell_nr;
+                   for (cell_nr = 0;
+                        cell_nr < (property->sizeof_array / sizeof (unsigned_cell));
+                        cell_nr++)
+                     {
+                       hw_printf (me, " 0x%lx", (unsigned long) BE2H_cell (w[cell_nr]));
+                     }
+                 }
+               else
+                 {
+                   unsigned8 *w = (unsigned8*)property->array;
+                   hw_printf (me, " [");
+                   while ((char*)w - (char*)property->array < property->sizeof_array) {
+                     hw_printf (me, " 0x%2x", BE2H_1 (*w));
+                     w++;
+                   }
+                 }
+               break;
+             }
+           case boolean_property:
+             {
+               int b = hw_find_boolean_property(me, property->name);
+               hw_printf (me, " %s", b ? "true"  : "false");
+               break;
+             }
+#if NOT_YET
+           case ihandle_property:
+             {
+               if (property->array != NULL)
+                 {
+                   device_instance *instance = hw_find_ihandle_property (me, property->name);
+                   hw_printf (me, " *%s", device_instance_path(instance));
+                 }
+               else
+                 {
+                   /* not yet initialized, ask the device for the path */
+                   ihandle_runtime_property_spec spec;
+                   hw_find_ihandle_runtime_property (me, property->name, &spec);
+                   hw_printf (me, " *%s", spec.full_path);
+                 }
+               break;
+             }
+#endif
+           case integer_property:
+             {
+               unsigned_word w = hw_find_integer_property (me, property->name);
+               hw_printf (me, " 0x%lx", (unsigned long)w);
+               break;
+             }
+           case range_array_property:
+             {
+               print_ranges_property (me, property);
+               break;
+             }
+           case reg_array_property:
+             {
+               print_reg_property (me, property);
+               break;
+             }
+           case string_property:
+             {
+               const char *s = hw_find_string_property (me, property->name);
+               print_string (me, s);
+               break;
+             }
+           case string_array_property:
+             {
+               print_string_array_property (me, property);
+               break;
+             }
+           }
+       }
+      hw_printf (me, "\n");
+    }
+}
+
+static void
+print_interrupts (struct hw *me,
+                  int my_port,
+                 struct hw *dest,
+                 int dest_port,
+                 void *ignore_or_null)
+{
+  char src[32];
+  char dst[32];
+  hw_port_encode (me, my_port, src, sizeof(src), output_port);
+  hw_port_encode (dest, dest_port, dst, sizeof(dst), input_port);
+  hw_printf (me, "%s > %s %s %s\n",
+            hw_path (me),
+            src, dst,
+            hw_path (dest));
+}
+
+static void
+print_device (struct hw *me,
+             void *ignore_or_null)
+{
+  hw_printf (me, "%s\n", hw_path (me));
+  print_properties (me);
+  hw_port_traverse (me, print_interrupts, NULL);
+}
+
+void
+hw_tree_print (struct hw *root)
+{
+  hw_tree_traverse (root,
+                   print_device, NULL,
+                   NULL);
+}
+
+
+\f
+#if NOT_YET
+device_instance *
+tree_instance(struct hw *root,
+             const char *device_specifier)
+{
+  /* find the device node */
+  struct hw *me;
+  name_specifier spec;
+  if (!split_device_specifier(root, device_specifier, &spec))
+    return NULL;
+  me = split_find_device(root, &spec);
+  if (spec.name != NULL)
+    return NULL;
+  /* create the instance */
+  return device_create_instance(me, device_specifier, spec.last_args);
+}
+#endif
+
+struct hw *
+hw_tree_find_device (struct hw *root,
+                    const char *path_to_device)
+{
+  struct hw *node;
+  name_specifier spec;
+  
+  /* parse the path */
+  split_device_specifier (root, path_to_device, &spec);
+  if (spec.value != NULL)
+    return NULL; /* something wierd */
+  
+  /* now find it */
+  node = split_find_device (root, &spec);
+  if (spec.name != NULL)
+    return NULL; /* not a leaf */
+  
+  return node;
+}
+
+
+const struct hw_property *
+hw_tree_find_property (struct hw *root,
+                      const char *path_to_property)
+{
+  name_specifier spec;
+  if (!split_property_specifier (root, path_to_property, &spec))
+    hw_abort (root, "Invalid property path %s", path_to_property);
+  root = split_find_device (root, &spec);
+  return hw_find_property (root, spec.property);
+}
+
+int
+hw_tree_find_boolean_property (struct hw *root,
+                              const char *path_to_property)
+{
+  name_specifier spec;
+  if (!split_property_specifier (root, path_to_property, &spec))
+    hw_abort (root, "Invalid property path %s", path_to_property);
+  root = split_find_device (root, &spec);
+  return hw_find_boolean_property (root, spec.property);
+}
+
+signed_cell
+hw_tree_find_integer_property (struct hw *root,
+                              const char *path_to_property)
+{
+  name_specifier spec;
+  if (!split_property_specifier (root, path_to_property, &spec))
+    hw_abort (root, "Invalid property path %s", path_to_property);
+  root = split_find_device (root, &spec);
+  return hw_find_integer_property (root, spec.property);
+}
+
+#if NOT_YET
+device_instance *
+hw_tree_find_ihandle_property (struct hw *root,
+                              const char *path_to_property)
+{
+  name_specifier spec;
+  if (!split_property_specifier (root, path_to_property, &spec))
+    hw_abort (root, "Invalid property path %s", path_to_property);
+  root = split_find_device (root, &spec);
+  return hw_find_ihandle_property (root, spec.property);
+}
+#endif
+
+const char *
+hw_tree_find_string_property (struct hw *root,
+                             const char *path_to_property)
+{
+  name_specifier spec;
+  if (!split_property_specifier (root, path_to_property, &spec))
+    hw_abort (root, "Invalid property path %s", path_to_property);
+  root = split_find_device (root, &spec);
+  return hw_find_string_property (root, spec.property);
+}