From 775b309a4ed05c21bb05c2f325da04635bef44b0 Mon Sep 17 00:00:00 2001 From: Andrew Cagney Date: Sun, 22 Mar 1998 05:49:30 +0000 Subject: Copy function ../ppc/device_table.c:generic_device_init_address() to hw-base.c:do_hw_attach_regs(). Use in dv-pal. Add hw_tree_delete to hw-tree.c. --- sim/common/ChangeLog | 12 + sim/common/dv-pal.c | 2 + sim/common/hw-base.c | 64 ++- sim/common/hw-tree.c | 1316 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1390 insertions(+), 4 deletions(-) create mode 100644 sim/common/hw-tree.c (limited to 'sim') diff --git a/sim/common/ChangeLog b/sim/common/ChangeLog index 9ecbe04..e454601 100644 --- a/sim/common/ChangeLog +++ b/sim/common/ChangeLog @@ -1,3 +1,13 @@ +Sun Mar 22 16:45:54 1998 Andrew Cagney + + * hw-base.h, hw-base.c (do_hw_attach_regs): Copy function from + ../ppc/device_table.c. + + * dv-pal.c (hw_pal_finish): Attach PAL device to parent bus. + + * hw-tree.c (print_properties): Supress path when printing + properties of root node. + Sun Mar 22 16:21:15 1998 Andrew Cagney * hw-device.h (HW_TRACE): Define. @@ -32,6 +42,8 @@ Sun Mar 22 15:23:35 1998 Andrew Cagney (hw_create): Allocate the base type using HW_ZALLOC before setting any methods. + * hw-tree.h, hw-tree.c (hw_tree_delete): New function. + * hw-properties.c: Replace zalloc/zfree with hw_zalloc/hw_free. * hw-ports.c: Replace zalloc/zfree with hw_zalloc/hw_free. diff --git a/sim/common/dv-pal.c b/sim/common/dv-pal.c index 2e00c3b..c98ff68 100644 --- a/sim/common/dv-pal.c +++ b/sim/common/dv-pal.c @@ -385,6 +385,8 @@ hw_pal_finish (struct hw *hw) set_hw_io_read_buffer (hw, hw_pal_io_read_buffer); set_hw_io_write_buffer (hw, hw_pal_io_write_buffer); set_hw_ports (hw, hw_pal_ports); + /* attach ourselves */ + do_hw_attach_regs (me); } diff --git a/sim/common/hw-base.c b/sim/common/hw-base.c index ad17df4..2057e90 100644 --- a/sim/common/hw-base.c +++ b/sim/common/hw-base.c @@ -442,10 +442,6 @@ hw_create (SIM_DESC sd, } } - /* Fill in the (hopefully) defined trace variable */ - if (hw_find_property (hw, "trace?") != NULL) - hw->trace_of_hw_p = hw_find_boolean_property (hw, "trace?"); - /* Attach dummy ports */ set_hw_ports (hw, empty_hw_ports); set_hw_port_event (hw, panic_hw_port_event); @@ -478,6 +474,10 @@ hw_finish (struct hw *me) else me->nr_size_cells_of_hw_unit = 1; + /* Fill in the (hopefully) defined trace variable */ + if (hw_find_property (hw, "trace?") != NULL) + hw->trace_of_hw_p = hw_find_boolean_property (hw, "trace?"); + /* Allow the real device to override any methods */ me->base_of_hw->descriptor->to_finish (me); me->base_of_hw->finished_p = 1; @@ -523,3 +523,59 @@ hw_delete (struct hw *me) zfree (me->base_of_hw); zfree (me); } + + +/* Go through the devices various reg properties for those that + specify attach addresses */ + + +void +do_hw_attach_regs (struct hw *hw) +{ + static const char *(reg_property_names[]) = { + "attach-addresses", + "assigned-addresses", + "reg", + "alternate-reg" , + NULL + }; + const char **reg_property_name; + int nr_valid_reg_properties = 0; + for (reg_property_name = reg_property_names; + *reg_property_name != NULL; + reg_property_name++) + { + if (hw_find_property (hw, *reg_property_name) != NULL) + { + reg_property_spec reg; + int reg_entry; + for (reg_entry = 0; + hw_find_reg_array_property (hw, *reg_property_name, reg_entry, + ®); + reg_entry++) + { + unsigned_word attach_address; + int attach_space; + unsigned attach_size; + if (!hw_unit_address_to_attach_address (hw_parent (hw), + ®.address, + &attach_space, + &attach_address, + hw)) + continue; + if (!hw_unit_size_to_attach_size (hw_parent (hw), + ®.size, + &attach_size, hw)) + continue; + hw_attach_address (hw_parent (hw), + 0, + attach_space, attach_address, attach_size, + hw); + nr_valid_reg_properties++; + } + /* if first option matches don't try for any others */ + if (reg_property_name == reg_property_names) + break; + } + } +} diff --git a/sim/common/hw-tree.c b/sim/common/hw-tree.c new file mode 100644 index 0000000..219b75b --- /dev/null +++ b/sim/common/hw-tree.c @@ -0,0 +1,1316 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, Andrew Cagney + + 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 "sim-main.h" + +#include "hw-base.h" +#include "hw-tree.h" + +#include "sim-assert.h" + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#endif +#endif + +#include + +/* manipulate/lookup device names */ + +typedef struct _name_specifier { + + /* components in the full length name */ + char *path; + char *property; + char *value; + + /* current device */ + char *family; + char *name; + char *unit; + char *args; + + /* previous device */ + char *last_name; + char *last_family; + char *last_unit; + char *last_args; + + /* work area */ + char buf[1024]; + +} name_specifier; + + + +/* Given a device specifier, break it up into its main components: + path (and if present) property name and property value. */ + +static int +split_device_specifier (struct hw *current, + const char *device_specifier, + name_specifier *spec) +{ + char *chp = NULL; + + /* expand any leading alias if present */ + if (current != NULL + && *device_specifier != '\0' + && *device_specifier != '.' + && *device_specifier != '/') + { + struct hw *aliases = hw_tree_find_device (current, "/aliases"); + char alias[32]; + int len = 0; + while (device_specifier[len] != '\0' + && device_specifier[len] != '/' + && device_specifier[len] != ':' + && !isspace (device_specifier[len])) + { + alias[len] = device_specifier[len]; + len++; + if (len >= sizeof(alias)) + hw_abort (NULL, "split_device_specifier: buffer overflow"); + } + alias[len] = '\0'; + if (aliases != NULL + && hw_find_property (aliases, alias)) + { + strcpy (spec->buf, hw_find_string_property(aliases, alias)); + strcat (spec->buf, device_specifier + len); + } + else + { + strcpy (spec->buf, device_specifier); + } + } + else + { + strcpy(spec->buf, device_specifier); + } + + /* check no overflow */ + if (strlen(spec->buf) >= sizeof(spec->buf)) + hw_abort (NULL, "split_device_specifier: buffer overflow\n"); + + /* strip leading spaces */ + chp = spec->buf; + while (*chp != '\0' && isspace(*chp)) + chp++; + if (*chp == '\0') + return 0; + + /* find the path and terminate it with null */ + spec->path = chp; + while (*chp != '\0' && !isspace(*chp)) + chp++; + if (*chp != '\0') + { + *chp = '\0'; + chp++; + } + + /* and any value */ + while (*chp != '\0' && isspace(*chp)) + chp++; + spec->value = chp; + + /* now go back and chop the property off of the path */ + if (spec->value[0] == '\0') + { + spec->property = NULL; /*not a property*/ + spec->value = NULL; + } + else if (spec->value[0] == '>' + || spec->value[0] == '<') + { + /* an interrupt spec */ + spec->property = NULL; + } + else { + chp = strrchr(spec->path, '/'); + if (chp == NULL) + { + spec->property = spec->path; + spec->path = strchr(spec->property, '\0'); + } + else { + *chp = '\0'; + spec->property = chp+1; + } + } + + /* and mark the rest as invalid */ + spec->name = NULL; + spec->family = NULL; + spec->unit = NULL; + spec->args = NULL; + spec->last_name = NULL; + spec->last_family = NULL; + spec->last_unit = NULL; + spec->last_args = NULL; + + return 1; +} + + +/* given a device specifier break it up into its main components - + path and property name - assuming that the last `device' is a + property name. */ + +static int +split_property_specifier (struct hw *current, + const char *property_specifier, + name_specifier *spec) +{ + if (split_device_specifier (current, property_specifier, spec)) + { + if (spec->property == NULL) + { + /* force the last name to be a property name */ + char *chp = strrchr (spec->path, '/'); + if (chp == NULL) + { + spec->property = spec->path; + spec->path = strrchr (spec->property, '\0');; + } + else + { + *chp = '\0'; + spec->property = chp + 1; + } + } + return 1; + } + else + return 0; +} + + +/* device the next device name and split it up, return 0 when no more + names to struct hw */ + +static int +split_device_name (name_specifier *spec) +{ + char *chp; + /* remember what came before */ + spec->last_name = spec->name; + spec->last_family = spec->family; + spec->last_unit = spec->unit; + spec->last_args = spec->args; + /* finished? */ + if (spec->path[0] == '\0') + { + spec->name = NULL; + spec->family = NULL; + spec->unit = NULL; + spec->args = NULL; + return 0; + } + /* break the current device spec from the path */ + spec->name = spec->path; + chp = strchr (spec->name, '/'); + if (chp == NULL) + spec->path = strchr (spec->name, '\0'); + else + { + spec->path = chp+1; + *chp = '\0'; + } + /* break out the base */ + if (spec->name[0] == '(') + { + chp = strchr(spec->name, ')'); + if (chp == NULL) + { + spec->family = spec->name; + } + else + { + *chp = '\0'; + spec->family = spec->name + 1; + spec->name = chp + 1; + } + } + else + { + spec->family = spec->name; + } + /* now break out the unit */ + chp = strchr(spec->name, '@'); + if (chp == NULL) + { + spec->unit = NULL; + chp = spec->name; + } + else + { + *chp = '\0'; + chp += 1; + spec->unit = chp; + } + /* finally any args */ + chp = strchr(chp, ':'); + if (chp == NULL) + spec->args = NULL; + else + { + *chp = '\0'; + spec->args = chp+1; + } + return 1; +} + + +/* device the value, returning the next non-space token */ + +static char * +split_value (name_specifier *spec) +{ + char *token; + if (spec->value == NULL) + return NULL; + /* skip leading white space */ + while (isspace (spec->value[0])) + spec->value++; + if (spec->value[0] == '\0') + { + spec->value = NULL; + return NULL; + } + token = spec->value; + /* find trailing space */ + while (spec->value[0] != '\0' && !isspace (spec->value[0])) + spec->value++; + /* chop this value out */ + if (spec->value[0] != '\0') + { + spec->value[0] = '\0'; + spec->value++; + } + return token; +} + + + +/* traverse the path specified by spec starting at current */ + +static struct hw * +split_find_device (struct hw *current, + name_specifier *spec) +{ + /* strip off (and process) any leading ., .., ./ and / */ + while (1) + { + if (strncmp (spec->path, "/", strlen ("/")) == 0) + { + /* cd /... */ + while (current != NULL && hw_parent (current) != NULL) + current = hw_parent (current); + spec->path += strlen ("/"); + } + else if (strncmp (spec->path, "./", strlen ("./")) == 0) + { + /* cd ./... */ + current = current; + spec->path += strlen ("./"); + } + else if (strncmp (spec->path, "../", strlen ("../")) == 0) + { + /* cd ../... */ + if (current != NULL && hw_parent (current) != NULL) + current = hw_parent (current); + spec->path += strlen ("../"); + } + else if (strcmp (spec->path, ".") == 0) + { + /* cd . */ + current = current; + spec->path += strlen ("."); + } + else if (strcmp (spec->path, "..") == 0) + { + /* cd .. */ + if (current != NULL && hw_parent (current) != NULL) + current = hw_parent (current); + spec->path += strlen (".."); + } + else + break; + } + + /* now go through the path proper */ + + if (current == NULL) + { + split_device_name (spec); + return NULL; + } + + while (split_device_name (spec)) + { + struct hw *child; + for (child = hw_child (current); + child != NULL; child = hw_sibling (child)) + { + if (strcmp (spec->name, hw_name (child)) == 0) + { + if (spec->unit == NULL) + break; + else + { + hw_unit phys; + hw_unit_decode (current, spec->unit, &phys); + if (memcmp (&phys, hw_unit_address (child), + sizeof (hw_unit)) == 0) + break; + } + } + } + if (child == NULL) + return current; /* search failed */ + current = child; + } + + return current; +} + + +static struct hw * +split_fill_path (struct hw *current, + const char *device_specifier, + name_specifier *spec) +{ + /* break it up */ + if (!split_device_specifier (current, device_specifier, spec)) + hw_abort (current, "error parsing %s\n", device_specifier); + + /* fill our tree with its contents */ + current = split_find_device (current, spec); + + /* add any additional devices as needed */ + if (spec->name != NULL) + { + do + { + if (current != NULL && !hw_finished_p (current)) + hw_finish (current); + current = hw_create (NULL, + current, + spec->family, + spec->name, + spec->unit, + spec->args); + } + while (split_device_name (spec)); + } + + return current; +} + + +/* */ + +static const char * +skip_token(const char *chp) +{ + while (!isspace(*chp) && *chp != '\0') + chp++; + while (isspace(*chp) && *chp != '\0') + chp++; + return chp; +} + + +/* count the number of entries */ + +static int +count_entries (struct hw *current, + const char *property_name, + const char *property_value, + int modulo) +{ + const char *chp = property_value; + int nr_entries = 0; + while (*chp != '\0') + { + nr_entries += 1; + chp = skip_token (chp); + } + if ((nr_entries % modulo) != 0) + { + hw_abort (current, "incorrect number of entries for %s property %s, should be multiple of %d", + property_name, property_value, modulo); + } + return nr_entries / modulo; +} + + + +/* parse:
::= ; device dependant */ + +static const char * +parse_address (struct hw *current, + struct hw *bus, + const char *chp, + hw_unit *address) +{ + if (hw_unit_decode (bus, chp, address) < 0) + hw_abort (current, "invalid unit address in %s", chp); + return skip_token (chp); +} + + +/* parse: ::= { "," } ; */ + +static const char * +parse_size (struct hw *current, + struct hw *bus, + const char *chp, + hw_unit *size) +{ + int i; + int nr; + const char *curr = chp; + memset(size, 0, sizeof(*size)); + /* parse the numeric list */ + size->nr_cells = hw_unit_nr_size_cells (bus); + nr = 0; + while (1) + { + char *next; + size->cells[nr] = strtoul (curr, &next, 0); + if (curr == next) + hw_abort (current, "Problem parsing %s", chp); + nr += 1; + if (next[0] != ',') + break; + if (nr == size->nr_cells) + hw_abort (current, "Too many values in %s", chp); + curr = next + 1; + } + ASSERT (nr > 0 && nr <= size->nr_cells); + /* right align the numbers */ + for (i = 1; i <= size->nr_cells; i++) + { + if (i <= nr) + size->cells[size->nr_cells - i] = size->cells[nr - i]; + else + size->cells[size->nr_cells - i] = 0; + } + return skip_token (chp); +} + + +/* parse: ::= {
} ; */ + +static void +parse_reg_property (struct hw *current, + const char *property_name, + const char *property_value) +{ + int nr_regs; + int reg_nr; + reg_property_spec *regs; + const char *chp; + + /* determine the number of reg entries by counting tokens */ + nr_regs = count_entries (current, property_name, property_value, 2); + + /* create working space */ + regs = zalloc (nr_regs * sizeof (*regs)); + + /* fill it in */ + chp = property_value; + for (reg_nr = 0; reg_nr < nr_regs; reg_nr++) + { + chp = parse_address (current, hw_parent(current), + chp, ®s[reg_nr].address); + chp = parse_size (current, hw_parent(current), + chp, ®s[reg_nr].size); + } + + /* create it */ + hw_add_reg_array_property (current, property_name, + regs, nr_regs); + + zfree (regs); +} + + +/* { }* */ + +static void +parse_ranges_property (struct hw *current, + const char *property_name, + const char *property_value) +{ + int nr_ranges; + int range_nr; + range_property_spec *ranges; + const char *chp; + + /* determine the number of ranges specified */ + nr_ranges = count_entries (current, property_name, property_value, 3); + + /* create a property of that size */ + ranges = zalloc (nr_ranges * sizeof(*ranges)); + + /* fill it in */ + chp = property_value; + for (range_nr = 0; range_nr < nr_ranges; range_nr++) + { + chp = parse_address (current, current, + chp, &ranges[range_nr].child_address); + chp = parse_address (current, hw_parent(current), + chp, &ranges[range_nr].parent_address); + chp = parse_size (current, current, + chp, &ranges[range_nr].size); + } + + /* create it */ + hw_add_range_array_property (current, property_name, ranges, nr_ranges); + + zfree (ranges); +} + + +/* ... */ + +static void +parse_integer_property (struct hw *current, + const char *property_name, + const char *property_value) +{ + int nr_entries; + unsigned_cell words[1024]; + /* integer or integer array? */ + nr_entries = 0; + while (1) + { + char *end; + words[nr_entries] = strtoul (property_value, &end, 0); + if (property_value == end) + break; + nr_entries += 1; + if (nr_entries * sizeof (words[0]) >= sizeof (words)) + hw_abort (current, "buffer overflow"); + property_value = end; + } + if (nr_entries == 0) + hw_abort (current, "error parsing integer property %s (%s)", + property_name, property_value); + else if (nr_entries == 1) + hw_add_integer_property (current, property_name, words[0]); + else + { + int i; + for (i = 0; i < nr_entries; i++) + { + H2BE (words[i]); + } + /* perhaphs integer array property is better */ + hw_add_array_property (current, property_name, words, + sizeof(words[0]) * nr_entries); + } +} + + +/* ... */ + +static void +parse_string_property (struct hw *current, + const char *property_name, + const char *property_value) +{ + char **strings; + const char *chp; + int nr_strings; + int approx_nr_strings; + + /* get an estimate as to the number of strings by counting double + quotes */ + approx_nr_strings = 2; + for (chp = property_value; *chp; chp++) + { + if (*chp == '"') + approx_nr_strings++; + } + approx_nr_strings = (approx_nr_strings) / 2; + + /* create a string buffer for that many (plus a null) */ + strings = (char**) zalloc ((approx_nr_strings + 1) * sizeof(char*)); + + /* now find all the strings */ + chp = property_value; + nr_strings = 0; + while (1) + { + + /* skip leading space */ + while (*chp != '\0' && isspace (*chp)) + chp += 1; + if (*chp == '\0') + break; + + /* copy it in */ + if (*chp == '"') + { + /* a quoted string - watch for '\' et.al. */ + /* estimate the size and allocate space for it */ + int pos; + chp++; + pos = 0; + while (chp[pos] != '\0' && chp[pos] != '"') + { + if (chp[pos] == '\\' && chp[pos+1] != '\0') + pos += 2; + else + pos += 1; + } + strings[nr_strings] = zalloc (pos + 1); + /* copy the string over */ + pos = 0; + while (*chp != '\0' && *chp != '"') + { + if (*chp == '\\' && *(chp+1) != '\0') { + strings[nr_strings][pos] = *(chp+1); + chp += 2; + pos++; + } + else + { + strings[nr_strings][pos] = *chp; + chp += 1; + pos++; + } + } + if (*chp != '\0') + chp++; + strings[nr_strings][pos] = '\0'; + } + else + { + /* copy over a single unquoted token */ + int len = 0; + while (chp[len] != '\0' && !isspace(chp[len])) + len++; + strings[nr_strings] = zalloc(len + 1); + strncpy(strings[nr_strings], chp, len); + strings[nr_strings][len] = '\0'; + chp += len; + } + nr_strings++; + if (nr_strings > approx_nr_strings) + hw_abort (current, "String property %s badly formatted", + property_name); + } + ASSERT (strings[nr_strings] == NULL); /* from zalloc */ + + /* install it */ + if (nr_strings == 0) + hw_add_string_property (current, property_name, ""); + else if (nr_strings == 1) + hw_add_string_property (current, property_name, strings[0]); + else + { + const char **specs = (const char**) strings; /* stop a bogus error */ + hw_add_string_array_property (current, property_name, + specs, nr_strings); + } + + /* flush the created string */ + while (nr_strings > 0) + { + nr_strings--; + zfree (strings[nr_strings]); + } + zfree(strings); +} + + +/* */ + +#if NOT_YET +static void +parse_ihandle_property (struct hw *current, + const char *property, + const char *value) +{ + ihandle_runtime_property_spec ihandle; + + /* pass the full path */ + ihandle.full_path = value; + + /* save this ready for the ihandle create */ + hw_add_ihandle_runtime_property (current, property, + &ihandle); +} +#endif + + +struct hw * +hw_tree_create (SIM_DESC sd, + const char *family) +{ + return hw_create (sd, NULL, family, family, NULL, NULL); +} + +void +hw_tree_delete (struct hw *me) +{ + /* Need to allow devices to disapear under our feet */ + while (hw_child (me) != NULL) + { + hw_tree_delete (hw_child (me)); + } + hw_delete (me); +} + + +struct hw * +hw_tree_parse (struct hw *current, + const char *fmt, + ...) +{ + char device_specifier[1024]; + name_specifier spec; + + /* format the path */ + { + va_list ap; + va_start (ap, fmt); + vsprintf (device_specifier, fmt, ap); + va_end (ap); + if (strlen (device_specifier) >= sizeof (device_specifier)) + hw_abort (NULL, "device_tree_add_deviced: buffer overflow\n"); + } + + /* construct the tree down to the final struct hw */ + current = split_fill_path (current, device_specifier, &spec); + + /* is there an interrupt spec */ + if (spec.property == NULL + && spec.value != NULL) + { + char *op = split_value (&spec); + switch (op[0]) + { + case '>': + { + char *my_port_name = split_value (&spec); + int my_port; + char *dest_port_name = split_value (&spec); + int dest_port; + name_specifier dest_spec; + char *dest_hw_name = split_value (&spec); + struct hw *dest; + /* find my name */ + my_port = hw_port_decode (current, my_port_name, + output_port); + /* find the dest device and port */ + dest = split_fill_path(current, dest_hw_name, &dest_spec); + dest_port = hw_port_decode (dest, dest_port_name, + input_port); + /* connect the two */ + hw_port_attach (current, + my_port, + dest, + dest_port, + permenant_object); + break; + } + default: + hw_abort (current, "unreconised interrupt spec %s\n", spec.value); + break; + } + } + + /* is there a property */ + if (spec.property != NULL) + { + if (strcmp (spec.value, "true") == 0) + hw_add_boolean_property (current, spec.property, 1); + else if (strcmp (spec.value, "false") == 0) + hw_add_boolean_property (current, spec.property, 0); + else + { + const struct hw_property *property; + switch (spec.value[0]) + { +#if NOT_YET + case '*': + { + parse_ihandle_property (current, spec.property, spec.value + 1); + break; + } +#endif + case '[': + { + unsigned8 words[1024]; + char *curr = spec.value + 1; + int nr_words = 0; + while (1) + { + char *next; + words[nr_words] = H2BE_1 (strtoul (curr, &next, 0)); + if (curr == next) + break; + curr = next; + nr_words += 1; + } + hw_add_array_property (current, spec.property, + words, sizeof(words[0]) * nr_words); + break; + } + case '"': + { + parse_string_property (current, spec.property, spec.value); + break; + } + case '!': + { + spec.value++; + property = hw_tree_find_property (current, spec.value); + if (property == NULL) + hw_abort (current, "property %s not found\n", spec.value); + hw_add_duplicate_property (current, + spec.property, + property); + break; + } + default: + { + if (strcmp (spec.property, "reg") == 0 + || strcmp (spec.property, "assigned-addresses") == 0 + || strcmp (spec.property, "alternate-reg") == 0) + { + parse_reg_property (current, spec.property, spec.value); + } + else if (strcmp (spec.property, "ranges") == 0) + { + parse_ranges_property (current, spec.property, spec.value); + } + else if (isdigit(spec.value[0]) + || (spec.value[0] == '-' && isdigit(spec.value[1])) + || (spec.value[0] == '+' && isdigit(spec.value[1]))) + { + parse_integer_property(current, spec.property, spec.value); + } + else + parse_string_property(current, spec.property, spec.value); + break; + } + } + } + } + return current; +} + + +static void +finish_hw_tree (struct hw *me, + void *data) +{ + if (!hw_finished_p (me)) + hw_finish (me); +} + +void +hw_tree_finish (struct hw *root) +{ + hw_tree_traverse (root, finish_hw_tree, NULL, NULL); +} + + + +void +hw_tree_traverse (struct hw *root, + hw_tree_traverse_function *prefix, + hw_tree_traverse_function *postfix, + void *data) +{ + struct hw *child; + if (prefix != NULL) + prefix (root, data); + for (child = hw_child (root); + child != NULL; + child = hw_sibling (child)) + { + hw_tree_traverse (child, prefix, postfix, data); + } + if (postfix != NULL) + postfix (root, data); +} + + +static void hw_printf +(struct hw *, + const char *, + ...) __attribute__ ((format (printf, 2, 3))); + +static void +hw_printf (struct hw *me, + const char *fmt, + ...) +{ + va_list ap; + va_start (ap, fmt); + sim_io_vprintf (hw_system (me), fmt, ap); + va_end (ap); +} + + +static void +print_address (struct hw *bus, + const hw_unit *phys) +{ + char unit[32]; + hw_unit_encode (bus, phys, unit, sizeof(unit)); + hw_printf (bus, " %s", unit); +} + +static void +print_size (struct hw *bus, + const hw_unit *size) +{ + int i; + for (i = 0; i < size->nr_cells; i++) + if (size->cells[i] != 0) + break; + if (i < size->nr_cells) { + hw_printf (bus, " 0x%lx", (unsigned long) size->cells[i]); + i++; + for (; i < size->nr_cells; i++) + hw_printf (bus, ",0x%lx", (unsigned long) size->cells[i]); + } + else + hw_printf (bus, " 0"); +} + +static void +print_reg_property(struct hw *me, + const struct hw_property *property) +{ + int reg_nr; + reg_property_spec reg; + for (reg_nr = 0; + hw_find_reg_array_property (me, property->name, reg_nr, ®); + reg_nr++) { + print_address (hw_parent (me), ®.address); + print_size (me, ®.size); + } +} + +static void +print_ranges_property(struct hw *me, + const struct hw_property *property) +{ + int range_nr; + range_property_spec range; + for (range_nr = 0; + hw_find_range_array_property (me, property->name, range_nr, &range); + range_nr++) + { + print_address (me, &range.child_address); + print_address (hw_parent (me), &range.parent_address); + print_size (me, &range.size); + } +} + +static void +print_string (struct hw *me, + const char *string) +{ + hw_printf (me, " \""); + while (*string != '\0') { + switch (*string) { + case '"': + hw_printf (me, "\\\""); + break; + case '\\': + hw_printf (me, "\\\\"); + break; + default: + hw_printf (me, "%c", *string); + break; + } + string++; + } + hw_printf (me, "\""); +} + +static void +print_string_array_property (struct hw *me, + const struct hw_property *property) +{ + int nr; + string_property_spec string; + for (nr = 0; + hw_find_string_array_property (me, property->name, nr, &string); + nr++) + { + print_string (me, string); + } +} + +static void +print_properties (struct hw *me) +{ + const struct hw_property *property; + for (property = hw_find_property (me, NULL); + property != NULL; + property = hw_next_property (property)) + { + if (hw_parent (me) == NULL) + hw_printf (me, "/%s", property->name); + else + hw_printf (me, "%s/%s", hw_path (me), property->name); + if (property->original != NULL) + { + hw_printf (me, " !"); + hw_printf (me, "%s/%s", + hw_path (property->original->owner), + property->original->name); + } + else + { + switch (property->type) + { + case array_property: + { + if ((property->sizeof_array % sizeof (signed_cell)) == 0) + { + unsigned_cell *w = (unsigned_cell*) property->array; + int cell_nr; + for (cell_nr = 0; + cell_nr < (property->sizeof_array / sizeof (unsigned_cell)); + cell_nr++) + { + hw_printf (me, " 0x%lx", (unsigned long) BE2H_cell (w[cell_nr])); + } + } + else + { + unsigned8 *w = (unsigned8*)property->array; + hw_printf (me, " ["); + while ((char*)w - (char*)property->array < property->sizeof_array) { + hw_printf (me, " 0x%2x", BE2H_1 (*w)); + w++; + } + } + break; + } + case boolean_property: + { + int b = hw_find_boolean_property(me, property->name); + hw_printf (me, " %s", b ? "true" : "false"); + break; + } +#if NOT_YET + case ihandle_property: + { + if (property->array != NULL) + { + device_instance *instance = hw_find_ihandle_property (me, property->name); + hw_printf (me, " *%s", device_instance_path(instance)); + } + else + { + /* not yet initialized, ask the device for the path */ + ihandle_runtime_property_spec spec; + hw_find_ihandle_runtime_property (me, property->name, &spec); + hw_printf (me, " *%s", spec.full_path); + } + break; + } +#endif + case integer_property: + { + unsigned_word w = hw_find_integer_property (me, property->name); + hw_printf (me, " 0x%lx", (unsigned long)w); + break; + } + case range_array_property: + { + print_ranges_property (me, property); + break; + } + case reg_array_property: + { + print_reg_property (me, property); + break; + } + case string_property: + { + const char *s = hw_find_string_property (me, property->name); + print_string (me, s); + break; + } + case string_array_property: + { + print_string_array_property (me, property); + break; + } + } + } + hw_printf (me, "\n"); + } +} + +static void +print_interrupts (struct hw *me, + int my_port, + struct hw *dest, + int dest_port, + void *ignore_or_null) +{ + char src[32]; + char dst[32]; + hw_port_encode (me, my_port, src, sizeof(src), output_port); + hw_port_encode (dest, dest_port, dst, sizeof(dst), input_port); + hw_printf (me, "%s > %s %s %s\n", + hw_path (me), + src, dst, + hw_path (dest)); +} + +static void +print_device (struct hw *me, + void *ignore_or_null) +{ + hw_printf (me, "%s\n", hw_path (me)); + print_properties (me); + hw_port_traverse (me, print_interrupts, NULL); +} + +void +hw_tree_print (struct hw *root) +{ + hw_tree_traverse (root, + print_device, NULL, + NULL); +} + + + +#if NOT_YET +device_instance * +tree_instance(struct hw *root, + const char *device_specifier) +{ + /* find the device node */ + struct hw *me; + name_specifier spec; + if (!split_device_specifier(root, device_specifier, &spec)) + return NULL; + me = split_find_device(root, &spec); + if (spec.name != NULL) + return NULL; + /* create the instance */ + return device_create_instance(me, device_specifier, spec.last_args); +} +#endif + +struct hw * +hw_tree_find_device (struct hw *root, + const char *path_to_device) +{ + struct hw *node; + name_specifier spec; + + /* parse the path */ + split_device_specifier (root, path_to_device, &spec); + if (spec.value != NULL) + return NULL; /* something wierd */ + + /* now find it */ + node = split_find_device (root, &spec); + if (spec.name != NULL) + return NULL; /* not a leaf */ + + return node; +} + + +const struct hw_property * +hw_tree_find_property (struct hw *root, + const char *path_to_property) +{ + name_specifier spec; + if (!split_property_specifier (root, path_to_property, &spec)) + hw_abort (root, "Invalid property path %s", path_to_property); + root = split_find_device (root, &spec); + return hw_find_property (root, spec.property); +} + +int +hw_tree_find_boolean_property (struct hw *root, + const char *path_to_property) +{ + name_specifier spec; + if (!split_property_specifier (root, path_to_property, &spec)) + hw_abort (root, "Invalid property path %s", path_to_property); + root = split_find_device (root, &spec); + return hw_find_boolean_property (root, spec.property); +} + +signed_cell +hw_tree_find_integer_property (struct hw *root, + const char *path_to_property) +{ + name_specifier spec; + if (!split_property_specifier (root, path_to_property, &spec)) + hw_abort (root, "Invalid property path %s", path_to_property); + root = split_find_device (root, &spec); + return hw_find_integer_property (root, spec.property); +} + +#if NOT_YET +device_instance * +hw_tree_find_ihandle_property (struct hw *root, + const char *path_to_property) +{ + name_specifier spec; + if (!split_property_specifier (root, path_to_property, &spec)) + hw_abort (root, "Invalid property path %s", path_to_property); + root = split_find_device (root, &spec); + return hw_find_ihandle_property (root, spec.property); +} +#endif + +const char * +hw_tree_find_string_property (struct hw *root, + const char *path_to_property) +{ + name_specifier spec; + if (!split_property_specifier (root, path_to_property, &spec)) + hw_abort (root, "Invalid property path %s", path_to_property); + root = split_find_device (root, &spec); + return hw_find_string_property (root, spec.property); +} -- cgit v1.1