📄 ld-insn.c
字号:
/* The IGEN simulator generator for GDB, the GNU Debugger. Copyright 2002 Free Software Foundation, Inc. Contributed by Andrew Cagney. 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 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include "misc.h"#include "lf.h"#include "table.h"#include "filter.h"#include "igen.h"#include "ld-insn.h"static insn_word_entry *parse_insn_word (line_ref *line, char *string, int word_nr){ char *chp; insn_word_entry *word = ZALLOC (insn_word_entry); /* create a leading sentinal */ word->first = ZALLOC (insn_field_entry); word->first->first = -1; word->first->last = -1; word->first->width = 0; /* and a trailing sentinal */ word->last = ZALLOC (insn_field_entry); word->last->first = options.insn_bit_size; word->last->last = options.insn_bit_size; word->last->width = 0; /* link them together */ word->first->next = word->last; word->last->prev = word->first; /* now work through the formats */ chp = skip_spaces (string); while (*chp != '\0') { char *start_pos; int strlen_pos; char *start_val; int strlen_val; insn_field_entry *new_field; /* create / link in the new field */ new_field = ZALLOC (insn_field_entry); new_field->next = word->last; new_field->prev = word->last->prev; new_field->next->prev = new_field; new_field->prev->next = new_field; new_field->word_nr = word_nr; /* break out the first field (if present) */ start_pos = chp; chp = skip_to_separator (chp, ".,!"); strlen_pos = back_spaces (start_pos, chp) - start_pos; /* break out the second field (if present) */ if (*chp != '.') { /* assume what was specified was the value (and not the start position). Assume the value length implicitly specifies the number of bits */ start_val = start_pos; strlen_val = strlen_pos; start_pos = ""; strlen_pos = 0; } else { chp++; /* skip `.' */ chp = skip_spaces (chp); start_val = chp; if (*chp == '/' || *chp == '*') { do { chp++; } while (*chp == '/' || *chp == '*'); } else if (isalpha (*start_val)) { do { chp++; } while (isalnum (*chp) || *chp == '_'); } else if (isdigit (*start_val)) { do { chp++; } while (isalnum (*chp)); } strlen_val = chp - start_val; chp = skip_spaces (chp); } if (strlen_val == 0) error (line, "Empty value field\n"); /* break out any conditional fields - { [ "!" | "=" [ <value> | <field-name> } */ while (*chp == '!' || *chp == '=') { char *start; char *end; int len; insn_field_cond *new_cond = ZALLOC (insn_field_cond); /* determine the conditional test */ switch (*chp) { case '=': new_cond->test = insn_field_cond_eq; break; case '!': new_cond->test = insn_field_cond_ne; break; default: ASSERT (0); } /* save the value */ chp++; chp = skip_spaces (chp); start = chp; chp = skip_to_separator (chp, "+,:!="); end = back_spaces (start, chp); len = end - start; if (len == 0) error (line, "Missing or invalid conditional value\n"); new_cond->string = NZALLOC (char, len + 1); strncpy (new_cond->string, start, len); /* determine the conditional type */ if (isdigit (*start)) { /* [ "!" | "=" ] <value> */ new_cond->type = insn_field_cond_value; new_cond->value = a2i (new_cond->string); } else { /* [ "!" | "=" ] <field> - check field valid */ new_cond->type = insn_field_cond_field; /* new_cond->field is determined in later */ } /* Only a single `=' is permitted. */ if ((new_cond->test == insn_field_cond_eq && new_field->conditions != NULL) || (new_field->conditions != NULL && new_field->conditions->test == insn_field_cond_eq)) error (line, "Only single conditional when `=' allowed\n"); /* insert it */ { insn_field_cond **last = &new_field->conditions; while (*last != NULL) last = &(*last)->next; *last = new_cond; } } /* NOW verify that the field was finished */ if (*chp == ',') { chp = skip_spaces (chp + 1); if (*chp == '\0') error (line, "empty field\n"); } else if (*chp != '\0') { error (line, "Missing field separator\n"); } /* copy the value */ new_field->val_string = NZALLOC (char, strlen_val + 1); strncpy (new_field->val_string, start_val, strlen_val); if (isdigit (new_field->val_string[0])) { if (strlen_pos == 0) { /* when the length/pos field is omited, an integer field is always binary */ unsigned64 val = 0; int i; for (i = 0; i < strlen_val; i++) { if (new_field->val_string[i] != '0' && new_field->val_string[i] != '1') error (line, "invalid binary field %s\n", new_field->val_string); val = (val << 1) + (new_field->val_string[i] == '1'); } new_field->val_int = val; new_field->type = insn_field_int; } else { new_field->val_int = a2i (new_field->val_string); new_field->type = insn_field_int; } } else if (new_field->val_string[0] == '/') { new_field->type = insn_field_reserved; } else if (new_field->val_string[0] == '*') { new_field->type = insn_field_wild; } else { new_field->type = insn_field_string; if (filter_is_member (word->field_names, new_field->val_string)) error (line, "Field name %s is duplicated\n", new_field->val_string); filter_parse (&word->field_names, new_field->val_string); } if (new_field->type != insn_field_string && new_field->conditions != NULL) error (line, "Conditionals can only be applied to named fields\n"); /* the copy the position */ new_field->pos_string = NZALLOC (char, strlen_pos + 1); strncpy (new_field->pos_string, start_pos, strlen_pos); if (strlen_pos == 0) { new_field->first = new_field->prev->last + 1; if (new_field->first == 0 /* first field */ && *chp == '\0' /* no further fields */ && new_field->type == insn_field_string) { /* A single string without any position, assume that it represents the entire instruction word */ new_field->width = options.insn_bit_size; } else { /* No explicit width/position, assume value implicitly supplies the width */ new_field->width = strlen_val; } new_field->last = new_field->first + new_field->width - 1; if (new_field->last >= options.insn_bit_size) error (line, "Bit position %d exceed instruction bit size (%d)\n", new_field->last, options.insn_bit_size); } else if (options.insn_specifying_widths) { new_field->first = new_field->prev->last + 1; new_field->width = a2i (new_field->pos_string); new_field->last = new_field->first + new_field->width - 1; if (new_field->last >= options.insn_bit_size) error (line, "Bit position %d exceed instruction bit size (%d)\n", new_field->last, options.insn_bit_size); } else { new_field->first = target_a2i (options.hi_bit_nr, new_field->pos_string); new_field->last = new_field->next->first - 1; /* guess */ new_field->width = new_field->last - new_field->first + 1; /* guess */ new_field->prev->last = new_field->first - 1; /*fix */ new_field->prev->width = new_field->first - new_field->prev->first; /*fix */ } } /* fiddle first/last so that the sentinals disapear */ ASSERT (word->first->last < 0); ASSERT (word->last->first >= options.insn_bit_size); word->first = word->first->next; word->last = word->last->prev; /* check that the last field goes all the way to the last bit */ if (word->last->last != options.insn_bit_size - 1) { if (options.warn.width) options.warning (line, "Instruction format is not %d bits wide\n", options.insn_bit_size); word->last->last = options.insn_bit_size - 1; } /* now go over this again, pointing each bit position at a field record */ { insn_field_entry *field; for (field = word->first; field->last < options.insn_bit_size; field = field->next) { int i; for (i = field->first; i <= field->last; i++) { word->bit[i] = ZALLOC (insn_bit_entry); word->bit[i]->field = field; switch (field->type) { case insn_field_invalid: ASSERT (0); break; case insn_field_int: word->bit[i]->mask = 1; word->bit[i]->value = ((field->val_int & ((insn_uint) 1 << (field->last - i))) != 0); case insn_field_reserved: case insn_field_wild: case insn_field_string: /* if we encounter a constant conditional, encode their bit value. */ if (field->conditions != NULL && field->conditions->test == insn_field_cond_eq && field->conditions->type == insn_field_cond_value) { word->bit[i]->mask = 1; word->bit[i]->value = ((field->conditions->value & ((insn_uint) 1 << (field->last - i))) != 0); } break; } } } } return word;}static voidparse_insn_words (insn_entry * insn, char *formats){ insn_word_entry **last_word = &insn->words; char *chp; /* now work through the formats */ insn->nr_words = 0; chp = formats; while (1) { char *start_pos; char *end_pos; int strlen_pos; char *format; insn_word_entry *new_word; /* skip leading spaces */ chp = skip_spaces (chp); /* break out the format */ start_pos = chp; chp = skip_to_separator (chp, "+"); end_pos = back_spaces (start_pos, chp); strlen_pos = end_pos - start_pos; /* check that something was there */ if (strlen_pos == 0) error (insn->line, "missing or empty instruction format\n"); /* parse the field */ format = NZALLOC (char, strlen_pos + 1); strncpy (format, start_pos, strlen_pos); new_word = parse_insn_word (insn->line, format, insn->nr_words); insn->nr_words++; if (filter_is_common (insn->field_names, new_word->field_names)) error (insn->line, "Field name duplicated between two words\n"); filter_add (&insn->field_names, new_word->field_names); /* insert it */ *last_word = new_word; last_word = &new_word->next; /* last format? */ if (*chp == '\0') break; ASSERT (*chp == '+'); chp++; } /* create a quick access array (indexed by word) of the same structure */ { int i; insn_word_entry *word; insn->word = NZALLOC (insn_word_entry *, insn->nr_words + 1); for (i = 0, word = insn->words; i < insn->nr_words; i++, word = word->next) insn->word[i] = word; } /* Go over all fields that have conditionals refering to other fields. Link the fields up. Verify that the two fields have the same size. Verify that the two fields are different */ { int i; for (i = 0; i < insn->nr_words; i++) { insn_word_entry *word = insn->word[i]; insn_field_entry *f; for (f = word->first; f->last < options.insn_bit_size; f = f->next) { insn_field_cond *cond; for (cond = f->conditions; cond != NULL; cond = cond->next) { if (cond->type == insn_field_cond_field) { int j; if (strcmp (cond->string, f->val_string) == 0) error (insn->line, "Conditional `%s' of field `%s' refers to its self\n", cond->string, f->val_string); for (j = 0; j <= i && cond->field == NULL; j++) { insn_word_entry *refered_word = insn->word[j]; insn_field_entry *refered_field; for (refered_field = refered_word->first; refered_field != NULL && cond->field == NULL; refered_field = refered_field->next) { if (refered_field->type == insn_field_string && strcmp (refered_field->val_string, cond->string) == 0) { /* found field being refered to by conditonal */ cond->field = refered_field; /* check refered to and this field are the same size */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -