OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gdb-7.2/] [sim/] [common/] [hw-tree.c] - Diff between revs 330 and 816

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 330 Rev 816
/* The common simulator framework for GDB, the GNU Debugger.
/* The common simulator framework for GDB, the GNU Debugger.
 
 
   Copyright 2002, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
   Copyright 2002, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 
   Contributed by Andrew Cagney and Red Hat.
   Contributed by Andrew Cagney and Red Hat.
 
 
   This file is part of GDB.
   This file is part of GDB.
 
 
   This program is free software; you can redistribute it and/or modify
   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
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
 
 
#include "hw-main.h"
#include "hw-main.h"
#include "hw-base.h"
#include "hw-base.h"
#include "hw-tree.h"
#include "hw-tree.h"
 
 
#include "sim-io.h"
#include "sim-io.h"
#include "sim-assert.h"
#include "sim-assert.h"
 
 
#ifdef HAVE_STDLIB_H
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#include <stdlib.h>
#endif
#endif
 
 
#ifdef HAVE_STRING_H
#ifdef HAVE_STRING_H
#include <string.h>
#include <string.h>
#else
#else
#ifdef HAVE_STRINGS_H
#ifdef HAVE_STRINGS_H
#include <strings.h>
#include <strings.h>
#endif
#endif
#endif
#endif
 
 
#include <ctype.h>
#include <ctype.h>
 
 
/* manipulate/lookup device names */
/* manipulate/lookup device names */
 
 
typedef struct _name_specifier {
typedef struct _name_specifier {
 
 
  /* components in the full length name */
  /* components in the full length name */
  char *path;
  char *path;
  char *property;
  char *property;
  char *value;
  char *value;
 
 
  /* current device */
  /* current device */
  char *family;
  char *family;
  char *name;
  char *name;
  char *unit;
  char *unit;
  char *args;
  char *args;
 
 
  /* previous device */
  /* previous device */
  char *last_name;
  char *last_name;
  char *last_family;
  char *last_family;
  char *last_unit;
  char *last_unit;
  char *last_args;
  char *last_args;
 
 
  /* work area */
  /* work area */
  char buf[1024];
  char buf[1024];
 
 
} name_specifier;
} name_specifier;
 
 
 
 
 
 
/* Given a device specifier, break it up into its main components:
/* Given a device specifier, break it up into its main components:
   path (and if present) property name and property value. */
   path (and if present) property name and property value. */
 
 
static int
static int
split_device_specifier (struct hw *current,
split_device_specifier (struct hw *current,
                        const char *device_specifier,
                        const char *device_specifier,
                        name_specifier *spec)
                        name_specifier *spec)
{
{
  char *chp = NULL;
  char *chp = NULL;
 
 
  /* expand any leading alias if present */
  /* expand any leading alias if present */
  if (current != NULL
  if (current != NULL
      && *device_specifier != '\0'
      && *device_specifier != '\0'
      && *device_specifier != '.'
      && *device_specifier != '.'
      && *device_specifier != '/')
      && *device_specifier != '/')
    {
    {
      struct hw *aliases = hw_tree_find_device (current, "/aliases");
      struct hw *aliases = hw_tree_find_device (current, "/aliases");
      char alias[32];
      char alias[32];
      int len = 0;
      int len = 0;
      while (device_specifier[len] != '\0'
      while (device_specifier[len] != '\0'
             && device_specifier[len] != '/'
             && device_specifier[len] != '/'
             && device_specifier[len] != ':'
             && device_specifier[len] != ':'
             && !isspace (device_specifier[len]))
             && !isspace (device_specifier[len]))
        {
        {
          alias[len] = device_specifier[len];
          alias[len] = device_specifier[len];
          len++;
          len++;
          if (len >= sizeof(alias))
          if (len >= sizeof(alias))
            hw_abort (NULL, "split_device_specifier: buffer overflow");
            hw_abort (NULL, "split_device_specifier: buffer overflow");
        }
        }
      alias[len] = '\0';
      alias[len] = '\0';
      if (aliases != NULL
      if (aliases != NULL
          && hw_find_property (aliases, alias))
          && hw_find_property (aliases, alias))
        {
        {
          strcpy (spec->buf, hw_find_string_property(aliases, alias));
          strcpy (spec->buf, hw_find_string_property(aliases, alias));
          strcat (spec->buf, device_specifier + len);
          strcat (spec->buf, device_specifier + len);
        }
        }
      else
      else
        {
        {
          strcpy (spec->buf, device_specifier);
          strcpy (spec->buf, device_specifier);
        }
        }
    }
    }
  else
  else
    {
    {
      strcpy(spec->buf, device_specifier);
      strcpy(spec->buf, device_specifier);
    }
    }
 
 
  /* check no overflow */
  /* check no overflow */
  if (strlen(spec->buf) >= sizeof(spec->buf))
  if (strlen(spec->buf) >= sizeof(spec->buf))
    hw_abort (NULL, "split_device_specifier: buffer overflow\n");
    hw_abort (NULL, "split_device_specifier: buffer overflow\n");
 
 
  /* strip leading spaces */
  /* strip leading spaces */
  chp = spec->buf;
  chp = spec->buf;
  while (*chp != '\0' && isspace(*chp))
  while (*chp != '\0' && isspace(*chp))
    chp++;
    chp++;
  if (*chp == '\0')
  if (*chp == '\0')
    return 0;
    return 0;
 
 
  /* find the path and terminate it with null */
  /* find the path and terminate it with null */
  spec->path = chp;
  spec->path = chp;
  while (*chp != '\0' && !isspace(*chp))
  while (*chp != '\0' && !isspace(*chp))
    chp++;
    chp++;
  if (*chp != '\0')
  if (*chp != '\0')
    {
    {
      *chp = '\0';
      *chp = '\0';
      chp++;
      chp++;
    }
    }
 
 
  /* and any value */
  /* and any value */
  while (*chp != '\0' && isspace(*chp))
  while (*chp != '\0' && isspace(*chp))
    chp++;
    chp++;
  spec->value = chp;
  spec->value = chp;
 
 
  /* now go back and chop the property off of the path */
  /* now go back and chop the property off of the path */
  if (spec->value[0] == '\0')
  if (spec->value[0] == '\0')
    {
    {
      spec->property = NULL; /*not a property*/
      spec->property = NULL; /*not a property*/
      spec->value = NULL;
      spec->value = NULL;
    }
    }
  else if (spec->value[0] == '>'
  else if (spec->value[0] == '>'
           || spec->value[0] == '<')
           || spec->value[0] == '<')
    {
    {
      /* an interrupt spec */
      /* an interrupt spec */
      spec->property = NULL;
      spec->property = NULL;
    }
    }
  else {
  else {
    chp = strrchr(spec->path, '/');
    chp = strrchr(spec->path, '/');
    if (chp == NULL)
    if (chp == NULL)
      {
      {
        spec->property = spec->path;
        spec->property = spec->path;
        spec->path = strchr(spec->property, '\0');
        spec->path = strchr(spec->property, '\0');
      }
      }
    else {
    else {
      *chp = '\0';
      *chp = '\0';
      spec->property = chp+1;
      spec->property = chp+1;
    }
    }
  }
  }
 
 
  /* and mark the rest as invalid */
  /* and mark the rest as invalid */
  spec->name = NULL;
  spec->name = NULL;
  spec->family = NULL;
  spec->family = NULL;
  spec->unit = NULL;
  spec->unit = NULL;
  spec->args = NULL;
  spec->args = NULL;
  spec->last_name = NULL;
  spec->last_name = NULL;
  spec->last_family = NULL;
  spec->last_family = NULL;
  spec->last_unit = NULL;
  spec->last_unit = NULL;
  spec->last_args = NULL;
  spec->last_args = NULL;
 
 
  return 1;
  return 1;
}
}
 
 
 
 
/* given a device specifier break it up into its main components -
/* given a device specifier break it up into its main components -
   path and property name - assuming that the last `device' is a
   path and property name - assuming that the last `device' is a
   property name. */
   property name. */
 
 
