mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-30 21:44:19 +08:00
6df01ab8ab
The defs.h header will take care of including the various config.h headers. For now, it's just config.h, but we'll add more when we integrate gnulib in. This header should be used instead of config.h, and should be the first include in every .c file. We won't rely on the old behavior where we expected files to include the port's sim-main.h which then includes the common sim-basics.h which then includes config.h. We have a ton of code that includes things before sim-main.h, and it sometimes needs to be that way. Creating a dedicated header avoids the ordering mess and implicit inclusion that shows up otherwise.
892 lines
23 KiB
C
892 lines
23 KiB
C
/* The common simulator framework for GDB, the GNU Debugger.
|
|
|
|
Copyright 2002-2021 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 <http://www.gnu.org/licenses/>. */
|
|
|
|
/* This must come before any other includes. */
|
|
#include "defs.h"
|
|
|
|
#include "hw-main.h"
|
|
#include "hw-base.h"
|
|
|
|
#include "sim-io.h"
|
|
#include "sim-assert.h"
|
|
|
|
#include <string.h>
|
|
|
|
/* 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);
|
|
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;
|
|
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;
|
|
|
|
/* 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;
|
|
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);
|
|
}
|