1 /* The common simulator framework for GDB, the GNU Debugger.
2 
3    Copyright 2002-2013 Free Software Foundation, Inc.
4 
5    Contributed by Andrew Cagney and Red Hat.
6 
7    This file is part of GDB.
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21 
22 #include "hw-main.h"
23 #include "hw-base.h"
24 
25 #include "sim-io.h"
26 #include "sim-assert.h"
27 
28 #ifdef HAVE_STRING_H
29 #include <string.h>
30 #else
31 #ifdef HAVE_STRINGS_H
32 #include <strings.h>
33 #endif
34 #endif
35 
36 /* property entries */
37 
38 struct hw_property_data
39 {
40   struct hw_property_data *next;
41   struct hw_property *property;
42   const void *init_array;
43   unsigned sizeof_init_array;
44 };
45 
46 void
create_hw_property_data(struct hw * me)47 create_hw_property_data (struct hw *me)
48 {
49 }
50 
51 void
delete_hw_property_data(struct hw * me)52 delete_hw_property_data (struct hw *me)
53 {
54 }
55 
56 
57 /* Device Properties: */
58 
59 static struct hw_property_data *
find_property_data(struct hw * me,const char * property)60 find_property_data (struct hw *me,
61 		    const char *property)
62 {
63   struct hw_property_data *entry;
64   ASSERT (property != NULL);
65   entry = me->properties_of_hw;
66   while (entry != NULL)
67     {
68       if (strcmp (entry->property->name, property) == 0)
69 	return entry;
70       entry = entry->next;
71     }
72   return NULL;
73 }
74 
75 
76 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)77 hw_add_property (struct hw *me,
78 		 const char *property,
79 		 hw_property_type type,
80 		 const void *init_array,
81 		 unsigned sizeof_init_array,
82 		 const void *array,
83 		 unsigned sizeof_array,
84 		 const struct hw_property *original,
85 		 object_disposition disposition)
86 {
87   struct hw_property_data *new_entry = NULL;
88   struct hw_property *new_value = NULL;
89 
90   /* find the list end */
91   struct hw_property_data **insertion_point = &me->properties_of_hw;
92   while (*insertion_point != NULL)
93     {
94       if (strcmp ((*insertion_point)->property->name, property) == 0)
95 	return;
96       insertion_point = &(*insertion_point)->next;
97     }
98 
99   /* create a new value */
100   new_value = HW_ZALLOC (me, struct hw_property);
101   new_value->name = (char *) strdup (property);
102   new_value->type = type;
103   if (sizeof_array > 0)
104     {
105       void *new_array = hw_zalloc (me, sizeof_array);
106       memcpy (new_array, array, sizeof_array);
107       new_value->array = new_array;
108       new_value->sizeof_array = sizeof_array;
109     }
110   new_value->owner = me;
111   new_value->original = original;
112   new_value->disposition = disposition;
113 
114   /* insert the value into the list */
115   new_entry = HW_ZALLOC (me, struct hw_property_data);
116   *insertion_point = new_entry;
117   if (sizeof_init_array > 0)
118     {
119       void *new_init_array = hw_zalloc (me, sizeof_init_array);
120       memcpy (new_init_array, init_array, sizeof_init_array);
121       new_entry->init_array = new_init_array;
122       new_entry->sizeof_init_array = sizeof_init_array;
123     }
124   new_entry->property = new_value;
125 }
126 
127 
128 static void
hw_set_property(struct hw * me,const char * property,hw_property_type type,const void * array,int sizeof_array)129 hw_set_property (struct hw *me,
130 		 const char *property,
131 		 hw_property_type type,
132 		 const void *array,
133 		 int sizeof_array)
134 {
135   /* find the property */
136   struct hw_property_data *entry = find_property_data (me, property);
137   if (entry != NULL)
138     {
139       /* existing property - update it */
140       void *new_array = 0;
141       struct hw_property *value = entry->property;
142       /* check the type matches */
143       if (value->type != type)
144 	hw_abort (me, "conflict between type of new and old value for property %s", property);
145       /* replace its value */
146       if (value->array != NULL)
147 	hw_free (me, (void*)value->array);
148       new_array = (sizeof_array > 0
149 		   ? hw_zalloc (me, sizeof_array)
150 		   : (void*)0);
151       value->array = new_array;
152       value->sizeof_array = sizeof_array;
153       if (sizeof_array > 0)
154 	memcpy (new_array, array, sizeof_array);
155       return;
156     }
157   else
158     {
159       /* new property - create it */
160       hw_add_property (me, property, type,
161 		       NULL, 0, array, sizeof_array,
162 		       NULL, temporary_object);
163     }
164 }
165 
166 
167 #if 0
168 static void
169 clean_hw_properties (struct hw *me)
170 {
171   struct hw_property_data **delete_point = &me->properties_of_hw;
172   while (*delete_point != NULL)
173     {
174       struct hw_property_data *current = *delete_point;
175       switch (current->property->disposition)
176 	{
177 	case permenant_object:
178 	  /* zap the current value, will be initialized later */
179 	  ASSERT (current->init_array != NULL);
180 	  if (current->property->array != NULL)
181 	    {
182 	      hw_free (me, (void*)current->property->array);
183 	      current->property->array = NULL;
184 	    }
185 	  delete_point = &(*delete_point)->next;
186 	  break;
187 	case temporary_object:
188 	  /* zap the actual property, was created during simulation run */
189 	  ASSERT (current->init_array == NULL);
190 	  *delete_point = current->next;
191 	  if (current->property->array != NULL)
192 	    hw_free (me, (void*)current->property->array);
193 	  hw_free (me, current->property);
194 	  hw_free (me, current);
195 	  break;
196 	}
197     }
198 }
199 #endif
200 
201 #if 0
202 void
203 hw_init_static_properties (SIM_DESC sd,
204 			   struct hw *me,
205 			   void *data)
206 {
207   struct hw_property_data *property;
208   for (property = me->properties_of_hw;
209        property != NULL;
210        property = property->next)
211     {
212       ASSERT (property->init_array != NULL);
213       ASSERT (property->property->array == NULL);
214       ASSERT (property->property->disposition == permenant_object);
215       switch (property->property->type)
216 	{
217 	case array_property:
218 	case boolean_property:
219 	case range_array_property:
220 	case reg_array_property:
221 	case string_property:
222 	case string_array_property:
223 	case integer_property:
224 	  /* delete the property, and replace it with the original */
225 	  hw_set_property (me, property->property->name,
226 			   property->property->type,
227 			   property->init_array,
228 			   property->sizeof_init_array);
229 	  break;
230 #if 0
231 	case ihandle_property:
232 	  break;
233 #endif
234 	}
235     }
236 }
237 #endif
238 
239 
240 #if 0
241 void
242 hw_init_runtime_properties (SIM_DESC sd,
243 			    struct hw *me,
244 			    void *data)
245 {
246   struct hw_property_data *property;
247   for (property = me->properties_of_hw;
248        property != NULL;
249        property = property->next)
250     {
251       switch (property->property->disposition)
252 	{
253 	case permenant_object:
254 	  switch (property->property->type)
255 	    {
256 #if 0
257 	    case ihandle_property:
258 	      {
259 		struct hw_instance *ihandle;
260 		ihandle_runtime_property_spec spec;
261 		ASSERT (property->init_array != NULL);
262 		ASSERT (property->property->array == NULL);
263 		hw_find_ihandle_runtime_property (me, property->property->name, &spec);
264 		ihandle = tree_instance (me, spec.full_path);
265 		hw_set_ihandle_property (me, property->property->name, ihandle);
266 		break;
267 	      }
268 #endif
269 	    case array_property:
270 	    case boolean_property:
271 	    case range_array_property:
272 	    case integer_property:
273 	    case reg_array_property:
274 	    case string_property:
275 	    case string_array_property:
276 	      ASSERT (property->init_array != NULL);
277 	      ASSERT (property->property->array != NULL);
278 	      break;
279 	    }
280 	  break;
281 	case temporary_object:
282 	  ASSERT (property->init_array == NULL);
283 	  ASSERT (property->property->array != NULL);
284 	  break;
285 	}
286     }
287 }
288 #endif
289 
290 
291 
292 const struct hw_property *
hw_next_property(const struct hw_property * property)293 hw_next_property (const struct hw_property *property)
294 {
295   /* find the property in the list */
296   struct hw *owner = property->owner;
297   struct hw_property_data *entry = owner->properties_of_hw;
298   while (entry != NULL && entry->property != property)
299     entry = entry->next;
300   /* now return the following property */
301   ASSERT (entry != NULL); /* must be a member! */
302   if (entry->next != NULL)
303     return entry->next->property;
304   else
305     return NULL;
306 }
307 
308 
309 const struct hw_property *
hw_find_property(struct hw * me,const char * property)310 hw_find_property (struct hw *me,
311 		  const char *property)
312 {
313   if (me == NULL)
314     {
315       return NULL;
316     }
317   else if (property == NULL || strcmp (property, "") == 0)
318     {
319       if (me->properties_of_hw == NULL)
320 	return NULL;
321       else
322 	return me->properties_of_hw->property;
323     }
324   else
325     {
326       struct hw_property_data *entry = find_property_data (me, property);
327       if (entry != NULL)
328 	return entry->property;
329     }
330   return NULL;
331 }
332 
333 
334 void
hw_add_array_property(struct hw * me,const char * property,const void * array,int sizeof_array)335 hw_add_array_property (struct hw *me,
336 		       const char *property,
337 		       const void *array,
338 		       int sizeof_array)
339 {
340   hw_add_property (me, property, array_property,
341 		   array, sizeof_array, array, sizeof_array,
342 		   NULL, permenant_object);
343 }
344 
345 void
hw_set_array_property(struct hw * me,const char * property,const void * array,int sizeof_array)346 hw_set_array_property (struct hw *me,
347 		       const char *property,
348 		       const void *array,
349 		       int sizeof_array)
350 {
351   hw_set_property (me, property, array_property, array, sizeof_array);
352 }
353 
354 const struct hw_property *
hw_find_array_property(struct hw * me,const char * property)355 hw_find_array_property (struct hw *me,
356 			const char *property)
357 {
358   const struct hw_property *node;
359   node = hw_find_property (me, property);
360   if (node == NULL)
361     hw_abort (me, "property \"%s\" not found", property);
362   if (node->type != array_property)
363     hw_abort (me, "property \"%s\" of wrong type (array)", property);
364   return node;
365 }
366 
367 
368 
369 void
hw_add_boolean_property(struct hw * me,const char * property,int boolean)370 hw_add_boolean_property (struct hw *me,
371 			 const char *property,
372 			 int boolean)
373 {
374   signed32 new_boolean = (boolean ? -1 : 0);
375   hw_add_property (me, property, boolean_property,
376 		   &new_boolean, sizeof (new_boolean),
377 		   &new_boolean, sizeof (new_boolean),
378 		   NULL, permenant_object);
379 }
380 
381 int
hw_find_boolean_property(struct hw * me,const char * property)382 hw_find_boolean_property (struct hw *me,
383 			  const char *property)
384 {
385   const struct hw_property *node;
386   unsigned_cell boolean;
387   node = hw_find_property (me, property);
388   if (node == NULL)
389     hw_abort (me, "property \"%s\" not found", property);
390   if (node->type != boolean_property)
391     hw_abort (me, "property \"%s\" of wrong type (boolean)", property);
392   ASSERT (sizeof (boolean) == node->sizeof_array);
393   memcpy (&boolean, node->array, sizeof (boolean));
394   return boolean;
395 }
396 
397 
398 
399 #if 0
400 void
401 hw_add_ihandle_runtime_property (struct hw *me,
402 				 const char *property,
403 				 const ihandle_runtime_property_spec *ihandle)
404 {
405   /* enter the full path as the init array */
406   hw_add_property (me, property, ihandle_property,
407 		   ihandle->full_path, strlen (ihandle->full_path) + 1,
408 		   NULL, 0,
409 		   NULL, permenant_object);
410 }
411 #endif
412 
413 #if 0
414 void
415 hw_find_ihandle_runtime_property (struct hw *me,
416 				  const char *property,
417 				  ihandle_runtime_property_spec *ihandle)
418 {
419   struct hw_property_data *entry = find_property_data (me, property);
420   HW_TRACE ((me, "hw_find_ihandle_runtime_property(property=%s)\n", property));
421   if (entry == NULL)
422     hw_abort (me, "property \"%s\" not found", property);
423   if (entry->property->type != ihandle_property
424       || entry->property->disposition != permenant_object)
425     hw_abort (me, "property \"%s\" of wrong type", property);
426   ASSERT (entry->init_array != NULL);
427   /* the full path */
428   ihandle->full_path = entry->init_array;
429 }
430 #endif
431 
432 
433 
434 #if 0
435 void
436 hw_set_ihandle_property (struct hw *me,
437 			 const char *property,
438 			 hw_instance *ihandle)
439 {
440   unsigned_cell cells;
441   cells = H2BE_cell (hw_instance_to_external (ihandle));
442   hw_set_property (me, property, ihandle_property,
443 		   &cells, sizeof (cells));
444 
445 }
446 #endif
447 
448 #if 0
449 hw_instance *
450 hw_find_ihandle_property (struct hw *me,
451 			  const char *property)
452 {
453   const hw_property_data *node;
454   unsigned_cell ihandle;
455   hw_instance *instance;
456 
457   node = hw_find_property (me, property);
458   if (node == NULL)
459     hw_abort (me, "property \"%s\" not found", property);
460   if (node->type != ihandle_property)
461     hw_abort (me, "property \"%s\" of wrong type (ihandle)", property);
462   if (node->array == NULL)
463     hw_abort (me, "runtime property \"%s\" not yet initialized", property);
464 
465   ASSERT (sizeof (ihandle) == node->sizeof_array);
466   memcpy (&ihandle, node->array, sizeof (ihandle));
467   instance = external_to_hw_instance (me, BE2H_cell (ihandle));
468   ASSERT (instance != NULL);
469   return instance;
470 }
471 #endif
472 
473 
474 void
hw_add_integer_property(struct hw * me,const char * property,signed_cell integer)475 hw_add_integer_property (struct hw *me,
476 			 const char *property,
477 			 signed_cell integer)
478 {
479   H2BE (integer);
480   hw_add_property (me, property, integer_property,
481 		   &integer, sizeof (integer),
482 		   &integer, sizeof (integer),
483 		   NULL, permenant_object);
484 }
485 
486 signed_cell
hw_find_integer_property(struct hw * me,const char * property)487 hw_find_integer_property (struct hw *me,
488 			  const char *property)
489 {
490   const struct hw_property *node;
491   signed_cell integer;
492   HW_TRACE ((me, "hw_find_integer(property=%s)\n", property));
493   node = hw_find_property (me, property);
494   if (node == NULL)
495     hw_abort (me, "property \"%s\" not found", property);
496   if (node->type != integer_property)
497     hw_abort (me, "property \"%s\" of wrong type (integer)", property);
498   ASSERT (sizeof (integer) == node->sizeof_array);
499   memcpy (&integer, node->array, sizeof (integer));
500   return BE2H_cell (integer);
501 }
502 
503 int
hw_find_integer_array_property(struct hw * me,const char * property,unsigned index,signed_cell * integer)504 hw_find_integer_array_property (struct hw *me,
505 				const char *property,
506 				unsigned index,
507 				signed_cell *integer)
508 {
509   const struct hw_property *node;
510   int sizeof_integer = sizeof (*integer);
511   signed_cell *cell;
512   HW_TRACE ((me, "hw_find_integer(property=%s)\n", property));
513 
514   /* check things sane */
515   node = hw_find_property (me, property);
516   if (node == NULL)
517     hw_abort (me, "property \"%s\" not found", property);
518   if (node->type != integer_property
519       && node->type != array_property)
520     hw_abort (me, "property \"%s\" of wrong type (integer or array)", property);
521   if ((node->sizeof_array % sizeof_integer) != 0)
522     hw_abort (me, "property \"%s\" contains an incomplete number of cells", property);
523   if (node->sizeof_array <= sizeof_integer * index)
524     return 0;
525 
526   /* Find and convert the value */
527   cell = ((signed_cell*)node->array) + index;
528   *integer = BE2H_cell (*cell);
529 
530   return node->sizeof_array / sizeof_integer;
531 }
532 
533 
534 static unsigned_cell *
unit_address_to_cells(const hw_unit * unit,unsigned_cell * cell,int nr_cells)535 unit_address_to_cells (const hw_unit *unit,
536 		       unsigned_cell *cell,
537 		       int nr_cells)
538 {
539   int i;
540   ASSERT (nr_cells == unit->nr_cells);
541   for (i = 0; i < unit->nr_cells; i++)
542     {
543       *cell = H2BE_cell (unit->cells[i]);
544       cell += 1;
545     }
546   return cell;
547 }
548 
549 
550 static const unsigned_cell *
cells_to_unit_address(const unsigned_cell * cell,hw_unit * unit,int nr_cells)551 cells_to_unit_address (const unsigned_cell *cell,
552 		       hw_unit *unit,
553 		       int nr_cells)
554 {
555   int i;
556   memset (unit, 0, sizeof (*unit));
557   unit->nr_cells = nr_cells;
558   for (i = 0; i < unit->nr_cells; i++)
559     {
560       unit->cells[i] = BE2H_cell (*cell);
561       cell += 1;
562     }
563   return cell;
564 }
565 
566 
567 static unsigned
nr_range_property_cells(struct hw * me,int nr_ranges)568 nr_range_property_cells (struct hw *me,
569 			 int nr_ranges)
570 {
571   return ((hw_unit_nr_address_cells (me)
572 	   + hw_unit_nr_address_cells (hw_parent (me))
573 	   + hw_unit_nr_size_cells (me))
574 	  ) * nr_ranges;
575 }
576 
577 void
hw_add_range_array_property(struct hw * me,const char * property,const range_property_spec * ranges,unsigned nr_ranges)578 hw_add_range_array_property (struct hw *me,
579 			     const char *property,
580 			     const range_property_spec *ranges,
581 			     unsigned nr_ranges)
582 {
583   unsigned sizeof_cells = (nr_range_property_cells (me, nr_ranges)
584 			   * sizeof (unsigned_cell));
585   unsigned_cell *cells = hw_zalloc (me, sizeof_cells);
586   unsigned_cell *cell;
587   int i;
588 
589   /* 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 
615 int
hw_find_range_array_property(struct hw * me,const char * property,unsigned index,range_property_spec * range)616 hw_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 
661 static unsigned
nr_reg_property_cells(struct hw * me,int nr_regs)662 nr_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 
670 void
hw_add_reg_array_property(struct hw * me,const char * property,const reg_property_spec * regs,unsigned nr_regs)671 hw_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 
705 int
hw_find_reg_array_property(struct hw * me,const char * property,unsigned index,reg_property_spec * reg)706 hw_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 
747 void
hw_add_string_property(struct hw * me,const char * property,const char * string)748 hw_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 
758 const char *
hw_find_string_property(struct hw * me,const char * property)759 hw_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 
774 void
hw_add_string_array_property(struct hw * me,const char * property,const string_property_spec * strings,unsigned nr_strings)775 hw_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 
811 int
hw_find_string_array_property(struct hw * me,const char * property,unsigned index,string_property_spec * string)812 hw_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 
876 void
hw_add_duplicate_property(struct hw * me,const char * property,const struct hw_property * original)877 hw_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