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.
23 #include "hw-device.h"
24 #include "hw-properties.h"
26 #include "sim-assert.h"
38 /* property entries */
40 struct hw_property_data
{
41 struct hw_property_data
*next
;
42 struct hw_property
*property
;
43 const void *init_array
;
44 unsigned sizeof_init_array
;
47 /* Device Properties: */
49 static struct hw_property_data
*
50 find_property_data (struct hw
*me
,
53 struct hw_property_data
*entry
;
54 ASSERT (property
!= NULL
);
55 entry
= me
->properties_of_hw
;
58 if (strcmp (entry
->property
->name
, property
) == 0)
67 hw_add_property (struct hw
*me
,
69 hw_property_type type
,
70 const void *init_array
,
71 unsigned sizeof_init_array
,
73 unsigned sizeof_array
,
74 const struct hw_property
*original
,
75 object_disposition disposition
)
77 struct hw_property_data
*new_entry
= NULL
;
78 struct hw_property
*new_value
= NULL
;
80 /* find the list end */
81 struct hw_property_data
**insertion_point
= &me
->properties_of_hw
;
82 while (*insertion_point
!= NULL
)
84 if (strcmp ((*insertion_point
)->property
->name
, property
) == 0)
86 insertion_point
= &(*insertion_point
)->next
;
89 /* create a new value */
90 new_value
= HW_ZALLOC (me
, struct hw_property
);
91 new_value
->name
= (char *) strdup (property
);
92 new_value
->type
= type
;
95 void *new_array
= hw_zalloc (me
, sizeof_array
);
96 memcpy (new_array
, array
, sizeof_array
);
97 new_value
->array
= new_array
;
98 new_value
->sizeof_array
= sizeof_array
;
100 new_value
->owner
= me
;
101 new_value
->original
= original
;
102 new_value
->disposition
= disposition
;
104 /* insert the value into the list */
105 new_entry
= HW_ZALLOC (me
, struct hw_property_data
);
106 *insertion_point
= new_entry
;
107 if (sizeof_init_array
> 0)
109 void *new_init_array
= hw_zalloc (me
, sizeof_init_array
);
110 memcpy (new_init_array
, init_array
, sizeof_init_array
);
111 new_entry
->init_array
= new_init_array
;
112 new_entry
->sizeof_init_array
= sizeof_init_array
;
114 new_entry
->property
= new_value
;
119 hw_set_property (struct hw
*me
,
120 const char *property
,
121 hw_property_type type
,
125 /* find the property */
126 struct hw_property_data
*entry
= find_property_data (me
, property
);
129 /* existing property - update it */
131 struct hw_property
*value
= entry
->property
;
132 /* check the type matches */
133 if (value
->type
!= type
)
134 hw_abort (me
, "conflict between type of new and old value for property %s", property
);
135 /* replace its value */
136 if (value
->array
!= NULL
)
137 hw_free (me
, (void*)value
->array
);
138 new_array
= (sizeof_array
> 0
139 ? hw_zalloc (me
, sizeof_array
)
141 value
->array
= new_array
;
142 value
->sizeof_array
= sizeof_array
;
143 if (sizeof_array
> 0)
144 memcpy (new_array
, array
, sizeof_array
);
149 /* new property - create it */
150 hw_add_property (me
, property
, type
,
151 NULL
, 0, array
, sizeof_array
,
152 NULL
, temporary_object
);
159 clean_hw_properties (struct hw
*me
)
161 struct hw_property_data
**delete_point
= &me
->properties_of_hw
;
162 while (*delete_point
!= NULL
)
164 struct hw_property_data
*current
= *delete_point
;
165 switch (current
->property
->disposition
)
167 case permenant_object
:
168 /* zap the current value, will be initialized later */
169 ASSERT (current
->init_array
!= NULL
);
170 if (current
->property
->array
!= NULL
)
172 hw_free (me
, (void*)current
->property
->array
);
173 current
->property
->array
= NULL
;
175 delete_point
= &(*delete_point
)->next
;
177 case temporary_object
:
178 /* zap the actual property, was created during simulation run */
179 ASSERT (current
->init_array
== NULL
);
180 *delete_point
= current
->next
;
181 if (current
->property
->array
!= NULL
)
182 hw_free (me
, (void*)current
->property
->array
);
183 hw_free (me
, current
->property
);
184 hw_free (me
, current
);
193 hw_init_static_properties (SIM_DESC sd
,
197 struct hw_property_data
*property
;
198 for (property
= me
->properties_of_hw
;
200 property
= property
->next
)
202 ASSERT (property
->init_array
!= NULL
);
203 ASSERT (property
->property
->array
== NULL
);
204 ASSERT(property
->property
->disposition
== permenant_object
);
205 switch (property
->property
->type
)
208 case boolean_property
:
209 case range_array_property
:
210 case reg_array_property
:
211 case string_property
:
212 case string_array_property
:
213 case integer_property
:
214 /* delete the property, and replace it with the original */
215 hw_set_property (me
, property
->property
->name
,
216 property
->property
->type
,
217 property
->init_array
,
218 property
->sizeof_init_array
);
221 case ihandle_property
:
232 hw_init_runtime_properties (SIM_DESC sd
,
236 struct hw_property_data
*property
;
237 for (property
= me
->properties_of_hw
;
239 property
= property
->next
)
241 switch (property
->property
->disposition
)
243 case permenant_object
:
244 switch (property
->property
->type
)
247 case ihandle_property
:
249 struct hw_instance
*ihandle
;
250 ihandle_runtime_property_spec spec
;
251 ASSERT (property
->init_array
!= NULL
);
252 ASSERT (property
->property
->array
== NULL
);
253 hw_find_ihandle_runtime_property (me
, property
->property
->name
, &spec
);
254 ihandle
= tree_instance (me
, spec
.full_path
);
255 hw_set_ihandle_property (me
, property
->property
->name
, ihandle
);
260 case boolean_property
:
261 case range_array_property
:
262 case integer_property
:
263 case reg_array_property
:
264 case string_property
:
265 case string_array_property
:
266 ASSERT (property
->init_array
!= NULL
);
267 ASSERT (property
->property
->array
!= NULL
);
271 case temporary_object
:
272 ASSERT (property
->init_array
== NULL
);
273 ASSERT (property
->property
->array
!= NULL
);
282 const struct hw_property
*
283 hw_next_property (const struct hw_property
*property
)
285 /* find the property in the list */
286 struct hw
*owner
= property
->owner
;
287 struct hw_property_data
*entry
= owner
->properties_of_hw
;
288 while (entry
!= NULL
&& entry
->property
!= property
)
290 /* now return the following property */
291 ASSERT (entry
!= NULL
); /* must be a member! */
292 if (entry
->next
!= NULL
)
293 return entry
->next
->property
;
299 const struct hw_property
*
300 hw_find_property (struct hw
*me
,
301 const char *property
)
307 else if (property
== NULL
|| strcmp (property
, "") == 0)
309 if (me
->properties_of_hw
== NULL
)
312 return me
->properties_of_hw
->property
;
316 struct hw_property_data
*entry
= find_property_data (me
, property
);
318 return entry
->property
;
325 hw_add_array_property (struct hw
*me
,
326 const char *property
,
330 hw_add_property (me
, property
, array_property
,
331 array
, sizeof_array
, array
, sizeof_array
,
332 NULL
, permenant_object
);
336 hw_set_array_property (struct hw
*me
,
337 const char *property
,
341 hw_set_property (me
, property
, array_property
, array
, sizeof_array
);
344 const struct hw_property
*
345 hw_find_array_property (struct hw
*me
,
346 const char *property
)
348 const struct hw_property
*node
;
349 node
= hw_find_property (me
, property
);
351 || node
->type
!= array_property
)
352 hw_abort(me
, "property %s not found or of wrong type", property
);
359 hw_add_boolean_property (struct hw
*me
,
360 const char *property
,
363 signed32 new_boolean
= (boolean
? -1 : 0);
364 hw_add_property (me
, property
, boolean_property
,
365 &new_boolean
, sizeof(new_boolean
),
366 &new_boolean
, sizeof(new_boolean
),
367 NULL
, permenant_object
);
371 hw_find_boolean_property (struct hw
*me
,
372 const char *property
)
374 const struct hw_property
*node
;
375 unsigned_cell boolean
;
376 node
= hw_find_property (me
, property
);
377 if (node
== NULL
|| node
->type
!= boolean_property
)
378 hw_abort (me
, "property %s not found or of wrong type", property
);
379 ASSERT (sizeof (boolean
) == node
->sizeof_array
);
380 memcpy (&boolean
, node
->array
, sizeof (boolean
));
388 hw_add_ihandle_runtime_property (struct hw
*me
,
389 const char *property
,
390 const ihandle_runtime_property_spec
*ihandle
)
392 /* enter the full path as the init array */
393 hw_add_property (me
, property
, ihandle_property
,
394 ihandle
->full_path
, strlen(ihandle
->full_path
) + 1,
396 NULL
, permenant_object
);
402 hw_find_ihandle_runtime_property (struct hw
*me
,
403 const char *property
,
404 ihandle_runtime_property_spec
*ihandle
)
406 struct hw_property_data
*entry
= find_property_data (me
, property
);
407 TRACE (trace_devices
,
408 ("hw_find_ihandle_runtime_property(me=0x%lx, property=%s)\n",
409 (long)me
, property
));
411 || entry
->property
->type
!= ihandle_property
412 || entry
->property
->disposition
!= permenant_object
)
413 hw_abort (me
, "property %s not found or of wrong type", property
);
414 ASSERT (entry
->init_array
!= NULL
);
416 ihandle
->full_path
= entry
->init_array
;
424 hw_set_ihandle_property (struct hw
*me
,
425 const char *property
,
426 hw_instance
*ihandle
)
429 cells
= H2BE_cell (hw_instance_to_external (ihandle
));
430 hw_set_property (me
, property
, ihandle_property
,
431 &cells
, sizeof (cells
));
438 hw_find_ihandle_property (struct hw
*me
,
439 const char *property
)
441 const hw_property_data
*node
;
442 unsigned_cell ihandle
;
443 hw_instance
*instance
;
445 node
= hw_find_property (me
, property
);
446 if (node
== NULL
|| node
->type
!= ihandle_property
)
447 hw_abort(me
, "property %s not found or of wrong type", property
);
448 if (node
->array
== NULL
)
449 hw_abort(me
, "runtime property %s not yet initialized", property
);
451 ASSERT (sizeof(ihandle
) == node
->sizeof_array
);
452 memcpy (&ihandle
, node
->array
, sizeof(ihandle
));
453 instance
= external_to_hw_instance (me
, BE2H_cell(ihandle
));
454 ASSERT (instance
!= NULL
);
461 hw_add_integer_property (struct hw
*me
,
462 const char *property
,
466 hw_add_property (me
, property
, integer_property
,
467 &integer
, sizeof(integer
),
468 &integer
, sizeof(integer
),
469 NULL
, permenant_object
);
473 hw_find_integer_property (struct hw
*me
,
474 const char *property
)
476 const struct hw_property
*node
;
478 TRACE (trace_devices
,
479 ("hw_find_integer(me=0x%lx, property=%s)\n",
480 (long)me
, property
));
481 node
= hw_find_property (me
, property
);
482 if (node
== NULL
|| node
->type
!= integer_property
)
483 hw_abort (me
, "property %s not found or of wrong type", property
);
484 ASSERT (sizeof(integer
) == node
->sizeof_array
);
485 memcpy (&integer
, node
->array
, sizeof (integer
));
486 return BE2H_cell (integer
);
490 hw_find_integer_array_property (struct hw
*me
,
491 const char *property
,
493 signed_cell
*integer
)
495 const struct hw_property
*node
;
496 int sizeof_integer
= sizeof (*integer
);
498 TRACE (trace_devices
,
499 ("hw_find_integer(me=0x%lx, property=%s)\n",
500 (long)me
, property
));
502 /* check things sane */
503 node
= hw_find_property (me
, property
);
505 || (node
->type
!= integer_property
506 && node
->type
!= array_property
))
507 hw_abort (me
, "property %s not found or of wrong type", property
);
508 if ((node
->sizeof_array
% sizeof_integer
) != 0)
509 hw_abort (me
, "property %s contains an incomplete number of cells", property
);
510 if (node
->sizeof_array
<= sizeof_integer
* index
)
513 /* Find and convert the value */
514 cell
= ((signed_cell
*)node
->array
) + index
;
515 *integer
= BE2H_cell (*cell
);
517 return node
->sizeof_array
/ sizeof_integer
;
521 static unsigned_cell
*
522 unit_address_to_cells (const hw_unit
*unit
,
527 ASSERT(nr_cells
== unit
->nr_cells
);
528 for (i
= 0; i
< unit
->nr_cells
; i
++)
530 *cell
= H2BE_cell (unit
->cells
[i
]);
537 static const unsigned_cell
*
538 cells_to_unit_address (const unsigned_cell
*cell
,
543 memset(unit
, 0, sizeof(*unit
));
544 unit
->nr_cells
= nr_cells
;
545 for (i
= 0; i
< unit
->nr_cells
; i
++)
547 unit
->cells
[i
] = BE2H_cell (*cell
);
555 nr_range_property_cells (struct hw
*me
,
558 return ((hw_unit_nr_address_cells (me
)
559 + hw_unit_nr_address_cells (hw_parent (me
))
560 + hw_unit_nr_size_cells (me
))
565 hw_add_range_array_property (struct hw
*me
,
566 const char *property
,
567 const range_property_spec
*ranges
,
570 unsigned sizeof_cells
= (nr_range_property_cells (me
, nr_ranges
)
571 * sizeof (unsigned_cell
));
572 unsigned_cell
*cells
= hw_zalloc (me
, sizeof_cells
);
576 /* copy the property elements over */
578 for (i
= 0; i
< nr_ranges
; i
++)
580 const range_property_spec
*range
= &ranges
[i
];
581 /* copy the child address */
582 cell
= unit_address_to_cells (&range
->child_address
, cell
,
583 hw_unit_nr_address_cells (me
));
584 /* copy the parent address */
585 cell
= unit_address_to_cells (&range
->parent_address
, cell
,
586 hw_unit_nr_address_cells (hw_parent (me
)));
588 cell
= unit_address_to_cells (&range
->size
, cell
,
589 hw_unit_nr_size_cells (me
));
591 ASSERT (cell
== &cells
[nr_range_property_cells (me
, nr_ranges
)]);
594 hw_add_property (me
, property
, range_array_property
,
597 NULL
, permenant_object
);
603 hw_find_range_array_property (struct hw
*me
,
604 const char *property
,
606 range_property_spec
*range
)
608 const struct hw_property
*node
;
609 unsigned sizeof_entry
= (nr_range_property_cells (me
, 1)
610 * sizeof (unsigned_cell
));
611 const unsigned_cell
*cells
;
613 /* locate the property */
614 node
= hw_find_property (me
, property
);
615 if (node
== NULL
|| node
->type
!= range_array_property
)
616 hw_abort (me
, "property %s not found or of wrong type", property
);
619 if ((node
->sizeof_array
% sizeof_entry
) != 0)
620 hw_abort (me
, "property %s contains an incomplete number of entries",
624 if (node
->sizeof_array
< sizeof_entry
* (index
+ 1))
627 /* find the range of interest */
628 cells
= (unsigned_cell
*)((char*)node
->array
+ sizeof_entry
* index
);
630 /* copy the child address out - converting as we go */
631 cells
= cells_to_unit_address (cells
, &range
->child_address
,
632 hw_unit_nr_address_cells (me
));
634 /* copy the parent address out - converting as we go */
635 cells
= cells_to_unit_address (cells
, &range
->parent_address
,
636 hw_unit_nr_address_cells (hw_parent (me
)));
638 /* copy the size - converting as we go */
639 cells
= cells_to_unit_address (cells
, &range
->size
,
640 hw_unit_nr_size_cells (me
));
642 return node
->sizeof_array
/ sizeof_entry
;
647 nr_reg_property_cells (struct hw
*me
,
650 return (hw_unit_nr_address_cells (hw_parent(me
))
651 + hw_unit_nr_size_cells (hw_parent(me
))
656 hw_add_reg_array_property (struct hw
*me
,
657 const char *property
,
658 const reg_property_spec
*regs
,
661 unsigned sizeof_cells
= (nr_reg_property_cells (me
, nr_regs
)
662 * sizeof (unsigned_cell
));
663 unsigned_cell
*cells
= hw_zalloc (me
, sizeof_cells
);
667 /* copy the property elements over */
669 for (i
= 0; i
< nr_regs
; i
++)
671 const reg_property_spec
*reg
= ®s
[i
];
672 /* copy the address */
673 cell
= unit_address_to_cells (®
->address
, cell
,
674 hw_unit_nr_address_cells (hw_parent (me
)));
676 cell
= unit_address_to_cells (®
->size
, cell
,
677 hw_unit_nr_size_cells (hw_parent (me
)));
679 ASSERT (cell
== &cells
[nr_reg_property_cells (me
, nr_regs
)]);
682 hw_add_property (me
, property
, reg_array_property
,
685 NULL
, permenant_object
);
691 hw_find_reg_array_property (struct hw
*me
,
692 const char *property
,
694 reg_property_spec
*reg
)
696 const struct hw_property
*node
;
697 unsigned sizeof_entry
= (nr_reg_property_cells (me
, 1)
698 * sizeof (unsigned_cell
));
699 const unsigned_cell
*cells
;
701 /* locate the property */
702 node
= hw_find_property (me
, property
);
703 if (node
== NULL
|| node
->type
!= reg_array_property
)
704 hw_abort (me
, "property %s not found or of wrong type", property
);
707 if ((node
->sizeof_array
% sizeof_entry
) != 0)
708 hw_abort (me
, "property %s contains an incomplete number of entries",
712 if (node
->sizeof_array
< sizeof_entry
* (index
+ 1))
715 /* find the range of interest */
716 cells
= (unsigned_cell
*)((char*)node
->array
+ sizeof_entry
* index
);
718 /* copy the address out - converting as we go */
719 cells
= cells_to_unit_address (cells
, ®
->address
,
720 hw_unit_nr_address_cells (hw_parent (me
)));
722 /* copy the size out - converting as we go */
723 cells
= cells_to_unit_address (cells
, ®
->size
,
724 hw_unit_nr_size_cells (hw_parent (me
)));
726 return node
->sizeof_array
/ sizeof_entry
;
731 hw_add_string_property (struct hw
*me
,
732 const char *property
,
735 hw_add_property (me
, property
, string_property
,
736 string
, strlen(string
) + 1,
737 string
, strlen(string
) + 1,
738 NULL
, permenant_object
);
742 hw_find_string_property (struct hw
*me
,
743 const char *property
)
745 const struct hw_property
*node
;
747 node
= hw_find_property (me
, property
);
748 if (node
== NULL
|| node
->type
!= string_property
)
749 hw_abort (me
, "property %s not found or of wrong type", property
);
750 string
= node
->array
;
751 ASSERT (strlen(string
) + 1 == node
->sizeof_array
);
756 hw_add_string_array_property (struct hw
*me
,
757 const char *property
,
758 const string_property_spec
*strings
,
766 hw_abort (me
, "property %s must be non-null", property
);
767 /* total up the size of the needed array */
768 for (sizeof_array
= 0, string_nr
= 0;
769 string_nr
< nr_strings
;
772 sizeof_array
+= strlen (strings
[string_nr
]) + 1;
774 /* create the array */
775 array
= (char*) hw_zalloc (me
, sizeof_array
);
778 string_nr
< nr_strings
;
781 strcpy (chp
, strings
[string_nr
]);
782 chp
+= strlen (chp
) + 1;
784 ASSERT (chp
== array
+ sizeof_array
);
786 hw_add_property (me
, property
, string_array_property
,
789 NULL
, permenant_object
);
793 hw_find_string_array_property (struct hw
*me
,
794 const char *property
,
796 string_property_spec
*string
)
798 const struct hw_property
*node
;
799 node
= hw_find_property (me
, property
);
801 hw_abort (me
, "property %s not found", property
);
805 hw_abort (me
, "property %s of wrong type", property
);
807 case string_property
:
810 *string
= node
->array
;
811 ASSERT (strlen(*string
) + 1 == node
->sizeof_array
);
816 if (node
->sizeof_array
== 0
817 || ((char*)node
->array
)[node
->sizeof_array
- 1] != '\0')
818 hw_abort (me
, "property %s invalid for string array", property
);
820 case string_array_property
:
821 ASSERT (node
->sizeof_array
> 0);
822 ASSERT (((char*)node
->array
)[node
->sizeof_array
- 1] == '\0');
824 const char *chp
= node
->array
;
826 /* count the number of strings, keeping an eye out for the one
836 if (nr_entries
== index
)
843 } while (chp
< (char*)node
->array
+ node
->sizeof_array
);
844 if (index
< nr_entries
)
858 hw_add_duplicate_property (struct hw
*me
,
859 const char *property
,
860 const struct hw_property
*original
)
862 struct hw_property_data
*master
;
863 TRACE (trace_devices
,
864 ("hw_add_duplicate_property(me=0x%lx, property=%s, ...)\n",
865 (long)me
, property
));
866 if (original
->disposition
!= permenant_object
)
867 hw_abort (me
, "Can only duplicate permenant objects");
868 /* find the original's master */
869 master
= original
->owner
->properties_of_hw
;
870 while (master
->property
!= original
)
872 master
= master
->next
;
873 ASSERT(master
!= NULL
);
875 /* now duplicate it */
876 hw_add_property (me
, property
,
878 master
->init_array
, master
->sizeof_init_array
,
879 original
->array
, original
->sizeof_array
,
880 original
, permenant_object
);