static int
static int
split_property_specifier (struct hw *current,
split_property_specifier (struct hw *current,
                          const char *property_specifier,
                          const char *property_specifier,
                          name_specifier *spec)
                          name_specifier *spec)
{
{
  if (split_device_specifier (current, property_specifier, spec))
  if (split_device_specifier (current, property_specifier, spec))
    {
    {
      if (spec->property == NULL)
      if (spec->property == NULL)
        {
        {
          /* force the last name to be a property name */
          /* force the last name to be a property name */
          char *chp = strrchr (spec->path, '/');
          char *chp = strrchr (spec->path, '/');
          if (chp == NULL)
          if (chp == NULL)
            {
            {
              spec->property = spec->path;
              spec->property = spec->path;
              spec->path = strrchr (spec->property, '\0');;
              spec->path = strrchr (spec->property, '\0');;
            }
            }
          else
          else
            {
            {
              *chp = '\0';
              *chp = '\0';
              spec->property = chp + 1;
              spec->property = chp + 1;
            }
            }
        }
        }
      return 1;
      return 1;
    }
    }
  else
  else
    return 0;
    return 0;
}
}
 
 
 
 
/* device the next device name and split it up, return 0 when no more
/* device the next device name and split it up, return 0 when no more
   names to struct hw */
   names to struct hw */
 
 
static int
static int
split_device_name (name_specifier *spec)
split_device_name (name_specifier *spec)
{
{
  char *chp;
  char *chp;
  /* remember what came before */
  /* remember what came before */
  spec->last_name = spec->name;
  spec->last_name = spec->name;
  spec->last_family = spec->family;
  spec->last_family = spec->family;
  spec->last_unit = spec->unit;
  spec->last_unit = spec->unit;
  spec->last_args = spec->args;
  spec->last_args = spec->args;
  /* finished? */
  /* finished? */
  if (spec->path[0] == '\0')
  if (spec->path[0] == '\0')
    {
    {
      spec->name = NULL;
      spec->name = NULL;
      spec->family = NULL;
      spec->family = NULL;
      spec->unit = NULL;
      spec->unit = NULL;
      spec->args = NULL;
      spec->args = NULL;
      return 0;
      return 0;
    }
    }
  /* break the current device spec from the path */
  /* break the current device spec from the path */
  spec->name = spec->path;
  spec->name = spec->path;
  chp = strchr (spec->name, '/');
  chp = strchr (spec->name, '/');
  if (chp == NULL)
  if (chp == NULL)
    spec->path = strchr (spec->name, '\0');
    spec->path = strchr (spec->name, '\0');
  else
  else
    {
    {
      spec->path = chp+1;
      spec->path = chp+1;
      *chp = '\0';
      *chp = '\0';
    }
    }
  /* break out the base */
  /* break out the base */
  if (spec->name[0] == '(')
  if (spec->name[0] == '(')
    {
    {
      chp = strchr(spec->name, ')');
      chp = strchr(spec->name, ')');
      if (chp == NULL)
      if (chp == NULL)
        {
        {
          spec->family = spec->name;
          spec->family = spec->name;
        }
        }
      else
      else
        {
        {
          *chp = '\0';
          *chp = '\0';
          spec->family = spec->name + 1;
          spec->family = spec->name + 1;
          spec->name = chp + 1;
          spec->name = chp + 1;
        }
        }
    }
    }
  else
  else
    {
    {
      spec->family = spec->name;
      spec->family = spec->name;
    }
    }
  /* now break out the unit */
  /* now break out the unit */
  chp = strchr(spec->name, '@');
  chp = strchr(spec->name, '@');
  if (chp == NULL)
  if (chp == NULL)
    {
    {
      spec->unit = NULL;
      spec->unit = NULL;
      chp = spec->name;
      chp = spec->name;
    }
    }
  else
  else
    {
    {
      *chp = '\0';
      *chp = '\0';
      chp += 1;
      chp += 1;
      spec->unit = chp;
      spec->unit = chp;
    }
    }
  /* finally any args */
  /* finally any args */
  chp = strchr(chp, ':');
  chp = strchr(chp, ':');
  if (chp == NULL)
  if (chp == NULL)
    spec->args = NULL;
    spec->args = NULL;
  else
  else
    {
    {
      *chp = '\0';
      *chp = '\0';
      spec->args = chp+1;
      spec->args = chp+1;
    }
    }
  return 1;
  return 1;
}
}
 
 
 
 
/* device the value, returning the next non-space token */
/* device the value, returning the next non-space token */
 
 
static char *
static char *
split_value (name_specifier *spec)
split_value (name_specifier *spec)
{
{
  char *token;
  char *token;
  if (spec->value == NULL)
  if (spec->value == NULL)
    return NULL;
    return NULL;
  /* skip leading white space */
  /* skip leading white space */
  while (isspace (spec->value[0]))
  while (isspace (spec->value[0]))
    spec->value++;
    spec->value++;
  if (spec->value[0] == '\0')
  if (spec->value[0] == '\0')
    {
    {
      spec->value = NULL;
      spec->value = NULL;
      return NULL;
      return NULL;
    }
    }
  token = spec->value;
  token = spec->value;
  /* find trailing space */
  /* find trailing space */
  while (spec->value[0] != '\0' && !isspace (spec->value[0]))
  while (spec->value[0] != '\0' && !isspace (spec->value[0]))
    spec->value++;
    spec->value++;
  /* chop this value out */
  /* chop this value out */
  if (spec->value[0] != '\0')
  if (spec->value[0] != '\0')
    {
    {
      spec->value[0] = '\0';
      spec->value[0] = '\0';
      spec->value++;
      spec->value++;
    }
    }
  return token;
  return token;
}
}
 
 
 
 
 
 
/* traverse the path specified by spec starting at current */
/* traverse the path specified by spec starting at current */
 
 
static struct hw *
static struct hw *
split_find_device (struct hw *current,
split_find_device (struct hw *current,
                   name_specifier *spec)
                   name_specifier *spec)
{
{
  /* strip off (and process) any leading ., .., ./ and / */
  /* strip off (and process) any leading ., .., ./ and / */
  while (1)
  while (1)
    {
    {
      if (strncmp (spec->path, "/", strlen ("/")) == 0)
      if (strncmp (spec->path, "/", strlen ("/")) == 0)
        {
        {
          /* cd /... */
          /* cd /... */
          while (current != NULL && hw_parent (current) != NULL)
          while (current != NULL && hw_parent (current) != NULL)
            current = hw_parent (current);
            current = hw_parent (current);
          spec->path += strlen ("/");
          spec->path += strlen ("/");
        }
        }
      else if (strncmp (spec->path, "./", strlen ("./")) == 0)
      else if (strncmp (spec->path, "./", strlen ("./")) == 0)
        {
        {
          /* cd ./... */
          /* cd ./... */
          current = current;
          current = current;
          spec->path += strlen ("./");
          spec->path += strlen ("./");
        }
        }
      else if (strncmp (spec->path, "../", strlen ("../")) == 0)
      else if (strncmp (spec->path, "../", strlen ("../")) == 0)
        {
        {
          /* cd ../... */
          /* cd ../... */
          if (current != NULL && hw_parent (current) != NULL)
          if (current != NULL && hw_parent (current) != NULL)
            current = hw_parent (current);
            current = hw_parent (current);
          spec->path += strlen ("../");
          spec->path += strlen ("../");
        }
        }
      else if (strcmp (spec->path, ".") == 0)
      else if (strcmp (spec->path, ".") == 0)
        {
        {
          /* cd . */
          /* cd . */
          current = current;
          current = current;
          spec->path += strlen (".");
          spec->path += strlen (".");
        }
        }
      else if (strcmp (spec->path, "..") == 0)
      else if (strcmp (spec->path, "..") == 0)
        {
        {
          /* cd .. */
          /* cd .. */
          if (current != NULL && hw_parent (current) != NULL)
          if (current != NULL && hw_parent (current) != NULL)
            current = hw_parent (current);
            current = hw_parent (current);
          spec->path += strlen ("..");
          spec->path += strlen ("..");
        }
        }
      else
      else
        break;
        break;
    }
    }
 
 
  /* now go through the path proper */
  /* now go through the path proper */
 
 
  if (current == NULL)
  if (current == NULL)
    {
    {
      split_device_name (spec);
      split_device_name (spec);
      return NULL;
      return NULL;
    }
    }
 
 
  while (split_device_name (spec))
  while (split_device_name (spec))
    {
    {
      struct hw *child;
      struct hw *child;
      for (child = hw_child (current);
      for (child = hw_child (current);
           child != NULL; child = hw_sibling (child))
           child != NULL; child = hw_sibling (child))
        {
        {
          if (strcmp (spec->name, hw_name (child)) == 0)
          if (strcmp (spec->name, hw_name (child)) == 0)
            {
            {
              if (spec->unit == NULL)
              if (spec->unit == NULL)
                break;
                break;
              else
              else
                {
                {
                  hw_unit phys;
                  hw_unit phys;
                  hw_unit_decode (current, spec->unit, &phys);
                  hw_unit_decode (current, spec->unit, &phys);
                  if (memcmp (&phys, hw_unit_address (child),
                  if (memcmp (&phys, hw_unit_address (child),
                              sizeof (hw_unit)) == 0)
                              sizeof (hw_unit)) == 0)
                    break;
                    break;
                }
                }
            }
            }
        }
        }
      if (child == NULL)
      if (child == NULL)
        return current; /* search failed */
        return current; /* search failed */
      current = child;
      current = child;
    }
    }
 
 
  return current;
  return current;
}
}
 
 
 
 
static struct hw *
static struct hw *
split_fill_path (struct hw *current,
split_fill_path (struct hw *current,
                 const char *device_specifier,
                 const char *device_specifier,
                 name_specifier *spec)
                 name_specifier *spec)
{
{
  /* break it up */
  /* break it up */
  if (!split_device_specifier (current, device_specifier, spec))
  if (!split_device_specifier (current, device_specifier, spec))
    hw_abort (current, "error parsing %s\n", device_specifier);
    hw_abort (current, "error parsing %s\n", device_specifier);
 
 
  /* fill our tree with its contents */
  /* fill our tree with its contents */
  current = split_find_device (current, spec);
  current = split_find_device (current, spec);
 
 
  /* add any additional devices as needed */
  /* add any additional devices as needed */
  if (spec->name != NULL)
  if (spec->name != NULL)
    {
    {
      do
      do
        {
        {
          if (current != NULL && !hw_finished_p (current))
          if (current != NULL && !hw_finished_p (current))
            hw_finish (current);
            hw_finish (current);
          current = hw_create (NULL,
          current = hw_create (NULL,
                               current,
                               current,
                               spec->family,
                               spec->family,
                               spec->name,
                               spec->name,
                               spec->unit,
                               spec->unit,
                               spec->args);
                               spec->args);
        }
        }
      while (split_device_name (spec));
      while (split_device_name (spec));
    }
    }
 
 
  return current;
  return current;
}
}
 
 


/* <non-white-space> */
/* <non-white-space> */
 
 
static const char *
static const char *
skip_token(const char *chp)
skip_token(const char *chp)
{
{
  while (!isspace(*chp) && *chp != '\0')
  while (!isspace(*chp) && *chp != '\0')
    chp++;
    chp++;
  while (isspace(*chp) && *chp != '\0')
  while (isspace(*chp) && *chp != '\0')
    chp++;
    chp++;
  return chp;
  return chp;
}
}
 
 
 
 
/* count the number of entries */
/* count the number of entries */
 
 
static int
static int
count_entries (struct hw *current,
count_entries (struct hw *current,
               const char *property_name,
               const char *property_name,
               const char *property_value,
               const char *property_value,
               int modulo)
               int modulo)
{
{
  const char *chp = property_value;
  const char *chp = property_value;
  int nr_entries = 0;
  int nr_entries = 0;
  while (*chp != '\0')
  while (*chp != '\0')
    {
    {
      nr_entries += 1;
      nr_entries += 1;
      chp = skip_token (chp);
      chp = skip_token (chp);
    }
    }
  if ((nr_entries % modulo) != 0)
  if ((nr_entries % modulo) != 0)
    {
    {
      hw_abort (current, "incorrect number of entries for %s property %s, should be multiple of %d",
      hw_abort (current, "incorrect number of entries for %s property %s, should be multiple of %d",
                property_name, property_value, modulo);
                property_name, property_value, modulo);
    }
    }
  return nr_entries / modulo;
  return nr_entries / modulo;
}
}
 
 
 
 
 
 
/* parse: <address> ::= <token> ; device dependant */
/* parse: <address> ::= <token> ; device dependant */
 
 
static const char *
static const char *
parse_address (struct hw *current,
parse_address (struct hw *current,
               struct hw *bus,
               struct hw *bus,
               const char *chp,
               const char *chp,
               hw_unit *address)
               hw_unit *address)
{
{
  if (hw_unit_decode (bus, chp, address) < 0)
  if (hw_unit_decode (bus, chp, address) < 0)
    hw_abort (current, "invalid unit address in %s", chp);
    hw_abort (current, "invalid unit address in %s", chp);
  return skip_token (chp);
  return skip_token (chp);
}
}
 
 
 
 
/* parse: <size> ::= <number> { "," <number> } ; */
/* parse: <size> ::= <number> { "," <number> } ; */
 
 
static const char *
static const char *
parse_size (struct hw *current,
parse_size (struct hw *current,
            struct hw *bus,
            struct hw *bus,
            const char *chp,
            const char *chp,
            hw_unit *size)
            hw_unit *size)
{
{
  int i;
  int i;
  int nr;
  int nr;
  const char *curr = chp;
  const char *curr = chp;
  memset(size, 0, sizeof(*size));
  memset(size, 0, sizeof(*size));
  /* parse the numeric list */
  /* parse the numeric list */
  size->nr_cells = hw_unit_nr_size_cells (bus);
  size->nr_cells = hw_unit_nr_size_cells (bus);
  nr = 0;
  nr = 0;
  while (1)
  while (1)
    {
    {
      char *next;
      char *next;
      size->cells[nr] = strtoul (curr, &next, 0);
      size->cells[nr] = strtoul (curr, &next, 0);
      if (curr == next)
      if (curr == next)
        hw_abort (current, "Problem parsing <size> %s", chp);
        hw_abort (current, "Problem parsing <size> %s", chp);
      nr += 1;
      nr += 1;
      if (next[0] != ',')
      if (next[0] != ',')
        break;
        break;
      if (nr == size->nr_cells)
      if (nr == size->nr_cells)
        hw_abort (current, "Too many values in <size> %s", chp);
        hw_abort (current, "Too many values in <size> %s", chp);
      curr = next + 1;
      curr = next + 1;
    }
    }
  ASSERT (nr > 0 && nr <= size->nr_cells);
  ASSERT (nr > 0 && nr <= size->nr_cells);
  /* right align the numbers */
  /* right align the numbers */
  for (i = 1; i <= size->nr_cells; i++)
  for (i = 1; i <= size->nr_cells; i++)
    {
    {
      if (i <= nr)
      if (i <= nr)
        size->cells[size->nr_cells - i] = size->cells[nr - i];
        size->cells[size->nr_cells - i] = size->cells[nr - i];
      else
      else
        size->cells[size->nr_cells - i] = 0;
        size->cells[size->nr_cells - i] = 0;
    }
    }
  return skip_token (chp);
  return skip_token (chp);
}
}
 
 
 
 
/* parse: <reg> ::= { <address> <size> } ; */
/* parse: <reg> ::= { <address> <size> } ; */
 
 
static void
static void
parse_reg_property (struct hw *current,
parse_reg_property (struct hw *current,
                    const char *property_name,
                    const char *property_name,
                    const char *property_value)
                    const char *property_value)
{
{
  int nr_regs;
  int nr_regs;
  int reg_nr;
  int reg_nr;
  reg_property_spec *regs;
  reg_property_spec *regs;
  const char *chp;
  const char *chp;
 
 
  /* determine the number of reg entries by counting tokens */
  /* determine the number of reg entries by counting tokens */
  nr_regs = count_entries (current, property_name, property_value, 2);
  nr_regs = count_entries (current, property_name, property_value, 2);
 
 
  /* create working space */
  /* create working space */
  regs = zalloc (nr_regs * sizeof (*regs));
  regs = zalloc (nr_regs * sizeof (*regs));
 
 
  /* fill it in */
  /* fill it in */
  chp = property_value;
  chp = property_value;
  for (reg_nr = 0; reg_nr < nr_regs; reg_nr++)
  for (reg_nr = 0; reg_nr < nr_regs; reg_nr++)
    {
    {
      chp = parse_address (current, hw_parent(current),
      chp = parse_address (current, hw_parent(current),
                           chp, &regs[reg_nr].address);
                           chp, &regs[reg_nr].address);
      chp = parse_size (current, hw_parent(current),
      chp = parse_size (current, hw_parent(current),
                        chp, &regs[reg_nr].size);
                        chp, &regs[reg_nr].size);
    }
    }
 
 
  /* create it */
  /* create it */
  hw_add_reg_array_property (current, property_name,
  hw_add_reg_array_property (current, property_name,
                             regs, nr_regs);
                             regs, nr_regs);
 
 
  zfree (regs);
  zfree (regs);
}
}
 
 
 
 
/* { <child-address> <parent-address> <child-size> }* */
/* { <child-address> <parent-address> <child-size> }* */
 
 
static void
static void
parse_ranges_property (struct hw *current,
parse_ranges_property (struct hw *current,
                       const char *property_name,
                       const char *property_name,
                       const char *property_value)
                       const char *property_value)
{
{
  int nr_ranges;
  int nr_ranges;
  int range_nr;
  int range_nr;
  range_property_spec *ranges;
  range_property_spec *ranges;
  const char *chp;
  const char *chp;
 
 
  /* determine the number of ranges specified */
  /* determine the number of ranges specified */
  nr_ranges = count_entries (current, property_name, property_value, 3);
  nr_ranges = count_entries (current, property_name, property_value, 3);
 
 
  /* create a property of that size */
  /* create a property of that size */
  ranges = zalloc (nr_ranges * sizeof(*ranges));
  ranges = zalloc (nr_ranges * sizeof(*ranges));
 
 
  /* fill it in */
  /* fill it in */
  chp = property_value;
  chp = property_value;
  for (range_nr = 0; range_nr < nr_ranges; range_nr++)
  for (range_nr = 0; range_nr < nr_ranges; range_nr++)
    {
    {
      chp = parse_address (current, current,
      chp = parse_address (current, current,
                           chp, &ranges[range_nr].child_address);
                           chp, &ranges[range_nr].child_address);
      chp = parse_address (current, hw_parent(current),
      chp = parse_address (current, hw_parent(current),
                           chp, &ranges[range_nr].parent_address);
                           chp, &ranges[range_nr].parent_address);
      chp = parse_size (current, current,
      chp = parse_size (current, current,
                        chp, &ranges[range_nr].size);
                        chp, &ranges[range_nr].size);
    }
    }
 
 
  /* create it */
  /* create it */
  hw_add_range_array_property (current, property_name, ranges, nr_ranges);
  hw_add_range_array_property (current, property_name, ranges, nr_ranges);
 
 
  zfree (ranges);
  zfree (ranges);
}
}
 
 
 
 
/* <integer> ... */
/* <integer> ... */
 
 
static void
static void
parse_integer_property (struct hw *current,
parse_integer_property (struct hw *current,
                        const char *property_name,
                        const char *property_name,
                        const char *property_value)
                        const char *property_value)
{
{
  int nr_entries;
  int nr_entries;
  unsigned_cell words[1024];
  unsigned_cell words[1024];
  /* integer or integer array? */
  /* integer or integer array? */
  nr_entries = 0;
  nr_entries = 0;
  while (1)
  while (1)
    {
    {
      char *end;
      char *end;
      words[nr_entries] = strtoul (property_value, &end, 0);
      words[nr_entries] = strtoul (property_value, &end, 0);
      if (property_value == end)
      if (property_value == end)
        break;
        break;
      nr_entries += 1;
      nr_entries += 1;
      if (nr_entries * sizeof (words[0]) >= sizeof (words))
      if (nr_entries * sizeof (words[0]) >= sizeof (words))
        hw_abort (current, "buffer overflow");
        hw_abort (current, "buffer overflow");
      property_value = end;
      property_value = end;
    }
    }
  if (nr_entries == 0)
  if (nr_entries == 0)
    hw_abort (current, "error parsing integer property %s (%s)",
    hw_abort (current, "error parsing integer property %s (%s)",
              property_name, property_value);
              property_name, property_value);
  else if (nr_entries == 1)
  else if (nr_entries == 1)
    hw_add_integer_property (current, property_name, words[0]);
    hw_add_integer_property (current, property_name, words[0]);
  else
  else
    {
    {
      int i;
      int i;
      for (i = 0; i < nr_entries; i++)
      for (i = 0; i < nr_entries; i++)
        {
        {
          H2BE (words[i]);
          H2BE (words[i]);
        }
        }
      /* perhaps integer array property is better */
      /* perhaps integer array property is better */
      hw_add_array_property (current, property_name, words,
      hw_add_array_property (current, property_name, words,
                             sizeof(words[0]) * nr_entries);
                             sizeof(words[0]) * nr_entries);
    }
    }
}
}
 
 
 
 
/* <string> ... */
/* <string> ... */
 
 
static void
static void
parse_string_property (struct hw *current,
parse_string_property (struct hw *current,
                       const char *property_name,
                       const char *property_name,
                       const char *property_value)
                       const char *property_value)
{
{
  char **strings;
  char **strings;
  const char *chp;
  const char *chp;
  int nr_strings;
  int nr_strings;
  int approx_nr_strings;
  int approx_nr_strings;
 
 
  /* get an estimate as to the number of strings by counting double
  /* get an estimate as to the number of strings by counting double
     quotes */
     quotes */
  approx_nr_strings = 2;
  approx_nr_strings = 2;
  for (chp = property_value; *chp; chp++)
  for (chp = property_value; *chp; chp++)
    {
    {
      if (*chp == '"')
      if (*chp == '"')
        approx_nr_strings++;
        approx_nr_strings++;
    }
    }
  approx_nr_strings = (approx_nr_strings) / 2;
  approx_nr_strings = (approx_nr_strings) / 2;
 
 
  /* create a string buffer for that many (plus a null) */
  /* create a string buffer for that many (plus a null) */
  strings = (char**) zalloc ((approx_nr_strings + 1) * sizeof(char*));
  strings = (char**) zalloc ((approx_nr_strings + 1) * sizeof(char*));
 
 
  /* now find all the strings */
  /* now find all the strings */
  chp = property_value;
  chp = property_value;
  nr_strings = 0;
  nr_strings = 0;
  while (1)
  while (1)
    {
    {
 
 
      /* skip leading space */
      /* skip leading space */
      while (*chp != '\0' && isspace (*chp))
      while (*chp != '\0' && isspace (*chp))
        chp += 1;
        chp += 1;
      if (*chp == '\0')
      if (*chp == '\0')
        break;
        break;
 
 
      /* copy it in */
      /* copy it in */
      if (*chp == '"')
      if (*chp == '"')
        {
        {
          /* a quoted string - watch for '\' et al. */
          /* a quoted string - watch for '\' et al. */
          /* estimate the size and allocate space for it */
          /* estimate the size and allocate space for it */
          int pos;
          int pos;
          chp++;
          chp++;
          pos = 0;
          pos = 0;
          while (chp[pos] != '\0' && chp[pos] != '"')
          while (chp[pos] != '\0' && chp[pos] != '"')
            {
            {
              if (chp[pos] == '\\' && chp[pos+1] != '\0')
              if (chp[pos] == '\\' && chp[pos+1] != '\0')
                pos += 2;
                pos += 2;
              else
              else
                pos += 1;
                pos += 1;
            }
            }
          strings[nr_strings] = zalloc (pos + 1);
          strings[nr_strings] = zalloc (pos + 1);
          /* copy the string over */
          /* copy the string over */
          pos = 0;
          pos = 0;
          while (*chp != '\0' && *chp != '"')
          while (*chp != '\0' && *chp != '"')
            {
            {
              if (*chp == '\\' && *(chp+1) != '\0') {
              if (*chp == '\\' && *(chp+1) != '\0') {
                strings[nr_strings][pos] = *(chp+1);
                strings[nr_strings][pos] = *(chp+1);
                chp += 2;
                chp += 2;
                pos++;
                pos++;
              }
              }
              else
              else
                {
                {
                  strings[nr_strings][pos] = *chp;
                  strings[nr_strings][pos] = *chp;
                  chp += 1;
                  chp += 1;
                  pos++;
                  pos++;
                }
                }
            }
            }
          if (*chp != '\0')
          if (*chp != '\0')
            chp++;
            chp++;
          strings[nr_strings][pos] = '\0';
          strings[nr_strings][pos] = '\0';
        }
        }
      else
      else
        {
        {
          /* copy over a single unquoted token */
          /* copy over a single unquoted token */
          int len = 0;
          int len = 0;
          while (chp[len] != '\0' && !isspace(chp[len]))
          while (chp[len] != '\0' && !isspace(chp[len]))
            len++;
            len++;
          strings[nr_strings] = zalloc(len + 1);
          strings[nr_strings] = zalloc(len + 1);
          strncpy(strings[nr_strings], chp, len);
          strncpy(strings[nr_strings], chp, len);
          strings[nr_strings][len] = '\0';
          strings[nr_strings][len] = '\0';
          chp += len;
          chp += len;
        }
        }
      nr_strings++;
      nr_strings++;
      if (nr_strings > approx_nr_strings)
      if (nr_strings > approx_nr_strings)
        hw_abort (current, "String property %s badly formatted",
        hw_abort (current, "String property %s badly formatted",
                  property_name);
                  property_name);
    }
    }
  ASSERT (strings[nr_strings] == NULL); /* from zalloc */
  ASSERT (strings[nr_strings] == NULL); /* from zalloc */
 
 
  /* install it */
  /* install it */
  if (nr_strings == 0)
  if (nr_strings == 0)
    hw_add_string_property (current, property_name, "");
    hw_add_string_property (current, property_name, "");
  else if (nr_strings == 1)
  else if (nr_strings == 1)
    hw_add_string_property (current, property_name, strings[0]);
    hw_add_string_property (current, property_name, strings[0]);
  else
  else
    {
    {
      const char **specs = (const char**) strings; /* stop a bogus error */
      const char **specs = (const char**) strings; /* stop a bogus error */
      hw_add_string_array_property (current, property_name,
      hw_add_string_array_property (current, property_name,
                                    specs, nr_strings);
                                    specs, nr_strings);
    }
    }
 
 
  /* flush the created string */
  /* flush the created string */
  while (nr_strings > 0)
  while (nr_strings > 0)
    {
    {
      nr_strings--;
      nr_strings--;
      zfree (strings[nr_strings]);
      zfree (strings[nr_strings]);
    }
    }
  zfree(strings);
  zfree(strings);
}
}
 
 
 
 
/* <path-to-ihandle-device> */
/* <path-to-ihandle-device> */
 
 
#if NOT_YET
#if NOT_YET
static void
static void
parse_ihandle_property (struct hw *current,
parse_ihandle_property (struct hw *current,
                        const char *property,
                        const char *property,
                        const char *value)
                        const char *value)
{
{
  ihandle_runtime_property_spec ihandle;
  ihandle_runtime_property_spec ihandle;
 
 
  /* pass the full path */
  /* pass the full path */
  ihandle.full_path = value;
  ihandle.full_path = value;
 
 
  /* save this ready for the ihandle create */
  /* save this ready for the ihandle create */
  hw_add_ihandle_runtime_property (current, property,
  hw_add_ihandle_runtime_property (current, property,
                                   &ihandle);
                                   &ihandle);
}
}
#endif
#endif
 
 
 
 
struct hw *
struct hw *
hw_tree_create (SIM_DESC sd,
hw_tree_create (SIM_DESC sd,
                const char *family)
                const char *family)
{
{
  return hw_create (sd, NULL, family, family, NULL, NULL);
  return hw_create (sd, NULL, family, family, NULL, NULL);
}
}
 
 
void
void
hw_tree_delete (struct hw *me)
hw_tree_delete (struct hw *me)
{
{
  /* Need to allow devices to disapear under our feet */
  /* Need to allow devices to disapear under our feet */
  while (hw_child (me) != NULL)
  while (hw_child (me) != NULL)
    {
    {
      hw_tree_delete (hw_child (me));
      hw_tree_delete (hw_child (me));
    }
    }
  hw_delete (me);
  hw_delete (me);
}
}
 
 
 
 
struct hw *
struct hw *
hw_tree_parse (struct hw *current,
hw_tree_parse (struct hw *current,
               const char *fmt,
               const char *fmt,
               ...)
               ...)
{
{
    va_list ap;
    va_list ap;
    va_start (ap, fmt);
    va_start (ap, fmt);
    current = hw_tree_vparse (current, fmt, ap);
    current = hw_tree_vparse (current, fmt, ap);
    va_end (ap);
    va_end (ap);
    return current;
    return current;
}
}
 
 
struct hw *
struct hw *
hw_tree_vparse (struct hw *current,
hw_tree_vparse (struct hw *current,
                const char *fmt,
                const char *fmt,
                va_list ap)
                va_list ap)
{
{
  char device_specifier[1024];
  char device_specifier[1024];
  name_specifier spec;
  name_specifier spec;
 
 
  /* format the path */
  /* format the path */
  vsprintf (device_specifier, fmt, ap);
  vsprintf (device_specifier, fmt, ap);
  if (strlen (device_specifier) >= sizeof (device_specifier))
  if (strlen (device_specifier) >= sizeof (device_specifier))
    hw_abort (NULL, "device_tree_add_deviced: buffer overflow\n");
    hw_abort (NULL, "device_tree_add_deviced: buffer overflow\n");
 
 
  /* construct the tree down to the final struct hw */
  /* construct the tree down to the final struct hw */
  current = split_fill_path (current, device_specifier, &spec);
  current = split_fill_path (current, device_specifier, &spec);
 
 
  /* is there an interrupt spec */
  /* is there an interrupt spec */
  if (spec.property == NULL
  if (spec.property == NULL
      && spec.value != NULL)
      && spec.value != NULL)
    {
    {
      char *op = split_value (&spec);
      char *op = split_value (&spec);
      switch (op[0])
      switch (op[0])
        {
        {
        case '>':
        case '>':
          {
          {
            char *my_port_name = split_value (&spec);
            char *my_port_name = split_value (&spec);
            int my_port;
            int my_port;
            char *dest_port_name = split_value (&spec);
            char *dest_port_name = split_value (&spec);
            int dest_port;
            int dest_port;
            name_specifier dest_spec;
            name_specifier dest_spec;
            char *dest_hw_name = split_value (&spec);
            char *dest_hw_name = split_value (&spec);
            struct hw *dest;
            struct hw *dest;
            /* find my name */
            /* find my name */
            if (!hw_finished_p (current))
            if (!hw_finished_p (current))
              hw_finish (current);
              hw_finish (current);
            my_port = hw_port_decode (current, my_port_name, output_port);
            my_port = hw_port_decode (current, my_port_name, output_port);
            /* find the dest device and port */
            /* find the dest device and port */
            dest = split_fill_path (current, dest_hw_name, &dest_spec);
            dest = split_fill_path (current, dest_hw_name, &dest_spec);
            if (!hw_finished_p (dest))
            if (!hw_finished_p (dest))
              hw_finish (dest);
              hw_finish (dest);
            dest_port = hw_port_decode (dest, dest_port_name,
            dest_port = hw_port_decode (dest, dest_port_name,
                                        input_port);
                                        input_port);
            /* connect the two */
            /* connect the two */
            hw_port_attach (current,
            hw_port_attach (current,
                            my_port,
                            my_port,
                            dest,
                            dest,
                            dest_port,
                            dest_port,
                            permenant_object);
                            permenant_object);
            break;
            break;
          }
          }
        default:
        default:
          hw_abort (current, "unreconised interrupt spec %s\n", spec.value);
          hw_abort (current, "unreconised interrupt spec %s\n", spec.value);
          break;
          break;
        }
        }
    }
    }
 
 
  /* is there a property */
  /* is there a property */
  if (spec.property != NULL)
  if (spec.property != NULL)
    {
    {
      if (strcmp (spec.value, "true") == 0)
      if (strcmp (spec.value, "true") == 0)
        hw_add_boolean_property (current, spec.property, 1);
        hw_add_boolean_property (current, spec.property, 1);
      else if (strcmp (spec.value, "false") == 0)
      else if (strcmp (spec.value, "false") == 0)
        hw_add_boolean_property (current, spec.property, 0);
        hw_add_boolean_property (current, spec.property, 0);
      else
      else
        {
        {
          const struct hw_property *property;
          const struct hw_property *property;
          switch (spec.value[0])
          switch (spec.value[0])
            {
            {
#if NOT_YET
#if NOT_YET
            case '*':
            case '*':
              {
              {
                parse_ihandle_property (current, spec.property, spec.value + 1);
                parse_ihandle_property (current, spec.property, spec.value + 1);
                break;
                break;
              }
              }
#endif
#endif
            case '[':
            case '[':
              {
              {
                unsigned8 words[1024];
                unsigned8 words[1024];
                char *curr = spec.value + 1;
                char *curr = spec.value + 1;
                int nr_words = 0;
                int nr_words = 0;
                while (1)
                while (1)
                  {
                  {
                    char *next;
                    char *next;
                    words[nr_words] = H2BE_1 (strtoul (curr, &next, 0));
                    words[nr_words] = H2BE_1 (strtoul (curr, &next, 0));
                    if (curr == next)
                    if (curr == next)
                      break;
                      break;
                    curr = next;
                    curr = next;
                    nr_words += 1;
                    nr_words += 1;
                  }
                  }
                hw_add_array_property (current, spec.property,
                hw_add_array_property (current, spec.property,
                                       words, sizeof(words[0]) * nr_words);
                                       words, sizeof(words[0]) * nr_words);
                break;
                break;
              }
              }
            case '"':
            case '"':
              {
              {
                parse_string_property (current, spec.property, spec.value);
                parse_string_property (current, spec.property, spec.value);
                break;
                break;
              }
              }
            case '!':
            case '!':
              {
              {
                spec.value++;
                spec.value++;
                property = hw_tree_find_property (current, spec.value);
                property = hw_tree_find_property (current, spec.value);
                if (property == NULL)
                if (property == NULL)
                  hw_abort (current, "property %s not found\n", spec.value);
                  hw_abort (current, "property %s not found\n", spec.value);
                hw_add_duplicate_property (current,
                hw_add_duplicate_property (current,
                                           spec.property,
                                           spec.property,
                                           property);
                                           property);
                break;
                break;
              }
              }
            default:
            default:
              {
              {
                if (strcmp (spec.property, "reg") == 0
                if (strcmp (spec.property, "reg") == 0
                    || strcmp (spec.property, "assigned-addresses") == 0
                    || strcmp (spec.property, "assigned-addresses") == 0
                    || strcmp (spec.property, "alternate-reg") == 0)
                    || strcmp (spec.property, "alternate-reg") == 0)
                  {
                  {
                    parse_reg_property (current, spec.property, spec.value);
                    parse_reg_property (current, spec.property, spec.value);
                  }
                  }
                else if (strcmp (spec.property, "ranges") == 0)
                else if (strcmp (spec.property, "ranges") == 0)
                  {
                  {
                    parse_ranges_property (current, spec.property, spec.value);
                    parse_ranges_property (current, spec.property, spec.value);
                  }
                  }
                else if (isdigit(spec.value[0])
                else if (isdigit(spec.value[0])
                         || (spec.value[0] == '-' && isdigit(spec.value[1]))
                         || (spec.value[0] == '-' && isdigit(spec.value[1]))
                         || (spec.value[0] == '+' && isdigit(spec.value[1])))
                         || (spec.value[0] == '+' && isdigit(spec.value[1])))
                  {
                  {
                    parse_integer_property(current, spec.property, spec.value);
                    parse_integer_property(current, spec.property, spec.value);
                  }
                  }
                else
                else
                  parse_string_property(current, spec.property, spec.value);
                  parse_string_property(current, spec.property, spec.value);
                break;
                break;
              }
              }
            }
            }
        }
        }
    }
    }
  return current;
  return current;
}
}
 
 
 
 
static void
static void
finish_hw_tree (struct hw *me,
finish_hw_tree (struct hw *me,
                void *data)
                void *data)
{
{
  if (!hw_finished_p (me))
  if (!hw_finished_p (me))
    hw_finish (me);
    hw_finish (me);
}
}
 
 
void
void
hw_tree_finish (struct hw *root)
hw_tree_finish (struct hw *root)
{
{
  hw_tree_traverse (root, finish_hw_tree, NULL, NULL);
  hw_tree_traverse (root, finish_hw_tree, NULL, NULL);
}
}
 
 
 
 
 
 
void
void
hw_tree_traverse (struct hw *root,
hw_tree_traverse (struct hw *root,
                  hw_tree_traverse_function *prefix,
                  hw_tree_traverse_function *prefix,
                  hw_tree_traverse_function *postfix,
                  hw_tree_traverse_function *postfix,
                  void *data)
                  void *data)
{
{
  struct hw *child;
  struct hw *child;
  if (prefix != NULL)
  if (prefix != NULL)
    prefix (root, data);
    prefix (root, data);
  for (child = hw_child (root);
  for (child = hw_child (root);
       child != NULL;
       child != NULL;
       child = hw_sibling (child))
       child = hw_sibling (child))
    {
    {
      hw_tree_traverse (child, prefix, postfix, data);
      hw_tree_traverse (child, prefix, postfix, data);
    }
    }
  if (postfix != NULL)
  if (postfix != NULL)
    postfix (root, data);
    postfix (root, data);
}
}
 
 
 
 


