📄 gen.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"#include "ld-decode.h"#include "gen.h"static insn_uintsub_val (insn_uint val, int val_last_pos, int first_pos, int last_pos){ return ((val >> (val_last_pos - last_pos)) & (((insn_uint) 1 << (last_pos - first_pos + 1)) - 1));}static voidupdate_depth (lf *file, gen_entry *entry, int depth, void *data){ int *max_depth = (int *) data; if (*max_depth < depth) *max_depth = depth;}intgen_entry_depth (gen_entry *table){ int depth = 0; gen_entry_traverse_tree (NULL, table, 1, NULL, /*start */ update_depth, NULL, /*end */ &depth); /* data */ return depth;}static voidprint_gen_entry_path (line_ref *line, gen_entry *table, error_func *print){ if (table->parent == NULL) { if (table->top->model != NULL) print (line, "%s", table->top->model->name); else print (line, ""); } else { print_gen_entry_path (line, table->parent, print); print (NULL, ".%d", table->opcode_nr); }}static voidprint_gen_entry_insns (gen_entry *table, error_func *print, char *first_message, char *next_message){ insn_list *i; char *message; message = first_message; for (i = table->insns; i != NULL; i = i->next) { insn_entry *insn = i->insn; print_gen_entry_path (insn->line, table, print); print (NULL, ": %s.%s %s\n", insn->format_name, insn->name, message); if (next_message != NULL) message = next_message; }}/* same as strcmp */static intinsn_field_cmp (insn_word_entry *l, insn_word_entry *r){ while (1) { int bit_nr; if (l == NULL && r == NULL) return 0; /* all previous fields the same */ if (l == NULL) return -1; /* left shorter than right */ if (r == NULL) return +1; /* left longer than right */ for (bit_nr = 0; bit_nr < options.insn_bit_size; bit_nr++) { if (l->bit[bit_nr]->field->type != insn_field_string) continue; if (r->bit[bit_nr]->field->type != insn_field_string) continue; if (l->bit[bit_nr]->field->conditions == NULL) continue; if (r->bit[bit_nr]->field->conditions == NULL) continue; if (0) printf ("%s%s%s VS %s%s%s\n", l->bit[bit_nr]->field->val_string, l->bit[bit_nr]->field->conditions->test == insn_field_cond_eq ? "=" : "!", l->bit[bit_nr]->field->conditions->string, r->bit[bit_nr]->field->val_string, r->bit[bit_nr]->field->conditions->test == insn_field_cond_eq ? "=" : "!", r->bit[bit_nr]->field->conditions->string); if (l->bit[bit_nr]->field->conditions->test == insn_field_cond_eq && r->bit[bit_nr]->field->conditions->test == insn_field_cond_eq) { if (l->bit[bit_nr]->field->conditions->type == insn_field_cond_field && r->bit[bit_nr]->field->conditions->type == insn_field_cond_field) /* somewhat arbitrary */ { int cmp = strcmp (l->bit[bit_nr]->field->conditions->string, r->bit[bit_nr]->field->conditions-> string); if (cmp != 0) return cmp; else continue; } if (l->bit[bit_nr]->field->conditions->type == insn_field_cond_field) return +1; if (r->bit[bit_nr]->field->conditions->type == insn_field_cond_field) return -1; /* The case of both fields having constant values should have already have been handled because such fields are converted into normal constant fields. */ continue; } if (l->bit[bit_nr]->field->conditions->test == insn_field_cond_eq) return +1; /* left = only */ if (r->bit[bit_nr]->field->conditions->test == insn_field_cond_eq) return -1; /* right = only */ /* FIXME: Need to some what arbitrarily order conditional lists */ continue; } l = l->next; r = r->next; }}/* same as strcmp */static intinsn_word_cmp (insn_word_entry *l, insn_word_entry *r){ while (1) { int bit_nr; if (l == NULL && r == NULL) return 0; /* all previous fields the same */ if (l == NULL) return -1; /* left shorter than right */ if (r == NULL) return +1; /* left longer than right */ for (bit_nr = 0; bit_nr < options.insn_bit_size; bit_nr++) { if (l->bit[bit_nr]->mask < r->bit[bit_nr]->mask) return -1; if (l->bit[bit_nr]->mask > r->bit[bit_nr]->mask) return 1; if (l->bit[bit_nr]->value < r->bit[bit_nr]->value) return -1; if (l->bit[bit_nr]->value > r->bit[bit_nr]->value) return 1; } l = l->next; r = r->next; }}/* same as strcmp */static intopcode_bit_cmp (opcode_bits *l, opcode_bits *r){ if (l == NULL && r == NULL) return 0; /* all previous bits the same */ if (l == NULL) return -1; /* left shorter than right */ if (r == NULL) return +1; /* left longer than right */ /* most significant word */ if (l->field->word_nr < r->field->word_nr) return +1; /* left has more significant word */ if (l->field->word_nr > r->field->word_nr) return -1; /* right has more significant word */ /* most significant bit? */ if (l->first < r->first) return +1; /* left as more significant bit */ if (l->first > r->first) return -1; /* right as more significant bit */ /* nr bits? */ if (l->last < r->last) return +1; /* left as less bits */ if (l->last > r->last) return -1; /* right as less bits */ /* value? */ if (l->value < r->value) return -1; if (l->value > r->value) return 1; return 0;}/* same as strcmp */static intopcode_bits_cmp (opcode_bits *l, opcode_bits *r){ while (1) { int cmp; if (l == NULL && r == NULL) return 0; /* all previous bits the same */ cmp = opcode_bit_cmp (l, r); if (cmp != 0) return cmp; l = l->next; r = r->next; }}/* same as strcmp */static opcode_bits *new_opcode_bits (opcode_bits *old_bits, int value, int first, int last, insn_field_entry *field, opcode_field *opcode){ opcode_bits *new_bits = ZALLOC (opcode_bits); new_bits->field = field; new_bits->value = value; new_bits->first = first; new_bits->last = last; new_bits->opcode = opcode; if (old_bits != NULL) { opcode_bits *new_list; opcode_bits **last = &new_list; new_list = new_opcode_bits (old_bits->next, old_bits->value, old_bits->first, old_bits->last, old_bits->field, old_bits->opcode); while (*last != NULL) { int cmp = opcode_bit_cmp (new_bits, *last); if (cmp < 0) /* new < new_list */ { break; } if (cmp == 0) { ERROR ("Duplicated insn bits in list"); } last = &(*last)->next; } new_bits->next = *last; *last = new_bits; return new_list; } else { return new_bits; }}/* Same as strcmp(). */static intname_cmp (const char *l, const char *r){ if (l == NULL && r == NULL) return 0; if (l != NULL && r == NULL) return -1; if (l == NULL && r != NULL) return +1; return strcmp (l, r);}typedef enum{ merge_duplicate_insns, report_duplicate_insns,}duplicate_insn_actions;static insn_list *insn_list_insert (insn_list **cur_insn_ptr, int *nr_insns, insn_entry * insn, opcode_bits *expanded_bits, opcode_field *opcodes, int nr_prefetched_words, duplicate_insn_actions duplicate_action){ /* insert it according to the order of the fields & bits */ for (; (*cur_insn_ptr) != NULL; cur_insn_ptr = &(*cur_insn_ptr)->next) { int cmp; /* key#1 sort according to the constant fields of each instruction */ cmp = insn_word_cmp (insn->words, (*cur_insn_ptr)->insn->words); if (cmp < 0) break; else if (cmp > 0) continue; /* key#2 sort according to the expanded bits of each instruction */ cmp = opcode_bits_cmp (expanded_bits, (*cur_insn_ptr)->expanded_bits); if (cmp < 0) break; else if (cmp > 0) continue; /* key#3 sort according to the non-constant fields of each instruction */ cmp = insn_field_cmp (insn->words, (*cur_insn_ptr)->insn->words); if (cmp < 0) break; else if (cmp > 0) continue; if (duplicate_action == merge_duplicate_insns) { /* key#4: If we're going to merge duplicates, also sort according to the format_name. Two instructions with identical decode patterns, but different names, are considered different when merging. Duplicates are only important when creating a decode table (implied by report_duplicate_insns) as such a table only has the instruction's bit code as a way of differentiating between instructions. */ int cmp = name_cmp (insn->format_name, (*cur_insn_ptr)->insn->format_name); if (cmp < 0) break; else if (cmp > 0) continue; } if (duplicate_action == merge_duplicate_insns) { /* key#5: If we're going to merge duplicates, also sort according to the name. See comment above for format_name. */ int cmp = name_cmp (insn->name, (*cur_insn_ptr)->insn->name); if (cmp < 0) break; else if (cmp > 0) continue; } /* duplicate keys, report problem */ switch (duplicate_action) { case report_duplicate_insns: /* It would appear that we have two instructions with the same constant field values across all words and bits. This error can also occure when insn_field_cmp() is failing to differentiate between two instructions that differ only in their conditional fields. */ warning (insn->line, "Two instructions with identical constant fields\n"); error ((*cur_insn_ptr)->insn->line, "Location of duplicate instruction\n"); case merge_duplicate_insns: /* Add the opcode path to the instructions list */ if (options.trace.insn_insertion) { notify ((*cur_insn_ptr)->insn->line, "%s.%s: insert merge %s.%s\n", (*cur_insn_ptr)->insn->format_name, (*cur_insn_ptr)->insn->name, insn->format_name, insn->name); } if (opcodes != NULL) { insn_opcodes **last = &(*cur_insn_ptr)->opcodes; while (*last != NULL) { last = &(*last)->next; } (*last) = ZALLOC (insn_opcodes); (*last)->opcode = opcodes; } /* Use the larger nr_prefetched_words */ if ((*cur_insn_ptr)->nr_prefetched_words < nr_prefetched_words) (*cur_insn_ptr)->nr_prefetched_words = nr_prefetched_words; return (*cur_insn_ptr); } } /* create a new list entry and insert it */ { insn_list *new_insn = ZALLOC (insn_list); if (options.trace.insn_insertion) { notify (insn->line, "%s.%s: insert new\n", insn->format_name, insn->name); } new_insn->insn = insn; new_insn->expanded_bits = expanded_bits; new_insn->next = (*cur_insn_ptr); new_insn->nr_prefetched_words = nr_prefetched_words; if (opcodes != NULL) { new_insn->opcodes = ZALLOC (insn_opcodes); new_insn->opcodes->opcode = opcodes;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -