sim: ppc: netbsd: Sync errno codes with NetBSD 9.99.49
[deliverable/binutils-gdb.git] / sim / ppc / device.c
index 83d9e3fd4ff939712447777a6b2cbb324a1ae0d8..d5093bbdadb192c0c8b83871d4e95d530fb646ac 100644 (file)
@@ -1,10 +1,10 @@
 /*  This file is part of the program psim.
 
-    Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
+    Copyright (C) 1994-1997, 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
+    the Free Software Foundation; either version 3 of the License, or
     (at your option) any later version.
 
     This program is distributed in the hope that it will be useful,
@@ -13,8 +13,7 @@
     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.
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
  
     */
 
@@ -27,6 +26,9 @@
 #include "device_table.h"
 #include "cap.h"
 
+#include "events.h"
+#include "psim.h"
+
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
@@ -42,7 +44,6 @@
 #include <ctype.h>
 
 STATIC_INLINE_DEVICE (void) clean_device_properties(device *);
-STATIC_INLINE_DEVICE (void) init_device_properties(device *, void*);
 
 /* property entries */
 
@@ -97,13 +98,13 @@ detach_device_interrupt_edge(device *me,
        && old_edge->dest_port == dest_port
        && old_edge->my_port == my_port) {
       if (old_edge->disposition == permenant_object)
-       device_error(me, "attempt to delete permenant interrupt\n");
+       device_error(me, "attempt to delete permenant interrupt");
       *list = old_edge->next;
-      zfree(old_edge);
+      free(old_edge);
       return;
     }
   }
-  device_error(me, "attempt to delete unattached interrupt\n");
+  device_error(me, "attempt to delete unattached interrupt");
 }
 
 STATIC_INLINE_DEVICE\
@@ -118,7 +119,7 @@ clean_device_interrupt_edges(device_interrupt_edge **list)
       break;
     case tempoary_object:
       *list = old_edge->next;
-      zfree(old_edge);
+      free(old_edge);
       break;
     }
   }