struct printer {
struct printer {
  hw_tree_print_callback *print;
  hw_tree_print_callback *print;
  void *file;
  void *file;
};
};
 
 
static void
static void
print_address (struct hw *bus,
print_address (struct hw *bus,
               const hw_unit *phys,
               const hw_unit *phys,
               struct printer *p)
               struct printer *p)
{
{
  char unit[32];
  char unit[32];
  hw_unit_encode (bus, phys, unit, sizeof(unit));
  hw_unit_encode (bus, phys, unit, sizeof(unit));
  p->print (p->file, " %s", unit);
  p->print (p->file, " %s", unit);
}
}
 
 
static void
static void
print_size (struct hw *bus,
print_size (struct hw *bus,
            const hw_unit *size,
            const hw_unit *size,
            struct printer *p)
            struct printer *p)
{
{
  int i;
  int i;
  for (i = 0; i < size->nr_cells; i++)
  for (i = 0; i < size->nr_cells; i++)
    if (size->cells[i] != 0)
    if (size->cells[i] != 0)
      break;
      break;
  if (i < size->nr_cells) {
  if (i < size->nr_cells) {
    p->print (p->file, " 0x%lx", (unsigned long) size->cells[i]);
    p->print (p->file, " 0x%lx", (unsigned long) size->cells[i]);
    i++;
    i++;
    for (; i < size->nr_cells; i++)
    for (; i < size->nr_cells; i++)
      p->print (p->file, ",0x%lx", (unsigned long) size->cells[i]);
      p->print (p->file, ",0x%lx", (unsigned long) size->cells[i]);
  }
  }
  else
  else
    p->print (p->file, " 0");
    p->print (p->file, " 0");
}
}
 
 
static void
static void
print_reg_property (struct hw *me,
print_reg_property (struct hw *me,
                    const struct hw_property *property,
                    const struct hw_property *property,
                    struct printer *p)
                    struct printer *p)
{
{
  int reg_nr;
  int reg_nr;
  reg_property_spec reg;
  reg_property_spec reg;
  for (reg_nr = 0;
  for (reg_nr = 0;
       hw_find_reg_array_property (me, property->name, reg_nr, &reg);
       hw_find_reg_array_property (me, property->name, reg_nr, &reg);
       reg_nr++) {
       reg_nr++) {
    print_address (hw_parent (me), &reg.address, p);
    print_address (hw_parent (me), &reg.address, p);
    print_size (me, &reg.size, p);
    print_size (me, &reg.size, p);
  }
  }
}
}
 
 
static void
static void
print_ranges_property (struct hw *me,
print_ranges_property (struct hw *me,
                       const struct hw_property *property,
                       const struct hw_property *property,
                       struct printer *p)
                       struct printer *p)
{
{
  int range_nr;
  int range_nr;
  range_property_spec range;
  range_property_spec range;
  for (range_nr = 0;
  for (range_nr = 0;
       hw_find_range_array_property (me, property->name, range_nr, &range);
       hw_find_range_array_property (me, property->name, range_nr, &range);
       range_nr++)
       range_nr++)
    {
    {
      print_address (me, &range.child_address, p);
      print_address (me, &range.child_address, p);
      print_address (hw_parent (me), &range.parent_address, p);
      print_address (hw_parent (me), &range.parent_address, p);
      print_size (me, &range.size, p);
      print_size (me, &range.size, p);
    }
    }
}
}
 
 
static void
static void
print_string (struct hw *me,
print_string (struct hw *me,
              const char *string,
              const char *string,
              struct printer *p)
              struct printer *p)
{
{
  p->print (p->file, " \"");
  p->print (p->file, " \"");
  while (*string != '\0') {
  while (*string != '\0') {
    switch (*string) {
    switch (*string) {
    case '"':
    case '"':
      p->print (p->file, "\\\"");
      p->print (p->file, "\\\"");
      break;
      break;
    case '\\':
    case '\\':
      p->print (p->file, "\\\\");
      p->print (p->file, "\\\\");
      break;
      break;
    default:
    default:
      p->print (p->file, "%c", *string);
      p->print (p->file, "%c", *string);
      break;
      break;
    }
    }
    string++;
    string++;
  }
  }
  p->print (p->file, "\"");
  p->print (p->file, "\"");
}
}
 
 
static void
static void
print_string_array_property (struct hw *me,
print_string_array_property (struct hw *me,
                             const struct hw_property *property,
                             const struct hw_property *property,
                             struct printer *p)
                             struct printer *p)
{
{
  int nr;
  int nr;
  string_property_spec string;
  string_property_spec string;
  for (nr = 0;
  for (nr = 0;
       hw_find_string_array_property (me, property->name, nr, &string);
       hw_find_string_array_property (me, property->name, nr, &string);
       nr++)
       nr++)
    {
    {
      print_string (me, string, p);
      print_string (me, string, p);
    }
    }
}
}
 
 
static void
static void
print_properties (struct hw *me,
print_properties (struct hw *me,
                  struct printer *p)
                  struct printer *p)
{
{
  const struct hw_property *property;
  const struct hw_property *property;
  for (property = hw_find_property (me, NULL);
  for (property = hw_find_property (me, NULL);
       property != NULL;
       property != NULL;
       property = hw_next_property (property))
       property = hw_next_property (property))
    {
    {
      if (hw_parent (me) == NULL)
      if (hw_parent (me) == NULL)
        p->print (p->file, "/%s", property->name);
        p->print (p->file, "/%s", property->name);
      else
      else
        p->print (p->file, "%s/%s", hw_path (me), property->name);
        p->print (p->file, "%s/%s", hw_path (me), property->name);
      if (property->original != NULL)
      if (property->original != NULL)
        {
        {
          p->print (p->file, " !");
          p->print (p->file, " !");
          p->print (p->file, "%s/%s",
          p->print (p->file, "%s/%s",
                     hw_path (property->original->owner),
                     hw_path (property->original->owner),
                     property->original->name);
                     property->original->name);
        }
        }
      else
      else
        {
        {
          switch (property->type)
          switch (property->type)
            {
            {
            case array_property:
            case array_property:
              {
              {
                if ((property->sizeof_array % sizeof (signed_cell)) == 0)
                if ((property->sizeof_array % sizeof (signed_cell)) == 0)
                  {
                  {
                    unsigned_cell *w = (unsigned_cell*) property->array;
                    unsigned_cell *w = (unsigned_cell*) property->array;
                    int cell_nr;
                    int cell_nr;
                    for (cell_nr = 0;
                    for (cell_nr = 0;
                         cell_nr < (property->sizeof_array / sizeof (unsigned_cell));
                         cell_nr < (property->sizeof_array / sizeof (unsigned_cell));
                         cell_nr++)
                         cell_nr++)
                      {
                      {
                        p->print (p->file, " 0x%lx", (unsigned long) BE2H_cell (w[cell_nr]));
                        p->print (p->file, " 0x%lx", (unsigned long) BE2H_cell (w[cell_nr]));
                      }
                      }
                  }
                  }
                else
                else
                  {
                  {
                    unsigned8 *w = (unsigned8*)property->array;
                    unsigned8 *w = (unsigned8*)property->array;
                    p->print (p->file, " [");
                    p->print (p->file, " [");
                    while ((char*)w - (char*)property->array < property->sizeof_array) {
                    while ((char*)w - (char*)property->array < property->sizeof_array) {
                      p->print (p->file, " 0x%2x", BE2H_1 (*w));
                      p->print (p->file, " 0x%2x", BE2H_1 (*w));
                      w++;
                      w++;
                    }
                    }
                  }
                  }
                break;
                break;
              }
              }
            case boolean_property:
            case boolean_property:
              {
              {
                int b = hw_find_boolean_property(me, property->name);
                int b = hw_find_boolean_property(me, property->name);
                p->print (p->file, " %s", b ? "true"  : "false");
                p->print (p->file, " %s", b ? "true"  : "false");
                break;
                break;
              }
              }
#if NOT_YET
#if NOT_YET
            case ihandle_property:
            case ihandle_property:
              {
              {
                if (property->array != NULL)
                if (property->array != NULL)
                  {
                  {
                    device_instance *instance = hw_find_ihandle_property (me, property->name);
                    device_instance *instance = hw_find_ihandle_property (me, property->name);
                    p->print (p->file, " *%s", device_instance_path(instance));
                    p->print (p->file, " *%s", device_instance_path(instance));
                  }
                  }
                else
                else
                  {
                  {
                    /* not yet initialized, ask the device for the path */
                    /* not yet initialized, ask the device for the path */
                    ihandle_runtime_property_spec spec;
                    ihandle_runtime_property_spec spec;
                    hw_find_ihandle_runtime_property (me, property->name, &spec);
                    hw_find_ihandle_runtime_property (me, property->name, &spec);
                    p->print (p->file, " *%s", spec.full_path);
                    p->print (p->file, " *%s", spec.full_path);
                  }
                  }
                break;
                break;
              }
              }
#endif
#endif
            case integer_property:
            case integer_property:
              {
              {
                unsigned_word w = hw_find_integer_property (me, property->name);
                unsigned_word w = hw_find_integer_property (me, property->name);
                p->print (p->file, " 0x%lx", (unsigned long)w);
                p->print (p->file, " 0x%lx", (unsigned long)w);
                break;
                break;
              }
              }
            case range_array_property:
            case range_array_property:
              {
              {
                print_ranges_property (me, property, p);
                print_ranges_property (me, property, p);
                break;
                break;
              }
              }
            case reg_array_property:
            case reg_array_property:
              {
              {
                print_reg_property (me, property, p);
                print_reg_property (me, property, p);
                break;
                break;
              }
              }
            case string_property:
            case string_property:
              {
              {
                const char *s = hw_find_string_property (me, property->name);
                const char *s = hw_find_string_property (me, property->name);
                print_string (me, s, p);
                print_string (me, s, p);
                break;
                break;
              }
              }
            case string_array_property:
            case string_array_property:
              {
              {
                print_string_array_property (me, property, p);
                print_string_array_property (me, property, p);
                break;
                break;
              }
              }
            }
            }
        }
        }
      p->print (p->file, "\n");
      p->print (p->file, "\n");
    }
    }
}
}
 
 
static void
static void
print_interrupts (struct hw *me,
print_interrupts (struct hw *me,
                  int my_port,
                  int my_port,
                  struct hw *dest,
                  struct hw *dest,
                  int dest_port,
                  int dest_port,
                  void *data)
                  void *data)
{
{
  struct printer *p = data;
  struct printer *p = data;
  char src[32];
  char src[32];
  char dst[32];
  char dst[32];
  hw_port_encode (me, my_port, src, sizeof(src), output_port);
  hw_port_encode (me, my_port, src, sizeof(src), output_port);
  hw_port_encode (dest, dest_port, dst, sizeof(dst), input_port);
  hw_port_encode (dest, dest_port, dst, sizeof(dst), input_port);
  p->print (p->file,
  p->print (p->file,
            "%s > %s %s %s\n",
            "%s > %s %s %s\n",
            hw_path (me),
            hw_path (me),
            src, dst,
            src, dst,
            hw_path (dest));
            hw_path (dest));
}
}
 
 
static void
static void
print_device (struct hw *me,
print_device (struct hw *me,
              void *data)
              void *data)
{
{
  struct printer *p = data;
  struct printer *p = data;
  p->print (p->file, "%s\n", hw_path (me));
  p->print (p->file, "%s\n", hw_path (me));
  print_properties (me, p);
  print_properties (me, p);
  hw_port_traverse (me, print_interrupts, data);
  hw_port_traverse (me, print_interrupts, data);
}
}
 
 
void
void
hw_tree_print (struct hw *root,
hw_tree_print (struct hw *root,
               hw_tree_print_callback *print,
               hw_tree_print_callback *print,
               void *file)
               void *file)
{
{
  struct printer p;
  struct printer p;
  p.print = print;
  p.print = print;
  p.file = file;
  p.file = file;
  hw_tree_traverse (root,
  hw_tree_traverse (root,
                    print_device, NULL,
                    print_device, NULL,
                    &p);
                    &p);
}
}
 
 
 
 


