1 /* This file is part of the program psim.
3 Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "sim-assert.h"
36 /* property entries */
38 struct hw_property_data
{
39 struct hw_property_data
*next
;
40 struct hw_property
*property
;
41 const void *init_array
;
42 unsigned sizeof_init_array
;
46 create_hw_property_data (struct hw
*me
)
51 delete_hw_property_data (struct hw
*me
)
56 /* Device Properties: */
58 static struct hw_property_data
*
59 find_property_data (struct hw
*me
,
62 struct hw_property_data
*entry
;
63 ASSERT (property
!= NULL
);
64 entry
= me
->properties_of_hw
;
67 if (strcmp (entry
->property
->name
, property
) == 0)
76 hw_add_property (struct hw
*me
,
78 hw_property_type type
,
79 const void *init_array
,
80 unsigned sizeof_init_array
,
82 unsigned sizeof_array
,
83 const struct hw_property
*original
,
84 object_disposition disposition
)
86 struct hw_property_data
*new_entry
= NULL
;
87 struct hw_property
*new_value
= NULL
;
89 /* find the list end */
90 struct hw_property_data
**insertion_point
= &me
->properties_of_hw
;
91 while (*insertion_point
!= NULL
)
93 if (strcmp ((*insertion_point
)->property
->name
, property
) == 0)
95 insertion_point
= &(*insertion_point
)->next
;
98 /* create a new value */
99 new_value
= HW_ZALLOC (me
, struct hw_property
);
100 new_value
->name
= (char *) strdup (property
);
101 new_value
->type
= type
;
102 if (sizeof_array
> 0)
104 void *new_array
= hw_zalloc (me
, sizeof_array
);
105 memcpy (new_array
, array
, sizeof_array
);
106 new_value
->array
= new_array
;
107 new_value
->sizeof_array
= sizeof_array
;
109 new_value
->owner
= me
;
110 new_value
->original
= original
;
111 new_value
->disposition
= disposition
;
113 /* insert the value into the list */
114 new_entry
= HW_ZALLOC (me
, struct hw_property_data
);
115 *insertion_point
= new_entry
;
116 if (sizeof_init_array
> 0)
118 void *new_init_array
= hw_zalloc (me
, sizeof_init_array
);
119 memcpy (new_init_array
, init_array
, sizeof_init_array
);
120 new_entry
->init_array
= new_init_array
;
121 new_entry
->sizeof_init_array
= sizeof_init_array
;
123 new_entry
->property
= new_value
;
128 hw_set_property (struct hw
*me
,
129 const char *property
,
130 hw_property_type type
,
134 /* find the property */
135 struct hw_property_data
*entry
= find_property_data (me
, property
);
138 /* existing property - update it */
140 struct hw_property
*value
= entry
->property
;
141 /* check the type matches */
142 if (value
->type
!= type
)
143 hw_abort (me
, "conflict between type of new and old value for property %s", property
);
144 /* replace its value */
145 if (value
->array
!= NULL
)
146 hw_free (me
, (void*)value
->array
);
147 new_array
= (sizeof_array
> 0
148 ? hw_zalloc (me
, sizeof_array
)
150 value
->array
= new_array
;
151 value
->sizeof_array
= sizeof_array
;
152 if (sizeof_array
> 0)
153 memcpy (new_array
, array
, sizeof_array
);
158 /* new property - create it */
159 hw_add_property (me
, property
, type
,
160 NULL
, 0, array
, sizeof_array
,
161 NULL
, temporary_object
);
168 clean_hw_properties (struct hw
*me
)
170 struct hw_property_data
**delete_point
= &me
->properties_of_hw
;
171 while (*delete_point
!= NULL
)
173 struct hw_property_data
*current
= *delete_point
;
174 switch (current
->property
->disposition
)
176 case permenant_object
:
177 /* zap the current value, will be initialized later */
178 ASSERT (current
->init_array
!= NULL
);
179 if (current
->property
->array
!= NULL
)
181 hw_free (me
, (void*)current
->property
->array
);
182 current
->property
->array
= NULL
;
184 delete_point
= &(*delete_point
)->next
;
186 case temporary_object
:
187 /* zap the actual property, was created during simulation run */
188 ASSERT (current
->init_array
== NULL
);
189 *delete_point
= current
->next
;
190 if (current
->property
->array
!= NULL
)
191 hw_free (me
, (void*)current
->property
->array
);
192 hw_free (me
, current
->property
);
193 hw_free (me
, current
);
202 hw_init_static_properties (SIM_DESC sd
,
206 struct hw_property_data
*property
;
207 for (property
= me
->properties_of_hw
;
209 property
= property
->next
)
211 ASSERT (property
->init_array
!= NULL
);
212 ASSERT (property
->property
->array
== NULL
);
213 ASSERT(property
->property
->disposition
== permenant_object
);
214 switch (property
->property
->type
)
217 case boolean_property
:
218 case range_array_property
:
219 case reg_array_property
:
220 case string_property
:
221 case string_array_property
:
222 case integer_property
:
223 /* delete the property, and replace it with the original */
224 hw_set_property (me
, property
->property
->name
,
225 property
->property
->type
,
226 property
->init_array
,
227 property
->sizeof_init_array
);
230 case ihandle_property
:
241 hw_init_runtime_properties (SIM_DESC sd
,
245 struct hw_property_data
*property
;
246 for (property
= me
->properties_of_hw
;
248 property
= property
->next
)
250 switch (property
->property
->disposition
)
252 case permenant_object
:
253 switch (property
->property
->type
)
256 case ihandle_property
:
258 struct hw_instance
*ihandle
;
259 ihandle_runtime_property_spec spec
;
260 ASSERT (property
->init_array
!= NULL
);
261 ASSERT (property
->property
->array
== NULL
);
262 hw_find_ihandle_runtime_property (me
, property
->property
->name
, &spec
);
263 ihandle
= tree_instance (me
, spec
.full_path
);
264 hw_set_ihandle_property (me
, property
->property
->name
, ihandle
);
269 case boolean_property
:
270 case range_array_property
:
271 case integer_property
:
272 case reg_array_property
:
273 case string_property
:
274 case string_array_property
:
275 ASSERT (property
->init_array
!= NULL
);
276 ASSERT (property
->property
->array
!= NULL
);
280 case temporary_object
:
281 ASSERT (property
->init_array
== NULL
);
282 ASSERT (property
->property
->array
!= NULL
);
291 const struct hw_property
*
292 hw_next_property (const struct hw_property
*property
)
294 /* find the property in the list */
295 struct hw
*owner
= property
->owner
;
296 struct hw_property_data
*entry
= owner
->properties_of_hw
;
297 while (entry
!= NULL
&& entry
->property
!= property
)
299 /* now return the following property */
300 ASSERT (entry
!= NULL
); /* must be a member! */
301 if (entry
->next
!= NULL
)
302 return entry
->next
->property
;
308 const struct hw_property
*
309 hw_find_property (struct hw
*me
,
310 const char *property
)
316 else if (property
== NULL
|| strcmp (property
, "") == 0)
318 if (me
->properties_of_hw
== NULL
)
321 return me
->properties_of_hw
->property
;
325 struct hw_property_data
*entry
= find_property_data (me
, property
);
327 return entry
->property
;
334 hw_add_array_property (struct hw
*me
,
335 const char *property
,
339 hw_add_property (me
, property
, array_property
,
340 array
, sizeof_array
, array
, sizeof_array
,
341 NULL
, permenant_object
);
345 hw_set_array_property (struct hw
*me
,
346 const char *property
,
350 hw_set_property (me
, property
, array_property
, array
, sizeof_array
);
353 const struct hw_property
*
354 hw_find_array_property (struct hw
*me
,
355 const char *property
)
357 const struct hw_property
*node
;
358 node
= hw_find_property (me
, property
);
360 hw_abort (me
, "property \"%s\" not found", property
);
361 if (node
->type
!= array_property
)
362 hw_abort (me
, "property \"%s\" of wrong type (array)", property
);
369 hw_add_boolean_property (struct hw
*me
,
370 const char *property
,
373 signed32 new_boolean
= (boolean
? -1 : 0);
374 hw_add_property (me
, property
, boolean_property
,
375 &new_boolean
, sizeof(new_boolean
),
376 &new_boolean
, sizeof(new_boolean
),
377 NULL
, permenant_object
);
381 hw_find_boolean_property (struct hw
*me
,
382 const char *property
)
384 const struct hw_property
*node
;
385 unsigned_cell boolean
;
386 node
= hw_find_property (me
, property
);
388 hw_abort (me
, "property \"%s\" not found", property
);
389 if (node
->type
!= boolean_property
)
390 hw_abort (me
, "property \"%s\" of wrong type (boolean)", property
);
391 ASSERT (sizeof (boolean
) == node
->sizeof_array
);
392 memcpy (&boolean
, node
->array
, sizeof (boolean
));
400 hw_add_ihandle_runtime_property (struct hw
*me
,
401 const char *property
,
402 const ihandle_runtime_property_spec
*ihandle
)
404 /* enter the full path as the init array */
405 hw_add_property (me
, property
, ihandle_property
,
406 ihandle
->full_path
, strlen(ihandle
->full_path
) + 1,
408 NULL
, permenant_object
);
414 hw_find_ihandle_runtime_property (struct hw
*me
,
415 const char *property
,
416 ihandle_runtime_property_spec
*ihandle
)
418 struct hw_property_data
*entry
= find_property_data (me
, property
);
419 TRACE (trace_devices
,
420 ("hw_find_ihandle_runtime_property(me=0x%lx, property=%s)\n",
421 (long)me
, property
));
423 hw_abort (me
, "property \"%s\" not found", property
);
424 if (entry
->property
->type
!= ihandle_property
425 || entry
->property
->disposition
!= permenant_object
)
426 hw_abort (me
, "property \"%s\" of wrong type", property
);
427 ASSERT (entry
->init_array
!= NULL
);
429 ihandle
->full_path
= entry
->init_array
;
437 hw_set_ihandle_property (struct hw
*me
,
438 const char *property
,
439 hw_instance
*ihandle
)
442 cells
= H2BE_cell (hw_instance_to_external (ihandle
));
443 hw_set_property (me
, property
, ihandle_property
,
444 &cells
, sizeof (cells
));
451 hw_find_ihandle_property (struct hw
*me
,
452 const char *property
)
454 const hw_property_data
*node
;
455 unsigned_cell ihandle
;
456 hw_instance
*instance
;
458 node
= hw_find_property (me
, property
);
460 hw_abort (me
, "property \"%s\" not found", property
);
461 if (node
->type
!= ihandle_property
)
462 hw_abort(me
, "property \"%s\" of wrong type (ihandle)", property
);
463 if (node
->array
== NULL
)
464 hw_abort(me
, "runtime property \"%s\" not yet initialized", property
);
466 ASSERT (sizeof(ihandle
) == node
->sizeof_array
);
467 memcpy (&ihandle
, node
->array
, sizeof(ihandle
));
468 instance
= external_to_hw_instance (me
, BE2H_cell(ihandle
));
469 ASSERT (instance
!= NULL
);
476 hw_add_integer_property (struct hw
*me
,
477 const char *property
,
481 hw_add_property (me
, property
, integer_property
,
482 &integer
, sizeof(integer
),
483 &integer
, sizeof(integer
),
484 NULL
, permenant_object
);
488 hw_find_integer_property (struct hw
*me
,
489 const char *property
)
491 const struct hw_property
*node
;
493 TRACE (trace_devices
,
494 ("hw_find_integer(me=0x%lx, property=%s)\n",
495 (long)me
, property
));
496 node
= hw_find_property (me
, property
);
498 hw_abort (me
, "property \"%s\" not found", property
);
499 if (node
->type
!= integer_property
)
500 hw_abort (me
, "property \"%s\" of wrong type (integer)", property
);
501 ASSERT (sizeof(integer
) == node
->sizeof_array
);
502 memcpy (&integer
, node
->array
, sizeof (integer
));
503 return BE2H_cell (integer
);
507 hw_find_integer_array_property (struct hw
*me
,
508 const char *property
,
510 signed_cell
*integer
)
512 const struct hw_property
*node
;
513 int sizeof_integer
= sizeof (*integer
);
515 TRACE (trace_devices
,
516 ("hw_find_integer(me=0x%lx, property=%s)\n",
517 (long)me
, property
));
519 /* check things sane */
520 node
= hw_find_property (me
, property
);
522 hw_abort (me
, "property \"%s\" not found", property
);
523 if (node
->type
!= integer_property
524 && node
->type
!= array_property
)
525 hw_abort (me
, "property \"%s\" of wrong type (integer or array)", property
);
526 if ((node
->sizeof_array
% sizeof_integer
) != 0)
527 hw_abort (me
, "property \"%s\" contains an incomplete number of cells", property
);
528 if (node
->sizeof_array
<= sizeof_integer
* index
)
531 /* Find and convert the value */
532 cell
= ((signed_cell
*)node
->array
) + index
;
533 *integer
= BE2H_cell (*cell
);
535 return node
->sizeof_array
/ sizeof_integer
;
539 static unsigned_cell
*
540 unit_address_to_cells (const hw_unit
*unit
,
545 ASSERT(nr_cells
== unit
->nr_cells
);
546 for (i
= 0; i
< unit
->nr_cells
; i
++)
548 *cell
= H2BE_cell (unit
->cells
[i
]);
555 static const unsigned_cell
*
556 cells_to_unit_address (const unsigned_cell
*cell
,
561 memset(unit
, 0, sizeof(*unit
));
562 unit
->nr_cells
= nr_cells
;
563 for (i
= 0; i
< unit
->nr_cells
; i
++)
565 unit
->cells
[i
] = BE2H_cell (*cell
);
573 nr_range_property_cells (struct hw
*me
,
576 return ((hw_unit_nr_address_cells (me
)
577 + hw_unit_nr_address_cells (hw_parent (me
))
578 + hw_unit_nr_size_cells (me
))
583 hw_add_range_array_property (struct hw
*me
,
584 const char *property
,
585 const range_property_spec
*ranges
,
588 unsigned sizeof_cells
= (nr_range_property_cells (me
, nr_ranges
)
589 * sizeof (unsigned_cell
));
590 unsigned_cell
*cells
= hw_zalloc (me
, sizeof_cells
);
594 /* copy the property elements over */
596 for (i
= 0; i
< nr_ranges
; i
++)
598 const range_property_spec
*range
= &ranges
[i
];
599 /* copy the child address */
600 cell
= unit_address_to_cells (&range
->child_address
, cell
,
601 hw_unit_nr_address_cells (me
));
602 /* copy the parent address */
603 cell
= unit_address_to_cells (&range
->parent_address
, cell
,
604 hw_unit_nr_address_cells (hw_parent (me
)));
606 cell
= unit_address_to_cells (&range
->size
, cell
,
607 hw_unit_nr_size_cells (me
));
609 ASSERT (cell
== &cells
[nr_range_property_cells (me
, nr_ranges
)]);
612 hw_add_property (me
, property
, range_array_property
,
615 NULL
, permenant_object
);
621 hw_find_range_array_property (struct hw
*me
,
622 const char *property
,
624 range_property_spec
*range
)
626 const struct hw_property
*node
;
627 unsigned sizeof_entry
= (nr_range_property_cells (me
, 1)
628 * sizeof (unsigned_cell
));
629 const unsigned_cell
*cells
;
631 /* locate the property */
632 node
= hw_find_property (me
, property
);
634 hw_abort (me
, "property \"%s\" not found", property
);
635 if (node
->type
!= range_array_property
)
636 hw_abort (me
, "property \"%s\" of wrong type (range array)", property
);
639 if ((node
->sizeof_array
% sizeof_entry
) != 0)
640 hw_abort (me
, "property \"%s\" contains an incomplete number of entries",
644 if (node
->sizeof_array
< sizeof_entry
* (index
+ 1))
647 /* find the range of interest */
648 cells
= (unsigned_cell
*)((char*)node
->array
+ sizeof_entry
* index
);
650 /* copy the child address out - converting as we go */
651 cells
= cells_to_unit_address (cells
, &range
->child_address
,
652 hw_unit_nr_address_cells (me
));
654 /* copy the parent address out - converting as we go */
655 cells
= cells_to_unit_address (cells
, &range
->parent_address
,
656 hw_unit_nr_address_cells (hw_parent (me
)));
658 /* copy the size - converting as we go */
659 cells
= cells_to_unit_address (cells
, &range
->size
,
660 hw_unit_nr_size_cells (me
));
662 return node
->sizeof_array
/ sizeof_entry
;
667 nr_reg_property_cells (struct hw
*me
,
670 return (hw_unit_nr_address_cells (hw_parent(me
))
671 + hw_unit_nr_size_cells (hw_parent(me
))
676 hw_add_reg_array_property (struct hw
*me
,
677 const char *property
,
678 const reg_property_spec
*regs
,
681 unsigned sizeof_cells
= (nr_reg_property_cells (me
, nr_regs
)
682 * sizeof (unsigned_cell
));
683 unsigned_cell
*cells
= hw_zalloc (me
, sizeof_cells
);
687 /* copy the property elements over */
689 for (i
= 0; i
< nr_regs
; i
++)
691 const reg_property_spec
*reg
= ®s
[i
];
692 /* copy the address */
693 cell
= unit_address_to_cells (®
->address
, cell
,
694 hw_unit_nr_address_cells (hw_parent (me
)));
696 cell
= unit_address_to_cells (®
->size
, cell
,
697 hw_unit_nr_size_cells (hw_parent (me
)));
699 ASSERT (cell
== &cells
[nr_reg_property_cells (me
, nr_regs
)]);
702 hw_add_property (me
, property
, reg_array_property
,
705 NULL
, permenant_object
);
711 hw_find_reg_array_property (struct hw
*me
,
712 const char *property
,
714 reg_property_spec
*reg
)
716 const struct hw_property
*node
;
717 unsigned sizeof_entry
= (nr_reg_property_cells (me
, 1)
718 * sizeof (unsigned_cell
));
719 const unsigned_cell
*cells
;
721 /* locate the property */
722 node
= hw_find_property (me
, property
);
724 hw_abort (me
, "property \"%s\" not found", property
);
725 if (node
->type
!= reg_array_property
)
726 hw_abort (me
, "property \"%s\" of wrong type (reg array)", property
);
729 if ((node
->sizeof_array
% sizeof_entry
) != 0)
730 hw_abort (me
, "property \"%s\" contains an incomplete number of entries",
734 if (node
->sizeof_array
< sizeof_entry
* (index
+ 1))
737 /* find the range of interest */
738 cells
= (unsigned_cell
*)((char*)node
->array
+ sizeof_entry
* index
);
740 /* copy the address out - converting as we go */
741 cells
= cells_to_unit_address (cells
, ®
->address
,
742 hw_unit_nr_address_cells (hw_parent (me
)));
744 /* copy the size out - converting as we go */
745 cells
= cells_to_unit_address (cells
, ®
->size
,
746 hw_unit_nr_size_cells (hw_parent (me
)));
748 return node
->sizeof_array
/ sizeof_entry
;
753 hw_add_string_property (struct hw
*me
,
754 const char *property
,
757 hw_add_property (me
, property
, string_property
,
758 string
, strlen(string
) + 1,
759 string
, strlen(string
) + 1,
760 NULL
, permenant_object
);
764 hw_find_string_property (struct hw
*me
,
765 const char *property
)
767 const struct hw_property
*node
;
769 node
= hw_find_property (me
, property
);
771 hw_abort (me
, "property \"%s\" not found", property
);
772 if (node
->type
!= string_property
)
773 hw_abort (me
, "property \"%s\" of wrong type (string)", property
);
774 string
= node
->array
;
775 ASSERT (strlen(string
) + 1 == node
->sizeof_array
);
780 hw_add_string_array_property (struct hw
*me
,
781 const char *property
,
782 const string_property_spec
*strings
,
790 hw_abort (me
, "property \"%s\" must be non-null", property
);
791 /* total up the size of the needed array */
792 for (sizeof_array
= 0, string_nr
= 0;
793 string_nr
< nr_strings
;
796 sizeof_array
+= strlen (strings
[string_nr
]) + 1;
798 /* create the array */
799 array
= (char*) hw_zalloc (me
, sizeof_array
);
802 string_nr
< nr_strings
;
805 strcpy (chp
, strings
[string_nr
]);
806 chp
+= strlen (chp
) + 1;
808 ASSERT (chp
== array
+ sizeof_array
);
810 hw_add_property (me
, property
, string_array_property
,
813 NULL
, permenant_object
);
817 hw_find_string_array_property (struct hw
*me
,
818 const char *property
,
820 string_property_spec
*string
)
822 const struct hw_property
*node
;
823 node
= hw_find_property (me
, property
);
825 hw_abort (me
, "property \"%s\" not found", property
);
829 hw_abort (me
, "property \"%s\" of wrong type", property
);
831 case string_property
:
834 *string
= node
->array
;
835 ASSERT (strlen(*string
) + 1 == node
->sizeof_array
);
840 if (node
->sizeof_array
== 0
841 || ((char*)node
->array
)[node
->sizeof_array
- 1] != '\0')
842 hw_abort (me
, "property \"%s\" invalid for string array", property
);
844 case string_array_property
:
845 ASSERT (node
->sizeof_array
> 0);
846 ASSERT (((char*)node
->array
)[node
->sizeof_array
- 1] == '\0');
848 const char *chp
= node
->array
;
850 /* count the number of strings, keeping an eye out for the one
860 if (nr_entries
== index
)
867 } while (chp
< (char*)node
->array
+ node
->sizeof_array
);
868 if (index
< nr_entries
)
882 hw_add_duplicate_property (struct hw
*me
,
883 const char *property
,
884 const struct hw_property
*original
)
886 struct hw_property_data
*master
;
887 TRACE (trace_devices
,
888 ("hw_add_duplicate_property(me=0x%lx, property=%s, ...)\n",
889 (long)me
, property
));
890 if (original
->disposition
!= permenant_object
)
891 hw_abort (me
, "Can only duplicate permenant objects");
892 /* find the original's master */
893 master
= original
->owner
->properties_of_hw
;
894 while (master
->property
!= original
)
896 master
= master
->next
;
897 ASSERT(master
!= NULL
);
899 /* now duplicate it */
900 hw_add_property (me
, property
,
902 master
->init_array
, master
->sizeof_init_array
,
903 original
->array
, original
->sizeof_array
,
904 original
, permenant_object
);