@@ -133,6 +134,8 @@ struct _device {
   const char *name;
   device_unit unit_address;
   const char *path;
+  int nr_address_cells;
+  int nr_size_cells;
 
   /* device tree */
   device *parent;
@@ -156,6 +159,9 @@ struct _device {
   cap *ihandles;
   cap *phandles;
   psim *system;
+
+  /* debugging */
+  int trace;
 };
 
 
@@ -175,76 +181,13 @@ struct _device_instance {
 
 
 \f
-/* Device node: */
-
-INLINE_DEVICE\
-(device *)
-device_parent(device *me)
-{
-  return me->parent;
-}
-
-INLINE_DEVICE\
-(device *)
-device_sibling(device *me)
-{
-  return me->sibling;
-}
-
-INLINE_DEVICE\
-(device *)
-device_child(device *me)
-{
-  return me->children;
-}
-
-INLINE_DEVICE\
-(const char *)
-device_name(device *me)
-{
-  return me->name;
-}
-
-INLINE_DEVICE\
-(const char *)
-device_path(device *me)
-{
-  return me->path;
-}
-
-INLINE_DEVICE\
-(void *)
-device_data(device *me)
-{
-  return me->data;
-}
-
-INLINE_DEVICE\
-(psim *)
-device_system(device *me)
-{
-  return me->system;
-}
-
-INLINE_DEVICE\
-(const device_unit *)
-device_unit_address(device *me)
-{
-  return &me->unit_address;
-}
-
-
-\f
-/* device template: */
-
-/* determine the full name of the device.  If buf is specified it is
-   stored in there.  Failing that, a safe area of memory is allocated */
+/* creation */
 
 STATIC_INLINE_DEVICE\
 (const char *)
 device_full_name(device *leaf,
-                char *buf,
-                unsigned sizeof_buf)
+                 char *buf,
+                 unsigned sizeof_buf)
 {
   /* get a buffer */
   char full_name[1024];
@@ -256,23 +199,23 @@ device_full_name(device *leaf,
   /* construct a name */
   if (leaf->parent == NULL) {
     if (sizeof_buf < 1)
-      error("device_full_name: buffer overflow\n");
+      error("device_full_name: buffer overflow");
     *buf = '\0';
   }
   else {
     char unit[1024];
     device_full_name(leaf->parent, buf, sizeof_buf);
     if (leaf->parent != NULL
-       && leaf->parent->callback->convert.encode_unit(leaf->parent,
-                                                      &leaf->unit_address,
-                                                      unit+1,
-                                                      sizeof(unit)-1) > 0)
+        && device_encode_unit(leaf->parent,
+                              &leaf->unit_address,
+                              unit+1,
+                              sizeof(unit)-1) > 0)
       unit[0] = '@';
     else
       unit[0] = '\0';
     if (strlen(buf) + strlen("/") + strlen(leaf->name) + strlen(unit)
-       >= sizeof_buf)
-      error("device_full_name: buffer overflow\n");
+        >= sizeof_buf)
+      error("device_full_name: buffer overflow");
     strcat(buf, "/");
     strcat(buf, leaf->name);
     strcat (buf, unit);
@@ -280,348 +223,285 @@ device_full_name(device *leaf,
   
   /* return it usefully */
   if (buf == full_name)
-    buf = strdup(full_name);
+    buf = (char *) strdup(full_name);
   return buf;
 }
 
-/* manipulate/lookup device names */
-
-typedef struct _name_specifier {
-  /* components in the full length name */
-  char *path;
-  char *property;
-  char *value;
-  /* current device */
-  char *name;
-  char *unit;
-  char *args;
-  /* previous device */
-  char *last_name;
-  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_INLINE_DEVICE\
-(int)
-split_device_specifier(const char *device_specifier,
-                      name_specifier *spec)
+(device *)
+device_create_from(const char *name,
+                  const device_unit *unit_address,
+                  void *data,
+                  const device_callbacks *callbacks,
+                  device *parent)
 {
-  char *chp;
-  if (strlen(device_specifier) >= sizeof(spec->buf))
-    error("split_device_specifier: buffer overflow\n");
+  device *new_device = ZALLOC(device);
 
-  /* expand aliases (later) */
-  strcpy(spec->buf, device_specifier);
+  /* insert it into the device tree */
+  new_device->parent = parent;
+  new_device->children = NULL;
+  if (parent != NULL) {
+    device **sibling = &parent->children;
+    while ((*sibling) != NULL)
+      sibling = &(*sibling)->sibling;
+    *sibling = new_device;
+  }
 
-  /* strip the leading spaces and check that remainder isn't a comment */
-  chp = spec->buf;
-  while (*chp != '\0' && isspace(*chp))
-    chp++;
-  if (*chp == '\0' || *chp == '#')
-    return 0;
+  /* give it a name */
+  new_device->name = (char *) strdup(name);
+  new_device->unit_address = *unit_address;
+  new_device->path = device_full_name(new_device, NULL, 0);
 
-  /* find the path and terminate it with null */
-  spec->path = chp;
-  while (*chp != '\0' && !isspace(*chp))
-    chp++;
-  if (*chp != '\0') {
-    *chp = '\0';
-    chp++;
-  }
+  /* its template */
+  new_device->data = data;
+  new_device->callback = callbacks;
 
-  /* and any value */
-  while (*chp != '\0' && isspace(*chp))
-    chp++;
-  spec->value = chp;
+  /* its properties - already null */
+  /* interrupts - already null */
 
-  /* 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;
+  /* mappings - if needed */
+  if (parent == NULL) {
+    new_device->ihandles = cap_create(name);
+    new_device->phandles = cap_create(name);
   }
   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;
-    }
+    new_device->ihandles = device_root(parent)->ihandles;
+    new_device->phandles = device_root(parent)->phandles;
   }
 
-  /* and mark the rest as invalid */
-  spec->name = NULL;
-  spec->unit = NULL;
-  spec->args = NULL;
-  spec->last_name = NULL;
-  spec->last_unit = NULL;
-  spec->last_args = NULL;
-
-  return 1;
+  cap_add(new_device->phandles, new_device);
+  return new_device;
 }
 
-/* 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_INLINE_DEVICE\
-(int)
-split_property_specifier(const char *property_specifier,
-                        name_specifier *spec)
-{
-  if (split_device_specifier(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;
+
+
+INLINE_DEVICE\
+(device *)
+device_create(device *parent,
+             const char *base,
+             const char *name,
+             const char *unit_address,
+             const char *args)
+{
+  const device_descriptor *const *table;
+  for (table = device_table; *table != NULL; table++) {
+    const device_descriptor *descr;
+    for (descr = *table; descr->name != NULL; descr++) {
+      if (strcmp(base, descr->name) == 0) {
+       device_unit address = { 0 };
+       void *data = NULL;
+       if (parent != NULL)
+         if (device_decode_unit(parent, unit_address, &address) < 0)
+           device_error(parent, "invalid address %s for device %s",
+                        unit_address, name);
+       if (descr->creator != NULL)
+         data = descr->creator(name, &address, args);
+       return device_create_from(name, &address, data,
+                                 descr->callbacks, parent);
       }
     }
-    return 1;
   }
-  else
-    return 0;
+  device_error(parent, "attempt to attach unknown device %s", name);
+  return NULL;
 }
 
-/* parse the next device name and split it up, return 0 when no more
-   names to parse */
-STATIC_INLINE_DEVICE\
-(int)
-split_device_name(name_specifier *spec)
+
+
+INLINE_DEVICE\
+(void)
+device_usage(int verbose)
 {
-  char *chp;
-  /* remember what came before */
-  spec->last_name = spec->name;
-  spec->last_unit = spec->unit;
-  spec->last_args = spec->args;
-  /* finished? */
-  if (spec->path[0] == '\0') {
-    spec->name = NULL;
-    spec->unit = NULL;
-    spec->args = NULL;
-    return 0;
-  }
-  /* break the device name 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';
-  }
-  /* 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;
+  const device_descriptor *const *table;
+  if (verbose == 1) {
+    int pos = 0;
+    for (table = device_table; *table != NULL; table++) {
+      const device_descriptor *descr;
+      for (descr = *table; descr->name != NULL; descr++) {
+       pos += strlen(descr->name) + 2;
+       if (pos > 75) {
+         pos = strlen(descr->name) + 2;
+         printf_filtered("\n");
+       }
+       printf_filtered("  %s", descr->name);
+      }
+      printf_filtered("\n");
+    }
   }
-  /* finally any args */
-  chp = strchr(chp, ':');
-  if (chp == NULL)
-    spec->args = NULL;
-  else {
-    *chp = '\0';
-    spec->args = chp+1;
+  if (verbose > 1) {
+    for (table = device_table; *table != NULL; table++) {
+      const device_descriptor *descr;
+      for (descr = *table; descr->name != NULL; descr++) {
+       printf_filtered("  %s:\n", descr->name);
+       /* interrupt ports */
+       if (descr->callbacks->interrupt.ports != NULL) {
+         const device_interrupt_port_descriptor *ports =
+           descr->callbacks->interrupt.ports;
+         printf_filtered("    interrupt ports:");
+         while (ports->name != NULL) {
+           printf_filtered(" %s", ports->name);
+           ports++;
+         }
+         printf_filtered("\n");
+       }
+       /* general info */
+       if (descr->callbacks->usage != NULL)
+         descr->callbacks->usage(verbose);
+      }
+    }
   }
-  return 1;
 }
 
-/* parse the value, returning the next non-space token */
 
-STATIC_INLINE_DEVICE\
-(char *)
-split_value(name_specifier *spec)
+
+\f
+/* Device node: */
+
+INLINE_DEVICE\
+(device *)
+device_parent(device *me)
 {
-  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;
+  return me->parent;
 }
 
+INLINE_DEVICE\
+(device *)
+device_root(device *me)
+{
+  ASSERT(me != NULL);
+  while (me->parent != NULL)
+    me = me->parent;
+  return me;
+}
 
+INLINE_DEVICE\
+(device *)
+device_sibling(device *me)
+{
+  return me->sibling;
+}
 
-/* traverse the path specified by spec starting at current */
-
-STATIC_INLINE_DEVICE\
+INLINE_DEVICE\
 (device *)
-split_find_device(device *current,
-                 name_specifier *spec)
-{
-  /* strip off (and process) any leading ., .., ./ and / */
-  while (1) {
-    if (strncmp(spec->path, "/", strlen("/")) == 0) {
-      /* cd /... */
-      while (current != NULL && current->parent != NULL)
-       current = current->parent;
-      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 && current->parent != NULL)
-       current = current->parent;
-      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 && current->parent != NULL)
-       current = current->parent;
-      spec->path += strlen("..");
-    }
-    else
-      break;
-  }
+device_child(device *me)
+{
+  return me->children;
+}
 
-  /* now go through the path proper */
+INLINE_DEVICE\
+(const char *)
+device_name(device *me)
+{
+  return me->name;
+}
 
-  if (current == NULL) {
-    split_device_name(spec);
-    return current;
-  }
+INLINE_DEVICE\
+(const char *)
+device_path(device *me)
+{
+  return me->path;
+}
 
-  while (split_device_name(spec)) {
-    device_unit phys;
-    device *child;
-    current->callback->convert.decode_unit(current, spec->unit, &phys);
-    for (child = current->children; child != NULL; child = child->sibling) {
-      if (strcmp(spec->name, child->name) == 0) {
-       if (phys.nr_cells == 0
-           || memcmp(&phys, &child->unit_address, sizeof(device_unit)) == 0)
-         break;
-      }
-    }
-    if (child == NULL)
-      return current; /* search failed */
-    current = child;
-  }
+INLINE_DEVICE\
+(void *)
+device_data(device *me)
+{
+  return me->data;
+}
 
-  return current;
+INLINE_DEVICE\
+(psim *)
+device_system(device *me)
+{
+  return me->system;
+}
+
+INLINE_DEVICE\
+(const device_unit *)
+device_unit_address(device *me)
+{
+  return &me->unit_address;
 }
 
 
-STATIC_INLINE_DEVICE\
-(device *)
-device_create_from(const char *name,
-                  const device_unit *unit_address,
-                  void *data,
-                  const device_callbacks *callbacks,
-                  device *parent)
+INLINE_DEVICE\
+(int)
+device_address_to_attach_address(device *me,
+                                const device_unit *address,
+                                int *attach_space,
+                                unsigned_word *attach_address,
+                                device *client)
 {
-  device *new_device = ZALLOC(device);
+  if (me->callback->convert.address_to_attach_address == NULL)
+    device_error(me, "no convert.address_to_attach_address method");
+  return me->callback->convert.address_to_attach_address(me, address, attach_space, attach_address, client);
+}
 
-  /* insert it into the device tree */
-  new_device->parent = parent;
-  new_device->children = NULL;
-  if (parent != NULL) {
-    device **sibling = &parent->children;
-    while ((*sibling) != NULL)
-      sibling = &(*sibling)->sibling;
-    *sibling = new_device;
-  }
 
-  /* give it a name */
-  new_device->name = strdup(name);
-  new_device->unit_address = *unit_address;
-  new_device->path = device_full_name(new_device, NULL, 0);
+INLINE_DEVICE\
+(int)
+device_size_to_attach_size(device *me,
+                          const device_unit *size,
+                          unsigned *nr_bytes,
+                          device *client)
+{
+  if (me->callback->convert.size_to_attach_size == NULL)
+    device_error(me, "no convert.size_to_attach_size method");
+  return me->callback->convert.size_to_attach_size(me, size, nr_bytes, client);
+}
 
-  /* its template */
-  new_device->data = data;
-  new_device->callback = callbacks;
 
-  /* its properties - already null */
-  /* interrupts - already null */
+INLINE_DEVICE\
+(int)
+device_decode_unit(device *bus,
+                  const char *unit,
+                  device_unit *address)
+{
+  if (bus->callback->convert.decode_unit == NULL)
+    device_error(bus, "no convert.decode_unit method");
+  return bus->callback->convert.decode_unit(bus, unit, address);
+}
 
-  /* mappings - if needed */
-  if (parent == NULL) {
-    new_device->ihandles = cap_create(name);
-    new_device->phandles = cap_create(name);
-  }
 
-  return new_device;
+INLINE_DEVICE\
+(int)
+device_encode_unit(device *bus,
+                  const device_unit *unit_address,
+                  char *buf,
+                  int sizeof_buf)
+{
+  if (bus->callback->convert.encode_unit == NULL)
+    device_error(bus, "no convert.encode_unit method");
+  return bus->callback->convert.encode_unit(bus, unit_address, buf, sizeof_buf);
 }
 
+INLINE_DEVICE\
+(unsigned)
+device_nr_address_cells(device *me)
+{
+  if (me->nr_address_cells == 0) {
+    if (device_find_property(me, "#address-cells") != NULL)
+      me->nr_address_cells = device_find_integer_property(me, "#address-cells");
+    else
+      me->nr_address_cells = 2;
+  }
+  return me->nr_address_cells;
+}
 
-STATIC_INLINE_DEVICE\
-(device *)
-device_template_create_device(device *parent,
-                             const char *name,
-                             const char *unit_address,
-                             const char *args)
+INLINE_DEVICE\
+(unsigned)
+device_nr_size_cells(device *me)
 {
-  const device_descriptor *const *table;
-  int name_len;
-  char *chp;
-  chp = strchr(name, '@');
-  name_len = (chp == NULL ? strlen(name) : chp - name);
-  for (table = device_table; *table != NULL; table++) {
-    const device_descriptor *descr;
-    for (descr = *table; descr->name != NULL; descr++) {
-      if (strncmp(name, descr->name, name_len) == 0
-         && (descr->name[name_len] == '\0'
-             || descr->name[name_len] == '@')) {
-       device_unit address = { 0 };
-       void *data = NULL;
-       if (parent != NULL && parent->callback->convert.decode_unit != NULL)
-         parent->callback->convert.decode_unit(parent, 
-                                               unit_address,
-                                               &address);
-       if (descr->creator != NULL)
-         data = descr->creator(name, &address, args);
-       return device_create_from(name, &address, data,
-                                 descr->callbacks, parent);
-      }
-    }
+  if (me->nr_size_cells == 0) {
+    if (device_find_property(me, "#size-cells") != NULL)
+      me->nr_size_cells = device_find_integer_property(me, "#size-cells");
+    else
+      me->nr_size_cells = 1;
   }
-  device_error(parent, "attempt to attach unknown device %s\n", name);
-  return NULL;
+  return me->nr_size_cells;
 }
 
+
 \f
 /* device-instance: */
 
@@ -636,29 +516,40 @@ device_create_instance_from(device *me,
 {
   device_instance *instance = ZALLOC(device_instance);
   if ((me == NULL) == (parent == NULL))
-    device_error(me, "can't have both parent instance and parent device\n");
-  instance->owner = me;
-  instance->parent = parent;
-  instance->data = data;
-  instance->args = (args == NULL ? NULL : strdup(args));
-  instance->path = (path == NULL ? NULL : strdup(path));
-  instance->callback = callbacks;
+    device_error(me, "can't have both parent instance and parent device");
   /*instance->unit*/
+  /* link this instance into the devices list */
   if (me != NULL) {
+    ASSERT(parent == NULL);
+    instance->owner = me;
+    instance->parent = NULL;
+    /* link this instance into the front of the devices instance list */
     instance->next = me->instances;
     me->instances = instance;
   }
   if (parent != NULL) {
     device_instance **previous;
+    ASSERT(parent->child == NULL);
     parent->child = instance;
+    ASSERT(me == NULL);
     instance->owner = parent->owner;
+    instance->parent = parent;
+    /* in the devices instance list replace the parent instance with
+       this one */
     instance->next = parent->next;
     /* replace parent with this new node */
     previous = &instance->owner->instances;
-    while (*previous != parent)
+    while (*previous != parent) {
+      ASSERT(*previous != NULL);
       previous = &(*previous)->next;
+    }
     *previous = instance;
   }
+  instance->data = data;
+  instance->args = (args == NULL ? NULL : (char *) strdup(args));
+  instance->path = (path == NULL ? NULL : (char *) strdup(path));
+  instance->callback = callbacks;
+  cap_add(instance->owner->ihandles, instance);
   return instance;
 }
 
@@ -666,22 +557,16 @@ device_create_instance_from(device *me,
 INLINE_DEVICE\
 (device_instance *)
 device_create_instance(device *me,
-                      const char *device_specifier)
+                      const char *path,
+                      const char *args)
 {
-  /* find the device node */
-  name_specifier spec;
-  if (!split_device_specifier(device_specifier, &spec))
-    return NULL;
-  me = split_find_device(me, &spec);
-  if (spec.name != NULL)
-    return NULL;
   /* create the instance */
   if (me->callback->instance_create == NULL)
-    device_error(me, "no instance_create method\n");
-  return me->callback->instance_create(me,
-                                      device_specifier, spec.last_args);
+    device_error(me, "no instance_create method");
+  return me->callback->instance_create(me, path, args);
 }
 
+
 STATIC_INLINE_DEVICE\
 (void)
 clean_device_instances(device *me)
@@ -694,25 +579,41 @@ clean_device_instances(device *me)
   }
 }
 
+
 INLINE_DEVICE\
 (void)
 device_instance_delete(device_instance *instance)
 {
   device *me = instance->owner;
-  device_instance **curr;
   if (instance->callback->delete == NULL)
-    device_error(me, "no delete method\n");
+    device_error(me, "no delete method");
   instance->callback->delete(instance);
   if (instance->args != NULL)
-    zfree(instance->args);
+    free(instance->args);
   if (instance->path != NULL)
-    zfree(instance->path);
-  curr = &me->instances;
-  while (*curr != NULL && *curr != instance)
-    curr = &(*curr)->next;
-  ASSERT(*curr != NULL);
-  *curr = instance->next;
-  zfree(instance);
+    free(instance->path);
+  if (instance->child == NULL) {
+    /* only remove leaf nodes */
+    device_instance **curr = &me->instances;
+    while (*curr != instance) {
+      ASSERT(*curr != NULL);
+      curr = &(*curr)->next;
+    }
+    *curr = instance->next;
+  }
+  else {
+    /* check it isn't in the instance list */
+    device_instance *curr = me->instances;
+    while (curr != NULL) {
+      ASSERT(curr != instance);
+      curr = curr->next;
+    }
+    /* unlink the child */
+    ASSERT(instance->child->parent == instance);
+    instance->child->parent = NULL;
+  }
+  cap_remove(me->ihandles, instance);
+  free(instance);
 }
 
 INLINE_DEVICE\
@@ -723,7 +624,7 @@ device_instance_read(device_instance *instance,
 {
   device *me = instance->owner;
   if (instance->callback->read == NULL)
-    device_error(me, "no read method\n");
+    device_error(me, "no read method");
   return instance->callback->read(instance, addr, len);
 }
 
@@ -735,7 +636,7 @@ device_instance_write(device_instance *instance,
 {
   device *me = instance->owner;
   if (instance->callback->write == NULL)
-    device_error(me, "no write method\n");
+    device_error(me, "no write method");
   return instance->callback->write(instance, addr, len);
 }
 
@@ -747,34 +648,36 @@ device_instance_seek(device_instance *instance,
 {
   device *me = instance->owner;
   if (instance->callback->seek == NULL)
-    device_error(me, "no seek method\n");
+    device_error(me, "no seek method");
   return instance->callback->seek(instance, pos_hi, pos_lo);
 }
 
 INLINE_DEVICE\
-(unsigned_word)
-device_instance_claim(device_instance *instance,
-                     unsigned_word address,
-                     unsigned_word length,
-                     unsigned_word alignment)
+(int)
+device_instance_call_method(device_instance *instance,
+                           const char *method_name,
+                           int n_stack_args,
+                           unsigned_cell stack_args[/*n_stack_args*/], 
+                           int n_stack_returns,
+                           unsigned_cell stack_returns[/*n_stack_args*/])
 {
   device *me = instance->owner;
-  if (instance->callback->claim == NULL)
-    device_error(me, "no claim method\n");
-  return instance->callback->claim(instance, address, length, alignment);
+  const device_instance_methods *method = instance->callback->methods;
+  if (method == NULL) {
+    device_error(me, "no methods (want %s)", method_name);
+  }
+  while (method->name != NULL) {
+    if (strcmp(method->name, method_name) == 0) {
+      return method->method(instance,
+                           n_stack_args, stack_args,
+                           n_stack_returns, stack_returns);
+    }
+    method++;
+  }
+  device_error(me, "no %s method", method_name);
+  return 0;
 }
 
-INLINE_DEVICE\
-(void)
-device_instance_release(device_instance *instance,
-                       unsigned_word address,
-                       unsigned_word length)
-{
-  device *me = instance->owner;
-  if (instance->callback->release == NULL)
-    device_error(me, "no release method\n");
-  instance->callback->release(instance, address, length);
-}
 
 INLINE_DEVICE\
 (device *)
@@ -799,64 +702,24 @@ device_instance_data(device_instance *instance)
 
 
 \f
-/* Device initialization: */
-
-STATIC_INLINE_DEVICE\
-(void)
-clean_device(device *root,
-            void *data)
-{
-  psim *system;
-  system = (psim*)data;
-  clean_device_interrupt_edges(&root->interrupt_destinations);
-  clean_device_instances(root);
-  clean_device_properties(root);
-}
-
-STATIC_INLINE_DEVICE\
-(void)
-init_device_address(device *me,
-                   void *data)
-{
-  psim *system = (psim*)data;
-  TRACE(trace_device_init, ("init_device_address() initializing %s\n", me->path));
-  me->system = system; /* misc things not known until now */
-  if (me->callback->init.address != NULL)
-    me->callback->init.address(me);
-}
+/* Device Properties: */
 
 STATIC_INLINE_DEVICE\
-(void)
-init_device_data(device *me,
-                void *data)
-{
-  TRACE(trace_device_init, ("device_init_data() initializing %s\n", me->path));
-  if (me->callback->init.data != NULL)
-    me->callback->init.data(me);
-}
-
-INLINE_DEVICE\
-(void)
-device_tree_init(device *root,
-                psim *system)
+(device_property_entry *)
+find_property_entry(device *me,
+                    const char *property)
 {
-  TRACE(trace_device_tree, ("device_tree_init(root=0x%lx, system=0x%lx)\n",
-                           (long)root,
-                           (long)system));
-  /* remove the old, rebuild the new */
-  device_tree_traverse(root, clean_device, NULL, system);
-  TRACE(trace_tbd, ("Need to dump the device tree here\n"));
-  device_tree_traverse(root, init_device_address, NULL, system);
-  device_tree_traverse(root, init_device_properties, NULL, system);
-  device_tree_traverse(root, init_device_data, NULL, system);
-  TRACE(trace_device_tree, ("device_tree_init() = void\n"));
+  device_property_entry *entry;
+  ASSERT(property != NULL);
+  entry = me->properties;
+  while (entry != NULL) {
+    if (strcmp(entry->value->name, property) == 0)
+      return entry;
+    entry = entry->next;
+  }
+  return NULL;
 }
 
-
-\f
-/* Device Properties: */
-
-/* local - not available externally */
 STATIC_INLINE_DEVICE\
 (void)
 device_add_property(device *me,
@@ -871,8 +734,6 @@ device_add_property(device *me,
 {
   device_property_entry *new_entry = NULL;
   device_property *new_value = NULL;
-  void *new_array = NULL;
-  void *new_init_array = NULL;
 
   /* find the list end */
   device_property_entry **insertion_point = &me->properties;
@@ -884,27 +745,28 @@ device_add_property(device *me,
 
   /* create a new value */
   new_value = ZALLOC(device_property);
-  new_value->name = strdup(property);
+  new_value->name = (char *) strdup(property);
   new_value->type = type;
-  new_value->sizeof_array = sizeof_array;
-  new_array = (sizeof_array > 0 ? zalloc(sizeof_array) : NULL);
-  new_value->array = new_array;
+  if (sizeof_array > 0) {
+    void *new_array = zalloc(sizeof_array);
+    memcpy(new_array, array, sizeof_array);
+    new_value->array = new_array;
+    new_value->sizeof_array = sizeof_array;
+  }
   new_value->owner = me;
   new_value->original = original;
   new_value->disposition = disposition;
-  if (sizeof_array > 0)
-    memcpy(new_array, array, sizeof_array);
 
   /* insert the value into the list */
   new_entry = ZALLOC(device_property_entry);
   *insertion_point = new_entry;
-  new_entry->sizeof_init_array = sizeof_init_array;
-  new_init_array = (sizeof_init_array > 0 ? zalloc(sizeof_init_array) : NULL);
-  new_entry->init_array = new_init_array;
-  new_entry->value = new_value;
-  if (sizeof_init_array > 0)
+  if (sizeof_init_array > 0) {
+    void *new_init_array = zalloc(sizeof_init_array);
     memcpy(new_init_array, init_array, sizeof_init_array);
-
+    new_entry->init_array = new_init_array;
+    new_entry->sizeof_init_array = sizeof_init_array;
+  }
+  new_entry->value = new_value;
 }
 
 
@@ -915,35 +777,35 @@ device_set_property(device *me,
                    const char *property,
                    device_property_type type,
                    const void *array,
-                   int sizeof_array,
-                   const device_property *original)
+                   int sizeof_array)
 {
   /* find the property */
-  device_property_entry *entry = me->properties;
-  while (entry != NULL) {
-    if (strcmp(entry->value->name, property) == 0) {
-      void *new_array = 0;
-      device_property *value = entry->value;
-      /* check the type matches */
-      if (value->type != type)
-       device_error(me, "conflict between type of new and old value for property %s\n", property);
-      /* replace its value */
-      if (value->array != NULL)
-       zfree((void*)value->array);
-      new_array = (sizeof_array > 0
-                  ? zalloc(sizeof_array)
-                  : (void*)0);
-      value->array = new_array;
-      value->sizeof_array = sizeof_array;
-      if (sizeof_array > 0)
-       memcpy(new_array, array, sizeof_array);
-      return;
-    }
-    entry = entry->next;
+  device_property_entry *entry = find_property_entry(me, property);
+  if (entry != NULL) {
+    /* existing property - update it */
+    void *new_array = 0;
+    device_property *value = entry->value;
+    /* check the type matches */
+    if (value->type != type)
+      device_error(me, "conflict between type of new and old value for property %s", property);
+    /* replace its value */
+    if (value->array != NULL)
+      free((void*)value->array);
+    new_array = (sizeof_array > 0
+                ? zalloc(sizeof_array)
+                : (void*)0);
+    value->array = new_array;
+    value->sizeof_array = sizeof_array;
+    if (sizeof_array > 0)
+      memcpy(new_array, array, sizeof_array);
+    return;
+  }
+  else {
+    /* new property - create it */
+    device_add_property(me, property, type,
+                       NULL, 0, array, sizeof_array,
+                       NULL, tempoary_object);
   }
-  device_add_property(me, property, type,
-                     NULL, 0, array, sizeof_array,
-                     original, tempoary_object);
 }
 
 
@@ -954,70 +816,103 @@ clean_device_properties(device *me)
   device_property_entry **delete_point = &me->properties;
   while (*delete_point != NULL) {
     device_property_entry *current = *delete_point;
-    device_property *property = current->value;
     switch (current->value->disposition) {
     case permenant_object:
-      {
-       /* delete the property, and replace it with the original */
-       ASSERT(((property->array == NULL) == (current->init_array == NULL))
-              || property->type == ihandle_property);
-       if (current->init_array != NULL) {
-         zfree((void*)current->value->array);
-         current->value->array = NULL;
-         if (property->type != ihandle_property) {
-           device_set_property(me, property->name,
-                               property->type,
-                               current->init_array, current->sizeof_init_array,
-                               NULL);
-         }
-       }
-       delete_point = &(*delete_point)->next;
+      /* zap the current value, will be initialized later */
+      ASSERT(current->init_array != NULL);
+      if (current->value->array != NULL) {
+       free((void*)current->value->array);
+       current->value->array = NULL;
       }
+      delete_point = &(*delete_point)->next;
       break;
     case tempoary_object:
-      {
-       /* zap the actual property, was created during simulation run */
-       *delete_point = current->next;
-       if (current->value->array != NULL)
-         zfree((void*)current->value->array);
-       zfree(current->value);
-       zfree(current);
-      }
+      /* zap the actual property, was created during simulation run */
+      ASSERT(current->init_array == NULL);
+      *delete_point = current->next;
+      if (current->value->array != NULL)
+       free((void*)current->value->array);
+      free(current->value);
+      free(current);
       break;
     }
   }
 }
 
 
-STATIC_INLINE_DEVICE\
+INLINE_DEVICE\
+(void)
+device_init_static_properties(device *me,
+                             void *data)
+{
+  device_property_entry *property;
+  for (property = me->properties;
+       property != NULL;
+       property = property->next) {
+    ASSERT(property->init_array != NULL);
+    ASSERT(property->value->array == NULL);
+    ASSERT(property->value->disposition == permenant_object);
+    switch (property->value->type) {
+    case array_property:
+    case boolean_property:
+    case range_array_property:
+    case reg_array_property:
+    case string_property:
+    case string_array_property:
+    case integer_property:
+      /* delete the property, and replace it with the original */
+      device_set_property(me, property->value->name,
+                         property->value->type,
+                         property->init_array,
+                         property->sizeof_init_array);
+      break;
+    case ihandle_property:
+      break;
+    }
+  }
+}
+
+
+INLINE_DEVICE\
 (void)
-init_device_properties(device *me,
-                      void *data)
-{
-  device_property_entry *property = me->properties;
-  while (property != NULL) {
-    /* now do the phandles */
-    if (property->value->type == ihandle_property) {
-      if (property->value->original != NULL) {
-       const device_property *original = property->value->original;
-       if (original->array == NULL) {
-         init_device_properties(original->owner, data);
+device_init_runtime_properties(device *me,
+                              void *data)
+{
+  device_property_entry *property;
+  for (property = me->properties;
+       property != NULL;
+       property = property->next) {
+    switch (property->value->disposition) {
+    case permenant_object:
+      switch (property->value->type) {
+      case ihandle_property:
+       {
+         device_instance *ihandle;
+         ihandle_runtime_property_spec spec;
+         ASSERT(property->init_array != NULL);
+         ASSERT(property->value->array == NULL);
+         device_find_ihandle_runtime_property(me, property->value->name, &spec);
+         ihandle = tree_instance(me, spec.full_path);
+         device_set_ihandle_property(me, property->value->name, ihandle);
+         break;
        }
-       ASSERT(original->array != NULL);
-       device_set_property(me, property->value->name,
-                           ihandle_property,
-                           original->array, original->sizeof_array, NULL);
-      }
-      else {
-       device_instance *instance =
-         device_create_instance(me, (char*)property->init_array);
-       unsigned32 ihandle = H2BE_4(device_instance_to_external(instance));
-       device_set_property(me, property->value->name,
-                           ihandle_property,
-                           &ihandle, sizeof(ihandle), NULL);
+      case array_property:
+      case boolean_property:
+      case range_array_property:
+      case integer_property:
+      case reg_array_property:
+      case string_property:
+      case string_array_property:
+       ASSERT(property->init_array != NULL);
+       ASSERT(property->value->array != NULL);
+       break;
       }
+      break;
+    case tempoary_object:
+      ASSERT(property->init_array == NULL);
+      ASSERT(property->value->array != NULL);
+      break;
     }
-    property = property->next;
   }
 }
 
@@ -1039,12 +934,12 @@ device_next_property(const device_property *property)
     return NULL;
 }
 
+
 INLINE_DEVICE\
 (const device_property *)
 device_find_property(device *me,
                     const char *property)
 {
-  name_specifier spec;
   if (me == NULL) {
     return NULL;
   }
@@ -1054,33 +949,25 @@ device_find_property(device *me,
     else
       return me->properties->value;
   }
-  else if (split_property_specifier(property, &spec)) {
-    me = split_find_device(me, &spec);
-    if (spec.name == NULL) { /*got to root*/
-      device_property_entry *entry = me->properties;
-      while (entry != NULL) {
-       if (strcmp(entry->value->name, spec.property) == 0)
-         return entry->value;
-       entry = entry->next;
-      }
-    }
+  else {
+    device_property_entry *entry = find_property_entry(me, property);
+    if (entry != NULL)
+      return entry->value;
   }
   return NULL;
 }
 
-STATIC_INLINE_DEVICE\
+
+INLINE_DEVICE\
 (void)
 device_add_array_property(device *me,
-                         const char *property,
-                         const void *array,
-                         int sizeof_array)
+                          const char *property,
+                          const void *array,
+                          int sizeof_array)
 {
-  TRACE(trace_devices,
-       ("device_add_array_property(me=0x%lx, property=%s, ...)\n",
-        (long)me, property));
   device_add_property(me, property, array_property,
-                     array, sizeof_array, array, sizeof_array,
-                     NULL, permenant_object);
+                      array, sizeof_array, array, sizeof_array,
+                      NULL, permenant_object);
 }
 
 INLINE_DEVICE\
@@ -1090,10 +977,7 @@ device_set_array_property(device *me,
                          const void *array,
                          int sizeof_array)
 {
-  TRACE(trace_devices,
-       ("device_set_array_property(me=0x%lx, property=%s, ...)\n",
-        (long)me, property));
-  device_set_property(me, property, array_property, array, sizeof_array, NULL);
+  device_set_property(me, property, array_property, array, sizeof_array);
 }
 
 INLINE_DEVICE\
@@ -1102,31 +986,25 @@ device_find_array_property(device *me,
                           const char *property)
 {
   const device_property *node;
-  TRACE(trace_devices,
-       ("device_find_integer(me=0x%lx, property=%s)\n",
-        (long)me, property));
   node = device_find_property(me, property);
   if (node == (device_property*)0
       || node->type != array_property)
-    device_error(me, "property %s not found or of wrong type\n", property);
+    device_error(me, "property %s not found or of wrong type", property);
   return node;
 }
 
 
-STATIC_INLINE_DEVICE\
+INLINE_DEVICE\
 (void)
 device_add_boolean_property(device *me,
-                           const char *property,
-                           int boolean)
+                            const char *property,
+                            int boolean)
 {
   signed32 new_boolean = (boolean ? -1 : 0);
-  TRACE(trace_devices,
-       ("device_add_boolean(me=0x%lx, property=%s, boolean=%d)\n",
-        (long)me, property, boolean));
   device_add_property(me, property, boolean_property,
-                     &new_boolean, sizeof(new_boolean),
-                     &new_boolean, sizeof(new_boolean),
-                     NULL, permenant_object);
+                      &new_boolean, sizeof(new_boolean),
+                      &new_boolean, sizeof(new_boolean),
+                      NULL, permenant_object);
 }
 
 INLINE_DEVICE\
@@ -1135,108 +1013,377 @@ device_find_boolean_property(device *me,
                             const char *property)
 {
   const device_property *node;
-  unsigned32 boolean;
-  TRACE(trace_devices,
-       ("device_find_boolean(me=0x%lx, property=%s)\n",
-        (long)me, property));
+  unsigned_cell boolean;
   node = device_find_property(me, property);
   if (node == (device_property*)0
       || node->type != boolean_property)
-    device_error(me, "property %s not found or of wrong type\n", property);
+    device_error(me, "property %s not found or of wrong type", property);
   ASSERT(sizeof(boolean) == node->sizeof_array);
   memcpy(&boolean, node->array, sizeof(boolean));
   return boolean;
 }
 
-STATIC_INLINE_DEVICE\
+
+INLINE_DEVICE\
 (void)
-device_add_ihandle_property(device *me,
-                           const char *property,
-                           const char *path)
+device_add_ihandle_runtime_property(device *me,
+                                   const char *property,
+                                   const ihandle_runtime_property_spec *ihandle)
 {
-  TRACE(trace_devices,
-       ("device_add_ihandle_property(me=0x%lx, property=%s, path=%s)\n",
-        (long)me, property, path));
+  /* enter the full path as the init array */
   device_add_property(me, property, ihandle_property,
-                     path, strlen(path) + 1,
+                     ihandle->full_path, strlen(ihandle->full_path) + 1,
                      NULL, 0,
                      NULL, permenant_object);
 }
 
+INLINE_DEVICE\
+(void)
+device_find_ihandle_runtime_property(device *me,
+                                    const char *property,
+                                    ihandle_runtime_property_spec *ihandle)
+{
+  device_property_entry *entry = find_property_entry(me, property);
+  TRACE(trace_devices,
+       ("device_find_ihandle_runtime_property(me=0x%lx, property=%s)\n",
+        (long)me, property));
+  if (entry == NULL
+      || entry->value->type != ihandle_property
+      || entry->value->disposition != permenant_object)
+    device_error(me, "property %s not found or of wrong type", property);
+  ASSERT(entry->init_array != NULL);
+  /* the full path */
+  ihandle->full_path = entry->init_array;
+}
+
+
+
+INLINE_DEVICE\
+(void)
+device_set_ihandle_property(device *me,
+                           const char *property,
+                           device_instance *ihandle)
+{
+  unsigned_cell cells;
+  cells = H2BE_cell(device_instance_to_external(ihandle));
+  device_set_property(me, property, ihandle_property,
+                     &cells, sizeof(cells));
+                     
+}
+
 INLINE_DEVICE\
 (device_instance *)
 device_find_ihandle_property(device *me,
                             const char *property)
 {
   const device_property *node;
-  unsigned32 ihandle;
+  unsigned_cell ihandle;
   device_instance *instance;
-  TRACE(trace_devices,
-       ("device_find_ihandle_property(me=0x%lx, property=%s)\n",
-        (long)me, property));
+
   node = device_find_property(me, property);
   if (node == NULL || node->type != ihandle_property)
-    device_error(me, "property %s not found or of wrong type\n", property);
+    device_error(me, "property %s not found or of wrong type", property);
   if (node->array == NULL)
-    device_error(me, "property %s not yet initialized\n", property);
+    device_error(me, "runtime property %s not yet initialized", property);
+
   ASSERT(sizeof(ihandle) == node->sizeof_array);
   memcpy(&ihandle, node->array, sizeof(ihandle));
-  BE2H(ihandle);
-  instance = external_to_device_instance(me, ihandle);
+  instance = external_to_device_instance(me, BE2H_cell(ihandle));
   ASSERT(instance != NULL);
   return instance;
 }
 
+
+INLINE_DEVICE\
+(void)
+device_add_integer_property(device *me,
+                           const char *property,
+                           signed_cell integer)
+{
+  H2BE(integer);
+  device_add_property(me, property, integer_property,
+                      &integer, sizeof(integer),
+                      &integer, sizeof(integer),
+                      NULL, permenant_object);
+}
+
+INLINE_DEVICE\
+(signed_cell)
+device_find_integer_property(device *me,
+                            const char *property)
+{
+  const device_property *node;
+  signed_cell integer;
+  TRACE(trace_devices,
+       ("device_find_integer(me=0x%lx, property=%s)\n",
+        (long)me, property));
+  node = device_find_property(me, property);
+  if (node == (device_property*)0
+      || node->type != integer_property)
+    device_error(me, "property %s not found or of wrong type", property);
+  ASSERT(sizeof(integer) == node->sizeof_array);
+  memcpy(&integer, node->array, sizeof(integer));
+  return BE2H_cell(integer);
+}
+
+INLINE_DEVICE\
+(int)
+device_find_integer_array_property(device *me,
+                                  const char *property,
+                                  unsigned index,
+                                  signed_cell *integer)
+{
+  const device_property *node;
+  int sizeof_integer = sizeof(*integer);
+  signed_cell *cell;
+  TRACE(trace_devices,
+       ("device_find_integer(me=0x%lx, property=%s)\n",
+        (long)me, property));
+
+  /* check things sane */
+  node = device_find_property(me, property);
+  if (node == (device_property*)0
+      || (node->type != integer_property
+         && node->type != array_property))
+    device_error(me, "property %s not found or of wrong type", property);
+  if ((node->sizeof_array % sizeof_integer) != 0)
+    device_error(me, "property %s contains an incomplete number of cells", property);
+  if (node->sizeof_array <= sizeof_integer * index)
+    return 0;
+
+  /* Find and convert the value */
+  cell = ((signed_cell*)node->array) + index;
+  *integer = BE2H_cell(*cell);
+
+  return node->sizeof_array / sizeof_integer;
+}
+
+
+STATIC_INLINE_DEVICE\
+(unsigned_cell *)
+unit_address_to_cells(const device_unit *unit,
+                     unsigned_cell *cell,
+                     int nr_cells)
+{
+  int i;
+  ASSERT(nr_cells == unit->nr_cells);
+  for (i = 0; i < unit->nr_cells; i++) {
+    *cell = H2BE_cell(unit->cells[i]);
+    cell += 1;
+  }
+  return cell;
+}
+
+
+STATIC_INLINE_DEVICE\
+(const unsigned_cell *)
+cells_to_unit_address(const unsigned_cell *cell,
+                     device_unit *unit,
+                     int nr_cells)
+{
+  int i;
+  memset(unit, 0, sizeof(*unit));
+  unit->nr_cells = nr_cells;
+  for (i = 0; i < unit->nr_cells; i++) {
+    unit->cells[i] = BE2H_cell(*cell);
+    cell += 1;
+  }
+  return cell;
+}
+
+
+STATIC_INLINE_DEVICE\
+(unsigned)
+nr_range_property_cells(device *me,
+                       int nr_ranges)
+{
+  return ((device_nr_address_cells(me)
+          + device_nr_address_cells(device_parent(me))
+          + device_nr_size_cells(me))
+         ) * nr_ranges;
+}
+
+INLINE_DEVICE\
+(void)
+device_add_range_array_property(device *me,
+                               const char *property,
+                               const range_property_spec *ranges,
+                               unsigned nr_ranges)
+{
+  unsigned sizeof_cells = (nr_range_property_cells(me, nr_ranges)
+                          * sizeof(unsigned_cell));
+  unsigned_cell *cells = zalloc(sizeof_cells);
+  unsigned_cell *cell;
+  int i;
+
+  /* copy the property elements over */
+  cell = cells;
+  for (i = 0; i < nr_ranges; i++) {
+    const range_property_spec *range = &ranges[i];
+    /* copy the child address */
+    cell = unit_address_to_cells(&range->child_address, cell,
+                                device_nr_address_cells(me));
+    /* copy the parent address */
+    cell = unit_address_to_cells(&range->parent_address, cell, 
+                                device_nr_address_cells(device_parent(me)));
+    /* copy the size */
+    cell = unit_address_to_cells(&range->size, cell, 
+                                device_nr_size_cells(me));
+  }
+  ASSERT(cell == &cells[nr_range_property_cells(me, nr_ranges)]);
+
+  /* add it */
+  device_add_property(me, property, range_array_property,
+                     cells, sizeof_cells,
+                     cells, sizeof_cells,
+                     NULL, permenant_object);
+
+  free(cells);
+}
+
+INLINE_DEVICE\
+(int)
+device_find_range_array_property(device *me,
+                                const char *property,
+                                unsigned index,
+                                range_property_spec *range)
+{
+  const device_property *node;
+  unsigned sizeof_entry = (nr_range_property_cells(me, 1)
+                          * sizeof(unsigned_cell));
+  const unsigned_cell *cells;
+
+  /* locate the property */
+  node = device_find_property(me, property);
+  if (node == (device_property*)0
+      || node->type != range_array_property)
+    device_error(me, "property %s not found or of wrong type", property);
+
+  /* aligned ? */
+  if ((node->sizeof_array % sizeof_entry) != 0)
+    device_error(me, "property %s contains an incomplete number of entries",
+                property);
+
+  /* within bounds? */
+  if (node->sizeof_array < sizeof_entry * (index + 1))
+    return 0;
+
+  /* find the range of interest */
+  cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
+
+  /* copy the child address out - converting as we go */
+  cells = cells_to_unit_address(cells, &range->child_address,
+                               device_nr_address_cells(me));
+
+  /* copy the parent address out - converting as we go */
+  cells = cells_to_unit_address(cells, &range->parent_address,
+                               device_nr_address_cells(device_parent(me)));
+
+  /* copy the size - converting as we go */
+  cells = cells_to_unit_address(cells, &range->size,
+                               device_nr_size_cells(me));
+
+  return node->sizeof_array / sizeof_entry;
+}
+
+
 STATIC_INLINE_DEVICE\
-(void)
-device_add_integer_property(device *me,
-                           const char *property,
-                           signed32 integer)
+(unsigned)
+nr_reg_property_cells(device *me,
+                     int nr_regs)
 {
-  TRACE(trace_devices,
-       ("device_add_integer_property(me=0x%lx, property=%s, integer=%ld)\n",
-        (long)me, property, (long)integer));
-  H2BE(integer);
-  device_add_property(me, property, integer_property,
-                     &integer, sizeof(integer),
-                     &integer, sizeof(integer),
+  return (device_nr_address_cells(device_parent(me))
+         + device_nr_size_cells(device_parent(me))
+         ) * nr_regs;
+}
+
+INLINE_DEVICE\
+(void)
+device_add_reg_array_property(device *me,
+                             const char *property,
+                             const reg_property_spec *regs,
+                             unsigned nr_regs)
+{
+  unsigned sizeof_cells = (nr_reg_property_cells(me, nr_regs)
+                          * sizeof(unsigned_cell));
+  unsigned_cell *cells = zalloc(sizeof_cells);
+  unsigned_cell *cell;
+  int i;
+
+  /* copy the property elements over */
+  cell = cells;
+  for (i = 0; i < nr_regs; i++) {
+    const reg_property_spec *reg = &regs[i];
+    /* copy the address */
+    cell = unit_address_to_cells(&reg->address, cell,
+                                device_nr_address_cells(device_parent(me)));
+    /* copy the size */
+    cell = unit_address_to_cells(&reg->size, cell,
+                                device_nr_size_cells(device_parent(me)));
+  }
+  ASSERT(cell == &cells[nr_reg_property_cells(me, nr_regs)]);
+
+  /* add it */
+  device_add_property(me, property, reg_array_property,
+                     cells, sizeof_cells,
+                     cells, sizeof_cells,
                      NULL, permenant_object);
+
+  free(cells);
 }
 
 INLINE_DEVICE\
-(signed_word)
-device_find_integer_property(device *me,
-                            const char *property)
+(int)
+device_find_reg_array_property(device *me,
+                              const char *property,
+                              unsigned index,
+                              reg_property_spec *reg)
 {
   const device_property *node;
-  signed32 integer;
-  TRACE(trace_devices,
-       ("device_find_integer(me=0x%lx, property=%s)\n",
-        (long)me, property));
+  unsigned sizeof_entry = (nr_reg_property_cells(me, 1)
+                          * sizeof(unsigned_cell));
+  const unsigned_cell *cells;
+
+  /* locate the property */
   node = device_find_property(me, property);
   if (node == (device_property*)0
-      || node->type != integer_property)
-    device_error(me, "property %s not found or of wrong type\n", property);
-  ASSERT(sizeof(integer) == node->sizeof_array);
-  memcpy(&integer, node->array, sizeof(integer));
-  BE2H(integer);
-  return integer;
+      || node->type != reg_array_property)
+    device_error(me, "property %s not found or of wrong type", property);
+
+  /* aligned ? */
+  if ((node->sizeof_array % sizeof_entry) != 0)
+    device_error(me, "property %s contains an incomplete number of entries",
+                property);
+
+  /* within bounds? */
+  if (node->sizeof_array < sizeof_entry * (index + 1))
+    return 0;
+
+  /* find the range of interest */
+  cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
+
+  /* copy the address out - converting as we go */
+  cells = cells_to_unit_address(cells, &reg->address,
+                               device_nr_address_cells(device_parent(me)));
+
+  /* copy the size out - converting as we go */
+  cells = cells_to_unit_address(cells, &reg->size,
+                               device_nr_size_cells(device_parent(me)));
+
+  return node->sizeof_array / sizeof_entry;
 }
 
-STATIC_INLINE_DEVICE\
+
+INLINE_DEVICE\
 (void)
 device_add_string_property(device *me,
-                          const char *property,
-                          const char *string)
+                           const char *property,
+                           const char *string)
 {
-
-  TRACE(trace_devices,
-       ("device_add_property(me=0x%lx, property=%s, string=%s)\n",
-        (long)me, property, string));
   device_add_property(me, property, string_property,
-                     string, strlen(string) + 1,
-                     string, strlen(string) + 1,
-                     NULL, permenant_object);
+                      string, strlen(string) + 1,
+                      string, strlen(string) + 1,
+                      NULL, permenant_object);
 }
 
 INLINE_DEVICE\
@@ -1246,32 +1393,133 @@ device_find_string_property(device *me,
 {
   const device_property *node;
   const char *string;
-  TRACE(trace_devices,
-       ("device_find_string(me=0x%lx, property=%s)\n",
-        (long)me, property));
   node = device_find_property(me, property);
   if (node == (device_property*)0
       || node->type != string_property)
-    device_error(me, "property %s not found or of wrong type\n", property);
+    device_error(me, "property %s not found or of wrong type", property);
   string = node->array;
   ASSERT(strlen(string) + 1 == node->sizeof_array);
   return string;
 }
 
-STATIC_INLINE_DEVICE\
+INLINE_DEVICE\
+(void)
+device_add_string_array_property(device *me,
+                                const char *property,
+                                const string_property_spec *strings,
+                                unsigned nr_strings)
+{
+  int sizeof_array;
+  int string_nr;
+  char *array;
+  char *chp;
+  if (nr_strings == 0)
+    device_error(me, "property %s must be non-null", property);
+  /* total up the size of the needed array */
+  for (sizeof_array = 0, string_nr = 0;
+       string_nr < nr_strings;
+       string_nr ++) {
+    sizeof_array += strlen(strings[string_nr]) + 1;
+  }
+  /* create the array */
+  array = (char*)zalloc(sizeof_array);
+  chp = array;
+  for (string_nr = 0;
+       string_nr < nr_strings;
+       string_nr++) {
+    strcpy(chp, strings[string_nr]);
+    chp += strlen(chp) + 1;
+  }
+  ASSERT(chp == array + sizeof_array);
+  /* now enter it */
+  device_add_property(me, property, string_array_property,
+                     array, sizeof_array,
+                     array, sizeof_array,
+                     NULL, permenant_object);
+}
+
+INLINE_DEVICE\
+(int)
+device_find_string_array_property(device *me,
+                                 const char *property,
+                                 unsigned index,
+                                 string_property_spec *string)
+{
+  const device_property *node;
+  node = device_find_property(me, property);
+  if (node == (device_property*)0)
+    device_error(me, "property %s not found", property);
+  switch (node->type) {
+  default:
+    device_error(me, "property %s of wrong type", property);
+    break;
+  case string_property:
+    if (index == 0) {
+      *string = node->array;
+      ASSERT(strlen(*string) + 1 == node->sizeof_array);
+      return 1;
+    }
+    break;
+  case array_property:
+    if (node->sizeof_array == 0
+       || ((char*)node->array)[node->sizeof_array - 1] != '\0')
+      device_error(me, "property %s invalid for string array", property);
+    /* FALL THROUGH */
+  case string_array_property:
+    ASSERT(node->sizeof_array > 0);
+    ASSERT(((char*)node->array)[node->sizeof_array - 1] == '\0');
+    {
+      const char *chp = node->array;
+      int nr_entries = 0;
+      /* count the number of strings, keeping an eye out for the one
+         we're looking for */
+      *string = chp;
+      do {
+       if (*chp == '\0') {
+         /* next string */
+         nr_entries++;
+         chp++;
+         if (nr_entries == index)
+           *string = chp;
+       }
+       else {
+         chp++;
+       }
+      } while (chp < (char*)node->array + node->sizeof_array);
+      if (index < nr_entries)
+       return nr_entries;
+      else {
+       *string = NULL;
+       return 0;
+      }
+    }
+    break;
+  }
+  return 0;
+}
+
+INLINE_DEVICE\
 (void)
 device_add_duplicate_property(device *me,
                              const char *property,
                              const device_property *original)
 {
+  device_property_entry *master;
   TRACE(trace_devices,
        ("device_add_duplicate_property(me=0x%lx, property=%s, ...)\n",
         (long)me, property));
   if (original->disposition != permenant_object)
-    device_error(me, "Can only duplicate permenant objects\n");
+    device_error(me, "Can only duplicate permenant objects");
+  /* find the original's master */
+  master = original->owner->properties;
+  while (master->value != original) {
+    master = master->next;
+    ASSERT(master != NULL);
+  }
+  /* now duplicate it */
   device_add_property(me, property,
                      original->type,
-                     original->array, original->sizeof_array,
+                     master->init_array, master->sizeof_init_array,
                      original->array, original->sizeof_array,
                      original, permenant_object);
 }
@@ -1291,7 +1539,7 @@ device_io_read_buffer(device *me,
                      unsigned_word cia)
 {
   if (me->callback->io.read_buffer == NULL)
-    device_error(me, "no io_read_buffer method\n");
+    device_error(me, "no io.read_buffer method");
   return me->callback->io.read_buffer(me, dest, space,
                                      addr, nr_bytes,
                                      processor, cia);
@@ -1308,7 +1556,7 @@ device_io_write_buffer(device *me,
                       unsigned_word cia)
 {
   if (me->callback->io.write_buffer == NULL)
-    device_error(me, "no io_write_buffer method\n");
+    device_error(me, "no io.write_buffer method");
   return me->callback->io.write_buffer(me, source, space,
                                       addr, nr_bytes,
                                       processor, cia);
@@ -1323,7 +1571,7 @@ device_dma_read_buffer(device *me,
                       unsigned nr_bytes)
 {
   if (me->callback->dma.read_buffer == NULL)
-    device_error(me, "no dma_read_buffer method\n");
+    device_error(me, "no dma.read_buffer method");
   return me->callback->dma.read_buffer(me, dest, space,
                                       addr, nr_bytes);
 }
@@ -1338,7 +1586,7 @@ device_dma_write_buffer(device *me,
                        int violate_read_only_section)
 {
   if (me->callback->dma.write_buffer == NULL)
-    device_error(me, "no dma_write_buffer method\n");
+    device_error(me, "no dma.write_buffer method");
   return me->callback->dma.write_buffer(me, source, space,
                                        addr, nr_bytes,
                                        violate_read_only_section);
@@ -1347,35 +1595,33 @@ device_dma_write_buffer(device *me,
 INLINE_DEVICE\
 (void)
 device_attach_address(device *me,
-                     const char *name,
                      attach_type attach,
                      int space,
                      unsigned_word addr,
                      unsigned nr_bytes,
                      access_type access,
-                     device *who) /*callback/default*/
+                     device *client) /*callback/default*/
 {
   if (me->callback->address.attach == NULL)
-    device_error(me, "no address_attach method\n");
-  me->callback->address.attach(me, name, attach, space,
-                              addr, nr_bytes, access, who);
+    device_error(me, "no address.attach method");
+  me->callback->address.attach(me, attach, space,
+                              addr, nr_bytes, access, client);
 }
 
 INLINE_DEVICE\
 (void)
 device_detach_address(device *me,
-                     const char *name,
                      attach_type attach,
                      int space,
                      unsigned_word addr,
                      unsigned nr_bytes,
                      access_type access,
-                     device *who) /*callback/default*/
+                     device *client) /*callback/default*/
 {
   if (me->callback->address.detach == NULL)
-    device_error(me, "no address_detach method\n");
-  me->callback->address.detach(me, name, attach, space,
-                              addr, nr_bytes, access, who);
+    device_error(me, "no address.detach method");
+  me->callback->address.detach(me, attach, space,
+                              addr, nr_bytes, access, client);
 }
 
 
@@ -1397,7 +1643,7 @@ device_interrupt_event(device *me,
        edge = edge->next) {
     if (edge->my_port == my_port) {
       if (edge->dest->callback->interrupt.event == NULL)
-       device_error(me, "no interrupt method\n");
+       device_error(me, "no interrupt method");
       edge->dest->callback->interrupt.event(edge->dest,
                                            edge->dest_port,
                                            me,
@@ -1408,7 +1654,7 @@ device_interrupt_event(device *me,
     }
   }
   if (!found_an_edge) {
-    device_error(me, "No interrupt edge for port %d\n", my_port);
+    device_error(me, "No interrupt edge for port %d", my_port);
   }
 }
 
@@ -1441,10 +1687,27 @@ device_interrupt_detach(device *me,
                               dest_port);
 }
 
+INLINE_DEVICE\
+(void)
+device_interrupt_traverse(device *me,
+                         device_interrupt_traverse_function *handler,
+                         void *data)
+{
+  device_interrupt_edge *interrupt_edge;
+  for (interrupt_edge = me->interrupt_destinations;
+       interrupt_edge != NULL;
+       interrupt_edge = interrupt_edge->next) {
+    handler(me, interrupt_edge->my_port,
+           interrupt_edge->dest, interrupt_edge->dest_port,
+           data);
+  }
+}
+
 INLINE_DEVICE\
 (int)
 device_interrupt_decode(device *me,
-                       const char *port_name)
+                       const char *port_name,
+                       port_direction direction)
 {
   if (port_name == NULL || port_name[0] == '\0')
     return 0;
@@ -1456,27 +1719,30 @@ device_interrupt_decode(device *me,
       me->callback->interrupt.ports;
     if (ports != NULL) {
       while (ports->name != NULL) {
-       if (ports->bound > ports->number) {
-         int len = strlen(ports->name);
-         if (strncmp(port_name, ports->name, len) == 0) {
-           if (port_name[len] == '\0')
-             return ports->number;
-           else if(isdigit(port_name[len])) {
-             int port = ports->number + strtoul(&port_name[len], NULL, 0);
-             if (port >= ports->bound)
-               device_error(me, "Interrupt port %s out of range\n",
-                            port_name);
-             return port;
+       if (ports->direction == bidirect_port
+           || ports->direction == direction) {
+         if (ports->nr_ports > 0) {
+           int len = strlen(ports->name);
+           if (strncmp(port_name, ports->name, len) == 0) {
+             if (port_name[len] == '\0')
+               return ports->number;
+             else if(isdigit(port_name[len])) {
+               int port = ports->number + strtoul(&port_name[len], NULL, 0);
+               if (port >= ports->number + ports->nr_ports)
+                 device_error(me, "Interrupt port %s out of range",
+                              port_name);
+               return port;
+             }
            }
          }
+         else if (strcmp(port_name, ports->name) == 0)
+           return ports->number;
        }
-       else if (strcmp(port_name, ports->name) == 0)
-         return ports->number;
        ports++;
       }
     }
   }
-  device_error(me, "Unreconized interrupt port %s\n", port_name);
+  device_error(me, "Unreconized interrupt port %s", port_name);
   return 0;
 }
 
@@ -1485,28 +1751,32 @@ INLINE_DEVICE\
 device_interrupt_encode(device *me,
                        int port_number,
                        char *buf,
-                       int sizeof_buf)
+                       int sizeof_buf,
+                       port_direction direction)
 {
   const device_interrupt_port_descriptor *ports = NULL;
   ports = me->callback->interrupt.ports;
   if (ports != NULL) {
     while (ports->name != NULL) {
-      if (ports->bound > ports->number) {
-       if (port_number >= ports->number
-           && port_number < ports->bound) {
-         strcpy(buf, ports->name);
-         sprintf(buf + strlen(buf), "%d", port_number - ports->number);
-         if (strlen(buf) >= sizeof_buf)
-           error("device_interrupt_encode:buffer overflow\n");
-         return strlen(buf);
+      if (ports->direction == bidirect_port
+         || ports->direction == direction) {
+       if (ports->nr_ports > 0) {
+         if (port_number >= ports->number
+             && port_number < ports->number + ports->nr_ports) {
+           strcpy(buf, ports->name);
+           sprintf(buf + strlen(buf), "%d", port_number - ports->number);
+           if (strlen(buf) >= sizeof_buf)
+             error("device_interrupt_encode: buffer overflow");
+           return strlen(buf);
+         }
        }
-      }
-      else {
-       if (ports->number == port_number) {
-         if (strlen(ports->name) >= sizeof_buf)
-           error("device_interrupt_encode: buffer overflow\n");
-         strcpy(buf, ports->name);
-         return strlen(buf);
+       else {
+         if (ports->number == port_number) {
+           if (strlen(ports->name) >= sizeof_buf)
+             error("device_interrupt_encode: buffer overflow");
+           strcpy(buf, ports->name);
+           return strlen(buf);
+         }
        }
       }
       ports++;
@@ -1514,7 +1784,7 @@ device_interrupt_encode(device *me,
   }
   sprintf(buf, "%d", port_number);
   if (strlen(buf) >= sizeof_buf)
-    error("device_interrupt_encode: buffer overflow\n");
+    error("device_interrupt_encode: buffer overflow");
   return strlen(buf);
 }
 
@@ -1527,14 +1797,15 @@ EXTERN_DEVICE\
 device_ioctl(device *me,
             cpu *processor,
             unsigned_word cia,
+            device_ioctl_request request,
             ...)
 {
   int status;
   va_list ap;
-  va_start(ap, cia);
+  va_start(ap, request);
   if (me->callback->ioctl == NULL)
-    device_error(me, "no ioctl method\n");
-  status = me->callback->ioctl(me, processor, cia, ap);
+    device_error(me, "no ioctl method");
+  status = me->callback->ioctl(me, processor, cia, request, ap);
   va_end(ap);
   return status;
 }
@@ -1544,7 +1815,7 @@ device_ioctl(device *me,
 /* I/O */
 
 EXTERN_DEVICE\
-(void volatile)
+(void)
 device_error(device *me,
             const char *fmt,
             ...)
@@ -1557,413 +1828,170 @@ device_error(device *me,
   va_end(ap);
   /* sanity check */
   if (strlen(message) >= sizeof(message))
-    error("device_error: buffer overflow\n");
+    error("device_error: buffer overflow");
   if (me == NULL)
-    error("device: %s\n", message);
+    error("device: %s", message);
+  else if (me->path != NULL && me->path[0] != '\0')
+    error("%s: %s", me->path, message);
+  else if (me->name != NULL && me->name[0] != '\0')
+    error("%s: %s", me->name, message);
   else
-    error("%s: %s\n", me->path, message);
+    error("device: %s", message);
   while(1);
 }
 
+INLINE_DEVICE\
+(int)
+device_trace(device *me)
+{
+  return me->trace;
+}
+
 \f
-/* Tree utilities: */
+/* External representation */
 
-EXTERN_DEVICE\
+INLINE_DEVICE\
 (device *)
-device_tree_add_parsed(device *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))
-      error("device_tree_add_parsed: buffer overflow\n");
-  }
-
-  /* break it up */
-  if (!split_device_specifier(device_specifier, &spec))
-    device_error(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 {
-      current =
-       device_template_create_device(current, spec.name, spec.unit, spec.args);
-    } while (split_device_name(&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);
-       char *dest_port_name = split_value(&spec);
-       device *dest = device_tree_find_device(current, split_value(&spec));
-       int my_port = device_interrupt_decode(current, my_port_name);
-       int dest_port  = device_interrupt_decode(dest, dest_port_name);
-       device_interrupt_attach(current,
-                               my_port,
-                               dest,
-                               dest_port,
-                               permenant_object);
-      }
-      break;
-    default:
-      device_error(current, "unreconised interrupt spec %s\n", spec.value);
-      break;
-    }
-  }
-
-  /* is there a property */
-  if (spec.property != NULL) {
-    if (strcmp(spec.value, "true") == 0)
-      device_add_boolean_property(current, spec.property, 1);
-    else if (strcmp(spec.value, "false") == 0)
-      device_add_boolean_property(current, spec.property, 0);
-    else {
-      const device_property *property;
-      switch (spec.value[0]) {
-      case '*':
-       {
-         spec.value++;
-         device_add_ihandle_property(current, spec.property, spec.value);
-       }
-       break;
-      case '-': case '+':
-      case '0': case '1': case '2': case '3': case '4':
-      case '5': case '6': case '7': case '8': case '9':
-       {
-         unsigned long ul = strtoul(spec.value, &spec.value, 0);
-         device_add_integer_property(current, spec.property, ul);
-       }
-       break;
-      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;
-         }
-         device_add_array_property(current, spec.property,
-                                   words, sizeof(words[0]) * nr_words);
-       }
-       break;
-      case '{':
-       {
-         unsigned32 words[1024];
-         char *curr = spec.value + 1;
-         int nr_words = 0;
-         while (1) {
-           char *next;
-           words[nr_words] = H2BE_4(strtoul(curr, &next, 0));
-           if (curr == next)
-             break;
-           curr = next;
-           nr_words += 1;
-         }
-         device_add_array_property(current, spec.property,
-                                   words, sizeof(words[0]) * nr_words);
-       }
-       break;
-      case '"':
-       spec.value++;
-      default:
-       device_add_string_property(current, spec.property, spec.value);
-       break;
-      case '!':
-       spec.value++;
-       property = device_find_property(current, spec.value);
-       if (property == NULL)
-         device_error(current, "property %s not found\n", spec.value);
-       device_add_duplicate_property(current,
-                                     spec.property,
-                                     property);
-       break;
-      }
-    }
-  }
-  return current;
+external_to_device(device *tree_member,
+                  unsigned_cell phandle)
+{
+  device *me = cap_internal(tree_member->phandles, phandle);
+  return me;
 }
 
 INLINE_DEVICE\
-(void)
-device_tree_traverse(device *root,
-                    device_tree_traverse_function *prefix,
-                    device_tree_traverse_function *postfix,
-                    void *data)
-{
-  device *child;
-  if (prefix != NULL)
-    prefix(root, data);
-  for (child = root->children; child != NULL; child = child->sibling) {
-    device_tree_traverse(child, prefix, postfix, data);
-  }
-  if (postfix != NULL)
-    postfix(root, data);
+(unsigned_cell)
+device_to_external(device *me)
+{
+  unsigned_cell phandle = cap_external(me->phandles, me);
+  return phandle;
 }
 
 INLINE_DEVICE\
-(void)
-device_tree_print_device(device *me,
-                        void *ignore_or_null)
+(device_instance *)
+external_to_device_instance(device *tree_member,
+                           unsigned_cell ihandle)
 {
-  const device_property *property;
-  device_interrupt_edge *interrupt_edge;
-  /* output my name */
-  printf_filtered("%s\n", me->path);
-  /* properties */
-  for (property = device_find_property(me, NULL);
-       property != NULL;
-       property = device_next_property(property)) {
-    printf_filtered("%s/%s", me->path, property->name);
-    if (property->original != NULL) {
-      printf_filtered(" !");
-      printf_filtered("%s/%s\n", property->original->owner->path,
-                     property->original->name);
-    }
-    else {
-      switch (property->type) {
-      case array_property:
-       {
-         if ((property->sizeof_array % sizeof(unsigned32)) == 0) {
-           unsigned32 *w = (unsigned32*)property->array;
-           printf_filtered(" {");
-           while ((char*)w - (char*)property->array < property->sizeof_array) {
-             printf_filtered(" 0x%lx", BE2H_4(*w));
-             w++;
-           }
-         }
-         else {
-           unsigned8 *w = (unsigned8*)property->array;
-           printf_filtered(" [");
-           while ((char*)w - (char*)property->array < property->sizeof_array) {
-             printf_filtered(" 0x%2x", BE2H_1(*w));
-             w++;
-           }
-         }
-         printf_filtered("\n");
-       }
-       break;
-      case boolean_property:
-       {
-         int b = device_find_boolean_property(me, property->name);
-         printf_filtered(" %s\n", b ? "true"  : "false");
-       }
-       break;
-      case ihandle_property:
-       {
-         if (property->array != NULL) {
-           device_instance *i = device_find_ihandle_property(me, property->name);
-           printf_filtered(" *%s\n", i->path);
-         }
-         else {
-           /* drats, the instance hasn't yet been created.  Grub
-               around and find the path that will be used to create
-               the ihandle */
-           device_property_entry *entry = me->properties;
-           while (entry->value != property) {
-             entry = entry->next;
-             ASSERT(entry != NULL);
-           }
-           ASSERT(entry->init_array != NULL);
-           printf_filtered(" *%s\n", (char*)entry->init_array);
-         }
-       }
-       break;
-      case integer_property:
-       {
-         unsigned_word w = device_find_integer_property(me, property->name);
-         printf_filtered(" 0x%lx\n", (unsigned long)w);
-       }
-       break;
-      case string_property:
-       {
-         const char *s = device_find_string_property(me, property->name);
-         printf_filtered(" \"%s\n", s);
-       }
-       break;
-      }
-    }
-  }
-  /* interrupts */
-  for (interrupt_edge = me->interrupt_destinations;
-       interrupt_edge != NULL;
-       interrupt_edge = interrupt_edge->next) {
-    char src[32];
-    char dst[32];
-    device_interrupt_encode(me, interrupt_edge->my_port, src, sizeof(src));
-    device_interrupt_encode(interrupt_edge->dest,
-                           interrupt_edge->dest_port, dst, sizeof(dst));
-    printf_filtered("%s > %s %s %s\n",
-                   me->path,
-                   src, dst,
-                   interrupt_edge->dest->path);
-  }
+  device_instance *instance = cap_internal(tree_member->ihandles, ihandle);
+  return instance;
 }
 
 INLINE_DEVICE\
-(device *)
-device_tree_find_device(device *root,
-                       const char *path)
-{
-  device *node;
-  name_specifier spec;
-  TRACE(trace_device_tree,
-       ("device_tree_find_device_tree(root=0x%lx, path=%s)\n",
-        (long)root, path));
-  /* parse the path */
-  split_device_specifier(path, &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 */
+(unsigned_cell)
+device_instance_to_external(device_instance *instance)
+{
+  unsigned_cell ihandle = cap_external(instance->owner->ihandles, instance);
+  return ihandle;
+}
 
-  return node;
+
+/* Map onto the event functions */
+
+INLINE_DEVICE\
+(event_entry_tag)
+device_event_queue_schedule(device *me,
+                           signed64 delta_time,
+                           device_event_handler *handler,
+                           void *data)
+{
+  return event_queue_schedule(psim_event_queue(me->system),
+                             delta_time,
+                             handler,
+                             data);
 }
 
 INLINE_DEVICE\
 (void)
-device_usage(int verbose)
+device_event_queue_deschedule(device *me,
+                             event_entry_tag event_to_remove)
 {
-  if (verbose == 1) {
-    const device_descriptor *const *table;
-    int pos;
-    printf_filtered("\n");
-    printf_filtered("A device/property specifier has the form:\n");
-    printf_filtered("\n");
-    printf_filtered("  /path/to/a/device [ property-value ]\n");
-    printf_filtered("\n");
-    printf_filtered("and a possible device is\n");
-    printf_filtered("\n");
-    pos = 0;
-    for (table = device_table; *table != NULL; table++) {
-      const device_descriptor *descr;
-      for (descr = *table; descr->name != NULL; descr++) {
-       pos += strlen(descr->name) + 2;
-       if (pos > 75) {
-         pos = strlen(descr->name) + 2;
-         printf_filtered("\n");
-       }
-       printf_filtered("  %s", descr->name);
-      }
-      printf_filtered("\n");
-    }
-  }
-  if (verbose > 1) {
-    const device_descriptor *const *table;
-    printf_filtered("\n");
-    printf_filtered("A device/property specifier (<spec>) has the format:\n");
-    printf_filtered("\n");
-    printf_filtered("  <spec> ::= <path> [ <value> ] ;\n");
-    printf_filtered("  <path> ::= { <prefix> } { <node> \"/\" } <node> ;\n");
-    printf_filtered("  <prefix> ::= ( | \"/\" | \"../\" | \"./\" ) ;\n");
-    printf_filtered("  <node> ::= <name> [ \"@\" <unit> ] [ \":\" <args> ] ;\n");
-    printf_filtered("  <unit> ::= <number> { \",\" <number> } ;\n");
-    printf_filtered("\n");
-    printf_filtered("Where:\n");
-    printf_filtered("\n");
-    printf_filtered("  <name>  is the name of a device (list below)\n");
-    printf_filtered("  <unit>  is the unit-address relative to the parent bus\n");
-    printf_filtered("  <args>  additional arguments used when creating the device\n");
-    printf_filtered("  <value> ::= ( <number> # integer property\n");
-    printf_filtered("              | \"[\" { <number> } # array property (byte)\n");
-    printf_filtered("              | \"{\" { <number> } # array property (cell)\n");
-    printf_filtered("              | [ \"true\" | \"false\" ] # boolean property\n");
-    printf_filtered("              | \"*\" <path> # ihandle property\n");
-    printf_filtered("              | \"!\" <path> # copy property\n");
-    printf_filtered("              | \">\" [ <number> ] <path> # attach interrupt\n");
-    printf_filtered("              | \"<\" <path> # attach child interrupt\n");
-    printf_filtered("              | \"\\\"\" <text> # string property\n");
-    printf_filtered("              | <text> # string property\n");
-    printf_filtered("              ) ;\n");
-    printf_filtered("\n");
-    printf_filtered("And the following are valid device names:\n");
-    printf_filtered("\n");
-    for (table = device_table; *table != NULL; table++) {
-      const device_descriptor *descr;
-      for (descr = *table; descr->name != NULL; descr++) {
-       printf_filtered("  %s:\n", descr->name);
-       /* interrupt ports */
-       if (descr->callbacks->interrupt.ports != NULL) {
-         const device_interrupt_port_descriptor *ports =
-           descr->callbacks->interrupt.ports;
-         printf_filtered("    interrupt ports:");
-         while (ports->name != NULL) {
-           printf_filtered(" %s", ports->name);
-           ports++;
-         }
-         printf_filtered("\n");
-       }
-       /* general info */
-       if (descr->callbacks->usage != NULL)
-         descr->callbacks->usage(verbose);
-      }
-    }
-  }
+  event_queue_deschedule(psim_event_queue(me->system),
+                        event_to_remove);
 }
 
-
-\f
-/* External representation */
-
 INLINE_DEVICE\
-(device *)
-external_to_device(device *tree_member,
-                  unsigned32 phandle)
+(signed64)
+device_event_queue_time(device *me)
 {
-  device *root = device_tree_find_device(tree_member, "/");
-  device *me = cap_internal(root->phandles, phandle);
-  return me;
+  return event_queue_time(psim_event_queue(me->system));
 }
 
+
+/* Initialization: */
+
+
 INLINE_DEVICE\
-(unsigned32)
-device_to_external(device *me)
+(void)
+device_clean(device *me,
+            void *data)
 {
-  device *root = device_tree_find_device(me, "/");
-  unsigned32 phandle = cap_external(root->phandles, me);
-  return phandle;
+  psim *system;
+  system = (psim*)data;
+  TRACE(trace_device_init, ("device_clean - initializing %s", me->path));
+  clean_device_interrupt_edges(&me->interrupt_destinations);
+  clean_device_instances(me);
+  clean_device_properties(me);
 }
 
+/* Device initialization: */
+
 INLINE_DEVICE\
-(device_instance *)
-external_to_device_instance(device *tree_member,
-                           unsigned32 ihandle)
+(void)
+device_init_address(device *me,
+                   void *data)
 {
-  device *root = device_tree_find_device(tree_member, "/");
-  device_instance *instance = cap_internal(root->ihandles, ihandle);
-  return instance;
+  psim *system = (psim*)data;
+  int nr_address_cells;
+  int nr_size_cells;
+  TRACE(trace_device_init, ("device_init_address - initializing %s", me->path));
+
+  /* ensure the cap database is valid */
+  if (me->parent == NULL) {
+    cap_init(me->ihandles);
+    cap_init(me->phandles);
+  }
+
+  /* some basics */
+  me->system = system; /* misc things not known until now */
+  me->trace = (device_find_property(me, "trace")
+              ? device_find_integer_property(me, "trace")
+              : 0);
+
+  /* Ensure that the first address found in the reg property matches
+     anything that was specified as part of the devices name */
+  if (device_find_property(me, "reg") != NULL) {
+    reg_property_spec unit;
+    device_find_reg_array_property(me, "reg", 0, &unit);
+    if (memcmp(device_unit_address(me), &unit.address, sizeof(unit.address))
+       != 0)
+      device_error(me, "Unit address as specified by the reg property in conflict with the value previously specified in the devices path");
+  }
+
+  /* ensure that the devices #address/size-cells is consistent */
+  nr_address_cells = device_nr_address_cells(me);
+  if (device_find_property(me, "#address-cells") != NULL
+      && (nr_address_cells
+         != device_find_integer_property(me, "#address-cells")))
+    device_error(me, "#address-cells property used before defined");
+  nr_size_cells = device_nr_size_cells(me);
+  if (device_find_property(me, "#size-cells") != NULL
+      && (nr_size_cells
+         != device_find_integer_property(me, "#size-cells")))
+    device_error(me, "#size-cells property used before defined");
+
+  /* now init it */
+  if (me->callback->init.address != NULL)
+    me->callback->init.address(me);
 }
 
 INLINE_DEVICE\
-(unsigned32)
-device_instance_to_external(device_instance *instance)
+(void)
+device_init_data(device *me,
+                   void *data)
 {
-  device *root = device_tree_find_device(instance->owner, "/");
-  unsigned32 ihandle = cap_external(root->ihandles, instance);
-  return ihandle;
+  TRACE(trace_device_init, ("device_init_data - initializing %s", me->path));
+  if (me->callback->init.data != NULL)
+    me->callback->init.data(me);
 }
 
 #endif /* _DEVICE_C_ */
This page took 0.083384 seconds and 4 git commands to generate.