diff options
Diffstat (limited to 'sim/common/hw-properties.c')
-rw-r--r-- | sim/common/hw-properties.c | 905 |
1 files changed, 905 insertions, 0 deletions
diff --git a/sim/common/hw-properties.c b/sim/common/hw-properties.c new file mode 100644 index 0000000..a1e9291 --- /dev/null +++ b/sim/common/hw-properties.c @@ -0,0 +1,905 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + +#include "hw-main.h" +#include "hw-base.h" + +#include "sim-assert.h" + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#define TRACE(A,B) + +/* property entries */ + +struct hw_property_data { + struct hw_property_data *next; + struct hw_property *property; + const void *init_array; + unsigned sizeof_init_array; +}; + +void +create_hw_property_data (struct hw *me) +{ +} + +void +delete_hw_property_data (struct hw *me) +{ +} + + +/* Device Properties: */ + +static struct hw_property_data * +find_property_data (struct hw *me, + const char *property) +{ + struct hw_property_data *entry; + ASSERT (property != NULL); + entry = me->properties_of_hw; + while (entry != NULL) + { + if (strcmp (entry->property->name, property) == 0) + return entry; + entry = entry->next; + } + return NULL; +} + + +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) +{ + struct hw_property_data *new_entry = NULL; + struct hw_property *new_value = NULL; + + /* find the list end */ + struct hw_property_data **insertion_point = &me->properties_of_hw; + while (*insertion_point != NULL) + { + if (strcmp ((*insertion_point)->property->name, property) == 0) + return; + insertion_point = &(*insertion_point)->next; + } + + /* create a new value */ + new_value = HW_ZALLOC (me, struct hw_property); + new_value->name = (char *) strdup (property); + new_value->type = type; + if (sizeof_array > 0) + { + void *new_array = hw_zalloc (me, sizeof_array); + memcpy (new_array, array, sizeof_array); + new_value->array = new_array; + new_value->sizeof_array = sizeof_array; + } + new_value->owner = me; + new_value->original = original; + new_value->disposition = disposition; + + /* insert the value into the list */ + new_entry = HW_ZALLOC (me, struct hw_property_data); + *insertion_point = new_entry; + if (sizeof_init_array > 0) + { + void *new_init_array = hw_zalloc (me, sizeof_init_array); + memcpy (new_init_array, init_array, sizeof_init_array); + new_entry->init_array = new_init_array; + new_entry->sizeof_init_array = sizeof_init_array; + } + new_entry->property = new_value; +} + + +static void +hw_set_property (struct hw *me, + const char *property, + hw_property_type type, + const void *array, + int sizeof_array) +{ + /* find the property */ + struct hw_property_data *entry = find_property_data (me, property); + if (entry != NULL) + { + /* existing property - update it */ + void *new_array = 0; + struct hw_property *value = entry->property; + /* check the type matches */ + if (value->type != type) + hw_abort (me, "conflict between type of new and old value for property %s", property); + /* replace its value */ + if (value->array != NULL) + hw_free (me, (void*)value->array); + new_array = (sizeof_array > 0 + ? hw_zalloc (me, sizeof_array) + : (void*)0); + value->array = new_array; + value->sizeof_array = sizeof_array; + if (sizeof_array > 0) + memcpy (new_array, array, sizeof_array); + return; + } + else + { + /* new property - create it */ + hw_add_property (me, property, type, + NULL, 0, array, sizeof_array, + NULL, temporary_object); + } +} + + +#if 0 +static void +clean_hw_properties (struct hw *me) +{ + struct hw_property_data **delete_point = &me->properties_of_hw; + while (*delete_point != NULL) + { + struct hw_property_data *current = *delete_point; + switch (current->property->disposition) + { + case permenant_object: + /* zap the current value, will be initialized later */ + ASSERT (current->init_array != NULL); + if (current->property->array != NULL) + { + hw_free (me, (void*)current->property->array); + current->property->array = NULL; + } + delete_point = &(*delete_point)->next; + break; + case temporary_object: + /* zap the actual property, was created during simulation run */ + ASSERT (current->init_array == NULL); + *delete_point = current->next; + if (current->property->array != NULL) + hw_free (me, (void*)current->property->array); + hw_free (me, current->property); + hw_free (me, current); + break; + } + } +} +#endif + +#if 0 +void +hw_init_static_properties (SIM_DESC sd, + struct hw *me, + void *data) +{ + struct hw_property_data *property; + for (property = me->properties_of_hw; + property != NULL; + property = property->next) + { + ASSERT (property->init_array != NULL); + ASSERT (property->property->array == NULL); + ASSERT(property->property->disposition == permenant_object); + switch (property->property->type) + { + case array_property: + case boolean_property: + case range_array_property: + case reg_array_property: + case string_property: + case string_array_property: + case integer_property: + /* delete the property, and replace it with the original */ + hw_set_property (me, property->property->name, + property->property->type, + property->init_array, + property->sizeof_init_array); + break; +#if 0 + case ihandle_property: + break; +#endif + } + } +} +#endif + + +#if 0 +void +hw_init_runtime_properties (SIM_DESC sd, + struct hw *me, + void *data) +{ + struct hw_property_data *property; + for (property = me->properties_of_hw; + property != NULL; + property = property->next) + { + switch (property->property->disposition) + { + case permenant_object: + switch (property->property->type) + { +#if 0 + case ihandle_property: + { + struct hw_instance *ihandle; + ihandle_runtime_property_spec spec; + ASSERT (property->init_array != NULL); + ASSERT (property->property->array == NULL); + hw_find_ihandle_runtime_property (me, property->property->name, &spec); + ihandle = tree_instance (me, spec.full_path); + hw_set_ihandle_property (me, property->property->name, ihandle); + break; + } +#endif + case array_property: + case boolean_property: + case range_array_property: + case integer_property: + case reg_array_property: + case string_property: + case string_array_property: + ASSERT (property->init_array != NULL); + ASSERT (property->property->array != NULL); + break; + } + break; + case temporary_object: + ASSERT (property->init_array == NULL); + ASSERT (property->property->array != NULL); + break; + } + } +} +#endif + + + +const struct hw_property * +hw_next_property (const struct hw_property *property) +{ + /* find the property in the list */ + struct hw *owner = property->owner; + struct hw_property_data *entry = owner->properties_of_hw; + while (entry != NULL && entry->property != property) + entry = entry->next; + /* now return the following property */ + ASSERT (entry != NULL); /* must be a member! */ + if (entry->next != NULL) + return entry->next->property; + else + return NULL; +} + + +const struct hw_property * +hw_find_property (struct hw *me, + const char *property) +{ + if (me == NULL) + { + return NULL; + } + else if (property == NULL || strcmp (property, "") == 0) + { + if (me->properties_of_hw == NULL) + return NULL; + else + return me->properties_of_hw->property; + } + else + { + struct hw_property_data *entry = find_property_data (me, property); + if (entry != NULL) + return entry->property; + } + return NULL; +} + + +void +hw_add_array_property (struct hw *me, + const char *property, + const void *array, + int sizeof_array) +{ + hw_add_property (me, property, array_property, + array, sizeof_array, array, sizeof_array, + NULL, permenant_object); +} + +void +hw_set_array_property (struct hw *me, + const char *property, + const void *array, + int sizeof_array) +{ + hw_set_property (me, property, array_property, array, sizeof_array); +} + +const struct hw_property * +hw_find_array_property (struct hw *me, + const char *property) +{ + const struct hw_property *node; + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != array_property) + hw_abort (me, "property \"%s\" of wrong type (array)", property); + return node; +} + + + +void +hw_add_boolean_property (struct hw *me, + const char *property, + int boolean) +{ + signed32 new_boolean = (boolean ? -1 : 0); + hw_add_property (me, property, boolean_property, + &new_boolean, sizeof(new_boolean), + &new_boolean, sizeof(new_boolean), + NULL, permenant_object); +} + +int +hw_find_boolean_property (struct hw *me, + const char *property) +{ + const struct hw_property *node; + unsigned_cell boolean; + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != boolean_property) + hw_abort (me, "property \"%s\" of wrong type (boolean)", property); + ASSERT (sizeof (boolean) == node->sizeof_array); + memcpy (&boolean, node->array, sizeof (boolean)); + return boolean; +} + + + +#if 0 +void +hw_add_ihandle_runtime_property (struct hw *me, + const char *property, + const ihandle_runtime_property_spec *ihandle) +{ + /* enter the full path as the init array */ + hw_add_property (me, property, ihandle_property, + ihandle->full_path, strlen(ihandle->full_path) + 1, + NULL, 0, + NULL, permenant_object); +} +#endif + +#if 0 +void +hw_find_ihandle_runtime_property (struct hw *me, + const char *property, + ihandle_runtime_property_spec *ihandle) +{ + struct hw_property_data *entry = find_property_data (me, property); + TRACE (trace_devices, + ("hw_find_ihandle_runtime_property(me=0x%lx, property=%s)\n", + (long)me, property)); + if (entry == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (entry->property->type != ihandle_property + || entry->property->disposition != permenant_object) + hw_abort (me, "property \"%s\" of wrong type", property); + ASSERT (entry->init_array != NULL); + /* the full path */ + ihandle->full_path = entry->init_array; +} +#endif + + + +#if 0 +void +hw_set_ihandle_property (struct hw *me, + const char *property, + hw_instance *ihandle) +{ + unsigned_cell cells; + cells = H2BE_cell (hw_instance_to_external (ihandle)); + hw_set_property (me, property, ihandle_property, + &cells, sizeof (cells)); + +} +#endif + +#if 0 +hw_instance * +hw_find_ihandle_property (struct hw *me, + const char *property) +{ + const hw_property_data *node; + unsigned_cell ihandle; + hw_instance *instance; + + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != ihandle_property) + hw_abort(me, "property \"%s\" of wrong type (ihandle)", property); + if (node->array == NULL) + hw_abort(me, "runtime property \"%s\" not yet initialized", property); + + ASSERT (sizeof(ihandle) == node->sizeof_array); + memcpy (&ihandle, node->array, sizeof(ihandle)); + instance = external_to_hw_instance (me, BE2H_cell(ihandle)); + ASSERT (instance != NULL); + return instance; +} +#endif + + +void +hw_add_integer_property (struct hw *me, + const char *property, + signed_cell integer) +{ + H2BE (integer); + hw_add_property (me, property, integer_property, + &integer, sizeof(integer), + &integer, sizeof(integer), + NULL, permenant_object); +} + +signed_cell +hw_find_integer_property (struct hw *me, + const char *property) +{ + const struct hw_property *node; + signed_cell integer; + TRACE (trace_devices, + ("hw_find_integer(me=0x%lx, property=%s)\n", + (long)me, property)); + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != integer_property) + hw_abort (me, "property \"%s\" of wrong type (integer)", property); + ASSERT (sizeof(integer) == node->sizeof_array); + memcpy (&integer, node->array, sizeof (integer)); + return BE2H_cell (integer); +} + +int +hw_find_integer_array_property (struct hw *me, + const char *property, + unsigned index, + signed_cell *integer) +{ + const struct hw_property *node; + int sizeof_integer = sizeof (*integer); + signed_cell *cell; + TRACE (trace_devices, + ("hw_find_integer(me=0x%lx, property=%s)\n", + (long)me, property)); + + /* check things sane */ + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != integer_property + && node->type != array_property) + hw_abort (me, "property \"%s\" of wrong type (integer or array)", property); + if ((node->sizeof_array % sizeof_integer) != 0) + hw_abort (me, "property \"%s\" contains an incomplete number of cells", property); + if (node->sizeof_array <= sizeof_integer * index) + return 0; + + /* Find and convert the value */ + cell = ((signed_cell*)node->array) + index; + *integer = BE2H_cell (*cell); + + return node->sizeof_array / sizeof_integer; +} + + +static unsigned_cell * +unit_address_to_cells (const hw_unit *unit, + unsigned_cell *cell, + int nr_cells) +{ + int i; + ASSERT(nr_cells == unit->nr_cells); + for (i = 0; i < unit->nr_cells; i++) + { + *cell = H2BE_cell (unit->cells[i]); + cell += 1; + } + return cell; +} + + +static const unsigned_cell * +cells_to_unit_address (const unsigned_cell *cell, + hw_unit *unit, + int nr_cells) +{ + int i; + memset(unit, 0, sizeof(*unit)); + unit->nr_cells = nr_cells; + for (i = 0; i < unit->nr_cells; i++) + { + unit->cells[i] = BE2H_cell (*cell); + cell += 1; + } + return cell; +} + + +static unsigned +nr_range_property_cells (struct hw *me, + int nr_ranges) +{ + return ((hw_unit_nr_address_cells (me) + + hw_unit_nr_address_cells (hw_parent (me)) + + hw_unit_nr_size_cells (me)) + ) * nr_ranges; +} + +void +hw_add_range_array_property (struct hw *me, + const char *property, + const range_property_spec *ranges, + unsigned nr_ranges) +{ + unsigned sizeof_cells = (nr_range_property_cells (me, nr_ranges) + * sizeof (unsigned_cell)); + unsigned_cell *cells = hw_zalloc (me, sizeof_cells); + unsigned_cell *cell; + int i; + + /* copy the property elements over */ + cell = cells; + for (i = 0; i < nr_ranges; i++) + { + const range_property_spec *range = &ranges[i]; + /* copy the child address */ + cell = unit_address_to_cells (&range->child_address, cell, + hw_unit_nr_address_cells (me)); + /* copy the parent address */ + cell = unit_address_to_cells (&range->parent_address, cell, + hw_unit_nr_address_cells (hw_parent (me))); + /* copy the size */ + cell = unit_address_to_cells (&range->size, cell, + hw_unit_nr_size_cells (me)); + } + ASSERT (cell == &cells[nr_range_property_cells (me, nr_ranges)]); + + /* add it */ + hw_add_property (me, property, range_array_property, + cells, sizeof_cells, + cells, sizeof_cells, + NULL, permenant_object); + + hw_free (me, cells); +} + +int +hw_find_range_array_property (struct hw *me, + const char *property, + unsigned index, + range_property_spec *range) +{ + const struct hw_property *node; + unsigned sizeof_entry = (nr_range_property_cells (me, 1) + * sizeof (unsigned_cell)); + const unsigned_cell *cells; + + /* locate the property */ + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != range_array_property) + hw_abort (me, "property \"%s\" of wrong type (range array)", property); + + /* aligned ? */ + if ((node->sizeof_array % sizeof_entry) != 0) + hw_abort (me, "property \"%s\" contains an incomplete number of entries", + property); + + /* within bounds? */ + if (node->sizeof_array < sizeof_entry * (index + 1)) + return 0; + + /* find the range of interest */ + cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index); + + /* copy the child address out - converting as we go */ + cells = cells_to_unit_address (cells, &range->child_address, + hw_unit_nr_address_cells (me)); + + /* copy the parent address out - converting as we go */ + cells = cells_to_unit_address (cells, &range->parent_address, + hw_unit_nr_address_cells (hw_parent (me))); + + /* copy the size - converting as we go */ + cells = cells_to_unit_address (cells, &range->size, + hw_unit_nr_size_cells (me)); + + return node->sizeof_array / sizeof_entry; +} + + +static unsigned +nr_reg_property_cells (struct hw *me, + int nr_regs) +{ + return (hw_unit_nr_address_cells (hw_parent(me)) + + hw_unit_nr_size_cells (hw_parent(me)) + ) * nr_regs; +} + +void +hw_add_reg_array_property (struct hw *me, + const char *property, + const reg_property_spec *regs, + unsigned nr_regs) +{ + unsigned sizeof_cells = (nr_reg_property_cells (me, nr_regs) + * sizeof (unsigned_cell)); + unsigned_cell *cells = hw_zalloc (me, sizeof_cells); + unsigned_cell *cell; + int i; + + /* copy the property elements over */ + cell = cells; + for (i = 0; i < nr_regs; i++) + { + const reg_property_spec *reg = ®s[i]; + /* copy the address */ + cell = unit_address_to_cells (®->address, cell, + hw_unit_nr_address_cells (hw_parent (me))); + /* copy the size */ + cell = unit_address_to_cells (®->size, cell, + hw_unit_nr_size_cells (hw_parent (me))); + } + ASSERT (cell == &cells[nr_reg_property_cells (me, nr_regs)]); + + /* add it */ + hw_add_property (me, property, reg_array_property, + cells, sizeof_cells, + cells, sizeof_cells, + NULL, permenant_object); + + hw_free (me, cells); +} + +int +hw_find_reg_array_property (struct hw *me, + const char *property, + unsigned index, + reg_property_spec *reg) +{ + const struct hw_property *node; + unsigned sizeof_entry = (nr_reg_property_cells (me, 1) + * sizeof (unsigned_cell)); + const unsigned_cell *cells; + + /* locate the property */ + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != reg_array_property) + hw_abort (me, "property \"%s\" of wrong type (reg array)", property); + + /* aligned ? */ + if ((node->sizeof_array % sizeof_entry) != 0) + hw_abort (me, "property \"%s\" contains an incomplete number of entries", + property); + + /* within bounds? */ + if (node->sizeof_array < sizeof_entry * (index + 1)) + return 0; + + /* find the range of interest */ + cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index); + + /* copy the address out - converting as we go */ + cells = cells_to_unit_address (cells, ®->address, + hw_unit_nr_address_cells (hw_parent (me))); + + /* copy the size out - converting as we go */ + cells = cells_to_unit_address (cells, ®->size, + hw_unit_nr_size_cells (hw_parent (me))); + + return node->sizeof_array / sizeof_entry; +} + + +void +hw_add_string_property (struct hw *me, + const char *property, + const char *string) +{ + hw_add_property (me, property, string_property, + string, strlen(string) + 1, + string, strlen(string) + 1, + NULL, permenant_object); +} + +const char * +hw_find_string_property (struct hw *me, + const char *property) +{ + const struct hw_property *node; + const char *string; + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != string_property) + hw_abort (me, "property \"%s\" of wrong type (string)", property); + string = node->array; + ASSERT (strlen(string) + 1 == node->sizeof_array); + return string; +} + +void +hw_add_string_array_property (struct hw *me, + const char *property, + const string_property_spec *strings, + unsigned nr_strings) +{ + int sizeof_array; + int string_nr; + char *array; + char *chp; + if (nr_strings == 0) + hw_abort (me, "property \"%s\" must be non-null", property); + /* total up the size of the needed array */ + for (sizeof_array = 0, string_nr = 0; + string_nr < nr_strings; + string_nr ++) + { + sizeof_array += strlen (strings[string_nr]) + 1; + } + /* create the array */ + array = (char*) hw_zalloc (me, sizeof_array); + chp = array; + for (string_nr = 0; + string_nr < nr_strings; + string_nr++) + { + strcpy (chp, strings[string_nr]); + chp += strlen (chp) + 1; + } + ASSERT (chp == array + sizeof_array); + /* now enter it */ + hw_add_property (me, property, string_array_property, + array, sizeof_array, + array, sizeof_array, + NULL, permenant_object); +} + +int +hw_find_string_array_property (struct hw *me, + const char *property, + unsigned index, + string_property_spec *string) +{ + const struct hw_property *node; + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + switch (node->type) + { + default: + hw_abort (me, "property \"%s\" of wrong type", property); + break; + case string_property: + if (index == 0) + { + *string = node->array; + ASSERT (strlen(*string) + 1 == node->sizeof_array); + return 1; + } + break; + case array_property: + if (node->sizeof_array == 0 + || ((char*)node->array)[node->sizeof_array - 1] != '\0') + hw_abort (me, "property \"%s\" invalid for string array", property); + /* FALL THROUGH */ + case string_array_property: + ASSERT (node->sizeof_array > 0); + ASSERT (((char*)node->array)[node->sizeof_array - 1] == '\0'); + { + const char *chp = node->array; + int nr_entries = 0; + /* count the number of strings, keeping an eye out for the one + we're looking for */ + *string = chp; + do + { + if (*chp == '\0') + { + /* next string */ + nr_entries++; + chp++; + if (nr_entries == index) + *string = chp; + } + else + { + chp++; + } + } while (chp < (char*)node->array + node->sizeof_array); + if (index < nr_entries) + return nr_entries; + else + { + *string = NULL; + return 0; + } + } + break; + } + return 0; +} + +void +hw_add_duplicate_property (struct hw *me, + const char *property, + const struct hw_property *original) +{ + struct hw_property_data *master; + TRACE (trace_devices, + ("hw_add_duplicate_property(me=0x%lx, property=%s, ...)\n", + (long)me, property)); + if (original->disposition != permenant_object) + hw_abort (me, "Can only duplicate permenant objects"); + /* find the original's master */ + master = original->owner->properties_of_hw; + while (master->property != original) + { + master = master->next; + ASSERT(master != NULL); + } + /* now duplicate it */ + hw_add_property (me, property, + original->type, + master->init_array, master->sizeof_init_array, + original->array, original->sizeof_array, + original, permenant_object); +} |