Add hw_{malloc,zalloc,free} functions to hw_device. Any memory
authorAndrew Cagney <cagney@redhat.com>
Sun, 22 Mar 1998 05:06:27 +0000 (05:06 +0000)
committerAndrew Cagney <cagney@redhat.com>
Sun, 22 Mar 1998 05:06:27 +0000 (05:06 +0000)
allocated using these functions is reclaimed when the corresponding
device is deleted.

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

index 65499fd..e760208 100644 (file)
@@ -1,3 +1,32 @@
+Sun Mar 22 15:23:35 1998  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * hw-device.h (HW_ZALLOC, HW_MALLOC): New macros.
+       (hw_alloc_data): Delcare.
+       (struct hw): Add member alloc_of_hw.
+       
+       * hw-device.c (hw_zalloc, hw_malloc, hw_free, hw_free_all): New
+       functions. Assocate memory with a device.
+       (stdlib.h): Include.
+       
+       * hw-base.h (set_hw_delete): Define.
+       (hw_delete_callback): Declare.
+       (hw_delete): Declare.
+
+       * hw-base.c (hw_delete): Implement function.
+       (struct hw_base_data): Add member to_delete.
+       (ignore_hw_delete): New function, does nothing.
+       (hw_create): Set the hw_delete method.
+       (hw_create): Allocate the base type using HW_ZALLOC before setting
+       any methods.
+
+       * hw-properties.c: Replace zalloc/zfree with hw_zalloc/hw_free.
+       
+       * hw-ports.c: Replace zalloc/zfree with hw_zalloc/hw_free.
+       (attach_hw_port_edge): Add struct hw argument
+
+       * dv-pal.c (hw_pal_finish): Replace zalloc/zfree with
+       hw_zalloc/hw_free.
+
 Sun Mar 22 15:09:52 1998  Andrew Cagney  <cagney@b1.cygnus.com>
 
        * hw-device.h (hw_attach_address_callback,
index afef9c8..f15f5c9 100644 (file)
@@ -368,7 +368,7 @@ static void
 hw_pal_finish (struct hw *hw)
 {
   /* create the descriptor */
-  hw_pal_device *hw_pal = ZALLOC (hw_pal_device);
+  hw_pal_device *hw_pal = HW_ZALLOC (hw, hw_pal_device);
   hw_pal->output.status = 1;
   hw_pal->output.buffer = '\0';
   hw_pal->input.status = 0;
index 0c4b8a5..495f96d 100644 (file)
 
 
 /* LATER: #include "hwconfig.h" */
-struct hw_base_data {
-  int finished_p;
-  const struct hw_device_descriptor *descriptor;
-};
 extern const struct hw_device_descriptor dv_core_descriptor[];
 extern const struct hw_device_descriptor dv_pal_descriptor[];
 const struct hw_device_descriptor *hw_descriptors[] = {
@@ -50,6 +46,11 @@ const struct hw_device_descriptor *hw_descriptors[] = {
 
 #include <ctype.h>
 
+struct hw_base_data {
+  int finished_p;
+  const struct hw_device_descriptor *descriptor;
+  hw_delete_callback *to_delete;
+};
 
 static int
 generic_hw_unit_decode (struct hw *bus,
@@ -287,6 +288,14 @@ panic_hw_port_event (struct hw *me,
   hw_abort (me, "no port method");
 }
 
+static void
+ignore_hw_delete (struct hw *me)
+{
+  /* NOP */
+}
+
+
+
 
 static const char *
 full_name_of_hw (struct hw *leaf,
@@ -345,6 +354,7 @@ hw_create (SIM_DESC sd,
           const char *unit,
           const char *args)
 {
+ /* NOTE: HW must be allocated using ZALLOC, others use HW_ZALLOC */
   struct hw *hw = ZALLOC (struct hw);
 
   /* our identity */
@@ -391,6 +401,10 @@ hw_create (SIM_DESC sd,
   else
     hw->path_of_hw = "/";
 
+  /* create our base type */
+  hw->base_of_hw = HW_ZALLOC (hw, struct hw_base_data);
+  hw->base_of_hw->finished_p = 0;
+
   /* our callbacks */
   set_hw_io_read_buffer (hw, panic_hw_io_read_buffer);
   set_hw_io_write_buffer (hw, panic_hw_io_write_buffer);
@@ -402,6 +416,7 @@ hw_create (SIM_DESC sd,
   set_hw_unit_size_to_attach_size (hw, generic_hw_unit_size_to_attach_size);
   set_hw_attach_address (hw, passthrough_hw_attach_address);
   set_hw_detach_address (hw, passthrough_hw_detach_address);
+  set_hw_delete (hw, ignore_hw_delete);
 
   /* locate a descriptor */
   {
@@ -417,13 +432,11 @@ hw_create (SIM_DESC sd,
          {
            if (strcmp (family, entry->family) == 0)
              {
-               hw->base_of_hw = ZALLOC (struct hw_base_data);
                hw->base_of_hw->descriptor = entry;
-               hw->base_of_hw->finished_p = 0;
              }
          }
       }
-    if (hw->base_of_hw == NULL)
+    if (hw->base_of_hw->descriptor == NULL)
       {
        hw_abort (parent, "Unknown device `%s'", family);
       }
@@ -465,3 +478,44 @@ hw_finish (struct hw *me)
   me->base_of_hw->descriptor->to_finish (me);
   me->base_of_hw->finished_p = 1;
 }
+
+
+void
+hw_delete (struct hw *me)
+{
+  /* give the object a chance to tidy up */
+  me->base_of_hw->to_delete (me);
+
+  /* now unlink us from the tree */
+  if (hw_parent (me))
+    {
+      struct hw **sibling = &hw_parent (me)->child_of_hw;
+      while (*sibling != NULL)
+       {
+         if (*sibling == me)
+           {
+             *sibling = me->sibling_of_hw;
+             me->sibling_of_hw = NULL;
+             me->parent_of_hw = NULL;
+             break;
+           }
+       }
+    }
+
+  /* some sanity checks */
+  if (hw_child (me) != NULL)
+    {
+      hw_abort (me, "attempt to delete device with children");
+    }
+  if (hw_sibling (me) != NULL)
+    {
+      hw_abort (me, "attempt to delete device with siblings");
+    }
+
+  /* blow away all memory belonging to the device */
+  hw_free_all (me);
+
+  /* finally */
+  zfree (me->base_of_hw);
+  zfree (me);
+}
diff --git a/sim/common/hw-base.h b/sim/common/hw-base.h
new file mode 100644 (file)
index 0000000..ee787dd
--- /dev/null
@@ -0,0 +1,128 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+    */
+
+
+#ifndef HW_ROOT
+#define HW_ROOT
+
+/* A root device from which dv-* devices can be built */
+
+#include "hw-device.h"
+
+#include "hw-properties.h"
+/* #include "hw-instances.h" */
+/* #include "hw-handles.h" */
+#include "hw-ports.h"
+
+typedef void (hw_finish_callback)
+     (struct hw *me);
+
+struct hw_device_descriptor {
+  const char *family;
+  hw_finish_callback *to_finish;
+};
+
+/* Create a primative device */
+
+struct hw *hw_create
+(SIM_DESC sd,
+ struct hw *parent,
+ const char *family,
+ const char *name,
+ const char *unit,
+ const char *args);
+
+
+/* Complete the creation of that device (finish overrides methods
+   using the set_hw_* operations below) */
+
+void hw_finish
+(struct hw *me);
+
+int hw_finished_p
+(struct hw *me);
+
+
+/* Delete the entire device */
+
+void hw_delete
+(struct hw *me);
+
+
+/* Override device methods */
+
+#define set_hw_data(hw, value) \
+((hw)->data_of_hw = (value))
+
+#define set_hw_reset(hw, method) \
+((hw)->to_reset = method)
+
+#define set_hw_io_read_buffer(hw, method) \
+((hw)->to_io_read_buffer = (method))
+#define set_hw_io_write_buffer(hw, method) \
+((hw)->to_io_write_buffer = (method))
+
+#define set_hw_dma_read_buffer(me, method) \
+((me)->to_dma_read_buffer = (method))
+#define set_hw_dma_write_buffer(me, method) \
+((me)->to_dma_write_buffer = (method))
+
+#define set_hw_attach_address(hw, method) \
+((hw)->to_attach_address = (method))
+#define set_hw_detach_address(hw, method) \
+((hw)->to_detach_address = (method))
+
+#define set_hw_unit_decode(hw, method) \
+((hw)->to_unit_decode = (method))
+#define set_hw_unit_encode(hw, method) \
+((hw)->to_unit_encode = (method))
+
+#define set_hw_unit_address_to_attach_address(hw, method) \
+((hw)->to_unit_address_to_attach_address = (method))
+#define set_hw_unit_size_to_attach_size(hw, method) \
+((hw)->to_unit_size_to_attach_size = (method))
+
+typedef void (hw_delete_callback)
+     (struct hw *me);
+
+#define set_hw_delete(hw, method) \
+((hw)->base_of_hw->to_delete = (method))
+
+
+struct hw_port_descriptor {
+  const char *name;
+  int number; 
+  int nr_ports;
+  port_direction direction;
+};
+
+typedef void (hw_port_event_callback)
+     (struct hw *me,
+      int my_port,
+      struct hw *source,
+      int source_port,
+      int level,
+      sim_cpu *processor,
+      sim_cia cia);
+
+extern void set_hw_ports (struct hw *hw, const struct hw_port_descriptor ports[]);
+extern void set_hw_port_event (struct hw *hw, hw_port_event_callback *to_port_event);
+
+#endif
diff --git a/sim/common/hw-device.c b/sim/common/hw-device.c
new file mode 100644 (file)
index 0000000..3f57190
--- /dev/null
@@ -0,0 +1,214 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+    */
+
+
+#include "sim-main.h"
+
+#include "hw-device.h"
+#include "hw-properties.h"
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+\f
+/* Address methods */
+
+const hw_unit *
+hw_unit_address (struct hw *me)
+{
+  return &me->unit_address_of_hw;
+}
+
+
+\f
+/* IOCTL: */
+
+int
+hw_ioctl (struct hw *me,
+         sim_cpu *processor,
+         sim_cia cia,
+         hw_ioctl_request request,
+         ...)
+{
+  int status;
+  va_list ap;
+  va_start(ap, request);
+  status = me->to_ioctl (me, processor, cia, request, ap);
+  va_end(ap);
+  return status;
+}
+      
+/* I/O */
+
+void volatile
+hw_abort (struct hw *me,
+         const char *fmt,
+         ...)
+{
+  SIM_DESC sd;
+  const char *name;
+  va_list ap;
+  va_start(ap, fmt);
+  /* find a system to abort through */
+  if (me == NULL || hw_system (me) == NULL)
+    sd = NULL;
+  else
+    sd = hw_system (me);
+  /* find an identity */
+  if (me != NULL && hw_path (me) != NULL && hw_path (me) [0] != '\0')
+    name = hw_path (me);
+  else if (me != NULL && hw_name (me) != NULL && hw_name (me)[0] != '\0')
+    name = hw_name (me);
+  else if (me != NULL && hw_family (me) != NULL && hw_family (me)[0] != '\0')
+    name = hw_family (me);
+  else
+    name = "device";
+  /* report the problem */
+  sim_io_eprintf (sd, "%s: ", name);
+  sim_io_evprintf (sd, fmt, ap);
+  sim_io_error (sd, "%s", "");
+}
+
+\f
+/* The event queue abstraction (for devices) */
+
+
+struct _hw_event {
+  void *data;
+  struct hw *me;
+  hw_event_handler *handler;
+  sim_event *real;
+};
+
+/* Pass the H/W event onto the real handler */
+
+static void
+bounce_hw_event (SIM_DESC sd,
+                void *data)
+{
+  hw_event event = * (hw_event*) data;
+  zfree (data);
+  event.handler (event.me, event.data);
+}
+
+
+/* Map onto the event functions */
+
+hw_event *
+hw_event_queue_schedule (struct hw *me,
+                        signed64 delta_time,
+                        hw_event_handler *handler,
+                        void *data)
+{
+  hw_event *event = ZALLOC (hw_event);
+  event->data = data;
+  event->handler = handler;
+  event->me = me;
+  event->real = sim_events_schedule (hw_system (me),
+                                    delta_time,
+                                    bounce_hw_event,
+                                    event);
+  return event;
+}
+
+void
+hw_event_queue_deschedule (struct hw *me,
+                          hw_event *event_to_remove)
+{
+  sim_events_deschedule (hw_system (me),
+                        event_to_remove->real);
+  zfree (event_to_remove);
+}
+
+signed64
+hw_event_queue_time (struct hw *me)
+{
+  return sim_events_time (hw_system (me));
+}
+
+\f
+/* Mechanism for associating allocated memory regions to a device.
+   When a device is deleted any remaining memory regions are also
+   reclaimed.
+
+   FIXME: Perhaphs this can be generalized, perhaphs it should not
+   be. */
+
+struct hw_alloc_data {
+  void *alloc;
+  int zalloc_p;
+  struct hw_alloc_data *next;
+};
+
+extern void *
+hw_zalloc (struct hw *me, unsigned long size)
+{
+  struct hw_alloc_data *memory = ZALLOC (struct hw_alloc_data);
+  memory->alloc = zalloc (size);
+  memory->zalloc_p = 1;
+  memory->next = me->alloc_of_hw;
+  me->alloc_of_hw = memory;
+  return memory->alloc;
+}
+
+extern void *
+hw_malloc (struct hw *me, unsigned long size)
+{
+  struct hw_alloc_data *memory = ZALLOC (struct hw_alloc_data);
+  memory->alloc = zalloc (size);
+  memory->zalloc_p = 0;
+  memory->next = me->alloc_of_hw;
+  me->alloc_of_hw = memory;
+  return memory->alloc;
+}
+
+extern void
+hw_free (struct hw *me,
+        void *alloc)
+{
+  struct hw_alloc_data **memory;
+  for (memory = &me->alloc_of_hw;
+       *memory != NULL;
+       memory = &(*memory)->next)
+    {
+      if ((*memory)->alloc == alloc)
+       {
+         struct hw_alloc_data *die = (*memory);
+         (*memory) = die->next;
+         if (die->zalloc_p)
+           zfree (die->alloc);
+         else
+           free (die->alloc);
+         zfree (die);
+         return;
+       }
+    }
+  hw_abort (me, "free of memory not belonging to a device");
+}
+
+extern void
+hw_free_all (struct hw *me)
+{
+  while (me->alloc_of_hw != NULL)
+    {
+      hw_free (me, me->alloc_of_hw->alloc);
+    }
+}
index ecbedca..4abe207 100644 (file)
@@ -350,6 +350,25 @@ typedef int (hw_unit_size_to_attach_size_callback)
 
 
 \f
+/* Memory allocator / de-allocator.
+
+   All memory allocated using the below will be automatically
+   reclaimed when the device is deleted.
+
+   A device implementation can either use these functions when
+   allocating memory or use malloc/zalloc/free an co-ordinate its own
+   garbage collection. */
+
+#define HW_ZALLOC(me,type) (type*) hw_zalloc (me, sizeof (type))
+#define HW_MALLOC(me,type) (type*) hw_malloc (me, sizeof (type))
+
+extern void *hw_zalloc (struct hw *me, unsigned long size);
+extern void *hw_malloc (struct hw *me, unsigned long size);
+extern void hw_free (struct hw *me, void *);
+extern void hw_free_all (struct hw *me);
+
+
+\f
 /* Utilities:
 
    */
@@ -435,6 +454,7 @@ void volatile NORETURN hw_abort
 struct hw_property_data;
 struct hw_port_data;
 struct hw_base_data;
+struct hw_alloc_data;
 
 /* Finally the hardware device - keep your grubby little mits off of
    these internals! :-) */
@@ -489,6 +509,7 @@ struct hw {
   struct hw_property_data *properties_of_hw;
   struct hw_port_data *ports_of_hw;
   struct hw_base_data *base_of_hw;
+  struct hw_alloc_data *alloc_of_hw;
 
 };
 
diff --git a/sim/common/hw-properties.c b/sim/common/hw-properties.c
new file mode 100644 (file)
index 0000000..a42c0c9
--- /dev/null
@@ -0,0 +1,881 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+    */
+
+#include "sim-main.h"
+
+#include "hw-device.h"
+#include "hw-properties.h"
+
+#include "sim-assert.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+
+#define TRACE(A,B)
+
+/* property entries */
+
+struct hw_property_data {
+  struct hw_property_data *next;
+  struct hw_property *property;
+  const void *init_array;
+  unsigned sizeof_init_array;
+};
+
+/* Device Properties: */
+
+static struct hw_property_data *
+find_property_data (struct hw *me,
+                   const char *property)
+{
+  struct hw_property_data *entry;
+  ASSERT (property != NULL);
+  entry = me->properties_of_hw;
+  while (entry != NULL)
+    {
+      if (strcmp (entry->property->name, property) == 0)
+       return entry;
+      entry = entry->next;
+    }
+  return NULL;
+}
+
+
+static void
+hw_add_property (struct hw *me,
+                const char *property,
+                hw_property_type type,
+                const void *init_array,
+                unsigned sizeof_init_array,
+                const void *array,
+                unsigned sizeof_array,
+                const struct hw_property *original,
+                object_disposition disposition)
+{
+  struct hw_property_data *new_entry = NULL;
+  struct hw_property *new_value = NULL;
+  
+  /* find the list end */
+  struct hw_property_data **insertion_point = &me->properties_of_hw;
+  while (*insertion_point != NULL)
+    {
+      if (strcmp ((*insertion_point)->property->name, property) == 0)
+       return;
+      insertion_point = &(*insertion_point)->next;
+    }
+  
+  /* create a new value */
+  new_value = HW_ZALLOC (me, struct hw_property);
+  new_value->name = (char *) strdup (property);
+  new_value->type = type;
+  if (sizeof_array > 0)
+    {
+      void *new_array = hw_zalloc (me, 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;
+  
+  /* insert the value into the list */
+  new_entry = HW_ZALLOC (me, struct hw_property_data);
+  *insertion_point = new_entry;
+  if (sizeof_init_array > 0)
+    {
+      void *new_init_array = hw_zalloc (me, 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->property = new_value;
+}
+
+
+static void
+hw_set_property (struct hw *me,
+                const char *property,
+                hw_property_type type,
+                const void *array,
+                int sizeof_array)
+{
+  /* find the property */
+  struct hw_property_data *entry = find_property_data (me, property);
+  if (entry != NULL)
+    {
+      /* existing property - update it */
+      void *new_array = 0;
+      struct hw_property *value = entry->property;
+      /* check the type matches */
+      if (value->type != type)
+       hw_abort (me, "conflict between type of new and old value for property %s", property);
+      /* replace its value */
+      if (value->array != NULL)
+       hw_free (me, (void*)value->array);
+      new_array = (sizeof_array > 0
+                  ? hw_zalloc (me, 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 */
+      hw_add_property (me, property, type,
+                      NULL, 0, array, sizeof_array,
+                      NULL, temporary_object);
+    }
+}
+
+
+#if 0
+static void
+clean_hw_properties (struct hw *me)
+{
+  struct hw_property_data **delete_point = &me->properties_of_hw;
+  while (*delete_point != NULL)
+    {
+      struct hw_property_data *current = *delete_point;
+      switch (current->property->disposition)
+       {
+       case permenant_object:
+         /* zap the current value, will be initialized later */
+         ASSERT (current->init_array != NULL);
+         if (current->property->array != NULL)
+           {
+             hw_free (me, (void*)current->property->array);
+             current->property->array = NULL;
+           }
+         delete_point = &(*delete_point)->next;
+         break;
+       case temporary_object:
+         /* zap the actual property, was created during simulation run */
+         ASSERT (current->init_array == NULL);
+         *delete_point = current->next;
+         if (current->property->array != NULL)
+           hw_free (me, (void*)current->property->array);
+         hw_free (me, current->property);
+         hw_free (me, current);
+         break;
+       }
+    }
+}
+#endif
+
+#if 0
+void
+hw_init_static_properties (SIM_DESC sd,
+                          struct hw *me,
+                          void *data)
+{
+  struct hw_property_data *property;
+  for (property = me->properties_of_hw;
+       property != NULL;
+       property = property->next)
+    {
+      ASSERT (property->init_array != NULL);
+      ASSERT (property->property->array == NULL);
+      ASSERT(property->property->disposition == permenant_object);
+      switch (property->property->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 */
+         hw_set_property (me, property->property->name,
+                          property->property->type,
+                          property->init_array,
+                          property->sizeof_init_array);
+         break;
+#if 0
+       case ihandle_property:
+         break;
+#endif
+       }
+    }
+}
+#endif
+
+
+#if 0
+void
+hw_init_runtime_properties (SIM_DESC sd,
+                           struct hw *me,
+                           void *data)
+{
+  struct hw_property_data *property;
+  for (property = me->properties_of_hw;
+       property != NULL;
+       property = property->next)
+    {
+      switch (property->property->disposition)
+       {
+       case permenant_object:
+         switch (property->property->type)
+           {
+#if 0
+           case ihandle_property:
+             {
+               struct hw_instance *ihandle;
+               ihandle_runtime_property_spec spec;
+               ASSERT (property->init_array != NULL);
+               ASSERT (property->property->array == NULL);
+               hw_find_ihandle_runtime_property (me, property->property->name, &spec);
+               ihandle = tree_instance (me, spec.full_path);
+               hw_set_ihandle_property (me, property->property->name, ihandle);
+               break;
+             }
+#endif
+           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->property->array != NULL);
+             break;
+           }
+         break;
+       case temporary_object:
+         ASSERT (property->init_array == NULL);
+         ASSERT (property->property->array != NULL);
+         break;
+       }
+    }
+}
+#endif
+
+
+
+const struct hw_property *
+hw_next_property (const struct hw_property *property)
+{
+  /* find the property in the list */
+  struct hw *owner = property->owner;
+  struct hw_property_data *entry = owner->properties_of_hw;
+  while (entry != NULL && entry->property != property)
+    entry = entry->next;
+  /* now return the following property */
+  ASSERT (entry != NULL); /* must be a member! */
+  if (entry->next != NULL)
+    return entry->next->property;
+  else
+    return NULL;
+}
+
+
+const struct hw_property *
+hw_find_property (struct hw *me,
+                 const char *property)
+{
+  if (me == NULL)
+    {
+      return NULL;
+    }
+  else if (property == NULL || strcmp (property, "") == 0)
+    {
+      if (me->properties_of_hw == NULL)
+       return NULL;
+      else
+       return me->properties_of_hw->property;
+    }
+  else
+    {
+      struct hw_property_data *entry = find_property_data (me, property);
+      if (entry != NULL)
+       return entry->property;
+    }
+  return NULL;
+}
+
+
+void
+hw_add_array_property (struct hw *me,
+                      const char *property,
+                      const void *array,
+                      int sizeof_array)
+{
+  hw_add_property (me, property, array_property,
+                  array, sizeof_array, array, sizeof_array,
+                  NULL, permenant_object);
+}
+
+void
+hw_set_array_property (struct hw *me,
+                      const char *property,
+                      const void *array,
+                      int sizeof_array)
+{
+  hw_set_property (me, property, array_property, array, sizeof_array);
+}
+
+const struct hw_property *
+hw_find_array_property (struct hw *me,
+                       const char *property)
+{
+  const struct hw_property *node;
+  node = hw_find_property (me, property);
+  if (node == NULL
+      || node->type != array_property)
+    hw_abort(me, "property %s not found or of wrong type", property);
+  return node;
+}
+
+
+
+void
+hw_add_boolean_property (struct hw *me,
+                        const char *property,
+                        int boolean)
+{
+  signed32 new_boolean = (boolean ? -1 : 0);
+  hw_add_property (me, property, boolean_property,
+                  &new_boolean, sizeof(new_boolean),
+                  &new_boolean, sizeof(new_boolean),
+                  NULL, permenant_object);
+}
+
+int
+hw_find_boolean_property (struct hw *me,
+                         const char *property)
+{
+  const struct hw_property *node;
+  unsigned_cell boolean;
+  node = hw_find_property (me, property);
+  if (node == NULL || node->type != boolean_property)
+    hw_abort (me, "property %s not found or of wrong type", property);
+  ASSERT (sizeof (boolean) == node->sizeof_array);
+  memcpy (&boolean, node->array, sizeof (boolean));
+  return boolean;
+}
+
+
+
+#if 0
+void
+hw_add_ihandle_runtime_property (struct hw *me,
+                                const char *property,
+                                const ihandle_runtime_property_spec *ihandle)
+{
+  /* enter the full path as the init array */
+  hw_add_property (me, property, ihandle_property,
+                  ihandle->full_path, strlen(ihandle->full_path) + 1,
+                  NULL, 0,
+                  NULL, permenant_object);
+}
+#endif
+
+#if 0
+void
+hw_find_ihandle_runtime_property (struct hw *me,
+                                 const char *property,
+                                 ihandle_runtime_property_spec *ihandle)
+{
+  struct hw_property_data *entry = find_property_data (me, property);
+  TRACE (trace_devices,
+        ("hw_find_ihandle_runtime_property(me=0x%lx, property=%s)\n",
+         (long)me, property));
+  if (entry == NULL
+      || entry->property->type != ihandle_property
+      || entry->property->disposition != permenant_object)
+    hw_abort (me, "property %s not found or of wrong type", property);
+  ASSERT (entry->init_array != NULL);
+  /* the full path */
+  ihandle->full_path = entry->init_array;
+}
+#endif
+
+
+
+#if 0
+void
+hw_set_ihandle_property (struct hw *me,
+                        const char *property,
+                        hw_instance *ihandle)
+{
+  unsigned_cell cells;
+  cells = H2BE_cell (hw_instance_to_external (ihandle));
+  hw_set_property (me, property, ihandle_property,
+                  &cells, sizeof (cells));
+                     
+}
+#endif
+
+#if 0
+hw_instance *
+hw_find_ihandle_property (struct hw *me,
+                         const char *property)
+{
+  const hw_property_data *node;
+  unsigned_cell ihandle;
+  hw_instance *instance;
+
+  node = hw_find_property (me, property);
+  if (node == NULL || node->type != ihandle_property)
+    hw_abort(me, "property %s not found or of wrong type", property);
+  if (node->array == NULL)
+    hw_abort(me, "runtime property %s not yet initialized", property);
+
+  ASSERT (sizeof(ihandle) == node->sizeof_array);
+  memcpy (&ihandle, node->array, sizeof(ihandle));
+  instance = external_to_hw_instance (me, BE2H_cell(ihandle));
+  ASSERT (instance != NULL);
+  return instance;
+}
+#endif
+
+
+void
+hw_add_integer_property (struct hw *me,
+                        const char *property,
+                        signed_cell integer)
+{
+  H2BE (integer);
+  hw_add_property (me, property, integer_property,
+                  &integer, sizeof(integer),
+                  &integer, sizeof(integer),
+                  NULL, permenant_object);
+}
+
+signed_cell
+hw_find_integer_property (struct hw *me,
+                         const char *property)
+{
+  const struct hw_property *node;
+  signed_cell integer;
+  TRACE (trace_devices,
+        ("hw_find_integer(me=0x%lx, property=%s)\n",
+         (long)me, property));
+  node = hw_find_property (me, property);
+  if (node == NULL || node->type != integer_property)
+    hw_abort (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);
+}
+
+int
+hw_find_integer_array_property (struct hw *me,
+                               const char *property,
+                               unsigned index,
+                               signed_cell *integer)
+{
+  const struct hw_property *node;
+  int sizeof_integer = sizeof (*integer);
+  signed_cell *cell;
+  TRACE (trace_devices,
+        ("hw_find_integer(me=0x%lx, property=%s)\n",
+         (long)me, property));
+  
+  /* check things sane */
+  node = hw_find_property (me, property);
+  if (node == NULL
+      || (node->type != integer_property
+         && node->type != array_property))
+    hw_abort (me, "property %s not found or of wrong type", property);
+  if ((node->sizeof_array % sizeof_integer) != 0)
+    hw_abort (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 unsigned_cell *
+unit_address_to_cells (const hw_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 const unsigned_cell *
+cells_to_unit_address (const unsigned_cell *cell,
+                      hw_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 unsigned
+nr_range_property_cells (struct hw *me,
+                        int nr_ranges)
+{
+  return ((hw_unit_nr_address_cells (me)
+          + hw_unit_nr_address_cells (hw_parent (me))
+          + hw_unit_nr_size_cells (me))
+         ) * nr_ranges;
+}
+
+void
+hw_add_range_array_property (struct hw *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 = hw_zalloc (me, 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,
+                                   hw_unit_nr_address_cells (me));
+      /* copy the parent address */
+      cell = unit_address_to_cells (&range->parent_address, cell, 
+                                   hw_unit_nr_address_cells (hw_parent (me)));
+      /* copy the size */
+      cell = unit_address_to_cells (&range->size, cell, 
+                                   hw_unit_nr_size_cells (me));
+    }
+  ASSERT (cell == &cells[nr_range_property_cells (me, nr_ranges)]);
+  
+  /* add it */
+  hw_add_property (me, property, range_array_property,
+                  cells, sizeof_cells,
+                  cells, sizeof_cells,
+                  NULL, permenant_object);
+  
+  hw_free (me, cells);
+}
+
+int
+hw_find_range_array_property (struct hw *me,
+                             const char *property,
+                             unsigned index,
+                             range_property_spec *range)
+{
+  const struct hw_property *node;
+  unsigned sizeof_entry = (nr_range_property_cells (me, 1)
+                          * sizeof (unsigned_cell));
+  const unsigned_cell *cells;
+  
+  /* locate the property */
+  node = hw_find_property (me, property);
+  if (node == NULL || node->type != range_array_property)
+    hw_abort (me, "property %s not found or of wrong type", property);
+  
+  /* aligned ? */
+  if ((node->sizeof_array % sizeof_entry) != 0)
+    hw_abort (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,
+                                hw_unit_nr_address_cells (me));
+  
+  /* copy the parent address out - converting as we go */
+  cells = cells_to_unit_address (cells, &range->parent_address,
+                                hw_unit_nr_address_cells (hw_parent (me)));
+  
+  /* copy the size - converting as we go */
+  cells = cells_to_unit_address (cells, &range->size,
+                                hw_unit_nr_size_cells (me));
+  
+  return node->sizeof_array / sizeof_entry;
+}
+
+
+static unsigned
+nr_reg_property_cells (struct hw *me,
+                      int nr_regs)
+{
+  return (hw_unit_nr_address_cells (hw_parent(me))
+         + hw_unit_nr_size_cells (hw_parent(me))
+         ) * nr_regs;
+}
+
+void
+hw_add_reg_array_property (struct hw *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 = hw_zalloc (me, 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,
+                                   hw_unit_nr_address_cells (hw_parent (me)));
+      /* copy the size */
+      cell = unit_address_to_cells (&reg->size, cell,
+                                   hw_unit_nr_size_cells (hw_parent (me)));
+    }
+  ASSERT (cell == &cells[nr_reg_property_cells (me, nr_regs)]);
+  
+  /* add it */
+  hw_add_property (me, property, reg_array_property,
+                  cells, sizeof_cells,
+                  cells, sizeof_cells,
+                  NULL, permenant_object);
+  
+  hw_free (me, cells);
+}
+
+int
+hw_find_reg_array_property (struct hw *me,
+                           const char *property,
+                           unsigned index,
+                           reg_property_spec *reg)
+{
+  const struct hw_property *node;
+  unsigned sizeof_entry = (nr_reg_property_cells (me, 1)
+                          * sizeof (unsigned_cell));
+  const unsigned_cell *cells;
+  
+  /* locate the property */
+  node = hw_find_property (me, property);
+  if (node == NULL || node->type != reg_array_property)
+    hw_abort (me, "property %s not found or of wrong type", property);
+  
+  /* aligned ? */
+  if ((node->sizeof_array % sizeof_entry) != 0)
+    hw_abort (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,
+                                hw_unit_nr_address_cells (hw_parent (me)));
+  
+  /* copy the size out - converting as we go */
+  cells = cells_to_unit_address (cells, &reg->size,
+                                hw_unit_nr_size_cells (hw_parent (me)));
+  
+  return node->sizeof_array / sizeof_entry;
+}
+
+
+void
+hw_add_string_property (struct hw *me,
+                       const char *property,
+                       const char *string)
+{
+  hw_add_property (me, property, string_property,
+                  string, strlen(string) + 1,
+                  string, strlen(string) + 1,
+                  NULL, permenant_object);
+}
+
+const char *
+hw_find_string_property (struct hw *me,
+                        const char *property)
+{
+  const struct hw_property *node;
+  const char *string;
+  node = hw_find_property (me, property);
+  if (node == NULL || node->type != string_property)
+    hw_abort (me, "property %s not found or of wrong type", property);
+  string = node->array;
+  ASSERT (strlen(string) + 1 == node->sizeof_array);
+  return string;
+}
+
+void
+hw_add_string_array_property (struct hw *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)
+    hw_abort (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*) hw_zalloc (me, 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 */
+  hw_add_property (me, property, string_array_property,
+                  array, sizeof_array,
+                  array, sizeof_array,
+                  NULL, permenant_object);
+}
+
+int
+hw_find_string_array_property (struct hw *me,
+                              const char *property,
+                              unsigned index,
+                              string_property_spec *string)
+{
+  const struct hw_property *node;
+  node = hw_find_property (me, property);
+  if (node == NULL)
+    hw_abort (me, "property %s not found", property);
+  switch (node->type)
+    {
+    default:
+      hw_abort (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')
+       hw_abort (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;
+}
+
+void
+hw_add_duplicate_property (struct hw *me,
+                          const char *property,
+                          const struct hw_property *original)
+{
+  struct hw_property_data *master;
+  TRACE (trace_devices,
+        ("hw_add_duplicate_property(me=0x%lx, property=%s, ...)\n",
+         (long)me, property));
+  if (original->disposition != permenant_object)
+    hw_abort (me, "Can only duplicate permenant objects");
+  /* find the original's master */
+  master = original->owner->properties_of_hw;
+  while (master->property != original)
+    {
+      master = master->next;
+      ASSERT(master != NULL);
+    }
+  /* now duplicate it */
+  hw_add_property (me, property,
+                  original->type,
+                  master->init_array, master->sizeof_init_array,
+                  original->array, original->sizeof_array,
+                  original, permenant_object);
+}