| /* 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); |
| } |
| |
| /******************************************************************************/ |