1193323Sed/* The common simulator framework for GDB, the GNU Debugger.
2193323Sed
3193323Sed   Copyright 2002, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
4193323Sed
5193323Sed   Contributed by Andrew Cagney and Red Hat.
6193323Sed
7193323Sed   This file is part of GDB.
8193323Sed
9193323Sed   This program is free software; you can redistribute it and/or modify
10193323Sed   it under the terms of the GNU General Public License as published by
11193323Sed   the Free Software Foundation; either version 3 of the License, or
12193323Sed   (at your option) any later version.
13193323Sed
14193323Sed   This program is distributed in the hope that it will be useful,
15193323Sed   but WITHOUT ANY WARRANTY; without even the implied warranty of
16193323Sed   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17239462Sdim   GNU General Public License for more details.
18234353Sdim
19193323Sed   You should have received a copy of the GNU General Public License
20193323Sed   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21193323Sed
22193323Sed#include "hw-main.h"
23218893Sdim#include "hw-base.h"
24193323Sed
25193323Sed#include "sim-io.h"
26193323Sed#include "sim-assert.h"
27193323Sed
28193323Sed#ifdef HAVE_STRING_H
29193323Sed#include <string.h>
30193323Sed#else
31193323Sed#ifdef HAVE_STRINGS_H
32193323Sed#include <strings.h>
33193323Sed#endif
34193323Sed#endif
35193323Sed
36193323Sed/* property entries */
37193323Sed
38193323Sedstruct hw_property_data
39193323Sed{
40193323Sed  struct hw_property_data *next;
41193323Sed  struct hw_property *property;
42193323Sed  const void *init_array;
43193323Sed  unsigned sizeof_init_array;
44193323Sed};
45193323Sed
46193323Sedvoid
47193323Sedcreate_hw_property_data (struct hw *me)
48193323Sed{
49193323Sed}
50193323Sed
51193323Sedvoid
52193323Seddelete_hw_property_data (struct hw *me)
53193323Sed{
54207618Srdivacky}
55207618Srdivacky
56207618Srdivacky
57207618Srdivacky/* Device Properties: */
58207618Srdivacky
59193323Sedstatic struct hw_property_data *
60193323Sedfind_property_data (struct hw *me,
61193323Sed		    const char *property)
62193323Sed{
63193323Sed  struct hw_property_data *entry;
64193323Sed  ASSERT (property != NULL);
65193323Sed  entry = me->properties_of_hw;
66193323Sed  while (entry != NULL)
67193323Sed    {
68193323Sed      if (strcmp (entry->property->name, property) == 0)
69193323Sed	return entry;
70193323Sed      entry = entry->next;
71193323Sed    }
72193323Sed  return NULL;
73193323Sed}
74193323Sed
75193323Sed
76193323Sedstatic void
77193323Sedhw_add_property (struct hw *me,
78193323Sed		 const char *property,
79193323Sed		 hw_property_type type,
80193323Sed		 const void *init_array,
81193323Sed		 unsigned sizeof_init_array,
82218893Sdim		 const void *array,
83193323Sed		 unsigned sizeof_array,
84193323Sed		 const struct hw_property *original,
85193323Sed		 object_disposition disposition)
86193323Sed{
87193323Sed  struct hw_property_data *new_entry = NULL;
88193323Sed  struct hw_property *new_value = NULL;
89193323Sed
90193323Sed  /* find the list end */
91193323Sed  struct hw_property_data **insertion_point = &me->properties_of_hw;
92193323Sed  while (*insertion_point != NULL)
93193323Sed    {
94193323Sed      if (strcmp ((*insertion_point)->property->name, property) == 0)
95193323Sed	return;
96193323Sed      insertion_point = &(*insertion_point)->next;
97218893Sdim    }
98218893Sdim
99193323Sed  /* create a new value */
100193323Sed  new_value = HW_ZALLOC (me, struct hw_property);
101249423Sdim  new_value->name = (char *) strdup (property);
102239462Sdim  new_value->type = type;
103239462Sdim  if (sizeof_array > 0)
104239462Sdim    {
105239462Sdim      void *new_array = hw_zalloc (me, sizeof_array);
106239462Sdim      memcpy (new_array, array, sizeof_array);
107239462Sdim      new_value->array = new_array;
108193323Sed      new_value->sizeof_array = sizeof_array;
109218893Sdim    }
110193323Sed  new_value->owner = me;
111193323Sed  new_value->original = original;
112202375Srdivacky  new_value->disposition = disposition;
113202375Srdivacky
114202375Srdivacky  /* insert the value into the list */
115193323Sed  new_entry = HW_ZALLOC (me, struct hw_property_data);
116193323Sed  *insertion_point = new_entry;
117193323Sed  if (sizeof_init_array > 0)
118193323Sed    {
119193323Sed      void *new_init_array = hw_zalloc (me, sizeof_init_array);
120193323Sed      memcpy (new_init_array, init_array, sizeof_init_array);
121193323Sed      new_entry->init_array = new_init_array;
122193323Sed      new_entry->sizeof_init_array = sizeof_init_array;
123193323Sed    }
124193323Sed  new_entry->property = new_value;
125193323Sed}
126193323Sed
127234353Sdim
128193323Sedstatic void
129193323Sedhw_set_property (struct hw *me,
130193323Sed		 const char *property,
131193323Sed		 hw_property_type type,
132193323Sed		 const void *array,
133193323Sed		 int sizeof_array)
134193323Sed{
135193323Sed  /* find the property */
136193323Sed  struct hw_property_data *entry = find_property_data (me, property);
137193323Sed  if (entry != NULL)
138193323Sed    {
139218893Sdim      /* existing property - update it */
140218893Sdim      void *new_array = 0;
141218893Sdim      struct hw_property *value = entry->property;
142218893Sdim      /* check the type matches */
143218893Sdim      if (value->type != type)
144218893Sdim	hw_abort (me, "conflict between type of new and old value for property %s", property);
145193323Sed      /* replace its value */
146193323Sed      if (value->array != NULL)
147193323Sed	hw_free (me, (void*)value->array);
148193323Sed      new_array = (sizeof_array > 0
149193323Sed		   ? hw_zalloc (me, sizeof_array)
150193323Sed		   : (void*)0);
151193323Sed      value->array = new_array;
152193323Sed      value->sizeof_array = sizeof_array;
153193323Sed      if (sizeof_array > 0)
154193323Sed	memcpy (new_array, array, sizeof_array);
155193323Sed      return;
156193323Sed    }
157234353Sdim  else
158193323Sed    {
159234353Sdim      /* new property - create it */
160193323Sed      hw_add_property (me, property, type,
161193323Sed		       NULL, 0, array, sizeof_array,
162193323Sed		       NULL, temporary_object);
163193323Sed    }
164193323Sed}
165193323Sed
166193323Sed
167193323Sed#if 0
168193323Sedstatic void
169193323Sedclean_hw_properties (struct hw *me)
170193323Sed{
171193323Sed  struct hw_property_data **delete_point = &me->properties_of_hw;
172193323Sed  while (*delete_point != NULL)
173193323Sed    {
174193323Sed      struct hw_property_data *current = *delete_point;
175243830Sdim      switch (current->property->disposition)
176193323Sed	{
177193323Sed	case permenant_object:
178193323Sed	  /* zap the current value, will be initialized later */
179193323Sed	  ASSERT (current->init_array != NULL);
180234353Sdim	  if (current->property->array != NULL)
181193323Sed	    {
182234353Sdim	      hw_free (me, (void*)current->property->array);
183193323Sed	      current->property->array = NULL;
184193323Sed	    }
185193323Sed	  delete_point = &(*delete_point)->next;
186193323Sed	  break;
187193323Sed	case temporary_object:
188193323Sed	  /* zap the actual property, was created during simulation run */
189193323Sed	  ASSERT (current->init_array == NULL);
190234353Sdim	  *delete_point = current->next;
191193323Sed	  if (current->property->array != NULL)
192234353Sdim	    hw_free (me, (void*)current->property->array);
193193323Sed	  hw_free (me, current->property);
194193323Sed	  hw_free (me, current);
195193323Sed	  break;
196193323Sed	}
197193323Sed    }
198193323Sed}
199193323Sed#endif
200193323Sed
201193323Sed#if 0
202193323Sedvoid
203193323Sedhw_init_static_properties (SIM_DESC sd,
204193323Sed			   struct hw *me,
205193323Sed			   void *data)
206193323Sed{
207193323Sed  struct hw_property_data *property;
208193323Sed  for (property = me->properties_of_hw;
209193323Sed       property != NULL;
210193323Sed       property = property->next)
211193323Sed    {
212193323Sed      ASSERT (property->init_array != NULL);
213193323Sed      ASSERT (property->property->array == NULL);
214193323Sed      ASSERT(property->property->disposition == permenant_object);
215193323Sed      switch (property->property->type)
216193323Sed	{
217193323Sed	case array_property:
218193323Sed	case boolean_property:
219193323Sed	case range_array_property:
220193323Sed	case reg_array_property:
221193323Sed	case string_property:
222193323Sed	case string_array_property:
223193323Sed	case integer_property:
224193323Sed	  /* delete the property, and replace it with the original */
225193323Sed	  hw_set_property (me, property->property->name,
226193323Sed			   property->property->type,
227193323Sed			   property->init_array,
228193323Sed			   property->sizeof_init_array);
229193323Sed	  break;
230193323Sed#if 0
231193323Sed	case ihandle_property:
232193323Sed	  break;
233193323Sed#endif
234193323Sed	}
235193323Sed    }
236193323Sed}
237193323Sed#endif
238193323Sed
239193323Sed
240243830Sdim#if 0
241243830Sdimvoid
242243830Sdimhw_init_runtime_properties (SIM_DESC sd,
243243830Sdim			    struct hw *me,
244243830Sdim			    void *data)
245243830Sdim{
246243830Sdim  struct hw_property_data *property;
247243830Sdim  for (property = me->properties_of_hw;
248243830Sdim       property != NULL;
249243830Sdim       property = property->next)
250243830Sdim    {
251243830Sdim      switch (property->property->disposition)
252243830Sdim	{
253243830Sdim	case permenant_object:
254243830Sdim	  switch (property->property->type)
255243830Sdim	    {
256243830Sdim#if 0
257243830Sdim	    case ihandle_property:
258243830Sdim	      {
259243830Sdim		struct hw_instance *ihandle;
260243830Sdim		ihandle_runtime_property_spec spec;
261243830Sdim		ASSERT (property->init_array != NULL);
262243830Sdim		ASSERT (property->property->array == NULL);
263243830Sdim		hw_find_ihandle_runtime_property (me, property->property->name, &spec);
264243830Sdim		ihandle = tree_instance (me, spec.full_path);
265243830Sdim		hw_set_ihandle_property (me, property->property->name, ihandle);
266243830Sdim		break;
267243830Sdim	      }
268193323Sed#endif
269193323Sed	    case array_property:
270193323Sed	    case boolean_property:
271193323Sed	    case range_array_property:
272193323Sed	    case integer_property:
273193323Sed	    case reg_array_property:
274193323Sed	    case string_property:
275193323Sed	    case string_array_property:
276193323Sed	      ASSERT (property->init_array != NULL);
277193323Sed	      ASSERT (property->property->array != NULL);
278243830Sdim	      break;
279243830Sdim	    }
280243830Sdim	  break;
281243830Sdim	case temporary_object:
282243830Sdim	  ASSERT (property->init_array == NULL);
283243830Sdim	  ASSERT (property->property->array != NULL);
284243830Sdim	  break;
285243830Sdim	}
286243830Sdim    }
287243830Sdim}
288243830Sdim#endif
289243830Sdim
290243830Sdim
291243830Sdim
292243830Sdimconst struct hw_property *
293243830Sdimhw_next_property (const struct hw_property *property)
294243830Sdim{
295243830Sdim  /* find the property in the list */
296243830Sdim  struct hw *owner = property->owner;
297243830Sdim  struct hw_property_data *entry = owner->properties_of_hw;
298243830Sdim  while (entry != NULL && entry->property != property)
299243830Sdim    entry = entry->next;
300243830Sdim  /* now return the following property */
301243830Sdim  ASSERT (entry != NULL); /* must be a member! */
302243830Sdim  if (entry->next != NULL)
303243830Sdim    return entry->next->property;
304243830Sdim  else
305243830Sdim    return NULL;
306193323Sed}
307193323Sed
308193323Sed
309193323Sedconst struct hw_property *
310193323Sedhw_find_property (struct hw *me,
311193323Sed		  const char *property)
312193323Sed{
313193323Sed  if (me == NULL)
314193323Sed    {
315193323Sed      return NULL;
316193323Sed    }
317193323Sed  else if (property == NULL || strcmp (property, "") == 0)
318193323Sed    {
319193323Sed      if (me->properties_of_hw == NULL)
320193323Sed	return NULL;
321193323Sed      else
322193323Sed	return me->properties_of_hw->property;
323193323Sed    }
324193323Sed  else
325193323Sed    {
326193323Sed      struct hw_property_data *entry = find_property_data (me, property);
327193323Sed      if (entry != NULL)
328193323Sed	return entry->property;
329193323Sed    }
330193323Sed  return NULL;
331193323Sed}
332193323Sed
333193323Sed
334239462Sdimvoid
335239462Sdimhw_add_array_property (struct hw *me,
336239462Sdim		       const char *property,
337239462Sdim		       const void *array,
338239462Sdim		       int sizeof_array)
339239462Sdim{
340239462Sdim  hw_add_property (me, property, array_property,
341239462Sdim		   array, sizeof_array, array, sizeof_array,
342239462Sdim		   NULL, permenant_object);
343239462Sdim}
344193323Sed
345193323Sedvoid
346193323Sedhw_set_array_property (struct hw *me,
347193323Sed		       const char *property,
348193323Sed		       const void *array,
349193323Sed		       int sizeof_array)
350193323Sed{
351193323Sed  hw_set_property (me, property, array_property, array, sizeof_array);
352193323Sed}
353193323Sed
354193323Sedconst struct hw_property *
355193323Sedhw_find_array_property (struct hw *me,
356193323Sed			const char *property)
357193323Sed{
358193323Sed  const struct hw_property *node;
359193323Sed  node = hw_find_property (me, property);
360193323Sed  if (node == NULL)
361193323Sed    hw_abort (me, "property \"%s\" not found", property);
362193323Sed  if (node->type != array_property)
363193323Sed    hw_abort (me, "property \"%s\" of wrong type (array)", property);
364193323Sed  return node;
365193323Sed}
366193323Sed
367193323Sed
368193323Sed
369193323Sedvoid
370243830Sdimhw_add_boolean_property (struct hw *me,
371193323Sed			 const char *property,
372193323Sed			 int boolean)
373193323Sed{
374193323Sed  signed32 new_boolean = (boolean ? -1 : 0);
375193323Sed  hw_add_property (me, property, boolean_property,
376193323Sed		   &new_boolean, sizeof(new_boolean),
377193323Sed		   &new_boolean, sizeof(new_boolean),
378193323Sed		   NULL, permenant_object);
379193323Sed}
380193323Sed
381193323Sedint
382193323Sedhw_find_boolean_property (struct hw *me,
383193323Sed			  const char *property)
384193323Sed{
385193323Sed  const struct hw_property *node;
386193323Sed  unsigned_cell boolean;
387243830Sdim  node = hw_find_property (me, property);
388234353Sdim  if (node == NULL)
389234353Sdim    hw_abort (me, "property \"%s\" not found", property);
390234353Sdim  if (node->type != boolean_property)
391234353Sdim    hw_abort (me, "property \"%s\" of wrong type (boolean)", property);
392234353Sdim  ASSERT (sizeof (boolean) == node->sizeof_array);
393234353Sdim  memcpy (&boolean, node->array, sizeof (boolean));
394234353Sdim  return boolean;
395234353Sdim}
396234353Sdim
397243830Sdim
398243830Sdim
399243830Sdim#if 0
400243830Sdimvoid
401243830Sdimhw_add_ihandle_runtime_property (struct hw *me,
402243830Sdim				 const char *property,
403243830Sdim				 const ihandle_runtime_property_spec *ihandle)
404243830Sdim{
405243830Sdim  /* enter the full path as the init array */
406243830Sdim  hw_add_property (me, property, ihandle_property,
407243830Sdim		   ihandle->full_path, strlen(ihandle->full_path) + 1,
408243830Sdim		   NULL, 0,
409243830Sdim		   NULL, permenant_object);
410243830Sdim}
411243830Sdim#endif
412243830Sdim
413243830Sdim#if 0
414193323Sedvoid
415203954Srdivackyhw_find_ihandle_runtime_property (struct hw *me,
416203954Srdivacky				  const char *property,
417203954Srdivacky				  ihandle_runtime_property_spec *ihandle)
418193323Sed{
419193323Sed  struct hw_property_data *entry = find_property_data (me, property);
420193323Sed  HW_TRACE ((me, "hw_find_ihandle_runtime_property(property=%s)\n", property));
421193323Sed  if (entry == NULL)
422193323Sed    hw_abort (me, "property \"%s\" not found", property);
423203954Srdivacky  if (entry->property->type != ihandle_property
424203954Srdivacky      || entry->property->disposition != permenant_object)
425203954Srdivacky    hw_abort (me, "property \"%s\" of wrong type", property);
426193323Sed  ASSERT (entry->init_array != NULL);
427193323Sed  /* the full path */
428193323Sed  ihandle->full_path = entry->init_array;
429193323Sed}
430193323Sed#endif
431193323Sed
432193323Sed
433193323Sed
434193323Sed#if 0
435193323Sedvoid
436193323Sedhw_set_ihandle_property (struct hw *me,
437205407Srdivacky			 const char *property,
438218893Sdim			 hw_instance *ihandle)
439193323Sed{
440193323Sed  unsigned_cell cells;
441193323Sed  cells = H2BE_cell (hw_instance_to_external (ihandle));
442193323Sed  hw_set_property (me, property, ihandle_property,
443193323Sed		   &cells, sizeof (cells));
444193323Sed
445218893Sdim}
446218893Sdim#endif
447193323Sed
448193323Sed#if 0
449218893Sdimhw_instance *
450193323Sedhw_find_ihandle_property (struct hw *me,
451193323Sed			  const char *property)
452193323Sed{
453193323Sed  const hw_property_data *node;
454193323Sed  unsigned_cell ihandle;
455249423Sdim  hw_instance *instance;
456239462Sdim
457239462Sdim  node = hw_find_property (me, property);
458239462Sdim  if (node == NULL)
459239462Sdim    hw_abort (me, "property \"%s\" not found", property);
460239462Sdim  if (node->type != ihandle_property)
461239462Sdim    hw_abort(me, "property \"%s\" of wrong type (ihandle)", property);
462239462Sdim  if (node->array == NULL)
463239462Sdim    hw_abort(me, "runtime property \"%s\" not yet initialized", property);
464239462Sdim
465239462Sdim  ASSERT (sizeof(ihandle) == node->sizeof_array);
466239462Sdim  memcpy (&ihandle, node->array, sizeof(ihandle));
467239462Sdim  instance = external_to_hw_instance (me, BE2H_cell(ihandle));
468239462Sdim  ASSERT (instance != NULL);
469239462Sdim  return instance;
470202375Srdivacky}
471202375Srdivacky#endif
472202375Srdivacky
473202375Srdivacky
474202375Srdivackyvoid
475202375Srdivackyhw_add_integer_property (struct hw *me,
476234353Sdim			 const char *property,
477234353Sdim			 signed_cell integer)
478234353Sdim{
479234353Sdim  H2BE (integer);
480234353Sdim  hw_add_property (me, property, integer_property,
481234353Sdim		   &integer, sizeof(integer),
482234353Sdim		   &integer, sizeof(integer),
483234353Sdim		   NULL, permenant_object);
484234353Sdim}
485234353Sdim
486234353Sdimsigned_cell
487234353Sdimhw_find_integer_property (struct hw *me,
488234353Sdim			  const char *property)
489234353Sdim{
490234353Sdim  const struct hw_property *node;
491234353Sdim  signed_cell integer;
492234353Sdim  HW_TRACE ((me, "hw_find_integer(property=%s)\n", property));
493234353Sdim  node = hw_find_property (me, property);
494234353Sdim  if (node == NULL)
495234353Sdim    hw_abort (me, "property \"%s\" not found", property);
496234353Sdim  if (node->type != integer_property)
497234353Sdim    hw_abort (me, "property \"%s\" of wrong type (integer)", property);
498234353Sdim  ASSERT (sizeof(integer) == node->sizeof_array);
499234353Sdim  memcpy (&integer, node->array, sizeof (integer));
500234353Sdim  return BE2H_cell (integer);
501234353Sdim}
502234353Sdim
503234353Sdimint
504234353Sdimhw_find_integer_array_property (struct hw *me,
505234353Sdim				const char *property,
506234353Sdim				unsigned index,
507234353Sdim				signed_cell *integer)
508234353Sdim{
509234353Sdim  const struct hw_property *node;
510234353Sdim  int sizeof_integer = sizeof (*integer);
511234353Sdim  signed_cell *cell;
512193323Sed  HW_TRACE ((me, "hw_find_integer(property=%s)\n", property));
513193323Sed
514193323Sed  /* check things sane */
515193323Sed  node = hw_find_property (me, property);
516193323Sed  if (node == NULL)
517193323Sed    hw_abort (me, "property \"%s\" not found", property);
518193323Sed  if (node->type != integer_property
519193323Sed      && node->type != array_property)
520193323Sed    hw_abort (me, "property \"%s\" of wrong type (integer or array)", property);
521193323Sed  if ((node->sizeof_array % sizeof_integer) != 0)
522193323Sed    hw_abort (me, "property \"%s\" contains an incomplete number of cells", property);
523193323Sed  if (node->sizeof_array <= sizeof_integer * index)
524193323Sed    return 0;
525193323Sed
526193323Sed  /* Find and convert the value */
527243830Sdim  cell = ((signed_cell*)node->array) + index;
528243830Sdim  *integer = BE2H_cell (*cell);
529243830Sdim
530243830Sdim  return node->sizeof_array / sizeof_integer;
531243830Sdim}
532193323Sed
533193323Sed
534193323Sedstatic unsigned_cell *
535193323Sedunit_address_to_cells (const hw_unit *unit,
536193323Sed		       unsigned_cell *cell,
537193323Sed		       int nr_cells)
538193323Sed{
539193323Sed  int i;
540193323Sed  ASSERT(nr_cells == unit->nr_cells);
541218893Sdim  for (i = 0; i < unit->nr_cells; i++)
542218893Sdim    {
543193323Sed      *cell = H2BE_cell (unit->cells[i]);
544193323Sed      cell += 1;
545193323Sed    }
546193323Sed  return cell;
547193323Sed}
548193323Sed
549193323Sed
550234353Sdimstatic const unsigned_cell *
551234353Sdimcells_to_unit_address (const unsigned_cell *cell,
552234353Sdim		       hw_unit *unit,
553234353Sdim		       int nr_cells)
554234353Sdim{
555234353Sdim  int i;
556234353Sdim  memset(unit, 0, sizeof(*unit));
557234353Sdim  unit->nr_cells = nr_cells;
558234353Sdim  for (i = 0; i < unit->nr_cells; i++)
559234353Sdim    {
560234353Sdim      unit->cells[i] = BE2H_cell (*cell);
561234353Sdim      cell += 1;
562234353Sdim    }
563234353Sdim  return cell;
564234353Sdim}
565234353Sdim
566234353Sdim
567234353Sdimstatic unsigned
568234353Sdimnr_range_property_cells (struct hw *me,
569234353Sdim			 int nr_ranges)
570234353Sdim{
571234353Sdim  return ((hw_unit_nr_address_cells (me)
572234353Sdim	   + hw_unit_nr_address_cells (hw_parent (me))
573234353Sdim	   + hw_unit_nr_size_cells (me))
574234353Sdim	  ) * nr_ranges;
575234353Sdim}
576234353Sdim
577193323Sedvoid
578193323Sedhw_add_range_array_property (struct hw *me,
579193323Sed			     const char *property,
580202375Srdivacky			     const range_property_spec *ranges,
581202375Srdivacky			     unsigned nr_ranges)
582202375Srdivacky{
583202375Srdivacky  unsigned sizeof_cells = (nr_range_property_cells (me, nr_ranges)
584202375Srdivacky			   * sizeof (unsigned_cell));
585202375Srdivacky  unsigned_cell *cells = hw_zalloc (me, sizeof_cells);
586202375Srdivacky  unsigned_cell *cell;
587202375Srdivacky  int i;
588202375Srdivacky
589193323Sed  /* copy the property elements over */
590  cell = cells;
591  for (i = 0; i < nr_ranges; i++)
592    {
593      const range_property_spec *range = &ranges[i];
594      /* copy the child address */
595      cell = unit_address_to_cells (&range->child_address, cell,
596				    hw_unit_nr_address_cells (me));
597      /* copy the parent address */
598      cell = unit_address_to_cells (&range->parent_address, cell,
599				    hw_unit_nr_address_cells (hw_parent (me)));
600      /* copy the size */
601      cell = unit_address_to_cells (&range->size, cell,
602				    hw_unit_nr_size_cells (me));
603    }
604  ASSERT (cell == &cells[nr_range_property_cells (me, nr_ranges)]);
605
606  /* add it */
607  hw_add_property (me, property, range_array_property,
608		   cells, sizeof_cells,
609		   cells, sizeof_cells,
610		   NULL, permenant_object);
611
612  hw_free (me, cells);
613}
614
615int
616hw_find_range_array_property (struct hw *me,
617			      const char *property,
618			      unsigned index,
619			      range_property_spec *range)
620{
621  const struct hw_property *node;
622  unsigned sizeof_entry = (nr_range_property_cells (me, 1)
623			   * sizeof (unsigned_cell));
624  const unsigned_cell *cells;
625
626  /* locate the property */
627  node = hw_find_property (me, property);
628  if (node == NULL)
629    hw_abort (me, "property \"%s\" not found", property);
630  if (node->type != range_array_property)
631    hw_abort (me, "property \"%s\" of wrong type (range array)", property);
632
633  /* aligned ? */
634  if ((node->sizeof_array % sizeof_entry) != 0)
635    hw_abort (me, "property \"%s\" contains an incomplete number of entries",
636	      property);
637
638  /* within bounds? */
639  if (node->sizeof_array < sizeof_entry * (index + 1))
640    return 0;
641
642  /* find the range of interest */
643  cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
644
645  /* copy the child address out - converting as we go */
646  cells = cells_to_unit_address (cells, &range->child_address,
647				 hw_unit_nr_address_cells (me));
648
649  /* copy the parent address out - converting as we go */
650  cells = cells_to_unit_address (cells, &range->parent_address,
651				 hw_unit_nr_address_cells (hw_parent (me)));
652
653  /* copy the size - converting as we go */
654  cells = cells_to_unit_address (cells, &range->size,
655				 hw_unit_nr_size_cells (me));
656
657  return node->sizeof_array / sizeof_entry;
658}
659
660
661static unsigned
662nr_reg_property_cells (struct hw *me,
663		       int nr_regs)
664{
665  return (hw_unit_nr_address_cells (hw_parent(me))
666	  + hw_unit_nr_size_cells (hw_parent(me))
667	  ) * nr_regs;
668}
669
670void
671hw_add_reg_array_property (struct hw *me,
672			   const char *property,
673			   const reg_property_spec *regs,
674			   unsigned nr_regs)
675{
676  unsigned sizeof_cells = (nr_reg_property_cells (me, nr_regs)
677			   * sizeof (unsigned_cell));
678  unsigned_cell *cells = hw_zalloc (me, sizeof_cells);
679  unsigned_cell *cell;
680  int i;
681
682  /* copy the property elements over */
683  cell = cells;
684  for (i = 0; i < nr_regs; i++)
685    {
686      const reg_property_spec *reg = &regs[i];
687      /* copy the address */
688      cell = unit_address_to_cells (&reg->address, cell,
689				    hw_unit_nr_address_cells (hw_parent (me)));
690      /* copy the size */
691      cell = unit_address_to_cells (&reg->size, cell,
692				    hw_unit_nr_size_cells (hw_parent (me)));
693    }
694  ASSERT (cell == &cells[nr_reg_property_cells (me, nr_regs)]);
695
696  /* add it */
697  hw_add_property (me, property, reg_array_property,
698		   cells, sizeof_cells,
699		   cells, sizeof_cells,
700		   NULL, permenant_object);
701
702  hw_free (me, cells);
703}
704
705int
706hw_find_reg_array_property (struct hw *me,
707			    const char *property,
708			    unsigned index,
709			    reg_property_spec *reg)
710{
711  const struct hw_property *node;
712  unsigned sizeof_entry = (nr_reg_property_cells (me, 1)
713			   * sizeof (unsigned_cell));
714  const unsigned_cell *cells;
715
716  /* locate the property */
717  node = hw_find_property (me, property);
718  if (node == NULL)
719    hw_abort (me, "property \"%s\" not found", property);
720  if (node->type != reg_array_property)
721    hw_abort (me, "property \"%s\" of wrong type (reg array)", property);
722
723  /* aligned ? */
724  if ((node->sizeof_array % sizeof_entry) != 0)
725    hw_abort (me, "property \"%s\" contains an incomplete number of entries",
726	      property);
727
728  /* within bounds? */
729  if (node->sizeof_array < sizeof_entry * (index + 1))
730    return 0;
731
732  /* find the range of interest */
733  cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
734
735  /* copy the address out - converting as we go */
736  cells = cells_to_unit_address (cells, &reg->address,
737				 hw_unit_nr_address_cells (hw_parent (me)));
738
739  /* copy the size out - converting as we go */
740  cells = cells_to_unit_address (cells, &reg->size,
741				 hw_unit_nr_size_cells (hw_parent (me)));
742
743  return node->sizeof_array / sizeof_entry;
744}
745
746
747void
748hw_add_string_property (struct hw *me,
749			const char *property,
750			const char *string)
751{
752  hw_add_property (me, property, string_property,
753		   string, strlen(string) + 1,
754		   string, strlen(string) + 1,
755		   NULL, permenant_object);
756}
757
758const char *
759hw_find_string_property (struct hw *me,
760			 const char *property)
761{
762  const struct hw_property *node;
763  const char *string;
764  node = hw_find_property (me, property);
765  if (node == NULL)
766    hw_abort (me, "property \"%s\" not found", property);
767  if (node->type != string_property)
768    hw_abort (me, "property \"%s\" of wrong type (string)", property);
769  string = node->array;
770  ASSERT (strlen(string) + 1 == node->sizeof_array);
771  return string;
772}
773
774void
775hw_add_string_array_property (struct hw *me,
776			      const char *property,
777			      const string_property_spec *strings,
778			      unsigned nr_strings)
779{
780  int sizeof_array;
781  int string_nr;
782  char *array;
783  char *chp;
784  if (nr_strings == 0)
785    hw_abort (me, "property \"%s\" must be non-null", property);
786  /* total up the size of the needed array */
787  for (sizeof_array = 0, string_nr = 0;
788       string_nr < nr_strings;
789       string_nr ++)
790    {
791      sizeof_array += strlen (strings[string_nr]) + 1;
792    }
793  /* create the array */
794  array = (char*) hw_zalloc (me, sizeof_array);
795  chp = array;
796  for (string_nr = 0;
797       string_nr < nr_strings;
798       string_nr++)
799    {
800      strcpy (chp, strings[string_nr]);
801      chp += strlen (chp) + 1;
802    }
803  ASSERT (chp == array + sizeof_array);
804  /* now enter it */
805  hw_add_property (me, property, string_array_property,
806		   array, sizeof_array,
807		   array, sizeof_array,
808		   NULL, permenant_object);
809}
810
811int
812hw_find_string_array_property (struct hw *me,
813			       const char *property,
814			       unsigned index,
815			       string_property_spec *string)
816{
817  const struct hw_property *node;
818  node = hw_find_property (me, property);
819  if (node == NULL)
820    hw_abort (me, "property \"%s\" not found", property);
821  switch (node->type)
822    {
823    default:
824      hw_abort (me, "property \"%s\" of wrong type", property);
825      break;
826    case string_property:
827      if (index == 0)
828	{
829	  *string = node->array;
830	  ASSERT (strlen(*string) + 1 == node->sizeof_array);
831	  return 1;
832	}
833      break;
834    case array_property:
835      if (node->sizeof_array == 0
836	  || ((char*)node->array)[node->sizeof_array - 1] != '\0')
837	hw_abort (me, "property \"%s\" invalid for string array", property);
838      /* FALL THROUGH */
839    case string_array_property:
840      ASSERT (node->sizeof_array > 0);
841      ASSERT (((char*)node->array)[node->sizeof_array - 1] == '\0');
842      {
843	const char *chp = node->array;
844	int nr_entries = 0;
845	/* count the number of strings, keeping an eye out for the one
846	   we're looking for */
847	*string = chp;
848	do
849	  {
850	    if (*chp == '\0')
851	      {
852		/* next string */
853		nr_entries++;
854		chp++;
855		if (nr_entries == index)
856		  *string = chp;
857	      }
858	    else
859	      {
860		chp++;
861	      }
862	  } while (chp < (char*)node->array + node->sizeof_array);
863	if (index < nr_entries)
864	  return nr_entries;
865	else
866	  {
867	    *string = NULL;
868	    return 0;
869	  }
870      }
871      break;
872    }
873  return 0;
874}
875
876void
877hw_add_duplicate_property (struct hw *me,
878			   const char *property,
879			   const struct hw_property *original)
880{
881  struct hw_property_data *master;
882  HW_TRACE ((me, "hw_add_duplicate_property(property=%s, ...)\n", property));
883  if (original->disposition != permenant_object)
884    hw_abort (me, "Can only duplicate permenant objects");
885  /* find the original's master */
886  master = original->owner->properties_of_hw;
887  while (master->property != original)
888    {
889      master = master->next;
890      ASSERT(master != NULL);
891    }
892  /* now duplicate it */
893  hw_add_property (me, property,
894		   original->type,
895		   master->init_array, master->sizeof_init_array,
896		   original->array, original->sizeof_array,
897		   original, permenant_object);
898}
899