/* The common simulator framework for GDB, the GNU Debugger. Copyright 2002-2013 Free Software Foundation, Inc. Contributed by Andrew Cagney and Red Hat. This file is part of GDB. 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 3 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, see . */ #include "hw-main.h" #include "hw-base.h" #include "sim-io.h" #include "sim-assert.h" #ifdef HAVE_STRING_H #include #else #ifdef HAVE_STRINGS_H #include #endif #endif /* 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); HW_TRACE ((me, "hw_find_ihandle_runtime_property(property=%s)\n", 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; HW_TRACE ((me, "hw_find_integer(property=%s)\n", 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; HW_TRACE ((me, "hw_find_integer(property=%s)\n", 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; HW_TRACE ((me, "hw_add_duplicate_property(property=%s, ...)\n", 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); }