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.
25 #include "sim-assert.h"
37 /* property entries */
39 struct hw_property_data
{
40 struct hw_property_data
*next
;
41 struct hw_property
*property
;
42 const void *init_array
;
43 unsigned sizeof_init_array
;
47 create_hw_property_data (struct hw
*me
)
52 delete_hw_property_data (struct hw
*me
)
57 /* Device Properties: */
59 static struct hw_property_data
*
60 find_property_data (struct hw
*me
,
63 struct hw_property_data
*entry
;
64 ASSERT (property
!= NULL
);
65 entry
= me
->properties_of_hw
;
68 if (strcmp (entry
->property
->name
, property
) == 0)
77 hw_add_property (struct hw
*me
,
79 hw_property_type type
,
80 const void *init_array
,
81 unsigned sizeof_init_array
,
83 unsigned sizeof_array
,
84 const struct hw_property
*original
,
85 object_disposition disposition
)
87 struct hw_property_data
*new_entry
= NULL
;
88 struct hw_property
*new_value
= NULL
;
90 /* find the list end */
91 struct hw_property_data
**insertion_point
= &me
->properties_of_hw
;
92 while (*insertion_point
!= NULL
)
94 if (strcmp ((*insertion_point
)->property
->name
, property
) == 0)
96 insertion_point
= &(*insertion_point
)->next
;
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)
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
;
110 new_value
->owner
= me
;
111 new_value
->original
= original
;
112 new_value
->disposition
= disposition
;
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)
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
;
124 new_entry
->property
= new_value
;
129 hw_set_property (struct hw
*me
,
130 const char *property
,
131 hw_property_type type
,
135 /* find the property */
136 struct hw_property_data
*entry
= find_property_data (me
, property
);
139 /* existing property - update it */
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
)
151 value
->array
= new_array
;
152 value
->sizeof_array
= sizeof_array
;
153 if (sizeof_array
> 0)
154 memcpy (new_array
, array
, sizeof_array
);
159 /* new property - create it */
160 hw_add_property (me
, property
, type
,
161 NULL
, 0, array
, sizeof_array
,
162 NULL
, temporary_object
);
169 clean_hw_properties (struct hw
*me
)
171 struct hw_property_data
**delete_point
= &me
->properties_of_hw
;
172 while (*delete_point
!= NULL
)
174 struct hw_property_data
*current
= *delete_point
;
175 switch (current
->property
->disposition
)
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
)
182 hw_free (me
, (void*)current
->property
->array
);
183 current
->property
->array
= NULL
;
185 delete_point
= &(*delete_point
)->next
;
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
);
203 hw_init_static_properties (SIM_DESC sd
,
207 struct hw_property_data
*property
;
208 for (property
= me
->properties_of_hw
;
210 property
= property
->next
)
212 ASSERT (property
->init_array
!= NULL
);
213 ASSERT (property
->property
->array
== NULL
);
214 ASSERT(property
->property
->disposition
== permenant_object
);
215 switch (property
->property
->type
)
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
);
231 case ihandle_property
:
242 hw_init_runtime_properties (SIM_DESC sd
,
246 struct hw_property_data
*property
;
247 for (property
= me
->properties_of_hw
;
249 property
= property
->next
)
251 switch (property
->property
->disposition
)
253 case permenant_object
:
254 switch (property
->property
->type
)
257 case ihandle_property
:
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
);
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
);
281 case temporary_object
:
282 ASSERT (property
->init_array
== NULL
);
283 ASSERT (property
->property
->array
!= NULL
);
292 const struct hw_property
*
293 hw_next_property (const struct hw_property
*property
)
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
)
300 /* now return the following property */
301 ASSERT (entry
!= NULL
); /* must be a member! */
302 if (entry
->next
!= NULL
)
303 return entry
->next
->property
;
309 const struct hw_property
*
310 hw_find_property (struct hw
*me
,
311 const char *property
)
317 else if (property
== NULL
|| strcmp (property
, "") == 0)
319 if (me
->properties_of_hw
== NULL
)
322 return me
->properties_of_hw
->property
;
326 struct hw_property_data
*entry
= find_property_data (me
, property
);
328 return entry
->property
;
335 hw_add_array_property (struct hw
*me
,
336 const char *property
,
340 hw_add_property (me
, property
, array_property
,
341 array
, sizeof_array
, array
, sizeof_array
,
342 NULL
, permenant_object
);
346 hw_set_array_property (struct hw
*me
,
347 const char *property
,
351 hw_set_property (me
, property
, array_property
, array
, sizeof_array
);
354 const struct hw_property
*
355 hw_find_array_property (struct hw
*me
,
356 const char *property
)
358 const struct hw_property
*node
;
359 node
= hw_find_property (me
, property
);
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
);
370 hw_add_boolean_property (struct hw
*me
,
371 const char *property
,
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
);
382 hw_find_boolean_property (struct hw
*me
,
383 const char *property
)
385 const struct hw_property
*node
;
386 unsigned_cell boolean
;
387 node
= hw_find_property (me
, property
);
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
));
401 hw_add_ihandle_runtime_property (struct hw
*me
,
402 const char *property
,
403 const ihandle_runtime_property_spec
*ihandle
)
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,
409 NULL
, permenant_object
);
415 hw_find_ihandle_runtime_property (struct hw
*me
,
416 const char *property
,
417 ihandle_runtime_property_spec
*ihandle
)
419 struct hw_property_data
*entry
= find_property_data (me
, property
);
420 TRACE (trace_devices
,
421 ("hw_find_ihandle_runtime_property(me=0x%lx, property=%s)\n",
422 (long)me
, property
));
424 hw_abort (me
, "property \"%s\" not found", property
);
425 if (entry
->property
->type
!= ihandle_property
426 || entry
->property
->disposition
!= permenant_object
)
427 hw_abort (me
, "property \"%s\" of wrong type", property
);
428 ASSERT (entry
->init_array
!= NULL
);
430 ihandle
->full_path
= entry
->init_array
;
438 hw_set_ihandle_property (struct hw
*me
,
439 const char *property
,
440 hw_instance
*ihandle
)
443 cells
= H2BE_cell (hw_instance_to_external (ihandle
));
444 hw_set_property (me
, property
, ihandle_property
,
445 &cells
, sizeof (cells
));
452 hw_find_ihandle_property (struct hw
*me
,
453 const char *property
)
455 const hw_property_data
*node
;
456 unsigned_cell ihandle
;
457 hw_instance
*instance
;
459 node
= hw_find_property (me
, property
);
461 hw_abort (me
, "property \"%s\" not found", property
);
462 if (node
->type
!= ihandle_property
)
463 hw_abort(me
, "property \"%s\" of wrong type (ihandle)", property
);
464 if (node
->array
== NULL
)
465 hw_abort(me
, "runtime property \"%s\" not yet initialized", property
);
467 ASSERT (sizeof(ihandle
) == node
->sizeof_array
);
468 memcpy (&ihandle
, node
->array
, sizeof(ihandle
));
469 instance
= external_to_hw_instance (me
, BE2H_cell(ihandle
));
470 ASSERT (instance
!= NULL
);
477 hw_add_integer_property (struct hw
*me
,
478 const char *property
,
482 hw_add_property (me
, property
, integer_property
,
483 &integer
, sizeof(integer
),
484 &integer
, sizeof(integer
),
485 NULL
, permenant_object
);
489 hw_find_integer_property (struct hw
*me
,
490 const char *property
)
492 const struct hw_property
*node
;
494 TRACE (trace_devices
,
495 ("hw_find_integer(me=0x%lx, property=%s)\n",
496 (long)me
, property
));
497 node
= hw_find_property (me
, property
);
499 hw_abort (me
, "property \"%s\" not found", property
);
500 if (node
->type
!= integer_property
)
501 hw_abort (me
, "property \"%s\" of wrong type (integer)", property
);
502 ASSERT (sizeof(integer
) == node
->sizeof_array
);
503 memcpy (&integer
, node
->array
, sizeof (integer
));
504 return BE2H_cell (integer
);
508 hw_find_integer_array_property (struct hw
*me
,
509 const char *property
,
511 signed_cell
*integer
)
513 const struct hw_property
*node
;
514 int sizeof_integer
= sizeof (*integer
);
516 TRACE (trace_devices
,
517 ("hw_find_integer(me=0x%lx, property=%s)\n",
518 (long)me
, property
));
520 /* check things sane */
521 node
= hw_find_property (me
, property
);
523 hw_abort (me
, "property \"%s\" not found", property
);
524 if (node
->type
!= integer_property
525 && node
->type
!= array_property
)
526 hw_abort (me
, "property \"%s\" of wrong type (integer or array)", property
);
527 if ((node
->sizeof_array
% sizeof_integer
) != 0)
528 hw_abort (me
, "property \"%s\" contains an incomplete number of cells", property
);
529 if (node
->sizeof_array
<= sizeof_integer
* index
)
532 /* Find and convert the value */
533 cell
= ((signed_cell
*)node
->array
) + index
;
534 *integer
= BE2H_cell (*cell
);
536 return node
->sizeof_array
/ sizeof_integer
;
540 static unsigned_cell
*
541 unit_address_to_cells (const hw_unit
*unit
,
546 ASSERT(nr_cells
== unit
->nr_cells
);
547 for (i
= 0; i
< unit
->nr_cells
; i
++)
549 *cell
= H2BE_cell (unit
->cells
[i
]);
556 static const unsigned_cell
*
557 cells_to_unit_address (const unsigned_cell
*cell
,
562 memset(unit
, 0, sizeof(*unit
));
563 unit
->nr_cells
= nr_cells
;
564 for (i
= 0; i
< unit
->nr_cells
; i
++)
566 unit
->cells
[i
] = BE2H_cell (*cell
);
574 nr_range_property_cells (struct hw
*me
,
577 return ((hw_unit_nr_address_cells (me
)
578 + hw_unit_nr_address_cells (hw_parent (me
))
579 + hw_unit_nr_size_cells (me
))
584 hw_add_range_array_property (struct hw
*me
,
585 const char *property
,
586 const range_property_spec
*ranges
,
589 unsigned sizeof_cells
= (nr_range_property_cells (me
, nr_ranges
)
590 * sizeof (unsigned_cell
));
591 unsigned_cell
*cells
= hw_zalloc (me
, sizeof_cells
);
595 /* copy the property elements over */
597 for (i
= 0; i
< nr_ranges
; i
++)
599 const range_property_spec
*range
= &ranges
[i
];
600 /* copy the child address */
601 cell
= unit_address_to_cells (&range
->child_address
, cell
,
602 hw_unit_nr_address_cells (me
));
603 /* copy the parent address */
604 cell
= unit_address_to_cells (&range
->parent_address
, cell
,
605 hw_unit_nr_address_cells (hw_parent (me
)));
607 cell
= unit_address_to_cells (&range
->size
, cell
,
608 hw_unit_nr_size_cells (me
));
610 ASSERT (cell
== &cells
[nr_range_property_cells (me
, nr_ranges
)]);
613 hw_add_property (me
, property
, range_array_property
,
616 NULL
, permenant_object
);
622 hw_find_range_array_property (struct hw
*me
,
623 const char *property
,
625 range_property_spec
*range
)
627 const struct hw_property
*node
;
628 unsigned sizeof_entry
= (nr_range_property_cells (me
, 1)
629 * sizeof (unsigned_cell
));
630 const unsigned_cell
*cells
;
632 /* locate the property */
633 node
= hw_find_property (me
, property
);
635 hw_abort (me
, "property \"%s\" not found", property
);
636 if (node
->type
!= range_array_property
)
637 hw_abort (me
, "property \"%s\" of wrong type (range array)", property
);
640 if ((node
->sizeof_array
% sizeof_entry
) != 0)
641 hw_abort (me
, "property \"%s\" contains an incomplete number of entries",
645 if (node
->sizeof_array
< sizeof_entry
* (index
+ 1))
648 /* find the range of interest */
649 cells
= (unsigned_cell
*)((char*)node
->array
+ sizeof_entry
* index
);
651 /* copy the child address out - converting as we go */
652 cells
= cells_to_unit_address (cells
, &range
->child_address
,
653 hw_unit_nr_address_cells (me
));
655 /* copy the parent address out - converting as we go */
656 cells
= cells_to_unit_address (cells
, &range
->parent_address
,
657 hw_unit_nr_address_cells (hw_parent (me
)));
659 /* copy the size - converting as we go */
660 cells
= cells_to_unit_address (cells
, &range
->size
,
661 hw_unit_nr_size_cells (me
));
663 return node
->sizeof_array
/ sizeof_entry
;
668 nr_reg_property_cells (struct hw
*me
,
671 return (hw_unit_nr_address_cells (hw_parent(me
))
672 + hw_unit_nr_size_cells (hw_parent(me
))
677 hw_add_reg_array_property (struct hw
*me
,
678 const char *property
,
679 const reg_property_spec
*regs
,
682 unsigned sizeof_cells
= (nr_reg_property_cells (me
, nr_regs
)
683 * sizeof (unsigned_cell
));
684 unsigned_cell
*cells
= hw_zalloc (me
, sizeof_cells
);
688 /* copy the property elements over */
690 for (i
= 0; i
< nr_regs
; i
++)
692 const reg_property_spec
*reg
= ®s
[i
];
693 /* copy the address */
694 cell
= unit_address_to_cells (®
->address
, cell
,
695 hw_unit_nr_address_cells (hw_parent (me
)));
697 cell
= unit_address_to_cells (®
->size
, cell
,
698 hw_unit_nr_size_cells (hw_parent (me
)));
700 ASSERT (cell
== &cells
[nr_reg_property_cells (me
, nr_regs
)]);
703 hw_add_property (me
, property
, reg_array_property
,
706 NULL
, permenant_object
);
712 hw_find_reg_array_property (struct hw
*me
,
713 const char *property
,
715 reg_property_spec
*reg
)
717 const struct hw_property
*node
;
718 unsigned sizeof_entry
= (nr_reg_property_cells (me
, 1)
719 * sizeof (unsigned_cell
));
720 const unsigned_cell
*cells
;
722 /* locate the property */
723 node
= hw_find_property (me
, property
);
725 hw_abort (me
, "property \"%s\" not found", property
);
726 if (node
->type
!= reg_array_property
)
727 hw_abort (me
, "property \"%s\" of wrong type (reg array)", property
);
730 if ((node
->sizeof_array
% sizeof_entry
) != 0)
731 hw_abort (me
, "property \"%s\" contains an incomplete number of entries",
735 if (node
->sizeof_array
< sizeof_entry
* (index
+ 1))
738 /* find the range of interest */
739 cells
= (unsigned_cell
*)((char*)node
->array
+ sizeof_entry
* index
);
741 /* copy the address out - converting as we go */
742 cells
= cells_to_unit_address (cells
, ®
->address
,
743 hw_unit_nr_address_cells (hw_parent (me
)));
745 /* copy the size out - converting as we go */
746 cells
= cells_to_unit_address (cells
, ®
->size
,
747 hw_unit_nr_size_cells (hw_parent (me
)));
749 return node
->sizeof_array
/ sizeof_entry
;
754 hw_add_string_property (struct hw
*me
,
755 const char *property
,
758 hw_add_property (me
, property
, string_property
,
759 string
, strlen(string
) + 1,
760 string
, strlen(string
) + 1,
761 NULL
, permenant_object
);
765 hw_find_string_property (struct hw
*me
,
766 const char *property
)
768 const struct hw_property
*node
;
770 node
= hw_find_property (me
, property
);
772 hw_abort (me
, "property \"%s\" not found", property
);
773 if (node
->type
!= string_property
)
774 hw_abort (me
, "property \"%s\" of wrong type (string)", property
);
775 string
= node
->array
;
776 ASSERT (strlen(string
) + 1 == node
->sizeof_array
);
781 hw_add_string_array_property (struct hw
*me
,
782 const char *property
,
783 const string_property_spec
*strings
,
791 hw_abort (me
, "property \"%s\" must be non-null", property
);
792 /* total up the size of the needed array */
793 for (sizeof_array
= 0, string_nr
= 0;
794 string_nr
< nr_strings
;
797 sizeof_array
+= strlen (strings
[string_nr
]) + 1;
799 /* create the array */
800 array
= (char*) hw_zalloc (me
, sizeof_array
);
803 string_nr
< nr_strings
;
806 strcpy (chp
, strings
[string_nr
]);
807 chp
+= strlen (chp
) + 1;
809 ASSERT (chp
== array
+ sizeof_array
);
811 hw_add_property (me
, property
, string_array_property
,
814 NULL
, permenant_object
);
818 hw_find_string_array_property (struct hw
*me
,
819 const char *property
,
821 string_property_spec
*string
)
823 const struct hw_property
*node
;
824 node
= hw_find_property (me
, property
);
826 hw_abort (me
, "property \"%s\" not found", property
);
830 hw_abort (me
, "property \"%s\" of wrong type", property
);
832 case string_property
:
835 *string
= node
->array
;
836 ASSERT (strlen(*string
) + 1 == node
->sizeof_array
);
841 if (node
->sizeof_array
== 0
842 || ((char*)node
->array
)[node
->sizeof_array
- 1] != '\0')
843 hw_abort (me
, "property \"%s\" invalid for string array", property
);
845 case string_array_property
:
846 ASSERT (node
->sizeof_array
> 0);
847 ASSERT (((char*)node
->array
)[node
->sizeof_array
- 1] == '\0');
849 const char *chp
= node
->array
;
851 /* count the number of strings, keeping an eye out for the one
861 if (nr_entries
== index
)
868 } while (chp
< (char*)node
->array
+ node
->sizeof_array
);
869 if (index
< nr_entries
)
883 hw_add_duplicate_property (struct hw
*me
,
884 const char *property
,
885 const struct hw_property
*original
)
887 struct hw_property_data
*master
;
888 TRACE (trace_devices
,
889 ("hw_add_duplicate_property(me=0x%lx, property=%s, ...)\n",
890 (long)me
, property
));
891 if (original
->disposition
!= permenant_object
)
892 hw_abort (me
, "Can only duplicate permenant objects");
893 /* find the original's master */
894 master
= original
->owner
->properties_of_hw
;
895 while (master
->property
!= original
)
897 master
= master
->next
;
898 ASSERT(master
!= NULL
);
900 /* now duplicate it */
901 hw_add_property (me
, property
,
903 master
->init_array
, master
->sizeof_init_array
,
904 original
->array
, original
->sizeof_array
,
905 original
, permenant_object
);