#if NOT_YET
#if NOT_YET
device_instance *
device_instance *
tree_instance(struct hw *root,
tree_instance(struct hw *root,
              const char *device_specifier)
              const char *device_specifier)
{
{
  /* find the device node */
  /* find the device node */
  struct hw *me;
  struct hw *me;
  name_specifier spec;
  name_specifier spec;
  if (!split_device_specifier(root, device_specifier, &spec))
  if (!split_device_specifier(root, device_specifier, &spec))
    return NULL;
    return NULL;
  me = split_find_device(root, &spec);
  me = split_find_device(root, &spec);
  if (spec.name != NULL)
  if (spec.name != NULL)
    return NULL;
    return NULL;
  /* create the instance */
  /* create the instance */
  return device_create_instance(me, device_specifier, spec.last_args);
  return device_create_instance(me, device_specifier, spec.last_args);
}
}
#endif
#endif
 
 
struct hw *
struct hw *
hw_tree_find_device (struct hw *root,
hw_tree_find_device (struct hw *root,
                     const char *path_to_device)
                     const char *path_to_device)
{
{
  struct hw *node;
  struct hw *node;
  name_specifier spec;
  name_specifier spec;
 
 
  /* parse the path */
  /* parse the path */
  split_device_specifier (root, path_to_device, &spec);
  split_device_specifier (root, path_to_device, &spec);
  if (spec.value != NULL)
  if (spec.value != NULL)
    return NULL; /* something wierd */
    return NULL; /* something wierd */
 
 
  /* now find it */
  /* now find it */
  node = split_find_device (root, &spec);
  node = split_find_device (root, &spec);
  if (spec.name != NULL)
  if (spec.name != NULL)
    return NULL; /* not a leaf */
    return NULL; /* not a leaf */
 
 
  return node;
  return node;
}
}
 
 
 
 
const struct hw_property *
const struct hw_property *
hw_tree_find_property (struct hw *root,
hw_tree_find_property (struct hw *root,
                       const char *path_to_property)
                       const char *path_to_property)
{
{
  name_specifier spec;
  name_specifier spec;
  if (!split_property_specifier (root, path_to_property, &spec))
  if (!split_property_specifier (root, path_to_property, &spec))
    hw_abort (root, "Invalid property path %s", path_to_property);
    hw_abort (root, "Invalid property path %s", path_to_property);
  root = split_find_device (root, &spec);
  root = split_find_device (root, &spec);
  if (spec.name != NULL)
  if (spec.name != NULL)
    return NULL; /* not a leaf */
    return NULL; /* not a leaf */
  return hw_find_property (root, spec.property);
  return hw_find_property (root, spec.property);
}
}
 
 
int
int
hw_tree_find_boolean_property (struct hw *root,
hw_tree_find_boolean_property (struct hw *root,
                               const char *path_to_property)
                               const char *path_to_property)
{
{
  name_specifier spec;
  name_specifier spec;
  if (!split_property_specifier (root, path_to_property, &spec))
  if (!split_property_specifier (root, path_to_property, &spec))
    hw_abort (root, "Invalid property path %s", path_to_property);
    hw_abort (root, "Invalid property path %s", path_to_property);
  root = split_find_device (root, &spec);
  root = split_find_device (root, &spec);
  if (spec.name != NULL)
  if (spec.name != NULL)
    hw_abort (root, "device \"%s\" not found (property \"%s\")",
    hw_abort (root, "device \"%s\" not found (property \"%s\")",
              spec.name, path_to_property);
              spec.name, path_to_property);
  return hw_find_boolean_property (root, spec.property);
  return hw_find_boolean_property (root, spec.property);
}
}
 
 
signed_cell
signed_cell
hw_tree_find_integer_property (struct hw *root,
hw_tree_find_integer_property (struct hw *root,
                               const char *path_to_property)
                               const char *path_to_property)
{
{
  name_specifier spec;
  name_specifier spec;
  if (!split_property_specifier (root, path_to_property, &spec))
  if (!split_property_specifier (root, path_to_property, &spec))
    hw_abort (root, "Invalid property path %s", path_to_property);
    hw_abort (root, "Invalid property path %s", path_to_property);
  root = split_find_device (root, &spec);
  root = split_find_device (root, &spec);
  if (spec.name != NULL)
  if (spec.name != NULL)
    hw_abort (root, "device \"%s\" not found (property \"%s\")",
    hw_abort (root, "device \"%s\" not found (property \"%s\")",
              spec.name, path_to_property);
              spec.name, path_to_property);
  return hw_find_integer_property (root, spec.property);
  return hw_find_integer_property (root, spec.property);
}
}
 
 
#if NOT_YET
#if NOT_YET
device_instance *
device_instance *
hw_tree_find_ihandle_property (struct hw *root,
hw_tree_find_ihandle_property (struct hw *root,
                               const char *path_to_property)
                               const char *path_to_property)
{
{
  struct hw *root;
  struct hw *root;
  name_specifier spec;
  name_specifier spec;
  if (!split_property_specifier (root, path_to_property, &spec))
  if (!split_property_specifier (root, path_to_property, &spec))
    hw_abort (root, "Invalid property path %s", path_to_property);
    hw_abort (root, "Invalid property path %s", path_to_property);
  root = split_find_device (root, &spec);
  root = split_find_device (root, &spec);
  if (spec.name != NULL)
  if (spec.name != NULL)
    hw_abort (root, "device \"%s\" not found (property \"%s\")",
    hw_abort (root, "device \"%s\" not found (property \"%s\")",
              spec.name, path_to_property);
              spec.name, path_to_property);
  return hw_find_ihandle_property (root, spec.property);
  return hw_find_ihandle_property (root, spec.property);
}
}
#endif
#endif
 
 
const char *
const char *
hw_tree_find_string_property (struct hw *root,
hw_tree_find_string_property (struct hw *root,
                              const char *path_to_property)
                              const char *path_to_property)
{
{
  name_specifier spec;
  name_specifier spec;
  if (!split_property_specifier (root, path_to_property, &spec))
  if (!split_property_specifier (root, path_to_property, &spec))
    hw_abort (root, "Invalid property path %s", path_to_property);
    hw_abort (root, "Invalid property path %s", path_to_property);
  root = split_find_device (root, &spec);
  root = split_find_device (root, &spec);
  if (spec.name != NULL)
  if (spec.name != NULL)
    hw_abort (root, "device \"%s\" not found (property \"%s\")",
    hw_abort (root, "device \"%s\" not found (property \"%s\")",
              spec.name, path_to_property);
              spec.name, path_to_property);
  return hw_find_string_property (root, spec.property);
  return hw_find_string_property (root, spec.property);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.