diff options
author | Michael Meissner <gnu@the-meissners.org> | 1995-11-01 19:32:38 +0000 |
---|---|---|
committer | Michael Meissner <gnu@the-meissners.org> | 1995-11-01 19:32:38 +0000 |
commit | c143ef6296268bb98a697572a589d47bb375d372 (patch) | |
tree | a8803d93f14172ed925726d1d0ee680c57d63a36 /sim/ppc/igen.c | |
parent | 7f82c7e1ee2dc3533a913588d9909f568bce27eb (diff) | |
download | gdb-c143ef6296268bb98a697572a589d47bb375d372.zip gdb-c143ef6296268bb98a697572a589d47bb375d372.tar.gz gdb-c143ef6296268bb98a697572a589d47bb375d372.tar.bz2 |
Lots of changes
Diffstat (limited to 'sim/ppc/igen.c')
-rw-r--r-- | sim/ppc/igen.c | 2834 |
1 files changed, 2834 insertions, 0 deletions
diff --git a/sim/ppc/igen.c b/sim/ppc/igen.c new file mode 100644 index 0000000..78c1494 --- /dev/null +++ b/sim/ppc/igen.c @@ -0,0 +1,2834 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> + + 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 <stdio.h> +#include <ctype.h> +#include <string.h> +#include <getopt.h> + +#include "misc.h" +#include "lf.h" +#include "table.h" + + +/****************************************************************/ + +enum { + insn_size = 32, +}; + +int idecode_expand_semantics = 0; +int idecode_cache = 0; +int number_lines = 1; + + +/****************************************************************/ + + +char *cache_idecode_formal = "cpu *processor,\n instruction_word instruction,\n unsigned_word cia,\n idecode_cache *cache_entry"; +char *cache_idecode_actual = "processor, instruction, cia, cache_entry"; + +char *cache_semantic_formal = "cpu *processor,\n idecode_cache *cache_entry,\n unsigned_word cia"; +char *cache_semantic_actual = "processor, entry, cia"; + +char *semantic_formal = "cpu *processor,\n instruction_word instruction,\n unsigned_word cia"; +char *semantic_actual = "processor, instruction, cia"; + +char *semantic_local = "unsigned_word nia = cia + 4;"; + + +/****************************************************************/ + + +typedef struct _filter filter; +struct _filter { + char *flag; + filter *next; +}; +filter *filters = NULL; + + +/****************************************************************/ + + +typedef struct _cache_rules cache_rules; +struct _cache_rules { + int valid; + char *old_name; + char *new_name; + char *type; + char *expression; + cache_rules *next; +}; +cache_rules *cache_table; + + +enum { + ca_valid, + ca_old_name, + ca_new_name, + ca_type, + ca_expression, + nr_cache_rule_fields, +}; + +static cache_rules * +load_cache_rules(char *file_name) +{ + table *file = table_open(file_name, nr_cache_rule_fields); + table_entry *entry; + cache_rules *table = NULL; + cache_rules **curr_rule = &table; + while ((entry = table_entry_read(file)) != NULL) { + cache_rules *new_rule = ZALLOC(cache_rules); + new_rule->valid = a2i(entry->fields[ca_valid]); + new_rule->old_name = entry->fields[ca_old_name]; + new_rule->new_name = entry->fields[ca_new_name]; + new_rule->type = (strlen(entry->fields[ca_type]) + ? entry->fields[ca_type] + : NULL); + new_rule->expression = (strlen(entry->fields[ca_expression]) > 0 + ? entry->fields[ca_expression] + : NULL); + *curr_rule = new_rule; + curr_rule = &new_rule->next; + } + return table; +} + + + +static void +dump_cache_rule(cache_rules* rule, + int indent) +{ + dumpf(indent, "((cache_rules*)0x%x\n", rule); + dumpf(indent, " (valid %d)\n", rule->valid); + dumpf(indent, " (old_name \"%s\")\n", rule->old_name); + dumpf(indent, " (new_name \"%s\")\n", rule->new_name); + dumpf(indent, " (type \"%s\")\n", rule->type); + dumpf(indent, " (expression \"%s\")\n", rule->expression); + dumpf(indent, " (next 0x%x)\n", rule->next); + dumpf(indent, " )\n"); +} + + +static void +dump_cache_rules(cache_rules* rule, int indent) +{ + while (rule) { + dump_cache_rule(rule, indent); + rule = rule->next; + } +} + + +/****************************************************************/ + + +typedef struct _opcode_rules opcode_rules; +struct _opcode_rules { + int first; + int last; + int force_first; + int force_last; + int force_slash; + char *force_expansion; + int use_switch; + unsigned special_mask; + unsigned special_value; + unsigned special_rule; + opcode_rules *next; +}; +opcode_rules *opcode_table; + + +enum { + op_first, + op_last, + op_force_first, + op_force_last, + op_force_slash, + op_force_expansion, + op_use_switch, + op_special_mask, + op_special_value, + op_special_rule, + nr_opcode_fields, +}; + + +static opcode_rules * +load_opcode_rules(char *file_name) +{ + table *file = table_open(file_name, nr_opcode_fields); + table_entry *entry; + opcode_rules *table = NULL; + opcode_rules **curr_rule = &table; + while ((entry = table_entry_read(file)) != NULL) { + opcode_rules *new_rule = ZALLOC(opcode_rules); + new_rule->first = a2i(entry->fields[op_first]); + new_rule->last = a2i(entry->fields[op_last]); + new_rule->force_first = a2i(entry->fields[op_force_first]); + new_rule->force_last = a2i(entry->fields[op_force_last]); + new_rule->force_slash = a2i(entry->fields[op_force_slash]); + new_rule->force_expansion = entry->fields[op_force_expansion]; + new_rule->use_switch = a2i(entry->fields[op_use_switch]); + new_rule->special_mask = a2i(entry->fields[op_special_mask]); + new_rule->special_value = a2i(entry->fields[op_special_value]); + new_rule->special_rule = a2i(entry->fields[op_special_rule]); + *curr_rule = new_rule; + curr_rule = &new_rule->next; + } + return table; +} + + +static void +dump_opcode_rule(opcode_rules *rule, + int indent) +{ + dumpf(indent, "((opcode_rules*)%p\n", rule); + if (rule) { + dumpf(indent, " (first %d)\n", rule->first); + dumpf(indent, " (last %d)\n", rule->last); + dumpf(indent, " (force_first %d)\n", rule->force_first); + dumpf(indent, " (force_last %d)\n", rule->force_last); + dumpf(indent, " (force_slash %d)\n", rule->force_slash); + dumpf(indent, " (force_expansion \"%s\")\n", rule->force_expansion); + dumpf(indent, " (use_switch %d)\n", rule->use_switch); + dumpf(indent, " (special_mask 0x%x)\n", rule->special_mask); + dumpf(indent, " (special_value 0x%x)\n", rule->special_value); + dumpf(indent, " (special_rule 0x%x)\n", rule->special_rule); + dumpf(indent, " (next 0x%x)\n", rule->next); + } + dumpf(indent, " )\n"); +} + + +static void +dump_opcode_rules(opcode_rules *rule, + int indent) +{ + while (rule) { + dump_opcode_rule(rule, indent); + rule = rule->next; + } +} + + +/****************************************************************/ + +typedef struct _insn_field insn_field; +struct _insn_field { + int first; + int last; + int width; + int is_int; + int is_slash; + int is_string; + int val_int; + char *pos_string; + char *val_string; + insn_field *next; + insn_field *prev; +}; + +typedef struct _insn_fields insn_fields; +struct _insn_fields { + insn_field *bits[insn_size]; + insn_field *first; + insn_field *last; + unsigned value; +}; + +static insn_fields * +parse_insn_format(table_entry *entry, + char *format) +{ + char *chp; + insn_fields *fields = ZALLOC(insn_fields); + + /* create a leading sentinal */ + fields->first = ZALLOC(insn_field); + fields->first->first = -1; + fields->first->last = -1; + fields->first->width = 0; + + /* and a trailing sentinal */ + fields->last = ZALLOC(insn_field); + fields->last->first = insn_size; + fields->last->last = insn_size; + fields->last->width = 0; + + /* link them together */ + fields->first->next = fields->last; + fields->last->prev = fields->first; + + /* now work through the formats */ + chp = format; + + while (*chp != '\0') { + char *start_pos; + char *start_val; + int strlen_val; + int strlen_pos; + insn_field *new_field; + + /* sanity check */ + if (!isdigit(*chp)) { + error("%s:%d: missing position field at `%s'\n", + entry->file_name, entry->line_nr, chp); + } + + /* break out the bit position */ + start_pos = chp; + while (isdigit(*chp)) + chp++; + strlen_pos = chp - start_pos; + if (*chp == '.' && strlen_pos > 0) + chp++; + else { + error("%s:%d: missing field value at %s\n", + entry->file_name, entry->line_nr, chp); + break; + } + + /* break out the value */ + start_val = chp; + while ((*start_val == '/' && *chp == '/') + || (isdigit(*start_val) && isdigit(*chp)) + || (isalpha(*start_val) && (isalnum(*chp) || *chp == '_'))) + chp++; + strlen_val = chp - start_val; + if (*chp == ',') + chp++; + else if (*chp != '\0' || strlen_val == 0) { + error("%s:%d: missing field terminator at %s\n", + entry->file_name, entry->line_nr, chp); + break; + } + + /* create a new field and insert it */ + new_field = ZALLOC(insn_field); + new_field->next = fields->last; + new_field->prev = fields->last->prev; + new_field->next->prev = new_field; + new_field->prev->next = new_field; + + /* the value */ + new_field->val_string = (char*)zalloc(strlen_val+1); + strncpy(new_field->val_string, start_val, strlen_val); + if (isdigit(*new_field->val_string)) { + new_field->val_int = a2i(new_field->val_string); + new_field->is_int = 1; + } + else if (new_field->val_string[0] == '/') { + new_field->is_slash = 1; + } + else { + new_field->is_string = 1; + } + + /* the pos */ + new_field->pos_string = (char*)zalloc(strlen_pos+1); + strncpy(new_field->pos_string, start_pos, strlen_pos); + new_field->first = a2i(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(fields->first->last < 0); + ASSERT(fields->last->first >= insn_size); + fields->first = fields->first->next; + fields->last = fields->last->prev; + + /* now go over this again, pointing each bit position at a field + record */ + { + int i; + insn_field *field; + field = fields->first; + for (i = 0; i < insn_size; i++) { + while (field->last < i) + field = field->next; + fields->bits[i] = field; + } + } + + /* go over each of the fields, and compute a `value' for the insn */ + { + insn_field *field; + fields->value = 0; + for (field = fields->first; + field->last < insn_size; + field = field->next) { + fields->value <<= field->width; + if (field->is_int) + fields->value |= field->val_int; + } + } + return fields; +} + + +typedef enum { + field_constant_int = 1, + field_constant_slash = 2, + field_constant_string = 3 +} constant_field_types; + + +static int +insn_field_is_constant(insn_field *field, + opcode_rules *rule) +{ + /* field is an integer */ + if (field->is_int) + return field_constant_int; + /* field is `/' and treating that as a constant */ + if (field->is_slash && rule->force_slash) + return field_constant_slash; + /* field, though variable is on the list */ + if (field->is_string && rule->force_expansion != NULL) { + char *forced_fields = rule->force_expansion; + while (*forced_fields != '\0') { + int field_len; + char *end = strchr(forced_fields, ','); + if (end == NULL) + field_len = strlen(forced_fields); + else + field_len = end-forced_fields; + if (strncmp(forced_fields, field->val_string, field_len) == 0 + && field->val_string[field_len] == '\0') + return field_constant_string; + forced_fields += field_len; + if (*forced_fields == ',') + forced_fields++; + } + } + return 0; +} + + +static void +dump_insn_field(insn_field *field, + int indent) +{ + + printf("(insn_field*)0x%x\n", (unsigned)field); + + dumpf(indent, "(first %d)\n", field->first); + + dumpf(indent, "(last %d)\n", field->last); + + dumpf(indent, "(width %d)\n", field->width); + + if (field->is_int) + dumpf(indent, "(is_int %d)\n", field->val_int); + + if (field->is_slash) + dumpf(indent, "(is_slash)\n"); + + if (field->is_string) + dumpf(indent, "(is_string `%s')\n", field->val_string); + + dumpf(indent, "(next 0x%x)\n", field->next); + + dumpf(indent, "(prev 0x%x)\n", field->prev); + + +} + +static void +dump_insn_fields(insn_fields *fields, + int indent) +{ + int i; + + printf("(insn_fields*)%p\n", fields); + + dumpf(indent, "(first 0x%x)\n", fields->first); + dumpf(indent, "(last 0x%x)\n", fields->last); + + dumpf(indent, "(value 0x%x)\n", fields->value); + + for (i = 0; i < insn_size; i++) { + dumpf(indent, "(bits[%d] ", i, fields->bits[i]); + dump_insn_field(fields->bits[i], indent+1); + dumpf(indent, " )\n"); + } + +} + + +/****************************************************************/ + +typedef struct _opcode_field opcode_field; +struct _opcode_field { + int first; + int last; + int is_boolean; + opcode_field *parent; +}; + +static opcode_field * +opcode_field_new() +{ + opcode_field *new_field = (opcode_field*)zalloc(sizeof(opcode_field)); + ASSERT(new_field != NULL); + new_field->first = insn_size; + new_field->last = -1; + return new_field; +} + +static void +dump_opcode_field(opcode_field *field, int indent, int levels) +{ + printf("(opcode_field*)%p\n", field); + if (levels && field != NULL) { + dumpf(indent, "(first %d)\n", field->first); + dumpf(indent, "(last %d)\n", field->last); + dumpf(indent, "(is_boolean %d)\n", field->is_boolean); + dumpf(indent, "(parent "); + dump_opcode_field(field->parent, indent, levels-1); + } +} + + +/****************************************************************/ + +typedef struct _insn_bits insn_bits; +struct _insn_bits { + int is_expanded; + int value; + insn_field *field; + opcode_field *opcode; + insn_bits *last; +}; + + +static void +dump_insn_bits(insn_bits *bits, int indent, int levels) +{ + printf("(insn_bits*)%p\n", bits); + + if (levels && bits != NULL) { + dumpf(indent, "(value %d)\n", bits->value); + dumpf(indent, "(opcode "); + dump_opcode_field(bits->opcode, indent+1, 0); + dumpf(indent, " )\n"); + dumpf(indent, "(field "); + dump_insn_field(bits->field, indent+1); + dumpf(indent, " )\n"); + dumpf(indent, "(last "); + dump_insn_bits(bits->last, indent+1, levels-1); + } +} + + +/****************************************************************/ + + +typedef enum { + insn_format, + insn_form, + insn_flags, + insn_nmemonic, + insn_name, + insn_comment, + nr_insn_table_fields, +} insn_table_fields; +char *insn_field_name[nr_insn_table_fields] = { + "format", "form", "flags", "nmemonic", "name", "comments" +}; + +typedef enum { + function_type = insn_format, + function_name = insn_name, + function_param = insn_comment, +} function_table_fields; + + +typedef struct _insn insn; +struct _insn { + table_entry *file_entry; + insn_fields *fields; + insn *next; +}; + +typedef struct _insn_table insn_table; +struct _insn_table { + int opcode_nr; + insn_bits *expanded_bits; + int nr_insn; + insn *insns; + insn *functions; + opcode_rules *opcode_rule; + opcode_field *opcode; + int nr_entries; + insn_table *entries; + insn_table *sibling; + insn_table *parent; +}; + + + +static void +insn_table_insert_function(insn_table *table, + table_entry *file_entry) +{ + insn **ptr_to_cur_function = &table->functions; + + /* create a new function */ + insn *new_function = ZALLOC(insn); + new_function->file_entry = file_entry; + + /* append it to the end of the function list */ + while (*ptr_to_cur_function != NULL) { + ptr_to_cur_function = &(*ptr_to_cur_function)->next; + } + *ptr_to_cur_function = new_function; +} + + +static void +insn_table_insert_insn(insn_table *table, + table_entry *file_entry, + insn_fields *fields) +{ + insn **ptr_to_cur_insn = &table->insns; + insn *cur_insn = *ptr_to_cur_insn; + + /* create a new instruction */ + insn *new_insn = ZALLOC(insn); + new_insn->file_entry = file_entry; + new_insn->fields = fields; + + /* insert it according to the order of the fields */ + while (cur_insn != NULL + && new_insn->fields->value >= cur_insn->fields->value) { + ptr_to_cur_insn = &cur_insn->next; + cur_insn = *ptr_to_cur_insn; + } + + new_insn->next = cur_insn; + *ptr_to_cur_insn = new_insn; + + table->nr_insn++; +} + + +static opcode_field * +insn_table_find_opcode_field(insn *insns, + opcode_rules *rule, + int string_only) +{ + opcode_field *curr_opcode = opcode_field_new(); + insn *entry; + + ASSERT(rule); + + for (entry = insns; entry != NULL; entry = entry->next) { + insn_fields *fields = entry->fields; + opcode_field new_opcode; + + /* find a start point for the opcode field */ + new_opcode.first = rule->first; + while (new_opcode.first <= rule->last + && (!string_only + || insn_field_is_constant(fields->bits[new_opcode.first], + rule) != field_constant_string) + && (string_only + || !insn_field_is_constant(fields->bits[new_opcode.first], + rule))) + new_opcode.first = fields->bits[new_opcode.first]->last + 1; + ASSERT(new_opcode.first > rule->last + || (string_only + && insn_field_is_constant(fields->bits[new_opcode.first], + rule) == field_constant_string) + || (!string_only + && insn_field_is_constant(fields->bits[new_opcode.first], + rule))); + + /* find the end point for the opcode field */ + new_opcode.last = rule->last; + while (new_opcode.last >= rule->first + && (!string_only + || insn_field_is_constant(fields->bits[new_opcode.last], + rule) != field_constant_string) + && (string_only + || !insn_field_is_constant(fields->bits[new_opcode.last], + rule))) + new_opcode.last = fields->bits[new_opcode.last]->first - 1; + ASSERT(new_opcode.last < rule->first + || (string_only + && insn_field_is_constant(fields->bits[new_opcode.last], + rule) == field_constant_string) + || (!string_only + && insn_field_is_constant(fields->bits[new_opcode.last], + rule))); + + /* now see if our current opcode needs expanding */ + if (new_opcode.first <= rule->last + && curr_opcode->first > new_opcode.first) + curr_opcode->first = new_opcode.first; + if (new_opcode.last >= rule->first + && curr_opcode->last < new_opcode.last) + curr_opcode->last = new_opcode.last; + + } + + /* was any thing interesting found? */ + if (curr_opcode->first > rule->last) { + ASSERT(curr_opcode->last < rule->first); + return NULL; + } + ASSERT(curr_opcode->last >= rule->first); + ASSERT(curr_opcode->first <= rule->last); + + /* if something was found, check it includes the forced field range */ + if (!string_only + && curr_opcode->first > rule->force_first) { + curr_opcode->first = rule->force_first; + } + if (!string_only + && curr_opcode->last < rule->force_last) { + curr_opcode->last = rule->force_last; + } + /* handle special case elminating any need to do shift after mask */ + if (string_only + && rule->force_last == insn_size-1) { + curr_opcode->last = insn_size-1; + } + + /* handle any special cases */ + switch (rule->special_rule) { + case 0: /* let the above apply */ + break; + case 1: /* expand a limited nr of bits, ignoring the rest */ + curr_opcode->first = rule->force_first; + curr_opcode->last = rule->force_last; + break; + case 2: /* boolean field */ + curr_opcode->is_boolean = 1; + break; + } + + return curr_opcode; +} + + +static void +insn_table_insert_expanded(insn_table *table, + insn *old_insn, + int new_opcode_nr, + insn_bits *new_bits) +{ + insn_table **ptr_to_cur_entry = &table->entries; + insn_table *cur_entry = *ptr_to_cur_entry; + + /* find the new table for this entry */ + while (cur_entry != NULL + && cur_entry->opcode_nr < new_opcode_nr) { + ptr_to_cur_entry = &cur_entry->sibling; + cur_entry = *ptr_to_cur_entry; + } + + if (cur_entry == NULL || cur_entry->opcode_nr != new_opcode_nr) { + insn_table *new_entry = ZALLOC(insn_table); + new_entry->opcode_nr = new_opcode_nr; + new_entry->expanded_bits = new_bits; + new_entry->opcode_rule = table->opcode_rule->next; + new_entry->sibling = cur_entry; + new_entry->parent = table; + *ptr_to_cur_entry = new_entry; + cur_entry = new_entry; + table->nr_entries++; + } + /* ASSERT new_bits == cur_entry bits */ + ASSERT(cur_entry != NULL && cur_entry->opcode_nr == new_opcode_nr); + insn_table_insert_insn(cur_entry, + old_insn->file_entry, + old_insn->fields); +} + +static void +insn_table_expand_opcode(insn_table *table, + insn *instruction, + int field_nr, + int opcode_nr, + insn_bits *bits) +{ + + if (field_nr > table->opcode->last) { + insn_table_insert_expanded(table, instruction, opcode_nr, bits); + } + else { + insn_field *field = instruction->fields->bits[field_nr]; + if (field->is_int || field->is_slash) { + ASSERT(field->first >= table->opcode->first + && field->last <= table->opcode->last); + insn_table_expand_opcode(table, instruction, field->last+1, + ((opcode_nr << field->width) + field->val_int), + bits); + } + else { + int val; + int last_pos = ((field->last < table->opcode->last) + ? field->last : table->opcode->last); + int first_pos = ((field->first > table->opcode->first) + ? field->first : table->opcode->first); + int width = last_pos - first_pos + 1; + int last_val = (table->opcode->is_boolean + ? 2 : (1 << width)); + for (val = 0; val < last_val; val++) { + insn_bits *new_bits = ZALLOC(insn_bits); + new_bits->field = field; + new_bits->value = val; + new_bits->last = bits; + new_bits->opcode = table->opcode; + insn_table_expand_opcode(table, instruction, last_pos+1, + ((opcode_nr << width) | val), + new_bits); + } + } + } +} + +static void +insn_table_insert_expanding(insn_table *table, + insn *entry) +{ + insn_table_expand_opcode(table, + entry, + table->opcode->first, + 0, + table->expanded_bits); +} + + +static void +insn_table_expand_insns(insn_table *table) +{ + + ASSERT(table->nr_insn >= 1); + + /* determine a valid opcode */ + while (table->opcode_rule) { + /* specials only for single instructions */ + if ((table->nr_insn > 1 + && table->opcode_rule->special_mask == 0 + && table->opcode_rule->special_rule == 0) + || (table->nr_insn == 1 + && table->opcode_rule->special_mask != 0 + && ((table->insns->fields->value + & table->opcode_rule->special_mask) + == table->opcode_rule->special_value)) + || (idecode_expand_semantics + && table->opcode_rule->special_mask == 0 + && table->opcode_rule->special_rule == 0)) + table->opcode = + insn_table_find_opcode_field(table->insns, + table->opcode_rule, + table->nr_insn == 1/*string*/ + ); + if (table->opcode != NULL) + break; + table->opcode_rule = table->opcode_rule->next; + } + + /* did we find anything */ + if (table->opcode == NULL) { + return; + } + ASSERT(table->opcode != NULL); + + /* back link what we found to its parent */ + if (table->parent != NULL) { + ASSERT(table->parent->opcode != NULL); + table->opcode->parent = table->parent->opcode; + } + + /* expand the raw instructions according to the opcode */ + { + insn *entry; + for (entry = table->insns; entry != NULL; entry = entry->next) { + insn_table_insert_expanding(table, entry); + } + } + + /* and do the same for the sub entries */ + { + insn_table *entry; + for (entry = table->entries; entry != NULL; entry = entry->sibling) { + insn_table_expand_insns(entry); + } + } +} + + + +static insn_table * +insn_table_load_insns(char *file_name) +{ + table *file = table_open(file_name, nr_insn_table_fields); + insn_table *table = ZALLOC(insn_table); + table_entry *file_entry; + table->opcode_rule = opcode_table; + + while ((file_entry = table_entry_read(file)) != NULL) { + if (it_is("function", file_entry->fields[insn_flags]) + || it_is("internal", file_entry->fields[insn_flags])) { + insn_table_insert_function(table, file_entry); + } + else { + insn_fields *fields; + /* skip instructions that aren't relevant to the mode */ + filter *filt = filters; + while (filt != NULL) { + if (it_is(filt->flag, file_entry->fields[insn_flags])) + break; + filt = filt->next; + } + if (filt == NULL) { + /* create/insert the new instruction */ + fields = parse_insn_format(file_entry, + file_entry->fields[insn_format]); + insn_table_insert_insn(table, file_entry, fields); + } + } + } + return table; +} + + +static void +dump_insn(insn *entry, int indent, int levels) +{ + printf("(insn*)%p\n", entry); + + if (levels && entry != NULL) { + + dumpf(indent, "(file_entry "); + dump_table_entry(entry->file_entry, indent+1); + dumpf(indent, " )\n"); + + dumpf(indent, "(fields "); + dump_insn_fields(entry->fields, indent+1); + dumpf(indent, " )\n"); + + dumpf(indent, "(next "); + dump_insn(entry->next, indent+1, levels-1); + dumpf(indent, " )\n"); + + } + +} + + +static void +dump_insn_table(insn_table *table, + int indent, int levels) +{ + + printf("(insn_table*)%p\n", table); + + if (levels && table != NULL) { + + dumpf(indent, "(opcode_nr %d)\n", table->opcode_nr); + + dumpf(indent, "(expanded_bits "); + dump_insn_bits(table->expanded_bits, indent+1, -1); + dumpf(indent, " )\n"); + + dumpf(indent, "(int nr_insn %d)\n", table->nr_insn); + + dumpf(indent, "(insns "); + dump_insn(table->insns, indent+1, table->nr_insn); + dumpf(indent, " )\n"); + + dumpf(indent, "(opcode_rule "); + dump_opcode_rule(table->opcode_rule, indent+1); + dumpf(indent, " )\n"); + + dumpf(indent, "(opcode "); + dump_opcode_field(table->opcode, indent+1, 1); + dumpf(indent, " )\n"); + + dumpf(indent, "(nr_entries %d)\n", table->entries); + dumpf(indent, "(entries "); + dump_insn_table(table->entries, indent+1, table->nr_entries); + dumpf(indent, " )\n"); + + dumpf(indent, "(sibling ", table->sibling); + dump_insn_table(table->sibling, indent+1, levels-1); + dumpf(indent, " )\n"); + + dumpf(indent, "(parent ", table->parent); + dump_insn_table(table->parent, indent+1, 0); + dumpf(indent, " )\n"); + + } +} + + +/****************************************************************/ + + +static void +lf_print_insn_bits(lf *file, insn_bits *bits) +{ + if (bits == NULL) + return; + lf_print_insn_bits(file, bits->last); + lf_putchr(file, '_'); + lf_putstr(file, bits->field->val_string); + if (!bits->opcode->is_boolean || bits->value == 0) { + if (bits->opcode->last < bits->field->last) + lf_putint(file, bits->value << (bits->field->last - bits->opcode->last)); + else + lf_putint(file, bits->value); + } +} + +static void +lf_print_opcodes(lf *file, + insn_table *table) +{ + if (table != NULL) { + while (1) { + lf_printf(file, "_%d_%d", + table->opcode->first, + table->opcode->last); + if (table->parent == NULL) break; + lf_printf(file, "__%d", table->opcode_nr); + table = table->parent; + } + } +} + +static void +lf_print_table_name(lf *file, + insn_table *table) +{ + lf_printf(file, "idecode_table"); + lf_print_opcodes(file, table); +} + + + +typedef enum { + function_name_prefix_semantics, + function_name_prefix_idecode, + function_name_prefix_itable, + function_name_prefix_none +} lf_function_name_prefixes; + +static void +lf_print_function_name(lf *file, + char *basename, + insn_bits *expanded_bits, + lf_function_name_prefixes prefix) +{ + + /* the prefix */ + switch (prefix) { + case function_name_prefix_semantics: + lf_putstr(file, "semantic_"); + break; + case function_name_prefix_idecode: + lf_printf(file, "idecode_"); + break; + case function_name_prefix_itable: + lf_putstr(file, "itable_"); + break; + default: + break; + } + + /* the function name */ + { + char *pos; + for (pos = basename; + *pos != '\0'; + pos++) { + switch (*pos) { + case '/': + case '-': + break; + case ' ': + lf_putchr(file, '_'); + break; + default: + lf_putchr(file, *pos); + break; + } + } + } + + /* the suffix */ + if (idecode_expand_semantics) + lf_print_insn_bits(file, expanded_bits); +} + + +static void +lf_print_idecode_table(lf *file, + insn_table *entry) +{ + int can_assume_leaf; + opcode_rules *opcode_rule; + + /* have a look at the rule table, if all table rules follow all + switch rules, I can assume that all end points are leaves */ + opcode_rule = opcode_table; + while (opcode_rule != NULL + && opcode_rule->use_switch) + opcode_rule = opcode_rule->next; + while (opcode_rule != NULL + && opcode_rule->use_switch + && opcode_rule->special_rule) + opcode_rule = opcode_rule->next; + can_assume_leaf = opcode_rule == NULL; + + lf_printf(file, "{\n"); + lf_indent(file, +2); + { + lf_printf(file, "idecode_table_entry *table = "); + lf_print_table_name(file, entry); + lf_printf(file, ";\n"); + lf_printf(file, "int opcode = EXTRACTED32(instruction, %d, %d);\n", + entry->opcode->first, entry->opcode->last); + lf_printf(file, "idecode_table_entry *table_entry = table + opcode;\n"); + lf_printf(file, "while (1) {\n"); + lf_indent(file, +2); + { + lf_printf(file, "while (table_entry->mask != 0) {\n"); + lf_indent(file, +2); + { + lf_printf(file, "table = ((idecode_table_entry*)\n"); + lf_printf(file, " table_entry->function_or_table);\n"); + lf_printf(file, "opcode = ((instruction & table_entry->mask)\n"); + lf_printf(file, " >> table_entry->shift);\n"); + lf_printf(file, "table_entry = table + opcode;\n"); + } + lf_indent(file, -2); + lf_printf(file, "}\n"); + if (!idecode_cache && can_assume_leaf) { + lf_printf(file, "return (((idecode_semantic*)\n"); + lf_printf(file, " table_entry->function_or_table)\n"); + lf_printf(file, " (%s));\n", semantic_actual); + } + else if (!idecode_cache && !can_assume_leaf) { + lf_printf(file, "if (table_entry->shift == 0)"); + lf_printf(file, " return (((idecode_semantic*)\n"); + lf_printf(file, " table_entry->function_or_table)\n"); + lf_printf(file, " (%s));\n", semantic_actual); + } + else { + lf_printf(file, "if (table_entry->shift == 0)\n"); + lf_printf(file, " return (((idecode_crack*)\n"); + lf_printf(file, " table_entry->function_or_table)\n"); + lf_printf(file, " (%s));\n", cache_idecode_actual); + } + if (!can_assume_leaf) { + lf_printf(file, "opcode = (instruction & table_entry->shift) != 0;\n"); + lf_printf(file, "table = ((idecode_table_entry*)\n"); + lf_printf(file, " table_entry->function_or_table);\n"); + lf_printf(file, "table_entry = table + opcode;\n"); + } + } + lf_indent(file, -2); + lf_printf(file, "}\n"); + } + lf_indent(file, -2); + lf_printf(file, "}\n"); +} + + +static void +lf_print_my_prefix(lf *file, + table_entry *file_entry, + int idecode) +{ + lf_printf(file, "const char *const my_prefix = \n"); + lf_printf(file, " \"%s:%s:%s:%d\";\n", + filter_filename (file_entry->file_name), + (idecode ? "idecode" : "semantics"), + file_entry->fields[insn_name], + file_entry->line_nr); +} + + +static void +lf_print_ptrace(lf *file, + int idecode) +{ + lf_printf(file, "\n"); + lf_printf(file, "ITRACE(trace_%s, (\"\\n\"));\n", + (idecode ? "idecode" : "semantics")); +} + + +/****************************************************************/ + +typedef void leaf_handler +(insn_table *entry, + void *data, + int depth); +typedef void padding_handler +(insn_table *table, + void *data, + int depth, + int opcode_nr); + + +static void +insn_table_traverse_tree(insn_table *table, + void *data, + int depth, + leaf_handler *start, + leaf_handler *leaf, + leaf_handler *end, + padding_handler *padding) +{ + insn_table *entry; + int entry_nr; + + ASSERT(table != NULL + && table->opcode != NULL + && table->nr_entries > 0 + && table->entries != 0); + + if (start != NULL && depth >= 0) + start(table, data, depth); + + for (entry_nr = 0, entry = table->entries; + entry_nr < (table->opcode->is_boolean + ? 2 + : (1 << (table->opcode->last - table->opcode->first + 1))); + entry_nr ++) { + if (entry == NULL + || (!table->opcode->is_boolean + && entry_nr < entry->opcode_nr)) { + if (padding != NULL && depth >= 0) + padding(table, data, depth, entry_nr); + } + else { + ASSERT(entry != NULL && (entry->opcode_nr == entry_nr + || table->opcode->is_boolean)); + if (entry->opcode != NULL && depth != 0) { + insn_table_traverse_tree(entry, data, depth+1, + start, leaf, end, padding); + } + else if (depth >= 0) { + if (leaf != NULL) + leaf(entry, data, depth); + } + entry = entry->sibling; + } + } + if (end != NULL && depth >= 0) + end(table, data, depth); +} + + +typedef void function_handler +(insn_table *table, + void *data, + table_entry *function); + +static void +insn_table_traverse_function(insn_table *table, + void *data, + function_handler *leaf) +{ + insn *function; + for (function = table->functions; + function != NULL; + function = function->next) { + leaf(table, data, function->file_entry); + } +} + + +typedef void insn_handler +(insn_table *table, + void *data, + insn *instruction); + +static void +insn_table_traverse_insn(insn_table *table, + void *data, + insn_handler *leaf) +{ + insn *instruction; + for (instruction = table->insns; + instruction != NULL; + instruction = instruction->next) { + leaf(table, data, instruction); + } +} + + +static void +update_depth(insn_table *entry, + void *data, + int depth) +{ + int *max_depth = (int*)data; + if (*max_depth < depth) + *max_depth = depth; +} + + +static int +insn_table_depth(insn_table *table) +{ + int depth = 0; + insn_table_traverse_tree(table, + &depth, + 1, + NULL, /*start*/ + update_depth, + NULL, /*end*/ + NULL); /*padding*/ + return depth; +} + + +/****************************************************************/ + +static void +dump_traverse_start(insn_table *table, + void *data, + int depth) +{ + dumpf(depth*2, "(%d\n", table->opcode_nr); +} + +static void +dump_traverse_leaf(insn_table *entry, + void *data, + int depth) +{ + ASSERT(entry->nr_entries == 0 + && entry->nr_insn == 1 + && entry->opcode == NULL); + dumpf(depth*2, ".%d %s\n", entry->opcode_nr, + entry->insns->file_entry->fields[insn_format]); +} + +static void +dump_traverse_end(insn_table *table, + void *data, + int depth) +{ + dumpf(depth*2, ")\n"); +} + +static void +dump_traverse_padding(insn_table *table, + void *data, + int depth, + int opcode_nr) +{ + dumpf(depth*2, ".<%d>\n", opcode_nr); +} + + +static void +dump_traverse(insn_table *table) +{ + insn_table_traverse_tree(table, NULL, 1, + dump_traverse_start, + dump_traverse_leaf, + dump_traverse_end, + dump_traverse_padding); +} + + +/****************************************************************/ + + +static void +semantics_h_print_function(lf *file, + char *basename, + insn_bits *expanded_bits) +{ + lf_printf(file, "\n"); + lf_printf(file, "INLINE_SEMANTICS unsigned_word "); + lf_print_function_name(file, + basename, + expanded_bits, + function_name_prefix_semantics); + lf_printf(file, "\n(%s);\n", + (idecode_cache ? cache_semantic_formal : semantic_formal)); +} + + +static void +semantics_h_leaf(insn_table *entry, + void *data, + int depth) +{ + lf *file = (lf*)data; + ASSERT(entry->nr_insn == 1); + semantics_h_print_function(file, + entry->insns->file_entry->fields[insn_name], + entry->expanded_bits); +} + +static void +semantics_h_insn(insn_table *entry, + void *data, + insn *instruction) +{ + lf *file = (lf*)data; + semantics_h_print_function(file, + instruction->file_entry->fields[insn_name], + NULL); +} + +static void +semantics_h_function(insn_table *entry, + void *data, + table_entry *function) +{ + lf *file = (lf*)data; + if (function->fields[function_type] == NULL + || function->fields[function_type][0] == '\0') { + semantics_h_print_function(file, + function->fields[function_name], + NULL); + } + else { + lf_printf(file, "\n"); + lf_printf(file, "INLINE_SEMANTICS %s %s\n(%s);\n", + function->fields[function_type], + function->fields[function_name], + function->fields[function_param]); + } +} + + +static void +gen_semantics_h(insn_table *table, lf *file) +{ + + lf_print_copyleft(file); + lf_printf(file, "\n"); + lf_printf(file, "#ifndef _SEMANTICS_H_\n"); + lf_printf(file, "#define _SEMANTICS_H_\n"); + lf_printf(file, "\n"); + lf_printf(file, "#ifndef INLINE_SEMANTICS\n"); + lf_printf(file, "#define INLINE_SEMANTICS\n"); + lf_printf(file, "#endif\n"); + lf_printf(file, "\n"); + lf_printf(file, "\n"); + + /* output a declaration for all functions */ + insn_table_traverse_function(table, + file, + semantics_h_function); + + /* output a declaration for all instructions */ + if (idecode_expand_semantics) + insn_table_traverse_tree(table, + file, + 1, + NULL, /* start */ + semantics_h_leaf, /* leaf */ + NULL, /* end */ + NULL); /* padding */ + else + insn_table_traverse_insn(table, + file, + semantics_h_insn); + + lf_printf(file, "\n"); + lf_printf(file, "#endif /* _SEMANTICS_H_ */\n"); + +} + +/****************************************************************/ + +typedef struct _icache_tree icache_tree; +struct _icache_tree { + char *name; + icache_tree *next; + icache_tree *children; +}; + +static icache_tree * +icache_tree_insert(icache_tree *tree, + char *name) +{ + icache_tree *new_tree; + /* find it */ + icache_tree **ptr_to_cur_tree = &tree->children; + icache_tree *cur_tree = *ptr_to_cur_tree; + while (cur_tree != NULL + && strcmp(cur_tree->name, name) < 0) { + ptr_to_cur_tree = &cur_tree->next; + cur_tree = *ptr_to_cur_tree; + } + ASSERT(cur_tree == NULL + || strcmp(cur_tree->name, name) >= 0); + /* already in the tree */ + if (cur_tree != NULL + && strcmp(cur_tree->name, name) == 0) + return cur_tree; + /* missing, insert it */ + ASSERT(cur_tree == NULL + || strcmp(cur_tree->name, name) > 0); + new_tree = ZALLOC(icache_tree); + new_tree->name = name; + new_tree->next = cur_tree; + *ptr_to_cur_tree = new_tree; + return new_tree; +} + + +static icache_tree * +insn_table_cache_fields(insn_table *table) +{ + icache_tree *tree = ZALLOC(icache_tree); + insn *instruction; + for (instruction = table->insns; + instruction != NULL; + instruction = instruction->next) { + insn_field *field; + icache_tree *form = + icache_tree_insert(tree, + instruction->file_entry->fields[insn_form]); + for (field = instruction->fields->first; + field != NULL; + field = field->next) { + if (field->is_string) + icache_tree_insert(form, field->val_string); + } + } + return tree; +} + + + +static void +gen_icache_h(icache_tree *tree, + lf *file) +{ + lf_print_copyleft(file); + lf_printf(file, "\n"); + lf_printf(file, "#ifndef _ICACHE_H_\n"); + lf_printf(file, "#define _ICACHE_H_\n"); + lf_printf(file, "\n"); + lf_printf(file, "#ifndef INLINE_ICACHE\n"); + lf_printf(file, "#define INLINE_ICACHE\n"); + lf_printf(file, "#endif\n"); + lf_printf(file, "\n"); + + lf_printf(file, "#define WITH_IDECODE_CACHE_SIZE %d\n", + idecode_cache); + lf_printf(file, "\n"); + + /* create an instruction cache if being used */ + if (idecode_cache) { + icache_tree *form; + lf_printf(file, "typedef struct _idecode_cache {\n"); + lf_printf(file, " unsigned_word address;\n"); + lf_printf(file, " void *semantic;\n"); + lf_printf(file, " union {\n"); + for (form = tree->children; + form != NULL; + form = form->next) { + icache_tree *field; + lf_printf(file, " struct {\n"); + for (field = form->children; + field != NULL; + field = field->next) { + cache_rules *cache_rule; + int found_rule = 0; + for (cache_rule = cache_table; + cache_rule != NULL; + cache_rule = cache_rule->next) { + if (strcmp(field->name, cache_rule->old_name) == 0) { + found_rule = 1; + if (cache_rule->new_name != NULL) + lf_printf(file, " %s %s; /* %s */\n", + (cache_rule->type == NULL + ? "unsigned" + : cache_rule->type), + cache_rule->new_name, + cache_rule->old_name); + } + } + if (!found_rule) + lf_printf(file, " unsigned %s;\n", field->name); + } + lf_printf(file, " } %s;\n", form->name); + } + lf_printf(file, " } crack;\n"); + lf_printf(file, "} idecode_cache;\n"); + } + else { + /* alernativly, since no cache, #define the fields to be + extractions from the instruction variable */ + cache_rules *cache_rule; + lf_printf(file, "\n"); + for (cache_rule = cache_table; + cache_rule != NULL; + cache_rule = cache_rule->next) { + if (cache_rule->expression != NULL + && strlen(cache_rule->expression) > 0) + lf_printf(file, "#define %s %s\n", + cache_rule->new_name, cache_rule->expression); + } + } + + lf_printf(file, "\n"); + lf_printf(file, "#endif /* _ICACHE_H_ */\n"); +} + + + + +/****************************************************************/ + + +static void +lf_print_c_extraction(lf *file, + insn *instruction, + char *field_name, + char *field_type, + char *field_expression, + insn_field *cur_field, + insn_bits *bits, + int get_value_from_cache, + int put_value_in_cache) +{ + ASSERT(field_name != NULL); + if (bits != NULL + && (!bits->opcode->is_boolean || bits->value == 0) + && strcmp(field_name, cur_field->val_string) == 0) { + ASSERT(bits->field == cur_field); + ASSERT(field_type == NULL); + table_entry_lf_c_line_nr(file, instruction->file_entry); + lf_printf(file, "const unsigned %s = ", + field_name); + if (bits->opcode->last < bits->field->last) + lf_printf(file, "%d;\n", + bits->value << (bits->field->last - bits->opcode->last)); + else + lf_printf(file, "%d;\n", bits->value); + } + else { + /* put the field in the local variable */ + table_entry_lf_c_line_nr(file, instruction->file_entry); + lf_printf(file, "%s const %s = ", + field_type == NULL ? "unsigned" : field_type, + field_name); + /* getting it from the cache */ + if (get_value_from_cache || put_value_in_cache) { + lf_printf(file, "cache_entry->crack.%s.%s", + instruction->file_entry->fields[insn_form], + field_name); + if (put_value_in_cache) /* also put it in the cache? */ + lf_printf(file, " = "); + } + if (!get_value_from_cache) { + if (strcmp(field_name, cur_field->val_string) == 0) + lf_printf(file, "EXTRACTED32(instruction, %d, %d)", + cur_field->first, cur_field->last); + else if (field_expression != NULL) + lf_printf(file, "%s", field_expression); + else + lf_printf(file, "eval_%s", field_name); + } + lf_printf(file, ";\n"); + } +} + + +static void +lf_print_c_extractions(lf *file, + insn *instruction, + insn_bits *expanded_bits, + int get_value_from_cache, + int put_value_in_cache) +{ + insn_field *cur_field; + + /* extract instruction fields */ + lf_printf(file, "/* extraction: %s */\n", + instruction->file_entry->fields[insn_format]); + + for (cur_field = instruction->fields->first; + cur_field->first < insn_size; + cur_field = cur_field->next) { + if (cur_field->is_string) { + insn_bits *bits; + int found_rule = 0; + /* find any corresponding value */ + for (bits = expanded_bits; + bits != NULL; + bits = bits->last) { + if (bits->field == cur_field) + break; + } + /* try the cache rule table for what to do */ + if (get_value_from_cache || put_value_in_cache) { + cache_rules *cache_rule; + for (cache_rule = cache_table; + cache_rule != NULL; + cache_rule = cache_rule->next) { + if (strcmp(cur_field->val_string, cache_rule->old_name) == 0) { + found_rule = 1; + if (cache_rule->valid > 1 && put_value_in_cache) + lf_print_c_extraction(file, + instruction, + cache_rule->new_name, + cache_rule->type, + cache_rule->expression, + cur_field, + bits, + 0, + 0); + else if (cache_rule->valid == 1) + lf_print_c_extraction(file, + instruction, + cache_rule->new_name, + cache_rule->type, + cache_rule->expression, + cur_field, + bits, + get_value_from_cache, + put_value_in_cache); + } + } + } + if (found_rule == 0) + lf_print_c_extraction(file, + instruction, + cur_field->val_string, + 0, + 0, + cur_field, + bits, + get_value_from_cache, + put_value_in_cache); + /* if any (XXX == 0), output a corresponding test */ + if (instruction->file_entry->annex != NULL) { + char *field_name = cur_field->val_string; + char *is_0_ptr = instruction->file_entry->annex; + int field_len = strlen(field_name); + if (strlen(is_0_ptr) >= (strlen("_is_0") + field_len)) { + is_0_ptr += field_len; + while ((is_0_ptr = strstr(is_0_ptr, "_is_0")) != NULL) { + if (strncmp(is_0_ptr - field_len, field_name, field_len) == 0 + && !isalpha(is_0_ptr[ - field_len - 1])) { + table_entry_lf_c_line_nr(file, instruction->file_entry); + lf_printf(file, "const unsigned %s_is_0 = (", field_name); + if (bits != NULL) + lf_printf(file, "%d", bits->value); + else + lf_printf(file, "%s", field_name); + lf_printf(file, " == 0);\n"); + break; + } + is_0_ptr += strlen("_is_0"); + } + } + } + /* any thing else ... */ + } + } + lf_print_lf_c_line_nr(file); +} + + +static void +lf_print_idecode_illegal(lf *file) +{ + if (idecode_cache) + lf_printf(file, "return idecode_illegal(%s);\n", cache_idecode_actual); + else + lf_printf(file, "return semantic_illegal(%s);\n", semantic_actual); +} + + +static void +lf_print_idecode_floating_point_unavailable(lf *file) +{ + if (idecode_cache) + lf_printf(file, "return idecode_floating_point_unavailable(%s);\n", + cache_idecode_actual); + else + lf_printf(file, "return semantic_floating_point_unavailable(%s);\n", + semantic_actual); +} + + +/* Output code to do any final checks on the decoded instruction. + This includes things like verifying any on decoded fields have the + correct value and checking that (for floating point) floating point + hardware isn't disabled */ + +static void +lf_print_c_validate(lf *file, + insn *instruction, + opcode_field *opcodes) +{ + /* Validate: unchecked instruction fields + + If any constant fields in the instruction were not checked by the + idecode tables, output code to check that they have the correct + value here */ + { + unsigned check_mask = 0; + unsigned check_val = 0; + insn_field *field; + opcode_field *opcode; + + /* form check_mask/check_val containing what needs to be checked + in the instruction */ + for (field = instruction->fields->first; + field->first < insn_size; + field = field->next) { + + check_mask <<= field->width; + check_val <<= field->width; + + /* is it a constant that could need validating? */ + if (!field->is_int && !field->is_slash) + continue; + + /* has it been checked by a table? */ + for (opcode = opcodes; opcode != NULL; opcode = opcode->parent) { + if (field->first >= opcode->first + && field->last <= opcode->last) + break; + } + if (opcode != NULL) + continue; + + check_mask |= (1 << field->width)-1; + check_val |= field->val_int; + } + + /* if any bits not checked by opcode tables, output code to check them */ + if (check_mask) { + lf_printf(file, "\n"); + lf_printf(file, "/* validate: %s */\n", + instruction->file_entry->fields[insn_format]); + lf_printf(file, "if ((instruction & 0x%x) != 0x%x)\n", + check_mask, check_val); + lf_indent(file, +2); + lf_print_idecode_illegal(file); + lf_indent(file, -2); + } + } + + /* Validate floating point hardware + + If the simulator is being built with out floating point hardware + (different to it being disabled in the MSR) then floating point + instructions are invalid */ + { + if (it_is("f", instruction->file_entry->fields[insn_flags])) { + lf_printf(file, "\n"); + lf_printf(file, "/* Validate: FP hardware exists */\n"); + lf_printf(file, "if (CURRENT_FLOATING_POINT != HARD_FLOATING_POINT)\n"); + lf_indent(file, +2); + lf_print_idecode_illegal(file); + lf_indent(file, -2); + } + } + + /* Validate: Floating Point available + + If floating point is not available, we enter a floating point + unavailable interrupt into the cache instead of the instruction + proper. + + The PowerPC spec requires a CSI after MSR[FP] is changed and when + ever a CSI occures we flush the instruction cache. */ + + { + if (it_is("f", instruction->file_entry->fields[insn_flags])) { + lf_printf(file, "\n"); + lf_printf(file, "/* Validate: FP available according to MSR[FP] */\n"); + lf_printf(file, "if (!IS_FP_AVAILABLE(processor))\n"); + lf_indent(file, +2); + lf_print_idecode_floating_point_unavailable(file); + lf_indent(file, -2); + } + } +} + + +static void +lf_print_c_cracker(lf *file, + insn *instruction, + insn_bits *expanded_bits, + opcode_field *opcodes) +{ + + /* function header */ + lf_printf(file, "{\n"); + lf_indent(file, +2); + + lf_print_my_prefix(file, + instruction->file_entry, + 1/*putting-value-in-cache*/); + + lf_print_ptrace(file, + 1/*putting-value-in-cache*/); + + lf_print_c_validate(file, instruction, opcodes); + + lf_printf(file, "\n"); + lf_printf(file, "{\n"); + lf_indent(file, +2); + lf_print_c_extractions(file, + instruction, + expanded_bits, + 0/*get_value_from_cache*/, + 1/*put_value_in_cache*/); + lf_indent(file, -2); + lf_printf(file, "}\n"); + + /* return the function propper (main sorts this one out) */ + lf_printf(file, "\n"); + lf_printf(file, "/* semantic routine */\n"); + table_entry_lf_c_line_nr(file, instruction->file_entry); + lf_printf(file, "return "); + lf_print_function_name(file, + instruction->file_entry->fields[insn_name], + expanded_bits, + function_name_prefix_semantics); + lf_printf(file, ";\n"); + + lf_print_lf_c_line_nr(file); + lf_indent(file, -2); + lf_printf(file, "}\n"); +} + + +static void +lf_print_c_semantic(lf *file, + insn *instruction, + insn_bits *expanded_bits, + opcode_field *opcodes) +{ + + lf_printf(file, "{\n"); + lf_indent(file, +2); + + lf_print_my_prefix(file, + instruction->file_entry, + 0/*not putting value in cache*/); + lf_putstr(file, semantic_local); + lf_printf(file, "\n"); + + lf_printf(file, "\n"); + lf_print_c_extractions(file, + instruction, + expanded_bits, + idecode_cache/*get_value_from_cache*/, + 0/*put_value_in_cache*/); + + lf_print_ptrace(file, + 0/*put_value_in_cache*/); + + /* validate the instruction, if a cache this has already been done */ + if (!idecode_cache) + lf_print_c_validate(file, instruction, opcodes); + + /* generate the profileing call - this is delayed until after the + instruction has been verified */ + lf_printf(file, "\n"); + lf_printf(file, "if (WITH_MON & MONITOR_INSTRUCTION_ISSUE)\n"); + lf_printf(file, " mon_issue("); + lf_print_function_name(file, + instruction->file_entry->fields[insn_name], + NULL, + function_name_prefix_itable); + lf_printf(file, ", processor, cia);\n"); + + /* generate the code (or at least something */ + if (instruction->file_entry->annex != NULL) { + /* true code */ + lf_printf(file, "\n"); + table_entry_lf_c_line_nr(file, instruction->file_entry); + lf_printf(file, "{\n"); + lf_indent(file, +2); + lf_print_c_code(file, instruction->file_entry->annex); + lf_indent(file, -2); + lf_printf(file, "}\n"); + lf_print_lf_c_line_nr(file); + } + else if (it_is("nop", instruction->file_entry->fields[insn_flags])) { + lf_print_lf_c_line_nr(file); + } + else if (it_is("f", instruction->file_entry->fields[insn_flags])) { + /* unimplemented floating point instruction - call for assistance */ + lf_printf(file, "\n"); + lf_printf(file, "/* unimplemented floating point instruction - call for assistance */\n"); + table_entry_lf_c_line_nr(file, instruction->file_entry); + lf_putstr(file, "floating_point_assist_interrupt(processor, cia);\n"); + lf_print_lf_c_line_nr(file); + } + else { + /* abort so it is implemented now */ + table_entry_lf_c_line_nr(file, instruction->file_entry); + lf_putstr(file, "error(\"%s: unimplemented, cia=0x%x\\n\", my_prefix, cia);\n"); + lf_print_lf_c_line_nr(file); + lf_printf(file, "\n"); + } + + /* the function footer */ + lf_printf(file, "return nia;\n"); + lf_indent(file, -2); + lf_printf(file, "}\n"); +} + +static void +lf_print_c_semantic_function_header(lf *file, + char *basename, + insn_bits *expanded_bits) +{ + lf_printf(file, "\n"); + lf_printf(file, "INLINE_SEMANTICS unsigned_word\n"); + lf_print_function_name(file, + basename, + expanded_bits, + function_name_prefix_semantics); + lf_printf(file, "\n(%s)\n", + (idecode_cache ? cache_semantic_formal : semantic_formal)); +} + +static void +lf_print_c_semantic_function(lf *file, + insn *instruction, + insn_bits *expanded_bits, + opcode_field *opcodes) +{ + + /* build the semantic routine to execute the instruction */ + lf_print_c_semantic_function_header(file, + instruction->file_entry->fields[insn_name], + expanded_bits); + lf_print_c_semantic(file, + instruction, + expanded_bits, + opcodes); +} + + +static void +semantics_c_leaf(insn_table *entry, + void *data, + int depth) +{ + lf *file = (lf*)data; + ASSERT(entry->nr_insn == 1 + && entry->opcode == NULL + && entry->parent != NULL + && entry->parent->opcode != NULL); + lf_print_c_semantic_function(file, + entry->insns, + entry->expanded_bits, + entry->parent->opcode); +} + +static void +semantics_c_insn(insn_table *table, + void *data, + insn *instruction) +{ + lf *file = (lf*)data; + lf_print_c_semantic_function(file, instruction, + NULL, NULL); +} + +static void +semantics_c_function(insn_table *table, + void *data, + table_entry *function) +{ + lf *file = (lf*)data; + if (function->fields[function_type] == NULL + || function->fields[function_type][0] == '\0') { + lf_print_c_semantic_function_header(file, + function->fields[function_name], + NULL); + } + else { + lf_printf(file, "\n"); + lf_printf(file, "INLINE_SEMANTICS %s\n%s(%s)\n", + function->fields[function_type], + function->fields[function_name], + function->fields[function_param]); + } + table_entry_lf_c_line_nr(file, function); + lf_printf(file, "{\n"); + lf_indent(file, +2); + lf_print_c_code(file, function->annex); + lf_indent(file, -2); + lf_printf(file, "}\n"); + lf_print_lf_c_line_nr(file); +} + + + +static void +gen_semantics_c(insn_table *table, lf *file) +{ + lf_print_copyleft(file); + lf_printf(file, "\n"); + lf_printf(file, "#ifndef _SEMANTICS_C_\n"); + lf_printf(file, "#define _SEMANTICS_C_\n"); + lf_printf(file, "\n"); + lf_printf(file, "#ifndef STATIC_INLINE_SEMANTICS\n"); + lf_printf(file, "#define STATIC_INLINE_SEMANTICS STATIC_INLINE\n"); + lf_printf(file, "#endif\n"); + lf_printf(file, "\n"); + lf_printf(file, "#include \"cpu.h\"\n"); + lf_printf(file, "#include \"idecode.h\"\n"); + lf_printf(file, "#include \"semantics.h\"\n"); + lf_printf(file, "\n"); + + /* output a definition (c-code) for all functions */ + insn_table_traverse_function(table, + file, + semantics_c_function); + + /* output a definition (c-code) for all instructions */ + if (idecode_expand_semantics) + insn_table_traverse_tree(table, + file, + 1, + NULL, /* start */ + semantics_c_leaf, + NULL, /* end */ + NULL); /* padding */ + else + insn_table_traverse_insn(table, + file, + semantics_c_insn); + + lf_printf(file, "\n"); + lf_printf(file, "#endif /* _SEMANTICS_C_ */\n"); +} + + +/****************************************************************/ + +static void +gen_idecode_h(insn_table *table, lf *file) +{ + lf_print_copyleft(file); + lf_printf(file, "\n"); + lf_printf(file, "#ifndef _IDECODE_H_\n"); + lf_printf(file, "#define _IDECODE_H_\n"); + lf_printf(file, "\n"); + lf_printf(file, "#ifndef INLINE_IDECODE\n"); + lf_printf(file, "#define INLINE_IDECODE\n"); + lf_printf(file, "#endif\n"); + lf_printf(file, "\n"); + lf_printf(file, "#include \"idecode_expression.h\"\n"); + lf_printf(file, "#include \"idecode_fields.h\"\n"); + lf_printf(file, "#include \"idecode_branch.h\"\n"); + lf_printf(file, "\n"); + lf_printf(file, "#include \"icache.h\"\n"); + lf_printf(file, "\n"); + lf_printf(file, "typedef unsigned_word idecode_semantic\n(%s);\n", + (idecode_cache ? cache_semantic_formal : semantic_formal)); + lf_printf(file, "\n"); + if (idecode_cache) + lf_printf(file, "INLINE_IDECODE idecode_semantic *idecode\n(%s);\n", + cache_idecode_formal); + else + lf_printf(file, "INLINE_IDECODE unsigned_word idecode_issue\n(%s);\n", + semantic_formal); + lf_printf(file, "\n"); + lf_printf(file, "#endif /* _IDECODE_H_ */\n"); +} + + +/****************************************************************/ + + +static void +idecode_table_start(insn_table *table, + void *data, + int depth) +{ + lf *file = (lf*)data; + ASSERT(depth == 0); + /* start of the table */ + if (!table->opcode_rule->use_switch) { + lf_printf(file, "\n"); + lf_printf(file, "static idecode_table_entry "); + lf_print_table_name(file, table); + lf_printf(file, "[] = {\n"); + } +} + +static void +idecode_table_leaf(insn_table *entry, + void *data, + int depth) +{ + lf *file = (lf*)data; + ASSERT(entry->parent != NULL); + ASSERT(depth == 0); + + /* add an entry to the table */ + if (!entry->parent->opcode_rule->use_switch) { + if (entry->opcode == NULL) { + /* table leaf entry */ + lf_printf(file, " /*%d*/ { 0, 0, ", entry->opcode_nr); + lf_print_function_name(file, + entry->insns->file_entry->fields[insn_name], + entry->expanded_bits, + (idecode_cache + ? function_name_prefix_idecode + : function_name_prefix_semantics)); + lf_printf(file, " },\n"); + } + else if (entry->opcode_rule->use_switch) { + /* table calling switch statement */ + lf_printf(file, " /*%d*/ { -1, 0, ", + entry->opcode_nr); + lf_print_table_name(file, entry); + lf_printf(file, " },\n"); + } + else { + /* table `calling' another table */ + lf_printf(file, " /*%d*/ { ", entry->opcode_nr); + if (entry->opcode->is_boolean) + lf_printf(file, "MASK32(%d,%d), 0, ", + entry->opcode->first, entry->opcode->last); + else + lf_printf(file, "%d, MASK32(%d,%d), ", + insn_size - entry->opcode->last - 1, + entry->opcode->first, entry->opcode->last); + lf_print_table_name(file, entry); + lf_printf(file, " },\n"); + } + } +} + +static void +idecode_table_end(insn_table *table, + void *data, + int depth) +{ + lf *file = (lf*)data; + ASSERT(depth == 0); + + if (!table->opcode_rule->use_switch) { + lf_printf(file, "};\n"); + } +} + +static void +idecode_table_padding(insn_table *table, + void *data, + int depth, + int opcode_nr) +{ + lf *file = (lf*)data; + ASSERT(depth == 0); + + if (!table->opcode_rule->use_switch) { + lf_printf(file, " /*%d*/ { 0, 0, %s_illegal },\n", + opcode_nr, (idecode_cache ? "idecode" : "semantic")); + } +} + + +/****************************************************************/ + + +void lf_print_idecode_switch +(lf *file, + insn_table *table); + + +static void +idecode_switch_start(insn_table *table, + void *data, + int depth) +{ + lf *file = (lf*)data; + ASSERT(depth == 0); + ASSERT(table->opcode_rule->use_switch); + + lf_printf(file, "switch (EXTRACTED32(instruction, %d, %d)) {\n", + table->opcode->first, table->opcode->last); +} + + +static void +idecode_switch_leaf(insn_table *entry, + void *data, + int depth) +{ + lf *file = (lf*)data; + ASSERT(entry->parent != NULL); + ASSERT(depth == 0); + ASSERT(entry->parent->opcode_rule->use_switch); + + lf_printf(file, "case %d:\n", entry->opcode_nr); + lf_indent(file, +2); + { + if (entry->opcode == NULL) { + /* switch calling leaf */ + lf_printf(file, "return "); + lf_print_function_name(file, + entry->insns->file_entry->fields[insn_name], + entry->expanded_bits, + (idecode_cache + ? function_name_prefix_idecode + : function_name_prefix_semantics)); + if (idecode_cache) + lf_printf(file, "(%s);\n", cache_idecode_actual); + else + lf_printf(file, "(%s);\n", semantic_actual); + } + else if (entry->opcode_rule->use_switch) { + /* switch calling switch */ + lf_print_idecode_switch(file, entry); + } + else { + /* switch calling table */ + lf_printf(file, "return "); + lf_print_idecode_table(file, entry); + } + lf_printf(file, "break;\n"); + } + lf_indent(file, -2); +} + + +static void +lf_print_idecode_switch_illegal(lf *file) +{ + lf_indent(file, +2); + lf_print_idecode_illegal(file); + lf_printf(file, "break;\n"); + lf_indent(file, -2); +} + +static void +idecode_switch_end(insn_table *table, + void *data, + int depth) +{ + lf *file = (lf*)data; + ASSERT(depth == 0); + ASSERT(table->opcode_rule->use_switch); + + if (table->opcode_rule->use_switch == 1) { + lf_printf(file, "default:\n"); + lf_print_idecode_switch_illegal(file); + } + lf_printf(file, "}\n"); +} + +static void +idecode_switch_padding(insn_table *table, + void *data, + int depth, + int opcode_nr) +{ + lf *file = (lf*)data; + + ASSERT(depth == 0); + ASSERT(table->opcode_rule->use_switch); + + if (table->opcode_rule->use_switch > 1) { + lf_printf(file, "case %d:\n", opcode_nr); + lf_print_idecode_switch_illegal(file); + } +} + + +void +lf_print_idecode_switch(lf *file, + insn_table *table) +{ + insn_table_traverse_tree(table, + file, + 0, + idecode_switch_start, + idecode_switch_leaf, + idecode_switch_end, + idecode_switch_padding); +} + + +static void +idecode_expand_if_switch(insn_table *table, + void *data, + int depth) +{ + lf *file = (lf*)data; + + if (table->opcode_rule->use_switch + && table->parent != NULL /* don't expand the top one yet */ + && !table->parent->opcode_rule->use_switch) { + lf_printf(file, "\n"); + lf_printf(file, "STATIC_INLINE_IDECODE void\n"); + lf_print_table_name(file, table); + lf_printf(file, "\n(%s)\n", + (idecode_cache ? cache_idecode_formal : semantic_formal)); + lf_printf(file, "{\n"); + { + lf_indent(file, +2); + lf_print_idecode_switch(file, table); + lf_indent(file, -2); + } + lf_printf(file, "}\n"); + } +} + + +static void +lf_print_c_cracker_function(lf *file, + insn *instruction, + insn_bits *expanded_bits, + opcode_field *opcodes) +{ + /* if needed, generate code to enter this routine into a cache */ + lf_printf(file, "\n"); + lf_printf(file, "STATIC_INLINE_IDECODE idecode_semantic *\n"); + lf_print_function_name(file, + instruction->file_entry->fields[insn_name], + expanded_bits, + function_name_prefix_idecode); + lf_printf(file, "\n(%s)\n", cache_idecode_formal); + + lf_print_c_cracker(file, + instruction, + expanded_bits, + opcodes); +} + +static void +idecode_crack_leaf(insn_table *entry, + void *data, + int depth) +{ + lf *file = (lf*)data; + ASSERT(entry->nr_insn == 1 + && entry->opcode == NULL + && entry->parent != NULL + && entry->parent->opcode != NULL); + lf_print_c_cracker_function(file, + entry->insns, + entry->expanded_bits, + entry->opcode); +} + +static void +idecode_crack_insn(insn_table *entry, + void *data, + insn *instruction) +{ + lf *file = (lf*)data; + lf_print_c_cracker_function(file, + instruction, + NULL, + NULL); +} + +static void +idecode_c_internal_function(insn_table *table, + void *data, + table_entry *function) +{ + lf *file = (lf*)data; + ASSERT(idecode_cache != 0); + if (it_is("internal", function->fields[insn_flags])) { + lf_printf(file, "\n"); + lf_printf(file, "STATIC_INLINE_IDECODE idecode_semantic *\n"); + lf_print_function_name(file, + function->fields[insn_name], + NULL, + function_name_prefix_idecode); + lf_printf(file, "\n(%s)\n", cache_idecode_formal); + lf_printf(file, "{\n"); + lf_indent(file, +2); + lf_printf(file, "/* semantic routine */\n"); + table_entry_lf_c_line_nr(file, function); + lf_printf(file, "return "); + lf_print_function_name(file, + function->fields[insn_name], + NULL, + function_name_prefix_semantics); + lf_printf(file, ";\n"); + + lf_print_lf_c_line_nr(file); + lf_indent(file, -2); + lf_printf(file, "}\n"); + } +} + + +/****************************************************************/ + +static void +gen_idecode_c(insn_table *table, lf *file) +{ + int depth; + + /* the intro */ + lf_print_copyleft(file); + lf_printf(file, "\n"); + lf_printf(file, "\n"); + lf_printf(file, "#ifndef _IDECODE_C_\n"); + lf_printf(file, "#define _IDECODE_C_\n"); + lf_printf(file, "\n"); + lf_printf(file, "#ifndef STATIC_INLINE_IDECODE\n"); + lf_printf(file, "#define STATIC_INLINE_IDECODE STATIC_INLINE\n"); + lf_printf(file, "#endif\n"); + lf_printf(file, "\n"); + lf_printf(file, "#include \"cpu.h\"\n"); + lf_printf(file, "#include \"idecode.h\"\n"); + lf_printf(file, "#include \"semantics.h\"\n"); + lf_printf(file, "\n"); + lf_printf(file, "\n"); + lf_printf(file, "typedef idecode_semantic *idecode_crack\n(%s);\n", + (idecode_cache ? cache_idecode_formal : semantic_formal)); + lf_printf(file, "\n"); + lf_printf(file, "typedef struct _idecode_table_entry {\n"); + lf_printf(file, " unsigned shift;\n"); + lf_printf(file, " unsigned mask;\n"); + lf_printf(file, " void *function_or_table;\n"); + lf_printf(file, "} idecode_table_entry;\n"); + lf_printf(file, "\n"); + lf_printf(file, "\n"); + + /* output `internal' invalid/floating-point unavailable functions + where needed */ + if (idecode_cache) { + insn_table_traverse_function(table, + file, + idecode_c_internal_function); + } + + /* output cracking functions where needed */ + if (idecode_cache) { + if (idecode_expand_semantics) + insn_table_traverse_tree(table, + file, + 1, + NULL, + idecode_crack_leaf, + NULL, + NULL); + else + insn_table_traverse_insn(table, + file, + idecode_crack_insn); + } + + + /* output tables where needed */ + for (depth = insn_table_depth(table); + depth > 0; + depth--) { + insn_table_traverse_tree(table, + file, + 1-depth, + idecode_table_start, + idecode_table_leaf, + idecode_table_end, + idecode_table_padding); + } + + /* output switch functions where needed */ + insn_table_traverse_tree(table, + file, + 1, + idecode_expand_if_switch, /* START */ + NULL, NULL, NULL); + + /* output the main idecode routine */ + lf_printf(file, "\n"); + if (idecode_cache) + lf_printf(file, "INLINE_IDECODE idecode_semantic *\nidecode\n(%s)\n", + cache_idecode_formal); + else + lf_printf(file, "INLINE_IDECODE unsigned_word\nidecode_issue\n(%s)\n", + semantic_formal); + lf_printf(file, "{\n"); + lf_indent(file, +2); + if (table->opcode_rule->use_switch) + lf_print_idecode_switch(file, table); + else + lf_print_idecode_table(file, table); + lf_indent(file, -2); + lf_printf(file, "}\n"); + lf_printf(file, "\n"); + lf_printf(file, "#endif\n"); +} + + +/****************************************************************/ + +static void +itable_h_insn(insn_table *entry, + void *data, + insn *instruction) +{ + lf *file = (lf*)data; + lf_printf(file, " "); + lf_print_function_name(file, + instruction->file_entry->fields[insn_name], + NULL, + function_name_prefix_itable); + lf_printf(file, ",\n"); +} + + +static void +gen_itable_h(insn_table *table, lf *file) +{ + + lf_print_copyleft(file); + lf_printf(file, "\n"); + lf_printf(file, "#ifndef _ITABLE_H_\n"); + lf_printf(file, "#define _ITABLE_H_\n"); + lf_printf(file, "\n"); + lf_printf(file, "#ifndef INLINE_ITABLE\n"); + lf_printf(file, "#define INLINE_ITABLE\n"); + lf_printf(file, "#endif\n"); + lf_printf(file, "\n"); + lf_printf(file, "\n"); + + /* output an enumerated type for each instruction */ + lf_printf(file, "typedef enum {\n"); + insn_table_traverse_insn(table, + file, + itable_h_insn); + lf_printf(file, " nr_itable_entries,\n"); + lf_printf(file, "} itable_index;\n"); + lf_printf(file, "\n"); + + /* output the table that contains the actual instruction info */ + lf_printf(file, "typedef struct _itable_instruction_info {\n"); + lf_printf(file, " itable_index nr;\n"); + lf_printf(file, " char *format;\n"); + lf_printf(file, " char *form;\n"); + lf_printf(file, " char *flags;\n"); + lf_printf(file, " char *nmemonic;\n"); + lf_printf(file, " char *name;\n"); + lf_printf(file, "} itable_info;\n"); + lf_printf(file, "\n"); + lf_printf(file, "extern itable_info itable[nr_itable_entries];\n"); + + lf_printf(file, "\n"); + lf_printf(file, "#endif /* _ITABLE_C_ */\n"); + +} + +/****************************************************************/ + +static void +itable_c_insn(insn_table *entry, + void *data, + insn *instruction) +{ + lf *file = (lf*)data; + char **fields = instruction->file_entry->fields; + lf_printf(file, " { "); + lf_print_function_name(file, + instruction->file_entry->fields[insn_name], + NULL, + function_name_prefix_itable); + lf_printf(file, ",\n"); + lf_printf(file, " \"%s\",\n", fields[insn_format]); + lf_printf(file, " \"%s\",\n", fields[insn_form]); + lf_printf(file, " \"%s\",\n", fields[insn_flags]); + lf_printf(file, " \"%s\",\n", fields[insn_nmemonic]); + lf_printf(file, " \"%s\",\n", fields[insn_name]); + lf_printf(file, " },\n"); +} + + +static void +gen_itable_c(insn_table *table, lf *file) +{ + + lf_print_copyleft(file); + lf_printf(file, "\n"); + lf_printf(file, "#ifndef _ITABLE_C_\n"); + lf_printf(file, "#define _ITABLE_C_\n"); + lf_printf(file, "\n"); + lf_printf(file, "#ifndef STATIC_INLINE_ITABLE\n"); + lf_printf(file, "#define STATIC_INLINE_ITABLE STATIC_INLINE\n"); + lf_printf(file, "#endif\n"); + lf_printf(file, "\n"); + lf_printf(file, "#include \"itable.h\"\n"); + lf_printf(file, "\n"); + + /* output the table that contains the actual instruction info */ + lf_printf(file, "itable_info itable[nr_itable_entries] = {\n"); + insn_table_traverse_insn(table, + file, + itable_c_insn); + lf_printf(file, "};\n"); + lf_printf(file, "\n"); + + lf_printf(file, "\n"); + lf_printf(file, "#endif /* _ITABLE_C_ */\n"); + +} + +/****************************************************************/ + + +int +main(int argc, + char **argv, + char **envp) +{ + insn_table *instructions = NULL; + icache_tree *cache_fields = NULL; + char *real_file_name = NULL; + int ch; + + if (argc == 1) { + printf("Usage:\n"); + printf("-f <filter-out-flag> eg -f 64 to skip 64bit instructions\n"); + printf("-[Ii] <instruction-table> -I to dump internal table\n"); + printf("-[Oo] <opcode-rules>\n"); + printf("-[Kk] <cache-rules>\n"); + printf("-[Ss] <schematic> output schematic.h(S) schematic.c(s)\n"); + printf("-[Dd] <schematic> output idecode.h(S) idecode.c(s)\n"); + printf("-[Tt] <table> output itable.h(t) itable.c(t)\n"); + printf("-[Cc] <schematic> output icache.h(S) invalid(s)\n"); + printf("-e Expand (duplicate) semantic functions\n"); + printf("-r <size> Generate a cracking cache of <size>\n"); + printf("-l Supress includsion of CPP line numbering in output files\n"); + } + + while ((ch = getopt(argc, argv, + "ler:f:I:i:O:o:K:k:n:S:s:D:d:T:t:C:")) != -1) { + fprintf(stderr, "\t-%c %s\n", ch, (optarg ? optarg : "")); + switch(ch) { + case 'l': + number_lines = 0; + break; + case 'e': + idecode_expand_semantics = 1; + break; + case 'r': + idecode_cache = a2i(optarg); + break; + case 'f': + { + filter *new_filter = ZALLOC(filter); + new_filter->flag = strdup(optarg); + new_filter->next = filters; + filters = new_filter; + break; + } + case 'I': + case 'i': + ASSERT(opcode_table != NULL); + ASSERT(cache_table != NULL); + instructions = insn_table_load_insns(optarg); + fprintf(stderr, "\texpanding ...\n"); + insn_table_expand_insns(instructions); + fprintf(stderr, "\tcache fields ...\n"); + cache_fields = insn_table_cache_fields(instructions); + if (ch == 'I') { + dump_traverse(instructions); + dump_insn_table(instructions, 0, 1); + } + break; + case 'O': + case 'o': + opcode_table = load_opcode_rules(optarg); + if (ch == 'O') + dump_opcode_rules(opcode_table, 0); + break; + case 'K': + case 'k': + cache_table = load_cache_rules(optarg); + if (ch == 'K') + dump_cache_rules(cache_table, 0); + break; + case 'n': + real_file_name = strdup(optarg); + break; + case 'S': + case 's': + case 'D': + case 'd': + case 'T': + case 't': + case 'C': + { + lf *file = lf_open(optarg, real_file_name, number_lines); + ASSERT(instructions != NULL); + switch (ch) { + case 'S': + gen_semantics_h(instructions, file); + break; + case 's': + gen_semantics_c(instructions, file); + break; + case 'D': + gen_idecode_h(instructions, file); + break; + case 'd': + gen_idecode_c(instructions, file); + break; + case 'T': + gen_itable_h(instructions, file); + break; + case 't': + gen_itable_c(instructions, file); + break; + case 'C': + gen_icache_h(cache_fields, file); + break; + } + lf_close(file); + } + real_file_name = NULL; + break; + default: + error("unknown option\n"); + } + } + return 0; +} |