diff options
Diffstat (limited to 'gdb/arc-registers.c')
-rw-r--r-- | gdb/arc-registers.c | 2566 |
1 files changed, 2566 insertions, 0 deletions
diff --git a/gdb/arc-registers.c b/gdb/arc-registers.c new file mode 100644 index 00000000000..c0f7710cbb6 --- /dev/null +++ b/gdb/arc-registers.c @@ -0,0 +1,2566 @@ +/* Target dependent code for ARC processor family, for GDB, the GNU debugger. + + Copyright 2008, 2009 Free Software Foundation, Inc. + + Contributed by ARC International (www.arc.com) + + Author: + Richard Stuckey <richard.stuckey@arc.com> + + 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/>. */ + +/******************************************************************************/ +/* */ +/* Outline: */ +/* This module implements operations for manipulating the ARC processor */ +/* core registers and auxiliary registers. */ +/* */ +/******************************************************************************/ + +/* system header files */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +/* gdb header files */ +#include "defs.h" +#include "gdbcmd.h" +#include "regcache.h" +#include "objfiles.h" +#include "inferior.h" +#include "target.h" +#include "xml-support.h" +#include "gdb_assert.h" + +/* ARC header files */ +#include "arc-registers.h" +#include "arc-architecture.h" +#include "arc-tdep.h" +#include "arc-elf32-tdep.h" +#include "config/arc/tm-embed.h" + +/* ARC simulator header files */ +#include "sim/arc/arc-sim-registers.h" + + +/* -------------------------------------------------------------------------- */ +/* local types */ +/* -------------------------------------------------------------------------- */ + +typedef struct field_meaning +{ + char *description; + ARC_RegisterContents value; +} ARC_FieldMeaning; + + +typedef struct field_definition +{ + char *name; + char *description; + unsigned int offset; + unsigned int size; + RegisterAccess access; + ARC_RegisterContents value_for_write; + Boolean fixed; + ARC_FieldMeaning *meanings; + unsigned int meaning_count; +} ARC_FieldDefinition; + + +/* Complete the type (declared in the header file) here. */ +struct aux_register_definition +{ + char *name; + char *description; + ARC_RegisterNumber number; /* The number in the auxiliary register space. */ + int gdb_regno; + Boolean is_BCR; + ARC_Word mask; + RegisterAccess access; + ARC_FieldDefinition *fields; + unsigned int field_count; + unsigned int longest_field_name; + unsigned int max_bits_in_field; +}; + + +/* An instance of this structure is used to pass state data + between the parsing routines. + + The information is accumulated into the 'info' * field; + as each register or field description is parsed, the + information is held in the 'reg' or 'field' field before + validation is performed. If the information is valid, + it is copied into the 'info' structure. */ +typedef struct parsing_data +{ + const char *filename; + ARC_RegisterInfo *info; + ARC_AuxRegisterDefinition *currentRegister; + ARC_FieldDefinition *currentField; + ARC_RegisterContents maxFieldContents; + ARC_AuxRegisterDefinition reg; + ARC_FieldDefinition field; +} ParsingData; + + +/* -------------------------------------------------------------------------- */ +/* forward declarations */ +/* -------------------------------------------------------------------------- */ + +static gdb_xml_element_start_handler start_architecture; +static gdb_xml_element_end_handler end_architecture; +static gdb_xml_element_start_handler start_feature; +static gdb_xml_element_start_handler start_target; +static gdb_xml_element_start_handler start_auxregister; +static gdb_xml_element_start_handler start_bcr; +static gdb_xml_element_start_handler start_ecr; +static gdb_xml_element_start_handler start_field; +static gdb_xml_element_start_handler start_bcrfield; +static gdb_xml_element_start_handler start_meaning; + + +/* -------------------------------------------------------------------------- */ +/* externally visible data */ +/* -------------------------------------------------------------------------- */ + +/* This indicates whether a 'register architecture changed' event must be sent, + but has not yet been sent. */ +Boolean arc_pending_register_architecture_change_event; + + +/* -------------------------------------------------------------------------- */ +/* local data */ +/* -------------------------------------------------------------------------- */ + +#define REG_READ_FILE_COMMAND "arc-reg-read-file" +#define REG_READ_EXTRA_FILE_COMMAND "arc-reg-read-extra-file" +#define AUX_REG_READ_COMMAND "arc-aux-read" +#define AUX_REG_WRITE_COMMAND "arc-aux-write" +#define AUX_REG_SHOW_COMMAND "arc-aux-show" +#define AUX_LIST_REGISTER_COMMAND "arc-aux-list" +#define ARC_BCR_COMMAND "arc-bcr-registers" + +#define REG_READ_FILE_COMMAND_USAGE "Usage: " REG_READ_FILE_COMMAND " <FILE>\n" +#define REG_READ_EXTRA_FILE_COMMAND_USAGE "Usage: " REG_READ_EXTRA_FILE_COMMAND " <FILE>\n" +#define AUX_REG_READ_COMMAND_USAGE "Usage: " AUX_REG_READ_COMMAND " <REG-FROM> [ <REG-TO> ]\n" +#define AUX_REG_WRITE_COMMAND_USAGE "Usage: " AUX_REG_WRITE_COMMAND " <REG> = <VALUE>\n" +#define AUX_REG_SHOW_COMMAND_USAGE "Usage: " AUX_REG_SHOW_COMMAND " [ <REG> ] \n" +#define AUX_LIST_REGISTER_COMMAND_USAGE "Usage: " AUX_LIST_REGISTER_COMMAND " [ <REG> ]\n" +#define ARC_BCR_COMMAND_USAGE "Usage: info " ARC_BCR_COMMAND "\n" + + +#define ELEMENT_END_MARKER { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +#define ATTRIBUTE_END_MARKER { NULL, GDB_XML_AF_NONE, NULL, NULL } + + +/* Special values for the name and description fields. */ +static const char *NO_DESCRIPTION = ""; +static const char *RESERVED = "<reserved>"; +static const char *UNUSED = "<unused>"; + + +/* The elements and attributes of an XML target description. */ + +/* A handler_data for access values. */ + +static const struct gdb_xml_enum enums_access[] = +{ + { "RO", READ_ONLY }, + { "RW", READ_WRITE }, + { "WO", WRITE_ONLY }, + { NULL, 0 } +}; + + +static const struct gdb_xml_attribute aux_register_attributes[] = +{ + { "name", GDB_XML_AF_NONE, NULL, NULL }, + { "description", GDB_XML_AF_NONE, NULL, NULL }, + { "number", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "mask", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "access", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_enum, enums_access }, + ATTRIBUTE_END_MARKER +}; + + +static const struct gdb_xml_attribute core_register_attributes[] = +{ + { "number", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "mask", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "access", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_enum, enums_access }, + ATTRIBUTE_END_MARKER +}; + + +static const struct gdb_xml_attribute field_attributes[] = +{ + { "name", GDB_XML_AF_NONE, NULL, NULL }, + { "description", GDB_XML_AF_OPTIONAL, NULL, NULL }, + { "onwrite", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL }, + { "offset", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "size", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "access", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_enum, enums_access }, + ATTRIBUTE_END_MARKER +}; + + +static const struct gdb_xml_attribute bcrfield_attributes[] = +{ + { "name", GDB_XML_AF_NONE, NULL, NULL }, + { "description", GDB_XML_AF_OPTIONAL, NULL, NULL }, + { "offset", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "size", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + ATTRIBUTE_END_MARKER +}; + + +static const struct gdb_xml_attribute meaning_attributes[] = +{ + { "description", GDB_XML_AF_NONE, NULL, NULL }, + { "value", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + ATTRIBUTE_END_MARKER +}; + + +static const struct gdb_xml_attribute feature_attributes[] = +{ + { "name", GDB_XML_AF_NONE, NULL, NULL }, + ATTRIBUTE_END_MARKER +}; + + +static const struct gdb_xml_element field_children[] = +{ + { "meaning", meaning_attributes, NULL, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, start_meaning, NULL }, + ELEMENT_END_MARKER +}; + + +static const struct gdb_xml_element auxregister_children[] = +{ + { "field", field_attributes, field_children, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, start_field, NULL }, + ELEMENT_END_MARKER +}; + + +static const struct gdb_xml_element bcr_children[] = +{ + { "bcrfield", bcrfield_attributes, NULL, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, start_bcrfield, NULL }, + ELEMENT_END_MARKER +}; + + +static const struct gdb_xml_element feature_children[] = +{ + { "auxregister", aux_register_attributes, auxregister_children, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, start_auxregister, NULL }, + { "bcr", aux_register_attributes, bcr_children, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, start_bcr, NULL }, + { "ecr", core_register_attributes, NULL, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, start_ecr, NULL }, + ELEMENT_END_MARKER +}; + + +static const struct gdb_xml_attribute target_attributes[] = +{ + { "version", GDB_XML_AF_NONE, NULL, NULL }, + ATTRIBUTE_END_MARKER +}; + + +static const struct gdb_xml_element target_children[] = +{ + { "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL, start_architecture, end_architecture }, + { "feature", feature_attributes, feature_children, + GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, + start_feature, NULL }, + ELEMENT_END_MARKER +}; + + +static const struct gdb_xml_element elements[] = +{ + { "target", target_attributes, target_children, GDB_XML_EF_NONE, start_target, NULL }, + ELEMENT_END_MARKER +}; + + +/* -------------------------------------------------------------------------- */ +/* local macros */ +/* -------------------------------------------------------------------------- */ + +#define NAME_IS(ident) (strcmp(name, ident) == 0) + +#define INFO_OF(gdbarch) &gdbarch_tdep (gdbarch)->processor_variant_info->registers + +#define EXTRACT(argument, type, result) \ +{ \ + struct expression *expr = parse_expression(argument); \ + struct value *val = evaluate_expression(expr); \ + struct cleanup *chain = make_cleanup(free_current_contents, &expr); \ + \ + result = *(type*) (value_contents (val)); \ + do_cleanups (chain); \ +} + +#define FIND_REGISTER_DEFINITION_SUCH_THAT(condition) \ +{ \ + ARC_RegisterInfo *info = find_info(TRUE); \ + unsigned int i; \ + \ + for (i = 0; i < info->aux_register_count; i++) \ + { \ + ARC_AuxRegisterDefinition *def = &info->aux_registers[i]; \ + \ + if (condition) \ + return def; \ + } \ + \ + return NULL; \ +} + + +/* -------------------------------------------------------------------------- */ +/* local functions for XML file parsing */ +/* -------------------------------------------------------------------------- */ + +/* Return a string corresponding to the given access. */ + +static const char* +RegisterAccess_Image (RegisterAccess val) +{ + switch (val) + { + case READ_ONLY : return "read-only"; + case READ_WRITE: return "read/write"; + case WRITE_ONLY: return "write-only"; + default : return "???"; + } +} + + +static void +initialize_register (ARC_AuxRegisterDefinition *reg) +{ + reg->name = NULL; + reg->number = 0; + reg->gdb_regno = 0; + reg->is_BCR = FALSE; + reg->description = (char*) NO_DESCRIPTION; + reg->mask = 0xFFFFFFFF; + reg->access = READ_WRITE; + reg->field_count = 0; + reg->fields = NULL; + reg->longest_field_name = 0; + reg->max_bits_in_field = 0; +} + + +static void +initialize_field (ARC_FieldDefinition *field, RegisterAccess access) +{ + field->name = NULL; + field->description = (char*) NO_DESCRIPTION; + field->value_for_write = 0; + field->fixed = FALSE; + field->size = 1; + field->offset = 0; + field->access = access; + field->meanings = NULL; + field->meaning_count = 0; +} + + +static void +initialize_meaning (ARC_FieldMeaning *meaning) +{ + meaning->description = (char*) NO_DESCRIPTION; + meaning->value = 0; +} + + +/* Return TRUE if the given register fields overlap within the register. */ + +static Boolean +overlaps(ARC_FieldDefinition *field1, ARC_FieldDefinition *field2) +{ + unsigned int field1_start = field1->offset; + unsigned int field1_end = field1_start + field1->size - 1; + unsigned int field2_start = field2->offset; + unsigned int field2_end = field2_start + field2->size - 1; + + return !(field2_end < field1_start || field1_end < field2_start); +} + + +/* Release all the storage allocated to hold the given register information, + and re-initialize it. */ + +static void +free_register_set (ARC_RegisterInfo *info) +{ + if (info->aux_registers) + { + unsigned int i; + + for (i = 0; i < info->aux_register_count; i++) + { + ARC_AuxRegisterDefinition *r = &info->aux_registers[i]; + + if (r->name != UNUSED) + xfree (r->name); + if (r->description != NO_DESCRIPTION) + xfree (r->description); + + if (r->fields) + { + unsigned int j; + + for (j = 0; j < r->field_count; j++) + { + ARC_FieldDefinition *f = &r->fields[j]; + + if (f->name != RESERVED) + xfree (f->name); + + if (f->description != NO_DESCRIPTION) + xfree (f->description); + + if (f->meanings) + { + unsigned int k; + + for (k = 0; k < f->meaning_count; k++) + { + ARC_FieldMeaning *m = &f->meanings[k]; + + if (m->description != NO_DESCRIPTION) + xfree (m->description); + } + + xfree(f->meanings); + } + } + } + + xfree(r->fields); + } + + xfree(info->aux_registers); + + arc_initialize_aux_reg_info(info); + } +} + + +/* This function reads the contents of a file. + + Parameters: + filename : the name of the file to be accessed + baton : the path to the directory containing the file + + Result: + If the file contents were successfully read, a pointer to a buffer + containing those contents; otherwise NULL. */ + +static char* +read_file_contents (const char *filename, void *baton) +{ + char *name = (char*) filename; + const char *dirname = baton; + char *contents = NULL; + int fd; + + if ((dirname != NULL) && (*dirname != '\0')) + { + name = concat (dirname, "/", filename, NULL); + + if (name == NULL) + { + /* N.B. this does not return */ + nomem (0); + } + } + + if ((fd = open (name, O_RDONLY)) != -1) + { + struct stat stat; + int status; + + if ((status = fstat(fd, &stat)) != -1) + { + size_t size = (size_t) stat.st_size; + + /* Allocate buffer to hold the file contents; note that this space + is deliberately made larger than required, so that it is possible + to add extra characters to the end of the data. */ + if ((contents = xmalloc (size + 10))) + { + ssize_t bytes; + + if ((bytes = read (fd, contents, size)) == (ssize_t) size) + { + /* Append an explicit end-of-line to the data, in case there + was not one there already; also, explicitly NUL-terminate + the data so that it is a valid string. */ + contents[bytes] = '\n'; + contents[bytes + 1] = '\0'; + } + else + { + warning (_("can not read contents of file '%s': %s"), + name, strerror (errno)); + + /* Cannot trust the contents of the buffer. */ + xfree (contents); + contents = NULL; + } + + if ((status = close (fd)) != 0) + warning (_("can not close file '%s': %s"), name, + strerror (errno)); + } + else + warning (_("can not allocate buffer to hold contents of file '%s'"), name); + } + else + warning (_("can not get size of file '%s': %s"), name, + strerror (errno)); + } + else + warning (_("can not open file '%s': %s"), name, strerror (errno)); + + if (name != filename) + xfree (name); + + return contents; +} + + +/* This function is called by the XML parser when the start of a <target> element is seen. */ + +static void +start_target (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes) +{ +// ParsingData* data = user_data; + char *version = VEC_index (gdb_xml_value_s, attributes, 0)->value; + + if (strcmp (version, "1.0") != 0) + gdb_xml_error (parser, + _("Registers description has unsupported version \"%s\""), + version); + + DEBUG("target started\n"); +} + + +/* This function is called by the XML parser when the start of an <architecture> element is seen. */ + +static void +start_architecture (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes) +{ + DEBUG("architecture started\n"); +} + + +/* This function is called by the XML parser when the end of an <architecture> element is seen. */ + +static void +end_architecture (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + const char *body_text) +{ + ParsingData *data = user_data; + + if (body_text[0] != '\0') + { + data->info->processor = arc_version(body_text); + + if (data->info->processor == UNSUPPORTED_ARCHITECTURE) + warning(_("unknown target architecture '%s' in XML file '%s'\n"), + body_text, data->filename); + } +} + + +/* This function is called by the XML parser when the start of a <feature> element is seen. */ + +static void +start_feature (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes) +{ + DEBUG("feature started\n"); +} + + +/* This function checks the XML description of an auxiliary register for + correctness, and if it is correct, adds a definition of this register to the + register information that is currently being constructed. + + Parameters: + parser : the XML parser being used + element : a pointer to the parse structure + user_data : a pointer to the parsing data + attributes: a vector containing the attributes of the register from the XML + is_BCR : TRUE if the register is a Build Configuration Register + */ + +static void +add_aux_register (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes, + Boolean is_BCR) +{ + ParsingData *data = user_data; + ARC_RegisterInfo *info = data->info; + ARC_AuxRegisterDefinition *reg = &data->reg; + struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); + unsigned int length = VEC_length (gdb_xml_value_s, attributes); + unsigned int i; + Boolean add = TRUE; + + initialize_register(reg); + + /* Look at all the register attributes. */ + for (i = 0; i < length; i++) + { + const char *name = attrs[i].name; + void *value = attrs[i].value; + + if (NAME_IS("name")) reg->name = value; + else if (NAME_IS("description")) reg->description = xstrdup(value); + else if (NAME_IS("number")) reg->number = (ARC_RegisterNumber) *(ULONGEST*) value; + else if (NAME_IS("mask")) reg->mask = (ARC_Word) *(ULONGEST*) value; + else if (NAME_IS("access")) reg->access = (RegisterAccess) *(ULONGEST*) value; + } + + if (strcasecmp(reg->name, "unused") == 0) + reg->name = (char*) UNUSED; + else + reg->name = xstrdup (reg->name); + + if (is_BCR) + { + reg->is_BCR = is_BCR; + reg->access = READ_ONLY; + } + + /* Sanity checking. */ + for (i = 0; i < info->aux_register_count; i++) + { + if (reg->name != UNUSED) + if (strcasecmp(reg->name, info->aux_registers[i].name) == 0) + { + warning(_("auxiliary register with name '%s' already defined in file %s"), + reg->name, data->filename); + add = FALSE; + } + + if (reg->number == info->aux_registers[i].number) + { + warning(_("auxiliary register with number %u already defined in file %s"), + reg->number, data->filename); + add = FALSE; + } + } + + if (add) + { + unsigned int name_length = (unsigned int) strlen(reg->name); + + if (name_length > info->max_name_length) + info->max_name_length = name_length; + + info->aux_register_count++; + info->aux_registers = xrealloc(info->aux_registers, + info->aux_register_count * sizeof(ARC_AuxRegisterDefinition)); + + if (info->aux_registers == NULL) + { + /* N.B. this does not return. */ + nomem (0); + } + + /* Copy the register description into the array, and make it the current + register that will be referred to when parsing any fields. */ + data->currentRegister = &info->aux_registers[info->aux_register_count - 1]; + *data->currentRegister = *reg; + } + else + /* Do not copy it into the array, but still make it the current register. */ + data->currentRegister = reg; +} + + +/* This function is called by the XML parser when the start of a <auxregister> element is seen. */ + +static void +start_auxregister (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes) +{ + add_aux_register(parser, element, user_data, attributes, FALSE); +} + + +/* This function is called by the XML parser when the start of a <bcr> element is seen. */ + +static void +start_bcr (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes) +{ + add_aux_register(parser, element, user_data, attributes, TRUE); +} + + +/* This function is called by the XML parser when the start of a <ecr> element + is seen. It checks the XML description of an extension core register for + correctness, and if it is correct, adds a definition of this register to the + register information that is currently being constructed. + + Parameters: + parser : the XML parser being used + element : a pointer to the parse structure + user_data : a pointer to the parsing data + attributes: a vector containing the attributes of the register from the XML + */ + +static void +start_ecr (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes) +{ + ParsingData *data = user_data; + ARC_RegisterInfo *info = data->info; + struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); + unsigned int length = VEC_length (gdb_xml_value_s, attributes); + ARC_RegisterNumber number = 0; + ARC_Word mask = 0xFFFFFFFF; + RegisterAccess access = READ_WRITE; + unsigned int i; + + /* Look at all the register attributes. */ + for (i = 0; i < length; i++) + { + const char *name = attrs[i].name; + void *value = attrs[i].value; + + if (NAME_IS("number")) number = (ARC_RegisterNumber) *(ULONGEST*) value; + else if (NAME_IS("mask")) mask = (ARC_Word) *(ULONGEST*) value; + else if (NAME_IS("access")) access = (RegisterAccess) *(ULONGEST*) value; + } + + /* Sanity checking. */ + if (IS_EXTENSION_CORE_REGISTER(number)) + { + ARC_CoreRegisterDefinition *reg = &info->core_registers[number]; + + if (reg->exists) + { + warning(_("extension core register with number %d already defined in file %s"), + number, data->filename); + } + else + { + reg->mask = mask; + reg->access = access; + reg->exists = TRUE; + } + } + else + warning(_("extension core register with invalid number %d defined in file %s"), + number, data->filename); +} + + +/* This function checks the XML description of an auxiliary register field for + correctness, and if it is correct, adds a definition of this field to the + register information that is currently being constructed. + + Parameters: + parser : the XML parser being used + element : a pointer to the parse structure + user_data : a pointer to the parsing data + attributes: a vector containing the attributes of the field from the XML + is_BCR : TRUE if the field is part of a Build Configuration Register + */ + +static void +add_field (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes, + Boolean is_BCR) +{ + ParsingData *data = user_data; + ARC_AuxRegisterDefinition *reg = data->currentRegister; + ARC_FieldDefinition *field = &data->field; + struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); + unsigned int length = VEC_length (gdb_xml_value_s, attributes); + unsigned int i; + Boolean add = TRUE; + + /* By default, a field has the same access as the register that contains it + (though a particular field in a R/W register might be R/O or W/O). */ + initialize_field(field, reg->access); + + /* Look at all the field attributes. */ + for (i = 0; i < length; i++) + { + const char *name = attrs[i].name; + void *value = attrs[i].value; + + if (NAME_IS("name")) field->name = value; + else if (NAME_IS("description")) field->description = xstrdup(value); + else if (NAME_IS("offset")) field->offset = (unsigned int) *(ULONGEST*) value; + else if (NAME_IS("size")) field->size = (unsigned int) *(ULONGEST*) value; + else if (NAME_IS("access")) field->access = (RegisterAccess) *(ULONGEST*) value; + else if (NAME_IS("onwrite")) { field->value_for_write = (ARC_RegisterContents) *(ULONGEST*) value; + field->fixed = TRUE; } + } + + if (strcasecmp(field->name, "reserved") == 0) + field->name = (char*) RESERVED; + else + field->name = xstrdup (field->name); + + /* Sanity checking. */ + if (is_BCR) + { + /* BCRs are, by definition, read-only. */ + field->access = READ_ONLY; + } + else + { + if (field->access != WRITE_ONLY && reg->access == WRITE_ONLY) + { + warning (_("field '%s' is readable in write-only auxiliary register '%s' in file %s"), + field->name, reg->name, data->filename); + add = FALSE; + } + else if (field->access != READ_ONLY && reg->access == READ_ONLY) + { + warning (_("field '%s' is writable in read-only auxiliary register '%s' in file %s"), + field->name, reg->name, data->filename); + add = FALSE; + } + } + + if (field->size == 0) + { + warning(_("field '%s' contains no bits in auxiliary register '%s' in file %s"), + field->name, reg->name, data->filename); + add = FALSE; + } + + if (field->offset > BITS_IN_REGISTER - 1) + { + warning(_("field '%s' offset > %u in auxiliary register '%s' in file %s"), + field->name, BITS_IN_REGISTER - 1, reg->name, data->filename); + add = FALSE; + } + + if (field->offset + field->size > BITS_IN_REGISTER) + { + warning(_("field '%s' is too wide in auxiliary register '%s' in file %s"), + field->name, reg->name, data->filename); + add = FALSE; + } + + for (i = 0; i < reg->field_count; i++) + { + ARC_FieldDefinition *f = ®->fields[i]; + + if (field->name != RESERVED) + if (strcasecmp(field->name, f->name) == 0) + { + warning(_("field '%s' already defined in auxiliary register '%s' in file %s"), + field->name, reg->name, data->filename); + add = FALSE; + } + + if (overlaps(field, f)) + { + warning(_("field '%s' overlaps field '%s' in auxiliary register '%s' in file %s"), + field->name, f->name, reg->name, data->filename); + add = FALSE; + } + } + + data->maxFieldContents = 0; + + for (i = 0; i < field->size; i++) + data->maxFieldContents = (data->maxFieldContents << 1) + 1; + + if (field->value_for_write > data->maxFieldContents) + { + warning(_("value on write %u is too large for %u-bit reserved field in auxiliary register '%s' in file %s"), + field->value_for_write, field->size, reg->name, data->filename); + add = FALSE; + } + + if (add) + { + /* Keep track of the longest field name, and the most number of bits in a field. */ + unsigned int len = (unsigned int) strlen(field->name); + + if (len > reg->longest_field_name) + reg->longest_field_name = len; + + if (field->size > reg->max_bits_in_field) + reg->max_bits_in_field = field->size; + + reg->field_count++; + reg->fields = xrealloc(reg->fields, + reg->field_count * sizeof(ARC_FieldDefinition)); + + if (reg->fields == NULL) + { + /* N.B. this does not return. */ + nomem (0); + } + + /* Copy the field description into the array, and make it the current + field that will be referred to when parsing any meanings. */ + data->currentField = ®->fields[reg->field_count - 1]; + *data->currentField = *field; + } + else + /* Do not copy it into the array, but still make it the current field. */ + data->currentField = field; +} + + +/* This function is called by the XML parser when the start of a <field> element is seen. */ + +static void +start_field (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes) +{ + add_field(parser, element, user_data, attributes, FALSE); +} + + +/* This function is called by the XML parser when the start of a <bcrfield> element is seen. */ + +static void +start_bcrfield (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes) +{ + add_field(parser, element, user_data, attributes, TRUE); +} + + +/* This function is called by the XML parser when the start of a <meaning> + element is seen. It checks the XML description of the meaning for + correctness, and if it is correct, adds a definition of this meaning to the + register information that is currently being constructed. + + Parameters: + parser : the XML parser being used + element : a pointer to the parse structure + user_data : a pointer to the parsing data + attributes: a vector containing the attributes of the meaning from the XML + */ + +static void +start_meaning (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes) +{ + ParsingData *data = user_data; + ARC_AuxRegisterDefinition *reg = data->currentRegister; + ARC_FieldDefinition *field = data->currentField; + ARC_FieldMeaning meaning; + struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); + unsigned int length = VEC_length (gdb_xml_value_s, attributes); + unsigned int i; + Boolean add = TRUE; + + initialize_meaning(&meaning); + + /* Look at all the meaning attributes. */ + for (i = 0; i < length; i++) + { + const char *name = attrs[i].name; + void *value = attrs[i].value; + + if (NAME_IS("description")) meaning.description = xstrdup(value); + else if (NAME_IS("value")) meaning.value = (ARC_RegisterContents) *(ULONGEST*) value; + } + + if (meaning.value > data->maxFieldContents) + { + warning(_("value %u is too large for field '%s' in auxiliary register '%s' in file %s"), + meaning.value, field->name, reg->name, data->filename); + add = FALSE; + } + + /* Sanity checking. */ + for (i = 0; i < field->meaning_count; i++) + { + ARC_FieldMeaning *m = &field->meanings[i]; + + if (strcmp(meaning.description, m->description) == 0) + { + warning(_("meaning '%s' already defined for field '%s' in auxiliary register '%s' in file %s"), + meaning.description, field->name, reg->name, data->filename); + add = FALSE; + } + + if (meaning.value == m->value) + { + warning(_("value %u already has meaning for field '%s' in auxiliary register '%s' in file %s"), + meaning.value, field->name, reg->name, data->filename); + add = FALSE; + } + } + + if (add) + { + field->meaning_count++; + field->meanings = xrealloc(field->meanings, + field->meaning_count * sizeof(ARC_FieldMeaning)); + + if (field->meanings == NULL) + { + /* N.B. this does not return. */ + nomem (0); + } + + field->meanings[field->meaning_count - 1] = meaning; + } +} + + +/* This function is passed to qsort to sort the auxiliary registers into a + canonical order such that BCRs come after the non-BCR aux registers, but + otherwise, the registers are ordered by increasing number, with the + exception that the IDENTITY register must come first. */ + +static int +compare_auxiliary_registers(const void *p1, const void *p2) +{ + ARC_AuxRegisterDefinition* reg1 = (ARC_AuxRegisterDefinition*) p1; + ARC_AuxRegisterDefinition* reg2 = (ARC_AuxRegisterDefinition*) p2; + + if (reg1->is_BCR && !reg2->is_BCR) + return 1; + + if (!reg1->is_BCR && reg2->is_BCR) + return -1; + + if (!reg1->is_BCR && !reg2->is_BCR) + { + if (strcmp(reg1->name, "IDENTITY") == 0) + return -1; + if (strcmp(reg2->name, "IDENTITY") == 0) + return 1; + } + + return (reg1->number < reg2->number) ? -1 : 1; +} + + +/* This function assigns the gdb register numbers to the target processor's + registers, using the scheme defined in arc-elf32-tdep.c. */ + +static void +assign_gdb_register_numbers (struct gdbarch *gdbarch, ARC_RegisterInfo *info) +{ + unsigned int i; + int pc = -1; + + /* Core registers first. */ + for (i = 0; i < ELEMENTS_IN_ARRAY(info->core_registers); i++) + { + ARC_CoreRegisterDefinition *reg = &info->core_registers[i]; + + /* If this core register exists in the target, we have one more core + register in total; and the gdb number of this register is that number + less 1. */ + if (reg->exists) + reg->gdb_regno = (int) info->core_register_count++; + } + + info->first_aux_gdb_regno = (int) info->core_register_count; + + /* Then the auxiliary registers. */ + for (i = 0; i < info->aux_register_count; i++) + { + ARC_AuxRegisterDefinition *reg = &info->aux_registers[i]; + + reg->gdb_regno = info->first_aux_gdb_regno + i; + + /* Is this the PC? */ + if (strcasecmp(reg->name, "PC") == 0) + { + pc = reg->gdb_regno; + info->PC_number = pc; + } + } + + /* We must tell gdb that the total number of registers has changed. */ + set_gdbarch_num_regs (gdbarch, (int) (info->core_register_count + + info->aux_register_count)); + + /* The file may have contained a description of the PC, so we must tell gdb + what its number is. + N.B. if the 'replace' parameter to read_XML_file was true and the file + did NOT contain a description of the PC, we now no longer know which + auxiliary register is the PC, so we must set gdb's PC number back to + -1! */ + set_gdbarch_pc_regnum(gdbarch, pc); + + if (pc >= 0) + { + DEBUG("PC is reg #%d (arch %p)\n", pc, gdbarch); + + /* So PC is defined - so remove the guard. */ + arc_aux_pc_guard(gdbarch, FALSE); + } +} + + +/* Parse the XML file containing the register definitions. + + Parameters: + document : the XML document to be parsed (i.e. the XML text) + fetcher : a function which can be used to read an XML document from a file + fetcher_baton : the directory containing the XML file(s) + data : a pointer to a structure used to pass state data + between the parsing routines. */ + +static void +parse_XML (const char *document, + xml_fetch_another fetcher, + void *fetcher_baton, + ParsingData *data) + +{ + struct cleanup *back_to; + struct gdb_xml_parser *parser; + char *expanded_text; + + /* Expand all XInclude directives. */ + expanded_text = xml_process_xincludes (_("aux registers description"), + document, fetcher, fetcher_baton, 0); + if (expanded_text == NULL) + { + warning (_("can not load XML auxiliary registers description")); + return; + } + + back_to = make_cleanup (null_cleanup, NULL); + parser = gdb_xml_create_parser_and_cleanup (_("aux registers description"), + elements, data); + + /* Do the parsing; the DTD file defines the schema to be used by the XML. */ + gdb_xml_use_dtd (parser, "arc-registers.dtd"); + + (void) make_cleanup (xfree, expanded_text); + + if (gdb_xml_parse (parser, expanded_text) != 0) + warning (_("can not load XML auxiliary registers description")); + + do_cleanups (back_to); +} + + +/* Read an XML file containing the register definitions. + + Parameters: + filename : the path to the file + gdbarch : the architecture for which the register set is are being defined + replace : TRUE if any existing set of register defintions should be deleted first + inform : TRUE if a message should be output say that the file has been read + check : TRUE if an architectural check is to be performed once the file has been read + + Result: TRUE if the file was successfully read and its contents parsed. */ + +static Boolean +read_XML_file (const char *filename, + struct gdbarch *gdbarch, + Boolean replace, + Boolean inform, + Boolean check) +{ + char *xml = read_file_contents(filename, NULL); + + DEBUG("reading XML file: %s\n", filename); + + if (xml) + { + ARC_RegisterInfo *info = INFO_OF(gdbarch); + struct cleanup *back_to = make_cleanup (xfree, xml); + char *dirname = ldirname (filename); + ParsingData data; + + memset (&data, 0, sizeof (ParsingData)); + + if (replace) + free_register_set(info); + + info->processor = NO_ARCHITECTURE; + + data.info = info; + data.filename = filename; + + if (dirname != NULL) + (void) make_cleanup (xfree, dirname); + + parse_XML (xml, read_file_contents, dirname, &data); + do_cleanups (back_to); + + if (inform) + printf_filtered(_("Register definitions read from file %s\n"), filename); + + if (check) + ARCHITECTURE_CHECK(gdbarch, + (current_objfile) ? current_objfile->obfd : NULL); + + /* Sort the auxiliary registers into a canonical order: this allows + entries in the XML file to be in any order without affecting the gdb + register numbers assigned to them; in particular, it aids in ensuring + that when the xISS is being used as a remote debug target gdb and the + xISS agree upon the order in which register contents are held in the + RSP 'G' (set all registers) packet and the 'g' (get all registers) + response packet. */ + qsort(info->aux_registers, + (size_t) info->aux_register_count, + sizeof (ARC_AuxRegisterDefinition), + compare_auxiliary_registers); + + /* Now that we know all of the core and auxiliary registers in this + target, we can assign gdb register numbers to them. */ + assign_gdb_register_numbers(gdbarch, info); + + /* We can send the event now only if current_gdbarch is not NULL, or + it could cause an error elsewhere where gdbarch_num_regs or + gdbarch_num_pseudo_regs is used (e.g. in setup_architecture_data in + gdbtk/generic/gdbtk-register.c). */ + if (current_gdbarch == NULL) + arc_pending_register_architecture_change_event = TRUE; + else + reg_architecture_changed_event(); + + return TRUE; + } + + return FALSE; +} + + +/* Try to find a file containing the default AUX register definitions; look in + 1) the current working directory + 2) the user's home directory + + Parameters: + gdbarch : the architecture for which the register set is are being defined + inform : TRUE if a message should be output say that the file has been read + check : TRUE if an architectural check is to be performed once the file has been read +*/ + +static void +read_default_file (struct gdbarch *gdbarch, Boolean inform, Boolean check) +{ + ENTERARGS("inform = %d, check = %d", inform, check); + +#define DESCR "auxiliary registers definition file " + + if (access(REGISTER_DEFINITION_FILE, F_OK) == 0) + { + if (!read_XML_file(REGISTER_DEFINITION_FILE, gdbarch, FALSE, inform, check)) + error(_("Can not read " DESCR REGISTER_DEFINITION_FILE)); + } + else + { + const char *home_dir = getenv ("HOME"); + + if (home_dir) + { + char *home_file = xstrprintf (_("%s/%s"), home_dir, REGISTER_DEFINITION_FILE); + + if (access(home_file, F_OK) == 0) + { + if (!read_XML_file(home_file, gdbarch, FALSE, inform, check)) + error(_("Can not read " DESCR " %s"), home_file); + } + else + warning(_("can not find " DESCR REGISTER_DEFINITION_FILE " in either current directory or $HOME")); + + xfree (home_file); + } + else + warning(_("HOME environment variable is not set - can not find " DESCR REGISTER_DEFINITION_FILE)); + } +} + + +/* -------------------------------------------------------------------------- */ +/* miscellaneous local functions */ +/* -------------------------------------------------------------------------- */ + +/* This is a callback which is called from gdb when it writes the PC. + It is used to "guard" the PC. */ + +static CORE_ADDR +get_pc (struct regcache *regcache) +{ + struct gdbarch *gdbarch = get_regcache_arch (regcache); + + /* This does not return if PC is not defined. */ + arc_aux_check_pc_defined(gdbarch); + + /* So PC is defined - so remove the guard. */ + arc_aux_pc_guard(gdbarch, FALSE); + + /* Now read and return the PC. */ + return read_pc(); +} + + +/* This is a callback which is called from gdb when it reads the PC. + It is used to "guard" the PC. */ + +static void +set_pc (struct regcache *regcache, CORE_ADDR val) +{ + struct gdbarch *gdbarch = get_regcache_arch (regcache); + + /* This does not return if PC is not defined. */ + arc_aux_check_pc_defined(gdbarch); + + /* So PC is defined - so remove the guard. */ + arc_aux_pc_guard(gdbarch, FALSE); + + write_pc(val); +} + + +/* Try to find the register information for the current architecture. + + Parameter: + must_be_defined : TRUE if the register information must be known + + Result: a pointer to the info; NULL if there is none as yet. */ + +static ARC_RegisterInfo* +find_info (Boolean must_be_defined) +{ + gdb_assert (current_gdbarch != NULL); + + { + ARC_RegisterInfo *info = INFO_OF(current_gdbarch); + + /* If we have no aux register info. */ + if (must_be_defined && info->aux_register_count == 0) + { + /* Try to get it. */ + read_default_file(current_gdbarch, FALSE, FALSE); + + /* No, could not get it. */ + if (info->aux_register_count == 0) + error(_("No auxiliary registers have yet been defined for this target")); + } + + return info; + } +} + + +/* Map a gdb register number to the ARC processor hardware number, and + determine the class of the register (as known to the built-in simulator). */ + +static void +simulator_mapping (int gdb_regno, + int *hw_regno, + ARC_RegisterClass *reg_class) +{ + /* Just in case gdb_regno is invalid. */ + *hw_regno = -1; + *reg_class = ARC_UNKNOWN_REGISTER; + + if (arc_is_core_register(gdb_regno)) + { + *hw_regno = (int) arc_core_register_number(gdb_regno); + *reg_class = ARC_CORE_REGISTER; + } + else if (gdb_regno == arc_aux_pc_number(current_gdbarch)) + { + /* The hw_regno is irrelevant here. */ + *reg_class = ARC_PROGRAM_COUNTER; + } + else + { + ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_gdb_number(gdb_regno); + + if (def) + { + *hw_regno = (int) arc_aux_hw_register_number(def); + *reg_class = ARC_AUX_REGISTER; + } + } +} + + +/* -------------------------------------------------------------------------- */ +/* local functions for supporting commands */ +/* -------------------------------------------------------------------------- */ + +/* This function determines the h/w register number of an auxiliary register + from a command argument provided by a user. The argument might be a register + name, a number, or an expression to be evaluated. */ + +static ARC_RegisterNumber +extractRegisterNumber (char *arg) +{ + ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_name(arg); + ARC_RegisterNumber num; + + /* Is it a register name? */ + if (def) + num = arc_aux_hw_register_number(def); + else + { + int regnum; + + /* Is it some expression? */ + EXTRACT(arg, int, regnum) + + if (regnum < 0) + error(_("Register number '%s < 0"), arg); + + num = (ARC_RegisterNumber) regnum; + } + + return num; +} + + +/* This function finds the definition of an auxiliary register from a command + argument provided by a user. The argument might be a register name, a number, + or an expression to be evaluated. + + NULL is returned if the argumenmt does not identify a defined auxiliary + register. */ + +static ARC_AuxRegisterDefinition* +find_aux_register (char *arg) +{ + ARC_AuxRegisterDefinition* def = arc_find_aux_register_by_name(arg); + + /* Is it not a register name? */ + if (def == NULL) + { + int regnum; + + /* Is it some expression? */ + EXTRACT(arg, int, regnum) + + if (regnum < 0) + error(_("Register number '%s < 0"), arg); + + def = arc_find_aux_register_by_hw_number((ARC_RegisterNumber) regnum); + } + + return def; +} + + +/* This function list the description (but not the contents) of an auxiliary + register. + + Parameters: + r : a pointer to the register definition + full: TRUE if full information is to be listed. +*/ + +static void +list_register (ARC_AuxRegisterDefinition *r, Boolean full) +{ + printf_filtered("%s", r->name); + if (r->is_BCR) + printf_filtered(_(" (BCR)")); + printf_filtered(_("\n")); + + if (r->description != NO_DESCRIPTION) + printf_filtered(_(" description: %s\n"), r->description); + printf_filtered(_(" number : 0x%x\n"), r->number); + + if (full) + { + /* The gdb number of the register is internal information which would + be meaningless to the user; the mask is probably not useful either. */ + printf_filtered(_(" gdb number : %d\n"), r->gdb_regno); + printf_filtered(_(" mask : %08X\n"), r->mask); + } + + if (!r->is_BCR) + printf_filtered(_(" access : %s\n"), RegisterAccess_Image(r->access)); + + if (r->fields) + { + unsigned int j; + + printf_filtered(_(" fields\n")); + + for (j = 0; j < r->field_count; j++) + { + ARC_FieldDefinition *f = &r->fields[j]; + + printf_filtered(_(" %s\n"), f->name); + if (f->description != NO_DESCRIPTION) + printf_filtered(_(" description: %s\n"), f->description); + printf_filtered(_(" position : %u:%u\n"), f->offset, f->size); + printf_filtered(_(" access : %s\n"), RegisterAccess_Image(f->access)); + + if (f->meanings) + { + unsigned int k; + + printf_filtered(_(" field meanings\n")); + + for (k = 0; k < f->meaning_count; k++) + { + ARC_FieldMeaning *m = &f->meanings[k]; + + printf_filtered(_(" %x ==> %s\n"), m->value, m->description); + } + } + } + } + + printf_filtered(_("\n")); +} + + +/* This function list the descriptions (but not the contents) of all auxiliary + registers. + + Parameter: + full: TRUE if full information is to be listed. +*/ + +static void +list_registers (Boolean full) +{ + ARC_RegisterInfo *info = find_info(TRUE); + unsigned int i; + + for (i = 0; i < info->aux_register_count; i++) + { + ARC_AuxRegisterDefinition *def = info->aux_registers + i; + + if (def->name != UNUSED) + list_register(def, full); + } +} + + +/* This function reads the contents of an auxiliary register on the target. + + Parameters: + def : the definition of the register + value : set to the contents of the register + warn_on_failure: TRUE if a warning should be issued if the read fails + + Result: TRUE if the register contents are read. */ + +static Boolean +read_aux_register (ARC_AuxRegisterDefinition *def, + ARC_RegisterContents *value, + Boolean warn_on_failure) +{ + int gdb_regno = arc_aux_gdb_register_number(def); + struct regcache *regcache = get_current_regcache(); + + /* Read the register contents from the target to the register cache, + then collect the register value from the cache. */ + target_fetch_registers(regcache, gdb_regno); + regcache_raw_collect (regcache, gdb_regno, value); + + /* Unfortunately, the target_fetch_registers operation does not give us an + indication of success or failure. */ + return TRUE; +} + + +/* This function writes the contents of an auxiliary register on the target. + + Parameters: + def : the definition of the register + value : the contents of the register + warn_on_failure: TRUE if a warning should be issued if the write fails + + Result: TRUE if the register contents are written. */ + +static Boolean +write_aux_register (ARC_AuxRegisterDefinition *def, + ARC_RegisterContents value, + Boolean warn_on_failure) +{ + int gdb_regno = arc_aux_gdb_register_number(def); + struct regcache *regcache = get_current_regcache(); + ARC_RegisterContents written = arc_write_value(def, value); + + /* Supply the register value to the register cache, then write it from the + cache to the target. */ + regcache_raw_supply (regcache, gdb_regno, &written); + target_store_registers(regcache, gdb_regno); + + /* If the value we actually wrote to the target is not the same as the value + we were given (because the register has fields that must have particular + values when written). */ + if (written != value) + { + DEBUG("%s auxiliary register value %08X written as %08X\n", + arc_aux_register_name(def), value, written); + + /* Put the value we were actually given into the register cache, so if + the user then displays the register contents he will see the + unmodified value. */ + regcache_raw_supply (regcache, gdb_regno, &value); + } + + /* Unfortunately, the target_store_registers operation does not give us an + indication of success or failure. */ + return TRUE; +} + + +/* This function is passed to the arc_all_aux_registers iterator. + It is called for each auxiliary register defined for the current architecture; + if the register is a Build Configuration Register, and it is not unused, the + register's contents are read from the target and printed. */ + +static void +print_bcr (ARC_AuxRegisterDefinition *def, void *data) +{ + if (arc_aux_is_BCR(def) && !arc_aux_is_unused(def)) + { + ARC_RegisterNumber bcr = arc_aux_hw_register_number(def); + ARC_RegisterContents bcr_value; + + if (read_aux_register (def, &bcr_value, TRUE)) + printf_filtered(_("[%02x] %-16s : 0x%02x\n"), + bcr, arc_aux_register_name(def), bcr_value); + } +} + + +/* This function may be passed to the arc_all_aux_registers iterator. + It reads the contents of the register whose definition is given from + the target and prints those contents. */ + +static void +show_one_aux_register (ARC_AuxRegisterDefinition *def, void *data) +{ + ARC_RegisterNumber reg_no = arc_aux_hw_register_number(def); + ARC_RegisterContents contents; + + DEBUG("try to read aux reg %u\n", reg_no); + + if (read_aux_register(def, &contents, TRUE)) + arc_print_aux_register(def, contents); +} + + +/* Read the register definitions from a file. + + Parameters: + filename : the path to the file + gdbarch : the architecture for which the register set is are being defined + replace : TRUE if any existing set of register defintions should be deleted first + inform : TRUE if a message should be output say that the file has been read + check : TRUE if an architectural check is to be performed once the file has been read +*/ +static Boolean +read_aux_regs_file (const char *filename, + struct gdbarch *gdbarch, + Boolean replace, + Boolean inform, + Boolean check) +{ + /* Try to read the register descriptions from the file. */ + if (read_XML_file(filename, gdbarch, replace, inform, check)) + return TRUE; + + printf_filtered(_("can not read file '%s'\n"), filename); + return FALSE; +} + + +/* -------------------------------------------------------------------------- */ +/* local functions implementing commands */ +/* -------------------------------------------------------------------------- */ + +/* Command: <command> <from> [ <to> ] + + Read and display a range of auxiliary registers. + + We should eventually change this to use the ui_out stuff rather than + printf_filtered. */ + +static void +arc_aux_reg_read_command (char *arg, int from_tty) +{ + char *arg2; + ARC_RegisterNumber first_regnum, last_regnum, r; + char format[40]; + + if (!arg) + { + printf_filtered (_(AUX_REG_READ_COMMAND_USAGE)); + return; + } + + /* Strip leading spaces. */ + while (*arg == ' ') + arg++; + + /* This assumes that the first arg cannot have spaces (the disas command + also seems to work this way). */ + arg2 = strchr (arg, ' '); + + /* Are there two arguments? */ + if (arg2) + { + /* Split the input string up. */ + arg2[0] = (char) 0; + arg2++; + } + + /* First arg. */ + first_regnum = extractRegisterNumber(arg); + + /* So, how many regs do we want? */ + if (arg2) + { + last_regnum = extractRegisterNumber(arg2); + + if (last_regnum < first_regnum) + { + warning(_(AUX_REG_READ_COMMAND ": %s < %s, showing one register"), arg2, arg); + last_regnum = first_regnum; + } + } + else + last_regnum = first_regnum; + + DEBUG("try to read aux regs %d .. %d\n", first_regnum, last_regnum); + + (void) snprintf(format, sizeof(format), + _("0x%%08x %%-%us: %%08X\n"), + arc_aux_register_max_name_length() + 1); + + for (r = first_regnum; r <= last_regnum; r++) + { + ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_hw_number(r); + + /* If the aux register exists, and is used. */ + if ((def != NULL) && !arc_aux_is_unused(def)) + { + ARC_RegisterContents contents; + + DEBUG("try to read aux reg %u\n", r); + + if (read_aux_register(def, &contents, TRUE)) + printf_filtered (format, r, arc_aux_register_name(def), contents); + } + } +} + + +/* Command: <command> <reg> = <value> + + Write VALUE to auxiliary register REG. + + We should eventually change this to use the ui_out stuff rather than + printf_filtered. */ +static void +arc_aux_reg_write_command (char *arg, int from_tty) +{ + char *value_arg; + char *p; + ARC_RegisterNumber regnum; + ARC_RegisterContents value; + ARC_AuxRegisterDefinition *def; + + if (!arg) + { + printf_filtered (_(AUX_REG_WRITE_COMMAND_USAGE)); + return; + } + + p = strchr(arg, '='); + + if (p == NULL) + { + printf_filtered (_(AUX_REG_WRITE_COMMAND ": no second argument\n" AUX_REG_WRITE_COMMAND_USAGE)); + return; + } + + /* Split up the input string. */ + value_arg = p + 1; + p--; + while (*p == ' ') p--; + p[1] = '\0'; + + /* Register expression. */ + regnum = extractRegisterNumber(arg); + + /* Value expression. */ + EXTRACT(value_arg, ARC_RegisterContents, value) + + def = arc_find_aux_register_by_hw_number(regnum); + + if (def == NULL) + warning(_("no such auxiliary register: %s"), arg); + else + { + DEBUG("try to write aux reg %d = 0x%08X\n", regnum, value); + + /* Write it. */ + (void) write_aux_register(def, value, TRUE); + } +} + + +/* Command: <command> [ <reg> ] + + Display the values of one or all of the auxiliary registers. + + We should eventually change this to use the ui_out stuff rather than + printf_filtered. */ + +static void +arc_aux_reg_show_command (char *arg, int from_tty) +{ + if (arg) + { + ARC_AuxRegisterDefinition *def = find_aux_register(arg); + + if (def) + show_one_aux_register(def, NULL); + else + printf_filtered(_("There is no auxiliary register named '%s'\n"), arg); + } + else + /* list them all */ + arc_all_aux_registers(show_one_aux_register, NULL); +} + + +/* Command: <command> [ <file> ] + + Read a definition of a set of auxiliary registers from an XML file. + + We should eventually change this to use the ui_out stuff rather than + printf_filtered. */ + +static void +arc_aux_reg_file_read_command (char *arg, int from_tty) +{ + if (!arg) + { + printf_filtered (REG_READ_FILE_COMMAND_USAGE); + return; + } + + /* The new set replaces the existing set (if any). */ + (void) read_aux_regs_file(arg, current_gdbarch, TRUE, TRUE, TRUE); +} + + +/* Command: <command> <file> + + Read a definition of a set of auxiliary registers from an XML file. + + We should eventually change this to use the ui_out stuff rather than + printf_filtered. */ + +static void +arc_aux_reg_file_read_extra_command (char *arg, int from_tty) +{ + if (!arg) + { + printf_filtered (REG_READ_EXTRA_FILE_COMMAND_USAGE); + return; + } + + /* The new set is added to the existing set (if any). */ + (void) read_aux_regs_file(arg, current_gdbarch, FALSE, TRUE, TRUE); +} + + +/* Command: <command> [ <reg> ] + + Display a description of one or all auxiliary registers. + + We should eventually change this to use the ui_out stuff rather than + printf_filtered. */ + +static void +arc_aux_reg_list_command (char *arg, int from_tty) +{ + if (arg) + { + ARC_AuxRegisterDefinition *def = find_aux_register(arg); + + if (def) + list_register(def, FALSE); + else + printf_filtered(_("There is no auxiliary register named '%s'\n"), arg); + } + else + /* List them all. */ + list_registers(FALSE); +} + + +/* Command: <command> + + Display the Build Configuration Registers. + + We should eventually change this to use the ui_out stuff rather than + printf_filtered. */ + +static void +arc_print_bcr_regs (char *arg, int from_tty) +{ + arc_all_aux_registers(print_bcr, NULL); +} + + +/* -------------------------------------------------------------------------- */ +/* externally visible functions */ +/* -------------------------------------------------------------------------- */ + +/* Initialize the given register information to the base configuration: + 1) core registers exist + 2) extension core registers do not exist + 3) no aux registers + */ + +void +arc_initialize_aux_reg_info (ARC_RegisterInfo *info) +{ + unsigned int i; + + info->processor = NO_ARCHITECTURE; + info->aux_registers = NULL; + info->aux_register_count = 0; + info->max_name_length = 0; + info->PC_number = -1; + info->first_aux_gdb_regno = 0; + info->core_register_count = 0; + + /* All possible core registers. */ + for (i = 0; i < ELEMENTS_IN_ARRAY(info->core_registers); i++) + { + ARC_CoreRegisterDefinition *reg = &info->core_registers[i]; + + reg->exists = TRUE; + reg->mask = 0xFFFFFFFF; + reg->access = READ_WRITE; + } + + /* We do not yet know if we have any extension registers. */ + for (i = ARC_FIRST_EXTENSION_CORE_REGISTER; i <= ARC_LAST_EXTENSION_CORE_REGISTER; i++) + info->core_registers[i].exists = FALSE; + + /* R61 is reserved, R62 is not a real register. */ + info->core_registers[61].exists = FALSE; + info->core_registers[62].exists = FALSE; + + /* PCL is read-only */ + info->core_registers[63].access = READ_ONLY; +} + + +/* Read the XML registers definition for the given architecture from the default file. */ + +void +arc_read_default_aux_registers (struct gdbarch *gdbarch) +{ + ENTERMSG; + read_default_file(gdbarch, FALSE, FALSE); +} + + + +/* This function sets up or remaoves a "guard" on the PC */ + +void +arc_aux_pc_guard (struct gdbarch *gdbarch, Boolean on) +{ + set_gdbarch_read_pc (gdbarch, (on) ? get_pc : NULL); + set_gdbarch_write_pc(gdbarch, (on) ? set_pc : NULL); +} + + +/* Check whether the PC aux register is defined for the given architecture. */ + +void +arc_aux_check_pc_defined (struct gdbarch *gdbarch) +{ + ENTERARGS("target %s", current_target.to_shortname); + + if (gdbarch == NULL) + gdbarch = current_gdbarch; + + if (arc_aux_pc_number(gdbarch) < 0) + error(_("There is no auxiliary register description for the PC (Program Counter)")); +} + + +/* Return the gdb register number of the PC (Program Counter); -1 if the PC is not defined. */ + +int +arc_aux_pc_number (struct gdbarch *gdbarch) +{ + ARC_RegisterInfo *info = INFO_OF(gdbarch); + + return (info) ? info->PC_number : -1; +} + + +/* Find the register definition of the given aux register (identified by name). */ + +ARC_AuxRegisterDefinition* +arc_find_aux_register_by_name (const char *name) +{ + FIND_REGISTER_DEFINITION_SUCH_THAT(strcasecmp(name, def->name) == 0) +} + + +/* Find the register definition of the given aux register (identified by hardware register number). */ + +ARC_AuxRegisterDefinition* +arc_find_aux_register_by_hw_number (ARC_RegisterNumber hw_regno) +{ + FIND_REGISTER_DEFINITION_SUCH_THAT(hw_regno == def->number) +} + + +/* Find the register definition of the given aux register (identified by gdb register number). */ + +ARC_AuxRegisterDefinition* +arc_find_aux_register_by_gdb_number (int gdb_regno) +{ + /* N.B. the elements in the info->aux_registers array have strictly increasing + gdb numbers starting at info->first_aux_gdb_regno, so we can index the array + instead of searching it. */ + ARC_RegisterInfo *info = find_info(TRUE); + int index = gdb_regno - info->first_aux_gdb_regno; + + if (0 <= index && index < (int) info->aux_register_count) + { + ARC_AuxRegisterDefinition *def = info->aux_registers + index; + + /* Just to be sure we have found the right element. */ + gdb_assert(def->gdb_regno == gdb_regno); + + return def; + } + + return NULL; +} + + +/* Return the hardware register number of the given named auxiliary register; + if no register set is currently defined, or there is no register of that + name in the set, return the given default number. */ + +ARC_RegisterNumber +arc_aux_find_register_number (const char *name, + ARC_RegisterNumber defaultNumber) +{ + if (arc_aux_regs_defined(current_gdbarch)) + { + ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_name(name); + + if (def != NULL) + return arc_aux_hw_register_number(def); + } + + warning(_("there is no auxiliary register description for the %s register - " + "using 0x%x for the register number"), name, defaultNumber); + return defaultNumber; +} + + +/* Return the hardware register number of the given core register. */ + +ARC_RegisterNumber +arc_core_register_number (int gdb_regno) +{ + ARC_RegisterInfo *info = find_info(TRUE); + unsigned int i; + + /* The lower-numbered set of non-extension core registers (i.e. excluding + R60 .. R63) have fixed gdb numbers which are the same as the h/w number. */ + if (gdb_regno < ARC_FIRST_EXTENSION_CORE_REGISTER) + return (ARC_RegisterNumber) gdb_regno; + + /* Scan the rest of the array. */ + for (i = ARC_FIRST_EXTENSION_CORE_REGISTER; i < ELEMENTS_IN_ARRAY(info->core_registers); i++) + { + ARC_CoreRegisterDefinition *def = &info->core_registers[i]; + + if (def->exists) + if (gdb_regno == def->gdb_regno) + return (ARC_RegisterNumber) (i); + } + + /* Too large to be the number of a core register. */ + return ARC_MAX_CORE_REGS + 1000; +} + + +/* Return the gdb register number of the given core register. */ + +int +arc_core_register_gdb_number (ARC_RegisterNumber hw_regno) +{ + ARC_RegisterInfo *info = find_info(TRUE); + ARC_CoreRegisterDefinition *def = &info->core_registers[hw_regno]; + + gdb_assert(def->exists); + + return def->gdb_regno; +} + + +/* Print the aux register whose definition and contents are given. + The field and meaning information in the definition is used to + give a detailed display of the register. */ + +void +arc_print_aux_register (ARC_AuxRegisterDefinition *def, + ARC_RegisterContents contents) + +{ + printf_filtered (_("%s : %08x\n"), def->name, contents); + + if (def->fields) + { + unsigned int i; + char format[128]; + + printf_filtered(_(" fields\n")); + + /* Create a format string such as + + " %-10s: %8s" + + so that the field name is left-justified, and the field value is + right-justified. */ + (void) snprintf(format, sizeof(format), + _(" %%-%us: %%%us"), + def->longest_field_name, def->max_bits_in_field); + + for (i = 0; i < def->field_count; i++) + { + ARC_FieldDefinition *f = &def->fields[i]; + ARC_RegisterContents val = contents >> f->offset; + ARC_RegisterContents val2 = val; + ARC_RegisterContents mask = 0; + char bits[BITS_IN_REGISTER]; + char *p = &bits[BITS_IN_REGISTER - 1]; + unsigned int b; + + *p = '\0'; + + /* Build up a string representing the bits of the field, starting + with the least significant bit, which will be the rightmost digit + displayed; at the same time, construct a mask of 1-bits of the + same size as the field. */ + for (b = 0; b < f->size; b++) + { + p--; + *p = (val & 1) ? '1' : '0'; + val >>= 1; + + mask <<= 1; + mask++; + } + + printf_filtered(format, f->name, p); + + if (f->meanings) + { + unsigned int j; + + val2 &= mask; + + /* Look for a meaning for this particular value of the field. */ + for (j = 0; j < f->meaning_count; j++) + { + ARC_FieldMeaning *m = &f->meanings[j]; + + if (val2 == m->value) + { + printf_filtered(_(" (%s)"), m->description); + break; + } + } + } + + printf_filtered(_("\n")); + } + } + + printf_filtered(_("\n")); +} + + +/* Return the gdb register number of the given aux register. */ + +int +arc_aux_gdb_register_number (ARC_AuxRegisterDefinition *def) +{ + return def->gdb_regno; +} + + +/* Return the hardware register number of the given aux register. */ + +ARC_RegisterNumber +arc_aux_hw_register_number (ARC_AuxRegisterDefinition *def) +{ + return def->number; +} + + +/* Return the access mode (R/W, RO 0r WO) of the given aux register. */ + +RegisterAccess +arc_aux_register_access (ARC_AuxRegisterDefinition *def) +{ + return def->access; +} + + +/* Return TRUE if the given aux register is not used in the processor architecture, + i.e. there is a "place-holder" definition of that register (possibly a BCR) in + the XML file, but that register does not actually exist on the target. */ + +Boolean +arc_aux_is_unused (ARC_AuxRegisterDefinition *def) +{ + return (def->name == UNUSED); +} + + +/* Return TRUE if the given aux register is a BCR (Build Configuration Register). */ + +Boolean +arc_aux_is_BCR (ARC_AuxRegisterDefinition *def) +{ + return def->is_BCR; +} + + +/* Return the name of the given aux register. */ + +const char* +arc_aux_register_name (ARC_AuxRegisterDefinition *def) +{ + return def->name; +} + + +/* Return the access mode (R/W, RO 0r WO) of the given core register. */ + +RegisterAccess +arc_core_register_access (ARC_RegisterNumber hw_regno) +{ + ARC_RegisterInfo *info = find_info(TRUE); + ARC_CoreRegisterDefinition *def = &info->core_registers[hw_regno]; + + gdb_assert(def->exists); + + return def->access; +} + + +/* Return the name of the given auxiliary register. */ + +const char* +arc_aux_register_name_of (ARC_RegisterNumber hw_regno) +{ + ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_hw_number(hw_regno); + + return (def) ? def->name : "<no such register>"; +} + + +/* Return TRUE if the given register is a core register. */ + +Boolean +arc_is_core_register (int gdb_regno) +{ + ARC_RegisterInfo *info = find_info(TRUE); + + return (gdb_regno < info->first_aux_gdb_regno); +} + + +/* Iterate across all the aux registers; for each one, call the supplied + function, passing it the defintion of the register and the supplied data. */ + +void +arc_all_aux_registers (ARC_AuxRegisterFunction function, void *data) +{ + ARC_RegisterInfo *info = find_info(TRUE); + unsigned int i; + + for (i = 0; i < info->aux_register_count; i++) + function(info->aux_registers + i, data); +} + + +/* Return the length of the longest aux register name in the current architecture. */ +unsigned int +arc_aux_register_max_name_length (void) +{ + ARC_RegisterInfo *info = find_info(TRUE); + + return info->max_name_length; +} + + +/* Return the number of aux registers defined for the given architecture; + 0 if no register set has yet been defined. */ + +unsigned int +arc_aux_register_count (struct gdbarch *gdbarch) +{ + ARC_RegisterInfo *info = INFO_OF(gdbarch); + + return (info) ? info->aux_register_count : 0; +} + + +/* Return the number of core registers defined for the given architecture; + ARC_NUM_STANDARD_CORE_REGS if no register set has yet been defined. */ + +unsigned int +arc_core_register_count (struct gdbarch *gdbarch) +{ + ARC_RegisterInfo *info = INFO_OF(gdbarch); + + return (info) ? info->core_register_count : ARC_NUM_STANDARD_CORE_REGS; +} + + +/* Return TRUE if the register set has been defined for the given architecture. */ + +Boolean +arc_aux_regs_defined (struct gdbarch *gdbarch) +{ + ARC_RegisterInfo *info = INFO_OF(gdbarch); + + return (info->aux_register_count > 0 && info->aux_registers != NULL); +} + + +/* Return the architectural version of the register set associated with the + given architecture. */ + +ARC_ProcessorVersion +arc_aux_architecture (struct gdbarch *gdbarch) +{ + ARC_RegisterInfo *info = INFO_OF(gdbarch); + + return info->processor; +} + + +/* Compute the value to be written to an auxiliary register so that any fields it + has contain the values that they are required to have by the ARC architectural + specification. + + Parameters: + def : the definition of the aux register + value : the value to be adjusted + + Result: the adjusted register contents. */ + +ARC_RegisterContents +arc_write_value (ARC_AuxRegisterDefinition *def, + ARC_RegisterContents value) +{ + unsigned int i; + + for (i = 0; i < def->field_count; i++) + { + ARC_FieldDefinition *field = &def->fields[i]; + + if (field->fixed) + { + value &= ~(((1 << field->size) - 1) << field->offset); + value |= (field->value_for_write << field->offset); + } + } + + return value; +} + + +/* Adjust the value to be written to a register so that any fields it has contain + the values that they are required to have by the ARC architectural specification. + + Parameters: + gdb_regno : the number of the aux register + buffer : the value to be adjusted + */ + +void +arc_convert_aux_contents_for_write (int gdb_regno, void *buffer) +{ + ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_gdb_number(gdb_regno); + + /* Is it an auxiliary register? If not, do nothing. */ + if (def) + { + ARC_RegisterContents old; + ARC_RegisterContents new; + + memcpy(&old, buffer, BYTES_IN_REGISTER); + new = arc_write_value(def, old); + + if (new != old) + { + DEBUG("*** converted register %s value from %08X to %08X\n", + arc_aux_register_name(def), old, new); + memcpy(buffer, &new, BYTES_IN_REGISTER); + } + } +} + + +/* Initialize the module. This function is called from the gdb core on start-up. */ + +void +_initialize_arc_aux_regs (void) +{ + arc_pending_register_architecture_change_event = FALSE; + + /* If this module is being built with a test driver. */ +#ifdef STANDALONE_TEST + /* N.B. it would be better to set this up in the test driver, but that + causes problems when linking! */ + struct gdbarch_info info; + static ARC_VariantsInfo variant; + struct gdbarch_tdep *tdep = malloc (sizeof (struct gdbarch_tdep)); + struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep); + + tdep->processor_variant_info = &variant; + current_gdbarch = gdbarch; +#endif + + (void) add_cmd (REG_READ_FILE_COMMAND, + class_files, + arc_aux_reg_file_read_command, + _("Read a file describing a set of auxiliary registers.\n" + REG_READ_FILE_COMMAND_USAGE + "<FILE> is an XML file containing the auxiliary register definitions.\n"), + &cmdlist); + + (void) add_cmd (REG_READ_EXTRA_FILE_COMMAND, + class_files, + arc_aux_reg_file_read_extra_command, + _("Read a file describing an additional set of auxiliary registers.\n" + REG_READ_EXTRA_FILE_COMMAND_USAGE + "<FILE> is an XML file containing the auxiliary register definitions.\n"), + &cmdlist); + + (void) add_cmd (AUX_LIST_REGISTER_COMMAND, + class_vars, + arc_aux_reg_list_command, + _("Show a description of one or all auxiliary registers.\n" + AUX_LIST_REGISTER_COMMAND_USAGE + "<REG> is the name of an auxiliary register.\n"), + &cmdlist); + + (void) add_cmd(ARC_BCR_COMMAND, + class_info, + arc_print_bcr_regs, + _("Show Build Configuration Registers in the ARC processor variant.\n" + ARC_BCR_COMMAND_USAGE), + &infolist); + + (void) add_cmd (AUX_REG_READ_COMMAND, + class_vars, + arc_aux_reg_read_command, + _("Read and show a range of auxiliary registers.\n" + AUX_REG_READ_COMMAND_USAGE + "REG-FROM and REG-TO are the names or numbers of the registers.\n" + "If REG-TO is not specified, one register is displayed.\n"), + &cmdlist); + + (void) add_cmd (AUX_REG_WRITE_COMMAND, + class_vars, + arc_aux_reg_write_command, + _("Write to an auxiliary register.\n" + AUX_REG_WRITE_COMMAND_USAGE + "REG is the name or number of the register.\n" + "VALUE can be any expression that evaluates to an integer.\n"), + &cmdlist); + + (void) add_cmd (AUX_REG_SHOW_COMMAND, + class_vars, + arc_aux_reg_show_command, + _("Read and show one or all auxiliary registers.\n" + AUX_REG_SHOW_COMMAND_USAGE + "<REG> is the name of an auxiliary register.\n"), + &cmdlist); + + /* Provide the built-in simulator with a functions that it can use to map + from gdb register numbers to h/w register numbers, and set the fields + of aux registers to any values that they may be required to have on write. */ + arc_set_register_mapping(&simulator_mapping); + arc_set_aux_register_conversion(arc_convert_aux_contents_for_write); +} + +/******************************************************************************/ |