aboutsummaryrefslogtreecommitdiff
path: root/sim/ppc/igen.c
diff options
context:
space:
mode:
authorMichael Meissner <gnu@the-meissners.org>1995-11-01 19:32:38 +0000
committerMichael Meissner <gnu@the-meissners.org>1995-11-01 19:32:38 +0000
commitc143ef6296268bb98a697572a589d47bb375d372 (patch)
treea8803d93f14172ed925726d1d0ee680c57d63a36 /sim/ppc/igen.c
parent7f82c7e1ee2dc3533a913588d9909f568bce27eb (diff)
downloadgdb-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.c2834
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;
+}