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
;
45 /* Device Properties: */
47 static struct hw_property_data
*
48 find_property_data (struct hw
*me
,
51 struct hw_property_data
*entry
;
52 ASSERT (property
!= NULL
);
53 entry
= me
->properties_of_hw
;
56 if (strcmp (entry
->property
->name
, property
) == 0)
65 hw_add_property (struct hw
*me
,
67 hw_property_type type
,
68 const void *init_array
,
69 unsigned sizeof_init_array
,
71 unsigned sizeof_array
,
72 const struct hw_property
*original
,
73 object_disposition disposition
)
75 struct hw_property_data
*new_entry
= NULL
;
76 struct hw_property
*new_value
= NULL
;
78 /* find the list end */
79 struct hw_property_data
**insertion_point
= &me
->properties_of_hw
;
80 while (*insertion_point
!= NULL
)
82 if (strcmp ((*insertion_point
)->property
->name
, property
) == 0)
84 insertion_point
= &(*insertion_point
)->next
;
87 /* create a new value */
88 new_value
= HW_ZALLOC (me
, struct hw_property
);
89 new_value
->name
= (char *) strdup (property
);
90 new_value
->type
= type
;
93 void *new_array
= hw_zalloc (me
, sizeof_array
);
94 memcpy (new_array
, array
, sizeof_array
);
95 new_value
->array
= new_array
;
96 new_value
->sizeof_array
= sizeof_array
;
98 new_value
->owner
= me
;
99 new_value
->original
= original
;
100 new_value
->disposition
= disposition
;
102 /* insert the value into the list */
103 new_entry
= HW_ZALLOC (me
, struct hw_property_data
);
104 *insertion_point
= new_entry
;
105 if (sizeof_init_array
> 0)
107 void *new_init_array
= hw_zalloc (me
, sizeof_init_array
);
108 memcpy (new_init_array
, init_array
, sizeof_init_array
);
109 new_entry
->init_array
= new_init_array
;
110 new_entry
->sizeof_init_array
= sizeof_init_array
;
112 new_entry
->property
= new_value
;
117 hw_set_property (struct hw
*me
,
118 const char *property
,
119 hw_property_type type
,
123 /* find the property */
124 struct hw_property_data
*entry
= find_property_data (me
, property
);
127 /* existing property - update it */
129 struct hw_property
*value
= entry
->property
;
130 /* check the type matches */
131 if (value
->type
!= type
)
132 hw_abort (me
, "conflict between type of new and old value for property %s", property
);
133 /* replace its value */
134 if (value
->array
!= NULL
)
135 hw_free (me
, (void*)value
->array
);
136 new_array
= (sizeof_array
> 0
137 ? hw_zalloc (me
, sizeof_array
)
139 value
->array
= new_array
;
140 value
->sizeof_array
= sizeof_array
;
141 if (sizeof_array
> 0)
142 memcpy (new_array
, array
, sizeof_array
);
147 /* new property - create it */
148 hw_add_property (me
, property
, type
,
149 NULL
, 0, array
, sizeof_array
,
150 NULL
, temporary_object
);
157 clean_hw_properties (struct hw
*me
)
159 struct hw_property_data
**delete_point
= &me
->properties_of_hw
;
160 while (*delete_point
!= NULL
)
162 struct hw_property_data
*current
= *delete_point
;
163 switch (current
->property
->disposition
)
165 case permenant_object
:
166 /* zap the current value, will be initialized later */
167 ASSERT (current
->init_array
!= NULL
);
168 if (current
->property
->array
!= NULL
)
170 hw_free (me
, (void*)current
->property
->array
);
171 current
->property
->array
= NULL
;
173 delete_point
= &(*delete_point
)->next
;
175 case temporary_object
:
176 /* zap the actual property, was created during simulation run */
177 ASSERT (current
->init_array
== NULL
);
178 *delete_point
= current
->next
;
179 if (current
->property
->array
!= NULL
)
180 hw_free (me
, (void*)current
->property
->array
);
181 hw_free (me
, current
->property
);
182 hw_free (me
, current
);
191 hw_init_static_properties (SIM_DESC sd
,
195 struct hw_property_data
*property
;
196 for (property
= me
->properties_of_hw
;
198 property
= property
->next
)
200 ASSERT (property
->init_array
!= NULL
);
201 ASSERT (property
->property
->array
== NULL
);
202 ASSERT(property
->property
->disposition
== permenant_object
);
203 switch (property
->property
->type
)
206 case boolean_property
:
207 case range_array_property
:
208 case reg_array_property
:
209 case string_property
:
210 case string_array_property
:
211 case integer_property
:
212 /* delete the property, and replace it with the original */
213 hw_set_property (me
, property
->property
->name
,
214 property
->property
->type
,
215 property
->init_array
,
216 property
->sizeof_init_array
);
219 case ihandle_property
:
230 hw_init_runtime_properties (SIM_DESC sd
,
234 struct hw_property_data
*property
;
235 for (property
= me
->properties_of_hw
;
237 property
= property
->next
)
239 switch (property
->property
->disposition
)
241 case permenant_object
:
242 switch (property
->property
->type
)
245 case ihandle_property
:
247 struct hw_instance
*ihandle
;
248 ihandle_runtime_property_spec spec
;
249 ASSERT (property
->init_array
!= NULL
);
250 ASSERT (property
->property
->array
== NULL
);
251 hw_find_ihandle_runtime_property (me
, property
->property
->name
, &spec
);
252 ihandle
= tree_instance (me
, spec
.full_path
);
253 hw_set_ihandle_property (me
, property
->property
->name
, ihandle
);
258 case boolean_property
:
259 case range_array_property
:
260 case integer_property
:
261 case reg_array_property
:
262 case string_property
:
263 case string_array_property
:
264 ASSERT (property
->init_array
!= NULL
);
265 ASSERT (property
->property
->array
!= NULL
);
269 case temporary_object
:
270 ASSERT (property
->init_array
== NULL
);
271 ASSERT (property
->property
->array
!= NULL
);
280 const struct hw_property
*
281 hw_next_property (const struct hw_property
*property
)
283 /* find the property in the list */
284 struct hw
*owner
= property
->owner
;
285 struct hw_property_data
*entry
= owner
->properties_of_hw
;
286 while (entry
!= NULL
&& entry
->property
!= property
)
288 /* now return the following property */
289 ASSERT (entry
!= NULL
); /* must be a member! */
290 if (entry
->next
!= NULL
)
291 return entry
->next
->property
;
297 const struct hw_property
*
298 hw_find_property (struct hw
*me
,
299 const char *property
)
305 else if (property
== NULL
|| strcmp (property
, "") == 0)
307 if (me
->properties_of_hw
== NULL
)
310 return me
->properties_of_hw
->property
;
314 struct hw_property_data
*entry
= find_property_data (me
, property
);
316 return entry
->property
;
323 hw_add_array_property (struct hw
*me
,
324 const char *property
,
328 hw_add_property (me
, property
, array_property
,
329 array
, sizeof_array
, array
, sizeof_array
,
330 NULL
, permenant_object
);
334 hw_set_array_property (struct hw
*me
,
335 const char *property
,
339 hw_set_property (me
, property
, array_property
, array
, sizeof_array
);
342 const struct hw_property
*
343 hw_find_array_property (struct hw
*me
,
344 const char *property
)
346 const struct hw_property
*node
;
347 node
= hw_find_property (me
, property
);
349 hw_abort (me
, "property \"%s\" not found", property
);
350 if (node
->type
!= array_property
)
351 hw_abort (me
, "property \"%s\" of wrong type (array)", property
);
358 hw_add_boolean_property (struct hw
*me
,
359 const char *property
,
362 signed32 new_boolean
= (boolean
? -1 : 0);
363 hw_add_property (me
, property
, boolean_property
,
364 &new_boolean
, sizeof(new_boolean
),
365 &new_boolean
, sizeof(new_boolean
),
366 NULL
, permenant_object
);
370 hw_find_boolean_property (struct hw
*me
,
371 const char *property
)
373 const struct hw_property
*node
;
374 unsigned_cell boolean
;
375 node
= hw_find_property (me
, property
);
377 hw_abort (me
, "property \"%s\" not found", property
);
378 if (node
->type
!= boolean_property
)
379 hw_abort (me
, "property \"%s\" of wrong type (boolean)", property
);
380 ASSERT (sizeof (boolean
) == node
->sizeof_array
);
381 memcpy (&boolean
, node
->array
, sizeof (boolean
));
389 hw_add_ihandle_runtime_property (struct hw
*me
,
390 const char *property
,
391 const ihandle_runtime_property_spec
*ihandle
)
393 /* enter the full path as the init array */
394 hw_add_property (me
, property
, ihandle_property
,
395 ihandle
->full_path
, strlen(ihandle
->full_path
) + 1,
397 NULL
, permenant_object
);
403 hw_find_ihandle_runtime_property (struct hw
*me
,
404 const char *property
,
405 ihandle_runtime_property_spec
*ihandle
)
407 struct hw_property_data
*entry
= find_property_data (me
, property
);
408 TRACE (trace_devices
,
409 ("hw_find_ihandle_runtime_property(me=0x%lx, property=%s)\n",
410 (long)me
, property
));
412 hw_abort (me
, "property \"%s\" not found", property
);
413 if (entry
->property
->type
!= ihandle_property
414 || entry
->property
->disposition
!= permenant_object
)
415 hw_abort (me
, "property \"%s\" of wrong type", property
);
416 ASSERT (entry
->init_array
!= NULL
);
418 ihandle
->full_path
= entry
->init_array
;
426 hw_set_ihandle_property (struct hw
*me
,
427 const char *property
,
428 hw_instance
*ihandle
)
431 cells
= H2BE_cell (hw_instance_to_external (ihandle
));
432 hw_set_property (me
, property
, ihandle_property
,
433 &cells
, sizeof (cells
));
440 hw_find_ihandle_property (struct hw
*me
,
441 const char *property
)
443 const hw_property_data
*node
;
444 unsigned_cell ihandle
;
445 hw_instance
*instance
;
447 node
= hw_find_property (me
, property
);
449 hw_abort (me
, "property \"%s\" not found", property
);
450 if (node
->type
!= ihandle_property
)
451 hw_abort(me
, "property \"%s\" of wrong type (ihandle)", property
);
452 if (node
->array
== NULL
)
453 hw_abort(me
, "runtime property \"%s\" not yet initialized", property
);
455 ASSERT (sizeof(ihandle
) == node
->sizeof_array
);
456 memcpy (&ihandle
, node
->array
, sizeof(ihandle
));
457 instance
= external_to_hw_instance (me
, BE2H_cell(ihandle
));
458 ASSERT (instance
!= NULL
);
465 hw_add_integer_property (struct hw
*me
,
466 const char *property
,
470 hw_add_property (me
, property
, integer_property
,
471 &integer
, sizeof(integer
),
472 &integer
, sizeof(integer
),
473 NULL
, permenant_object
);
477 hw_find_integer_property (struct hw
*me
,
478 const char *property
)
480 const struct hw_property
*node
;
482 TRACE (trace_devices
,
483 ("hw_find_integer(me=0x%lx, property=%s)\n",
484 (long)me
, property
));
485 node
= hw_find_property (me
, property
);
487 hw_abort (me
, "property \"%s\" not found", property
);
488 if (node
->type
!= integer_property
)
489 hw_abort (me
, "property \"%s\" of wrong type (integer)", property
);
490 ASSERT (sizeof(integer
) == node
->sizeof_array
);
491 memcpy (&integer
, node
->array
, sizeof (integer
));
492 return BE2H_cell (integer
);
496 hw_find_integer_array_property (struct hw
*me
,
497 const char *property
,
499 signed_cell
*integer
)
501 const struct hw_property
*node
;
502 int sizeof_integer
= sizeof (*integer
);
504 TRACE (trace_devices
,
505 ("hw_find_integer(me=0x%lx, property=%s)\n",
506 (long)me
, property
));
508 /* check things sane */
509 node
= hw_find_property (me
, property
);
511 hw_abort (me
, "property \"%s\" not found", property
);
512 if (node
->type
!= integer_property
513 && node
->type
!= array_property
)
514 hw_abort (me
, "property \"%s\" of wrong type (integer or array)", property
);
515 if ((node
->sizeof_array
% sizeof_integer
) != 0)
516 hw_abort (me
, "property \"%s\" contains an incomplete number of cells", property
);
517 if (node
->sizeof_array
<= sizeof_integer
* index
)
520 /* Find and convert the value */
521 cell
= ((signed_cell
*)node
->array
) + index
;
522 *integer
= BE2H_cell (*cell
);
524 return node
->sizeof_array
/ sizeof_integer
;
528 static unsigned_cell
*
529 unit_address_to_cells (const hw_unit
*unit
,
534 ASSERT(nr_cells
== unit
->nr_cells
);
535 for (i
= 0; i
< unit
->nr_cells
; i
++)
537 *cell
= H2BE_cell (unit
->cells
[i
]);
544 static const unsigned_cell
*
545 cells_to_unit_address (const unsigned_cell
*cell
,
550 memset(unit
, 0, sizeof(*unit
));
551 unit
->nr_cells
= nr_cells
;
552 for (i
= 0; i
< unit
->nr_cells
; i
++)
554 unit
->cells
[i
] = BE2H_cell (*cell
);
562 nr_range_property_cells (struct hw
*me
,
565 return ((hw_unit_nr_address_cells (me
)
566 + hw_unit_nr_address_cells (hw_parent (me
))
567 + hw_unit_nr_size_cells (me
))
572 hw_add_range_array_property (struct hw
*me
,
573 const char *property
,
574 const range_property_spec
*ranges
,
577 unsigned sizeof_cells
= (nr_range_property_cells (me
, nr_ranges
)
578 * sizeof (unsigned_cell
));
579 unsigned_cell
*cells
= hw_zalloc (me
, sizeof_cells
);
583 /* copy the property elements over */
585 for (i
= 0; i
< nr_ranges
; i
++)
587 const range_property_spec
*range
= &ranges
[i
];
588 /* copy the child address */
589 cell
= unit_address_to_cells (&range
->child_address
, cell
,
590 hw_unit_nr_address_cells (me
));
591 /* copy the parent address */
592 cell
= unit_address_to_cells (&range
->parent_address
, cell
,
593 hw_unit_nr_address_cells (hw_parent (me
)));
595 cell
= unit_address_to_cells (&range
->size
, cell
,
596 hw_unit_nr_size_cells (me
));
598 ASSERT (cell
== &cells
[nr_range_property_cells (me
, nr_ranges
)]);
601 hw_add_property (me
, property
, range_array_property
,
604 NULL
, permenant_object
);
610 hw_find_range_array_property (struct hw
*me
,
611 const char *property
,
613 range_property_spec
*range
)
615 const struct hw_property
*node
;
616 unsigned sizeof_entry
= (nr_range_property_cells (me
, 1)
617 * sizeof (unsigned_cell
));
618 const unsigned_cell
*cells
;
620 /* locate the property */
621 node
= hw_find_property (me
, property
);
623 hw_abort (me
, "property \"%s\" not found", property
);
624 if (node
->type
!= range_array_property
)
625 hw_abort (me
, "property \"%s\" of wrong type (range array)", property
);
628 if ((node
->sizeof_array
% sizeof_entry
) != 0)
629 hw_abort (me
, "property \"%s\" contains an incomplete number of entries",
633 if (node
->sizeof_array
< sizeof_entry
* (index
+ 1))
636 /* find the range of interest */
637 cells
= (unsigned_cell
*)((char*)node
->array
+ sizeof_entry
* index
);
639 /* copy the child address out - converting as we go */
640 cells
= cells_to_unit_address (cells
, &range
->child_address
,
641 hw_unit_nr_address_cells (me
));
643 /* copy the parent address out - converting as we go */
644 cells
= cells_to_unit_address (cells
, &range
->parent_address
,
645 hw_unit_nr_address_cells (hw_parent (me
)));
647 /* copy the size - converting as we go */
648 cells
= cells_to_unit_address (cells
, &range
->size
,
649 hw_unit_nr_size_cells (me
));
651 return node
->sizeof_array
/ sizeof_entry
;
656 nr_reg_property_cells (struct hw
*me
,
659 return (hw_unit_nr_address_cells (hw_parent(me
))
660 + hw_unit_nr_size_cells (hw_parent(me
))
665 hw_add_reg_array_property (struct hw
*me
,
666 const char *property
,
667 const reg_property_spec
*regs
,
670 unsigned sizeof_cells
= (nr_reg_property_cells (me
, nr_regs
)
671 * sizeof (unsigned_cell
));
672 unsigned_cell
*cells
= hw_zalloc (me
, sizeof_cells
);
676 /* copy the property elements over */
678 for (i
= 0; i
< nr_regs
; i
++)
680 const reg_property_spec
*reg
= ®s
[i
];
681 /* copy the address */
682 cell
= unit_address_to_cells (®
->address
, cell
,
683 hw_unit_nr_address_cells (hw_parent (me
)));
685 cell
= unit_address_to_cells (®
->size
, cell
,
686 hw_unit_nr_size_cells (hw_parent (me
)));
688 ASSERT (cell
== &cells
[nr_reg_property_cells (me
, nr_regs
)]);
691 hw_add_property (me
, property
, reg_array_property
,
694 NULL
, permenant_object
);
700 hw_find_reg_array_property (struct hw
*me
,
701 const char *property
,
703 reg_property_spec
*reg
)
705 const struct hw_property
*node
;
706 unsigned sizeof_entry
= (nr_reg_property_cells (me
, 1)
707 * sizeof (unsigned_cell
));
708 const unsigned_cell
*cells
;
710 /* locate the property */
711 node
= hw_find_property (me
, property
);
713 hw_abort (me
, "property \"%s\" not found", property
);
714 if (node
->type
!= reg_array_property
)
715 hw_abort (me
, "property \"%s\" of wrong type (reg array)", property
);
718 if ((node
->sizeof_array
% sizeof_entry
) != 0)
719 hw_abort (me
, "property \"%s\" contains an incomplete number of entries",
723 if (node
->sizeof_array
< sizeof_entry
* (index
+ 1))
726 /* find the range of interest */
727 cells
= (unsigned_cell
*)((char*)node
->array
+ sizeof_entry
* index
);
729 /* copy the address out - converting as we go */
730 cells
= cells_to_unit_address (cells
, ®
->address
,
731 hw_unit_nr_address_cells (hw_parent (me
)));
733 /* copy the size out - converting as we go */
734 cells
= cells_to_unit_address (cells
, ®
->size
,
735 hw_unit_nr_size_cells (hw_parent (me
)));
737 return node
->sizeof_array
/ sizeof_entry
;
742 hw_add_string_property (struct hw
*me
,
743 const char *property
,
746 hw_add_property (me
, property
, string_property
,
747 string
, strlen(string
) + 1,
748 string
, strlen(string
) + 1,
749 NULL
, permenant_object
);
753 hw_find_string_property (struct hw
*me
,
754 const char *property
)
756 const struct hw_property
*node
;
758 node
= hw_find_property (me
, property
);
760 hw_abort (me
, "property \"%s\" not found", property
);
761 if (node
->type
!= string_property
)
762 hw_abort (me
, "property \"%s\" of wrong type (string)", property
);
763 string
= node
->array
;
764 ASSERT (strlen(string
) + 1 == node
->sizeof_array
);
769 hw_add_string_array_property (struct hw
*me
,
770 const char *property
,
771 const string_property_spec
*strings
,
779 hw_abort (me
, "property \"%s\" must be non-null", property
);
780 /* total up the size of the needed array */
781 for (sizeof_array
= 0, string_nr
= 0;
782 string_nr
< nr_strings
;
785 sizeof_array
+= strlen (strings
[string_nr
]) + 1;
787 /* create the array */
788 array
= (char*) hw_zalloc (me
, sizeof_array
);
791 string_nr
< nr_strings
;
794 strcpy (chp
, strings
[string_nr
]);
795 chp
+= strlen (chp
) + 1;
797 ASSERT (chp
== array
+ sizeof_array
);
799 hw_add_property (me
, property
, string_array_property
,
802 NULL
, permenant_object
);
806 hw_find_string_array_property (struct hw
*me
,
807 const char *property
,
809 string_property_spec
*string
)
811 const struct hw_property
*node
;
812 node
= hw_find_property (me
, property
);
814 hw_abort (me
, "property \"%s\" not found", property
);
818 hw_abort (me
, "property \"%s\" of wrong type", property
);
820 case string_property
:
823 *string
= node
->array
;
824 ASSERT (strlen(*string
) + 1 == node
->sizeof_array
);
829 if (node
->sizeof_array
== 0
830 || ((char*)node
->array
)[node
->sizeof_array
- 1] != '\0')
831 hw_abort (me
, "property \"%s\" invalid for string array", property
);
833 case string_array_property
:
834 ASSERT (node
->sizeof_array
> 0);
835 ASSERT (((char*)node
->array
)[node
->sizeof_array
- 1] == '\0');
837 const char *chp
= node
->array
;
839 /* count the number of strings, keeping an eye out for the one
849 if (nr_entries
== index
)
856 } while (chp
< (char*)node
->array
+ node
->sizeof_array
);
857 if (index
< nr_entries
)
871 hw_add_duplicate_property (struct hw
*me
,
872 const char *property
,
873 const struct hw_property
*original
)
875 struct hw_property_data
*master
;
876 TRACE (trace_devices
,
877 ("hw_add_duplicate_property(me=0x%lx, property=%s, ...)\n",
878 (long)me
, property
));
879 if (original
->disposition
!= permenant_object
)
880 hw_abort (me
, "Can only duplicate permenant objects");
881 /* find the original's master */
882 master
= original
->owner
->properties_of_hw
;
883 while (master
->property
!= original
)
885 master
= master
->next
;
886 ASSERT(master
!= NULL
);
888 /* now duplicate it */
889 hw_add_property (me
, property
,
891 master
->init_array
, master
->sizeof_init_array
,
892 original
->array
, original
->sizeof_array
,
893 original
, permenant_object
);