diff options
-rw-r--r-- | sim/igen/ChangeLog | 21 | ||||
-rw-r--r-- | sim/igen/igen.c | 301 | ||||
-rw-r--r-- | sim/igen/ld-insn.c | 23 | ||||
-rw-r--r-- | sim/igen/ld-insn.h | 608 | ||||
-rw-r--r-- | sim/igen/table.c | 812 |
5 files changed, 1348 insertions, 417 deletions
diff --git a/sim/igen/ChangeLog b/sim/igen/ChangeLog index aba94cb..b535133 100644 --- a/sim/igen/ChangeLog +++ b/sim/igen/ChangeLog @@ -1,3 +1,24 @@ +Mon Oct 27 15:14:26 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c (main): Change -I option to -I<directory>. Add optional + size to -Ggen-icache option. Add -Gno-... support. + + * igen.h (struct _igen_options): Add include field. + + * ld-insn.c (enum insn_record_type, insn_type_map): Add + include_record. + (load_insn_table): Call table_push when include record. + + * table.c (struct _open table, struct table): Make table object an + indirect ptr to the current table file. + (current_line, new_table_entry, next_line): Make file arg type + open_table. + (table_open): Use table_push. + (table_read): Point variable file at current table, at eof, pop + last open table. + + * table.h, table.c (table_push): New function. + Thu Oct 16 11:03:27 1997 Andrew Cagney <cagney@b1.cygnus.com> * gen-semantics.c (print_semantic_body): Use CIA not diff --git a/sim/igen/igen.c b/sim/igen/igen.c index 0fbe8e5..afd2904 100644 --- a/sim/igen/igen.c +++ b/sim/igen/igen.c @@ -979,15 +979,13 @@ main (int argc, printf ("\t Set the number of the high (most significant) instruction bit (depreciated).\n"); printf ("\t This option can now be set directly in the instruction table.\n"); printf ("\n"); - printf (" -I <icache-size>\n"); - printf ("\t Specify size of the cracking instruction cache (default %d instructions).\n", - options.gen.icache_size); - printf ("\t Implies -G icache.\n"); + printf (" -I <directory>\n"); + printf ("\t Add <directory> to the list of directories searched when opening a file\n"); printf ("\n"); printf (" -M <model-list>\n"); printf ("\t Filter out any instructions that do not support at least one of the listed\n"); printf ("\t models (An instructions with no model information is considered to support\n"); - printf ("\n all models.).\n"); + printf ("\t all models.).\n"); printf ("\n"); printf (" -N <nr-cpus>\n"); printf ("\t Generate a simulator supporting <nr-cpus>\n"); @@ -1020,7 +1018,8 @@ main (int argc, printf ("\t gen-delayed-branch - need both cia and nia passed around\n"); printf ("\t gen-direct-access - use #defines to directly access values\n"); printf ("\t gen-zero-r<N> - arch assumes GPR(<N>) == 0, keep it that way\n"); - printf ("\t gen-icache - generate an instruction cracking cache\n"); + printf ("\t gen-icache[=<N> - generate an instruction cracking cache of size <N>\n"); + printf ("\t Default size is %d\n", options.gen.icache_size); printf ("\t gen-insn-in-icache - save original instruction when cracking\n"); printf ("\t gen-multi-sim - generate multiple simulators - one per model\n"); printf ("\t By default, a single simulator that will\n"); @@ -1099,8 +1098,13 @@ main (int argc, break; case 'I': - options.gen.icache_size = a2i (optarg); - options.gen.icache = 1; + { + table_include **dir = &options.include; + while ((*dir) != NULL) + dir = &(*dir)->next; + (*dir) = ZALLOC (table_include); + (*dir)->dir = strdup (optarg); + } break; case 'B': @@ -1213,131 +1217,162 @@ main (int argc, case 'G': - if (strcmp (optarg, "decode-duplicate") == 0) - { - options.decode.duplicate = 1; - } - else if (strcmp (optarg, "decode-combine") == 0) - { - options.decode.combine = 1; - } - else if (strcmp (optarg, "decode-zero-reserved") == 0) - { - options.decode.zero_reserved = 1; - } - - else if (strcmp (optarg, "gen-conditional-issue") == 0) - { - options.gen.conditional_issue = 1; - } - else if (strcmp (optarg, "conditional-issue") == 0) - { - options.gen.conditional_issue = 1; - options.warning (NULL, "Option conditional-issue replaced by gen-conditional-issue\n"); - } - else if (strcmp (optarg, "gen-delayed-branch") == 0) - { - options.gen.delayed_branch = 1; - } - else if (strcmp (optarg, "delayed-branch") == 0) - { - options.gen.delayed_branch = 1; - options.warning (NULL, "Option delayed-branch replaced by gen-delayed-branch\n"); - } - else if (strcmp (optarg, "gen-direct-access") == 0) - { - options.gen.direct_access = 1; - } - else if (strcmp (optarg, "direct-access") == 0) - { - options.gen.direct_access = 1; - options.warning (NULL, "Option direct-access replaced by gen-direct-access\n"); - } - else if (strncmp (optarg, "gen-zero-r", strlen ("gen-zero-r")) == 0) - { - options.gen.zero_reg = 1; - options.gen.zero_reg_nr = atoi (optarg + strlen ("gen-zero-r")); - } - else if (strncmp (optarg, "zero-r", strlen ("zero-r")) == 0) - { - options.gen.zero_reg = 1; - options.gen.zero_reg_nr = atoi (optarg + strlen ("zero-r")); - options.warning (NULL, "Option zero-r<N> replaced by gen-zero-r<N>\n"); - } - else if (strcmp (optarg, "gen-icache") == 0) - { - options.gen.icache = 1; - } - else if (strcmp (optarg, "gen-insn-in-icache") == 0) - { - options.gen.insn_in_icache = 1; - } - else if (strcmp (optarg, "gen-multi-sim") == 0) - { - options.gen.multi_sim = 1; - } - else if (strcmp (optarg, "gen-multi-word") == 0) - { - options.gen.multi_word = 1; - } - else if (strcmp (optarg, "gen-semantic-icache") == 0) - { - options.gen.semantic_icache = 1; - } - else if (strcmp (optarg, "gen-slot-verification") == 0) - { - options.gen.slot_verification = 1; - } - else if (strcmp (optarg, "verify-slot") == 0) - { - options.gen.slot_verification = 1; - options.warning (NULL, "Option verify-slot replaced by gen-slot-verification\n"); - } - else if (strcmp (optarg, "gen-nia-invalid") == 0) - { - options.gen.nia = nia_is_invalid; - } - else if (strcmp (optarg, "default-nia-minus-one") == 0) - { - options.gen.nia = nia_is_invalid; - options.warning (NULL, "Option default-nia-minus-one replaced by gen-nia-invalid\n"); - } - else if (strcmp (optarg, "gen-nia-void") == 0) - { - options.gen.nia = nia_is_void; - } - else if (strcmp (optarg, "trace-combine") == 0) - { - options.trace.combine = 1; - } - else if (strcmp (optarg, "trace-entries") == 0) - { - options.trace.entries = 1; - } - else if (strcmp (optarg, "trace-rule-rejection") == 0) - { - options.trace.rule_rejection = 1; - } - else if (strcmp (optarg, "trace-rule-selection") == 0) - { - options.trace.rule_selection = 1; - } - else if (strcmp (optarg, "jumps") == 0) - { - options.gen.code = generate_jumps; - } - else if (strcmp (optarg, "field-widths") == 0) - { - options.insn_specifying_widths = 1; - } - else if (strcmp (optarg, "omit-line-numbers") == 0) - { - file_references = lf_omit_references; - } - else - error (NULL, "Unknown option %s\n", optarg); - break; - + { + int enable_p; + char *argp; + if (strncmp (optarg, "no-", strlen ("no-")) == 0) + { + argp = optarg + strlen ("no-"); + enable_p = 0; + } + else if (strncmp (optarg, "!", strlen ("!")) == 0) + { + argp = optarg + strlen ("no-"); + enable_p = 0; + } + else + { + argp = optarg; + enable_p = 1; + } + if (strcmp (argp, "decode-duplicate") == 0) + { + options.decode.duplicate = enable_p; + } + else if (strcmp (argp, "decode-combine") == 0) + { + options.decode.combine = enable_p; + } + else if (strcmp (argp, "decode-zero-reserved") == 0) + { + options.decode.zero_reserved = enable_p; + } + + else if (strcmp (argp, "gen-conditional-issue") == 0) + { + options.gen.conditional_issue = enable_p; + } + else if (strcmp (argp, "conditional-issue") == 0) + { + options.gen.conditional_issue = enable_p; + options.warning (NULL, "Option conditional-issue replaced by gen-conditional-issue\n"); + } + else if (strcmp (argp, "gen-delayed-branch") == 0) + { + options.gen.delayed_branch = enable_p; + } + else if (strcmp (argp, "delayed-branch") == 0) + { + options.gen.delayed_branch = enable_p; + options.warning (NULL, "Option delayed-branch replaced by gen-delayed-branch\n"); + } + else if (strcmp (argp, "gen-direct-access") == 0) + { + options.gen.direct_access = enable_p; + } + else if (strcmp (argp, "direct-access") == 0) + { + options.gen.direct_access = enable_p; + options.warning (NULL, "Option direct-access replaced by gen-direct-access\n"); + } + else if (strncmp (argp, "gen-zero-r", strlen ("gen-zero-r")) == 0) + { + options.gen.zero_reg = enable_p; + options.gen.zero_reg_nr = atoi (argp + strlen ("gen-zero-r")); + } + else if (strncmp (argp, "zero-r", strlen ("zero-r")) == 0) + { + options.gen.zero_reg = enable_p; + options.gen.zero_reg_nr = atoi (argp + strlen ("zero-r")); + options.warning (NULL, "Option zero-r<N> replaced by gen-zero-r<N>\n"); + } + else if (strncmp (argp, "gen-icache", strlen ("gen-icache")) == 0) + { + switch (argp[strlen ("gen-icache")]) + { + case '=': + options.gen.icache_size = atoi (argp + strlen ("gen-icache") + 1); + /* fall through */ + case '\0': + options.gen.icache = enable_p; + break; + default: + error (NULL, "Expecting -Ggen-icache or -Ggen-icache=<N>\n"); + } + } + else if (strcmp (argp, "gen-insn-in-icache") == 0) + { + options.gen.insn_in_icache = enable_p; + } + else if (strcmp (argp, "gen-multi-sim") == 0) + { + options.gen.multi_sim = enable_p; + } + else if (strcmp (argp, "gen-multi-word") == 0) + { + options.gen.multi_word = enable_p; + } + else if (strcmp (argp, "gen-semantic-icache") == 0) + { + options.gen.semantic_icache = enable_p; + } + else if (strcmp (argp, "gen-slot-verification") == 0) + { + options.gen.slot_verification = enable_p; + } + else if (strcmp (argp, "verify-slot") == 0) + { + options.gen.slot_verification = enable_p; + options.warning (NULL, "Option verify-slot replaced by gen-slot-verification\n"); + } + else if (strcmp (argp, "gen-nia-invalid") == 0) + { + options.gen.nia = nia_is_invalid; + } + else if (strcmp (argp, "default-nia-minus-one") == 0) + { + options.gen.nia = nia_is_invalid; + options.warning (NULL, "Option default-nia-minus-one replaced by gen-nia-invalid\n"); + } + else if (strcmp (argp, "gen-nia-void") == 0) + { + options.gen.nia = nia_is_void; + } + else if (strcmp (argp, "trace-combine") == 0) + { + options.trace.combine = enable_p; + } + else if (strcmp (argp, "trace-entries") == 0) + { + options.trace.entries = enable_p; + } + else if (strcmp (argp, "trace-rule-rejection") == 0) + { + options.trace.rule_rejection = enable_p; + } + else if (strcmp (argp, "trace-rule-selection") == 0) + { + options.trace.rule_selection = enable_p; + } + else if (strcmp (argp, "jumps") == 0) + { + options.gen.code = generate_jumps; + } + else if (strcmp (argp, "field-widths") == 0) + { + options.insn_specifying_widths = enable_p; + } + else if (strcmp (argp, "omit-line-numbers") == 0) + { + file_references = lf_omit_references; + } + else + { + error (NULL, "Unknown option %s\n", optarg); + } + break; + } + case 'i': isa = load_insn_table (optarg, cache_rules); if (isa->illegal_insn == NULL) diff --git a/sim/igen/ld-insn.c b/sim/igen/ld-insn.c index eaa7eca..c5c3679 100644 --- a/sim/igen/ld-insn.c +++ b/sim/igen/ld-insn.c @@ -374,6 +374,7 @@ typedef enum { function_record, internal_record, define_record, + include_record, model_processor_record, model_macro_record, model_data_record, @@ -388,6 +389,7 @@ static const name_map insn_type_map[] = { { "compute", compute_record }, { "scratch", scratch_record }, { "define", define_record }, + { "include", include_record }, { "%s", string_function_record }, { "function", function_record }, { "internal", internal_record }, @@ -744,6 +746,17 @@ load_insn_table (char *file_name, switch (record_type (record)) { + case include_record: + { + if (record->nr_fields < nr_include_record_fields) + error (record->line, + "Incorrect nr of fields for include record\n"); + table_push (file, record->line, options.include, + record->field[include_record_filename_field]); + record = table_read (file); + break; + } + case option_record: { if (isa->insns != NULL) @@ -757,7 +770,7 @@ load_insn_table (char *file_name, /* convert a string function field into an internal function field */ char *name; if (record->nr_fields < nr_function_fields) - error (record->line, "Incorrect nr of fields for %s record\n"); + error (record->line, "Incorrect nr of fields for %%s record\n"); name = NZALLOC (char, (strlen ("str_") + strlen (record->field[function_name_field]) @@ -1017,8 +1030,12 @@ load_insn_table (char *file_name, break; } - default: - error (record->line, "Unknown entry\n"); + case unknown_record: + case define_record: + case code_record: + error (record->line, "Unknown or unexpected entry\n"); + + } } return isa; diff --git a/sim/igen/ld-insn.h b/sim/igen/ld-insn.h new file mode 100644 index 0000000..be6f4be --- /dev/null +++ b/sim/igen/ld-insn.h @@ -0,0 +1,608 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996,1997 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. + + */ + + + +typedef unsigned64 insn_uint; + + +/* Common among most entries: + + */ + +enum { + record_type_field = 1, + old_record_type_field = 2, + record_filter_flags_field = 2, +}; + + +/* Include: + + Include the specified file. + + <include> ::= + ":" "include" + ":" <filter-flags> + ":" <filename> + <nl> + ; + + */ + +enum { + include_record_filename_field = 3, + nr_include_record_fields = 4, +}; + + + +/* Options: + + Valid options are: hi-bit-nr (default 0), insn-bit-size (default + 32), insn-specifying-widths (default true), multi-sim (default false). + + <option> ::= + ":" "option" + ":" <filter-flags> + ":" <option-name> + ":" <option-value> + <nl> + ; + + <option-name> ::= + "insn-bit-size" + | "insn-specifying-widths" + | "hi-bit-nr" + | "flags-filter" + | "model-filter" + | "multi-sim" + | "format-names" + ; + + <option-value> ::= + "true" + | "false" + | <integer> + | <list> + ; + + + These update the global options structure. */ + + +enum { + option_name_field = 3, + option_value_field = 4, + nr_option_fields = 5, +}; + + + +/* Macro definitions: + + <insn-macro> ::= + <expression> + ":" "define" + ":" <filter-flags> + ":" + ":" <name> + <nl> + ; + + Macro define/undef is currently unimplemented. */ + + +/* Functions and internal routins: + + <function> ::= + ":" "function" + <function-spec> + ; + + <internal> ::= + ":" "internal" + <function-spec> + ; + + <function-spec> ::= + ":" <filter-flags> + ":" <typedef> + ":" <name> + [ ":" <parameter-list> ] + <nl> + <code-block> + ; + + */ + +enum { + function_typedef_field = 3, + function_name_field = 4, + function_param_field = 5, + nr_function_fields = 5, +}; + +enum { + old_function_typedef_field = 0, + old_function_type_field = 2, + old_function_name_field = 4, + old_function_param_field = 5, + nr_old_function_fields = 6, +}; + + +typedef struct _function_entry function_entry; +struct _function_entry { + line_ref *line; + filter *flags; + char *type; + char *name; + char *param; + table_entry *code; + int is_internal; + function_entry *next; +}; + + +typedef void function_entry_handler +(lf *file, + function_entry *function, + void *data); + +extern void function_entry_traverse +(lf *file, + function_entry *functions, + function_entry_handler *handler, + void *data); + + +/* cache-macro: + + <cache-macro> ::= + ":" <macro-type> + ":" <filter-flags> + ":" <type> + ":" <name> + ":" <field-name> { "," <field-name> } + ":" <expression> + <nl> + ; + + <cache-macro-type> ::= + "scratch" + | "cache" + | "compute" + ; + + <name> ::= + <ident> + | <ident> "_is_" <integer> + ; + + A cache entry is defined (for an instruction) when all + <field-name>s are present as named opcode fields within the + instructions format. + + SCRATCH and CACHE macros are defined during the cache fill stage + while CACHE and COMPUTE macros are defined during the instruction + execution stage. + + */ + +enum { + cache_type_field = 3, + cache_name_field = 4, + cache_original_fields_field = 5, + cache_expression_field = 6, + nr_cache_fields = 7, +}; + +typedef enum { + scratch_value, + cache_value, + compute_value, +} cache_entry_type; + +typedef struct _cache_entry cache_entry; +struct _cache_entry { + line_ref *line; + filter *flags; + cache_entry_type entry_type; + char *name; + filter *original_fields; + char *type; + char *expression; + cache_entry *next; +}; + + + +/* Model specs: + + <model-processor> ::= + ":" "model" + ":" <filter-flags> + ":" <processor> + ":" <long-processor> + ":" <function-unit-data> + <nl> + ; + + <model-macro> ::= + ":" "model-macro" + ":" <filter-flags> + <nl> + <code-block> + ; + + <model-data> ::= + ":" "model-data" + ":" <filter-flags> + <nl> + <code-block> + ; + + <model-static> ::= + ":" "model-static" + <function-spec> + ; + + <model-internal> ::= + ":" "model-internal" + <function-spec> + ; + + <model-function> ::= + ":" "model-internal" + <function-spec> + ; + + */ + +enum { + nr_model_macro_fields = 3, + nr_model_data_fields = 3, + nr_model_static_fields = 6, + nr_model_internal_fields = 6, + nr_model_function_fields = 6, +}; + +typedef struct _model_data model_data; +struct _model_data { + line_ref *line; + filter *flags; + table_entry *entry; + table_entry *code; + model_data *next; +}; + +enum { + model_name_field = 3, + model_full_name_field = 4, + model_unit_data_field = 5, + nr_model_processor_fields = 6, +}; + +typedef struct _model_entry model_entry; +struct _model_entry { + line_ref *line; + filter *flags; + char *name; + char *full_name; + char *unit_data; + model_entry *next; +}; + + +typedef struct _model_table model_table; +struct _model_table { + filter *processors; + int nr_models; + model_entry *models; + model_data *macros; + model_data *data; + function_entry *statics; + function_entry *internals; + function_entry *functions; +}; + + + +/* Instruction format: + + An instruction is composed of a sequence of N bit instruction + words. Each word broken into a number of instruction fields. + Those fields being constant (ex. an opcode) or variable (register + spec). + + <insn-word> ::= + <insn-field> { "," <insn-field> } ; + + <insn-word> ::= + ( <binary-value-implying-width> + | <field-name-implying-width> + | [ <start-or-width> "." ] <field> + ) + { "!" <excluded-value> } + ; + + <field> ::= + "*" + + | "/" + + | <field-name> + | "0x" <hex-value> + | "0b" <binary-value> + | "0" <octal-value> + | <integer-value> ; + +*/ + +typedef struct _insn_field_exclusion insn_field_exclusion; +struct _insn_field_exclusion { + char *string; + insn_uint value; + insn_field_exclusion *next; +}; + +typedef enum { + insn_field_int, + insn_field_reserved, + insn_field_wild, + insn_field_string, +} insn_field_type; + +typedef struct _insn_field_entry insn_field_entry; +struct _insn_field_entry { + int first; + int last; + int width; + int word_nr; + insn_field_type type; + insn_uint val_int; + char *pos_string; + char *val_string; + insn_field_exclusion *exclusions; + insn_field_entry *next; + insn_field_entry *prev; +}; + +typedef struct _insn_bit_entry insn_bit_entry; +struct _insn_bit_entry { + int value; + int mask; + insn_field_entry *field; +}; + + + + +typedef struct _insn_entry insn_entry; /* forward */ + +typedef struct _insn_word_entry insn_word_entry; +struct _insn_word_entry { + /* list of sub-fields making up the instruction. bit provides + faster access to the field data for bit N. */ + insn_field_entry *first; + insn_field_entry *last; + insn_bit_entry *bit[max_insn_bit_size]; + /* set of all the string fields */ + filter *field_names; + /* For multi-word instructions, The Nth word (from zero). */ + insn_word_entry *next; +}; + + + +/* Instruction model: + + Provides scheduling data for the code modeling the instruction unit. + + <insn-model> ::= + "*" [ <processor> ] + ":" <function-unit-data> + <nl> + ; + + If <processor> is NULL, the model is made the default for this + instruction. + + */ + +enum { + insn_model_name_field = 0, + insn_model_unit_data_field = 1, + nr_insn_model_fields = 1, +}; + +typedef struct _insn_model_entry insn_model_entry; +struct _insn_model_entry { + line_ref *line; + insn_entry *insn; + char *name; + char *full_name; + char *unit_data; + insn_model_entry *next; +}; + + + +/* Instruction mnemonic: + + List of assembler mnemonics for the instruction. + + <insn-mnenonic> ::= + "\"" <assembler-mnemonic> "\"" + [ ":" <conditional-expression> ] + <nl> + ; + + */ + +enum { + insn_mnemonic_format_field = 0, + insn_mnemonic_condition_field = 1, + nr_insn_mnemonic_fields = 1, +}; + +typedef struct _insn_mnemonic_entry insn_mnemonic_entry; +struct _insn_mnemonic_entry { + line_ref *line; + insn_entry *insn; + char *format; + char *condition; + insn_mnemonic_entry *next; +}; + + + +/* Instruction: + + <insn> ::= + <insn-word> { "+" <insn-word> } + ":" <format-name> + ":" <filter-flags> + ":" <options> + ":" <name> + <nl> + { <insn-model> } + { <insn-mnemonic> } + <code-block> + + */ + +enum { + insn_word_field = 0, + insn_format_name_field = 1, + insn_filter_flags_field = 2, + insn_options_field = 3, + insn_name_field = 4, + nr_insn_fields = 5, +}; + + +/* typedef struct _insn_entry insn_entry; */ +struct _insn_entry { + line_ref *line; + filter *flags; /* filtered by options.filters */ + char *format_name; + filter *options; + char *name; + /* the words that make up the instruction. Word provides direct + access to word N. Pseudo instructions can be identified by + nr_words == 0. */ + int nr_words; + insn_word_entry *words; + insn_word_entry **word; + /* a set of all the fields from all the words */ + filter *field_names; + /* an array of processor models, missing models are NULL! */ + int nr_models; + insn_model_entry *models; + insn_model_entry **model; + filter *processors; + /* list of assember formats */ + int nr_mnemonics; + insn_mnemonic_entry *mnemonics; + /* code body */ + table_entry *code; + insn_entry *next; +}; + + +/* Instruction table: + + */ + +typedef struct _insn_table insn_table; +struct _insn_table { + cache_entry *caches; + int max_nr_words; + int nr_insns; + insn_entry *insns; + function_entry *functions; + insn_entry *illegal_insn; + model_table *model; + filter *options; + filter *flags; +}; + +extern insn_table *load_insn_table +(char *file_name, + cache_entry *cache); + +typedef void insn_entry_handler +(lf *file, + insn_table *isa, + insn_entry *insn, + void *data); + +extern void insn_table_traverse_insn +(lf *file, + insn_table *isa, + insn_entry_handler *handler, + void *data); + + + +/* Printing */ + +extern void print_insn_words +(lf *file, + insn_entry *insn); + + + +/* Debugging */ + +void +dump_insn_field +(lf *file, + char *prefix, + insn_field_entry *field, + char *suffix); + +void +dump_insn_word_entry +(lf *file, + char *prefix, + insn_word_entry *word, + char *suffix); + +void +dump_insn_entry +(lf *file, + char *prefix, + insn_entry *insn, + char *suffix); + +void +dump_cache_entries +(lf *file, + char *prefix, + cache_entry *entry, + char *suffix); + +void +dump_insn_table +(lf *file, + char *prefix, + insn_table *isa, + char *suffix); diff --git a/sim/igen/table.c b/sim/igen/table.c index 461a632..71be438 100644 --- a/sim/igen/table.c +++ b/sim/igen/table.c @@ -38,348 +38,598 @@ #include <stdlib.h> #endif -struct _table { +typedef struct _open_table open_table; +struct _open_table { size_t size; char *buffer; char *pos; - int nr_fields; - int nr_model_fields; - int line_nr; - char *file_name; - int current_file_line_offset; - char *current_file_name; + line_ref pseudo_line; + line_ref real_line; + open_table *parent; + table *root; +}; +struct _table { + open_table *current; }; -extern table * -table_open(const char *file_name, - int nr_fields, - int nr_model_fields) + +static line_ref * +current_line (open_table *file) +{ + line_ref *entry = ZALLOC (line_ref); + *entry = file->pseudo_line; + return entry; +} + +static table_entry * +new_table_entry (open_table *file, + table_entry_type type) +{ + table_entry *entry; + entry = ZALLOC (table_entry); + entry->file = file->root; + entry->line = current_line (file); + entry->type = type; + return entry; +} + +static void +set_nr_table_entry_fields (table_entry *entry, + int nr_fields) +{ + entry->field = NZALLOC (char*, nr_fields + 1); + entry->nr_fields = nr_fields; +} + + +void +table_push (table *root, + line_ref *line, + table_include *includes, + const char *file_name) { int fd; struct stat stat_buf; - table *file; + open_table *file; + table_include dummy; + table_include *include = &dummy; + + /* dummy up a search of this directory */ + dummy.next = includes; + dummy.dir = ""; /* create a file descriptor */ - file = ZALLOC(table); - ASSERT(file != NULL); - file->nr_fields = nr_fields; - file->nr_model_fields = nr_model_fields; - - /* save the file name */ - file->file_name = (char*)zalloc(strlen(file_name) + 1); - ASSERT(file->file_name != NULL); - strcpy(file->file_name, file_name); - file->current_file_name = file->file_name; - - /* open the file */ - fd = open(file->file_name, O_RDONLY, 0); - if (fd < 0) { - perror(file->file_name); - exit (1); + file = ZALLOC (open_table); + if (file == NULL) + { + perror (file_name); + exit (1); + } + file->root = root; + file->parent = root->current; + root->current = file; + + while (1) + { + /* save the file name */ + char *dup_name = NZALLOC (char, strlen (include->dir) + strlen (file_name) + 2); + if (dup_name == NULL) + { + perror (file_name); + exit (1); + } + if (include->dir[0] != '\0') + { + strcat (dup_name, include->dir); + strcat (dup_name, "/"); + } + strcat (dup_name, file_name); + file->real_line.file_name = dup_name; + file->pseudo_line.file_name = dup_name; +printf ("Trying `%s'\n", dup_name); + /* open the file */ + fd = open (dup_name, O_RDONLY, 0); + if (fd >= 0) + break; + /* zfree (dup_name); */ + if (include->next == NULL) + { + if (line != NULL) + error (line, "Problem opening file `%s'\n", file_name); + perror (file_name); + exit (1); + } + include = include->next; } + /* determine the size */ - if (fstat(fd, &stat_buf) < 0) { - perror("table_open.fstat"); - exit(1); + if (fstat (fd, &stat_buf) < 0) { + perror (file_name); + exit (1); } file->size = stat_buf.st_size; /* allocate this much memory */ - file->buffer = (char*)zalloc(file->size+1); - ASSERT(file->buffer != NULL); + file->buffer = (char*) zalloc (file->size + 1); + if (file->buffer == NULL) + { + perror (file_name); + exit (1); + } file->pos = file->buffer; - /* read it in */ - if (read(fd, file->buffer, file->size) < file->size) { - perror(file->file_name); - exit(1); + /* read it all in */ + if (read (fd, file->buffer, file->size) < file->size) { + perror (file_name); + exit (1); } file->buffer[file->size] = '\0'; /* set the initial line numbering */ - file->line_nr = 0; - file->current_file_line_offset = 0; + file->real_line.line_nr = 1; /* specifies current line */ + file->pseudo_line.line_nr = 1; /* specifies current line */ /* done */ - close(fd); - return file; + close (fd); } - -extern table_entry * -table_entry_read(table *file) +table * +table_open (const char *file_name) { - int field; - table_entry *entry; + table *root; - /* skip comments/blanks */ - while(1) { - /* leading white space */ - while (*file->pos != '\0' - && *file->pos != '\n' - && isspace(*file->pos)) - file->pos++; - /* cpp line nr directive - # <line-nr> "<file>" */ - if (file->pos[0] == '#' - && file->pos[1] == ' ' - && isdigit(file->pos[2])) { - file->pos += strlen("# "); - /* parse the number */ - file->current_file_line_offset = atoi(file->pos) - file->line_nr - 2; - /* skip to the file name */ - while (file->pos[0] != '0' - && file->pos[0] != '"' - && file->pos[0] != '\0') - file->pos++; - if (file->pos[0] != '"') { - error("%s:%d: Missing opening quote", - file->file_name, - file->line_nr); - } - /* parse the file name */ - file->pos++; - file->current_file_name = file->pos; - while (file->pos[0] != '"' - && file->pos[0] != '\0') - file->pos++; - if (file->pos[0] != '"') { - error("%s:%d: Missing closing quote", - file->file_name, - file->line_nr); - } - file->pos[0] = '\0'; - file->pos ++; - while (file->pos[0] != '\0' - && file->pos[0] != '\n') - file->pos[0]++; - if (file->pos[0] != '\n') - error("%s:%d: Missing newline", - file->file_name, - file->line_nr); + /* create a file descriptor */ + root = ZALLOC (table); + if (root == NULL) + { + perror (file_name); + exit (1); } - /* comment - leading // or # - skip */ - else if ((file->pos[0] == '/' && file->pos[1] == '/') - || (file->pos[0] == '#')) { - do { - file->pos++; - } while (*file->pos != '\0' && *file->pos != '\n'); + + table_push (root, NULL, NULL, file_name); + return root; +} + +char * +skip_spaces (char *chp) +{ + while (1) + { + if (*chp == '\0' + || *chp == '\n' + || !isspace (*chp)) + return chp; + chp++; } - /* end of line? */ - if (*file->pos == '\n') { - file->pos++; - file->line_nr++; +} + + +char * +back_spaces (char *start, char *chp) +{ + while (1) + { + if (chp <= start + || !isspace (chp[-1])) + return chp; + chp--; } - else - break; - } - if (*file->pos == '\0') - return NULL; - - /* create this new entry */ - entry = (table_entry*)zalloc(sizeof(table_entry) - + (file->nr_fields + 1) * sizeof(char*)); - ASSERT(entry != NULL); - entry->file_name = file->current_file_name; - entry->nr_fields = file->nr_fields; - - /* break the line into its colon delimitered fields */ - for (field = 0; field < file->nr_fields-1; field++) { - entry->fields[field] = file->pos; - while(*file->pos && *file->pos != ':' && *file->pos != '\n') - file->pos++; - if (*file->pos == ':') { - *file->pos = '\0'; - file->pos++; +} + +char * +skip_digits (char *chp) +{ + while (1) + { + if (*chp == '\0' + || *chp == '\n' + || !isdigit (*chp)) + return chp; + chp++; } - } +} - /* any trailing stuff not the last field */ - ASSERT(field == file->nr_fields-1); - entry->fields[field] = file->pos; - while (*file->pos && *file->pos != '\n') { - file->pos++; - } - if (*file->pos == '\n') { - *file->pos = '\0'; - file->pos++; - } - file->line_nr++; - - /* If following lines being with a double quote ("), add them to the - list of assembler lines */ - { - table_assembler_entry **current = &entry->assembler; - while (*file->pos == '"') { - char *tmpchp; - const char *format; - int strlen_format; - const char *condition; - int strlen_condition; - - /* skip over the format string */ - format = file->pos; - strlen_format = 0; - do { - if (file->pos[0] == '\\' && file->pos[1] == '"') - file->pos += 2; - else - file->pos += 1; - } while (*file->pos != '\0' && *file->pos != '\n' && *file->pos != '"'); - if (*file->pos != '"') - error ("%s:%d: Missing closing quote in assembler line", - file->file_name, - file->line_nr); - file->pos++; - strlen_format = file->pos - format; - - /* skip over the boolean condition */ - condition = NULL; - strlen_condition = 0; - if (*file->pos == ':') +char * +skip_to_separator (char *chp, + char *separators) +{ + while (1) + { + char *sep = separators; + while (1) + { + if (*chp == *sep) + return chp; + if (*sep == '\0') + break; + sep++; + } + chp++; + } +} + +static char * +skip_to_null (char *chp) +{ + return skip_to_separator (chp, ""); +} + + +static char * +skip_to_nl (char * chp) +{ + return skip_to_separator (chp, "\n"); +} + + +static void +next_line (open_table *file) +{ + file->pos = skip_to_nl (file->pos); + if (*file->pos == '0') + error (&file->pseudo_line, "Missing <nl> at end of line\n"); + *file->pos = '\0'; + file->pos += 1; + file->real_line.line_nr += 1; + file->pseudo_line.line_nr += 1; +} + + +extern table_entry * +table_read (table *root) +{ + open_table *file = root->current; + table_entry *entry = NULL; + while(1) + { + + /* end-of-file? */ + while (*file->pos == '\0') { - file->pos++; - while (isspace(*file->pos) && *file->pos != '\0' && *file->pos != '\n') - file->pos++; - condition = file->pos; - while (*file->pos != '\0' && *file->pos != '\n') - file->pos++; - strlen_condition = file->pos - condition; + if (file->parent != NULL) + { + file = file->parent; + root->current = file; + } + else + return NULL; } - /* create the new assembler entry */ - *current = ZALLOC (table_assembler_entry); - tmpchp = zalloc (strlen_format + 1); - strncpy (tmpchp, format, strlen_format); - (*current)->format = tmpchp; - (*current)->file_name = file->file_name; - (*current)->line_nr = file->line_nr; - if (condition != NULL && strlen_condition > 0) + /* code_block? */ + if (*file->pos == '{') { - tmpchp = zalloc (strlen_condition + 1); - strncpy (tmpchp, condition, strlen_condition); - (*current)->condition = tmpchp; + char *chp; + next_line (file); /* discard leading brace */ + entry = new_table_entry (file, table_code_entry); + chp = file->pos; + /* determine how many lines are involved - look for <nl> "}" */ + { + int nr_lines = 0; + while (*file->pos != '}') + { + next_line (file); + nr_lines++; + } + set_nr_table_entry_fields (entry, nr_lines); + } + /* now enter each line */ + { + int line_nr; + for (line_nr = 0; line_nr < entry->nr_fields; line_nr++) + { + if (strncmp (chp, " ", 2) == 0) + entry->field[line_nr] = chp + 2; + else + entry->field[line_nr] = chp; + chp = skip_to_null (chp) + 1; + } + /* skip trailing brace */ + ASSERT (*file->pos == '}'); + next_line (file); + } + break; } - current = &(*current)->next; - - /* end of line? */ - if (*file->pos != '\n') - error ("%s:%d: Missing eoln in assembler line", - file->file_name, - file->line_nr); - file->pos++; - file->line_nr++; - } - } - /* if following lines begin with a star, add them to the model - section. */ - while ((file->nr_model_fields > 0) && (*file->pos == '*')) { - table_model_entry *model = (table_model_entry*)zalloc(sizeof(table_model_entry) - + (file->nr_model_fields + 1) * sizeof(char*)); - if (entry->model_last) - entry->model_last->next = model; - else - entry->model_first = model; - entry->model_last = model; - - /* break the line into its colon delimitered fields */ - file->pos++; - for (field = 0; field < file->nr_model_fields-1; field++) { - model->fields[field] = file->pos; - while(*file->pos && *file->pos != ':' && *file->pos != '\n') - file->pos++; - if (*file->pos == ':') { - *file->pos = '\0'; - file->pos++; - } - } + /* tab block? */ + if (*file->pos == '\t') + { + char *chp = file->pos; + entry = new_table_entry (file, table_code_entry); + /* determine how many lines are involved - look for <nl> !<tab> */ + { + int nr_lines = 0; + int nr_blank_lines = 0; + while (1) + { + if (*file->pos == '\t') + { + nr_lines = nr_lines + nr_blank_lines + 1; + nr_blank_lines = 0; + next_line (file); + } + else + { + file->pos = skip_spaces (file->pos); + if (*file->pos != '\n') + break; + nr_blank_lines++; + next_line (file); + } + } + set_nr_table_entry_fields (entry, nr_lines); + } + /* now enter each line */ + { + int line_nr; + for (line_nr = 0; line_nr < entry->nr_fields; line_nr++) + { + if (*chp == '\t') + entry->field[line_nr] = chp + 1; + else + entry->field[line_nr] = ""; /* blank */ + chp = skip_to_null (chp) + 1; + } + } + break; + } - /* any trailing stuff not the last field */ - ASSERT(field == file->nr_model_fields-1); - model->fields[field] = file->pos; - while (*file->pos && *file->pos != '\n') { - file->pos++; - } - if (*file->pos == '\n') { - *file->pos = '\0'; - file->pos++; - } + /* cpp directive? */ + if (file->pos[0] == '#') + { + char *chp = skip_spaces (file->pos + 1); + + /* cpp line-nr directive - # <line-nr> "<file>" */ + if (isdigit (*chp) + && *skip_digits (chp) == ' ' + && *skip_spaces (skip_digits (chp)) == '"') + { + int line_nr; + char *file_name; + file->pos = chp; + /* parse the number */ + line_nr = atoi(file->pos) - 1; + /* skip to the file name */ + while (file->pos[0] != '0' + && file->pos[0] != '"' + && file->pos[0] != '\0') + file->pos++; + if (file->pos[0] != '"') + error (&file->real_line, "Missing opening quote in cpp directive\n"); + /* parse the file name */ + file->pos++; + file_name = file->pos; + while (file->pos[0] != '"' + && file->pos[0] != '\0') + file->pos++; + if (file->pos[0] != '"') + error (&file->real_line, "Missing closing quote in cpp directive\n"); + file->pos[0] = '\0'; + file->pos++; + file->pos = skip_to_nl (file->pos); + if (file->pos[0] != '\n') + error (&file->real_line, "Missing newline in cpp directive\n"); + file->pseudo_line.file_name = file_name; + file->pseudo_line.line_nr = line_nr; + next_line (file); + continue; + } + + /* #define and #undef - not implemented yet */ + + /* Old style # comment */ + next_line (file); + continue; + } - file->line_nr++; - model->line_nr = file->current_file_line_offset + file->line_nr; - } + /* blank line or end-of-file? */ + file->pos = skip_spaces (file->pos); + if (*file->pos == '\0') + error (&file->pseudo_line, "Missing <nl> at end of file\n"); + if (*file->pos == '\n') + { + next_line (file); + continue; + } - entry->line_nr = file->current_file_line_offset + file->line_nr; - - /* if following lines are tab indented, put in the annex */ - if (*file->pos == '\t') { - entry->annex = file->pos; - do { - do { - file->pos++; - } while (*file->pos != '\0' && *file->pos != '\n'); - if (*file->pos == '\n') { - char *save_pos = ++file->pos; - int extra_lines = 0; - file->line_nr++; - /* Allow tab indented to have blank lines */ - while (*save_pos == '\n') { - save_pos++; - extra_lines++; + /* comment - leading // or # - skip */ + if ((file->pos[0] == '/' && file->pos[1] == '/') + || (file->pos[0] == '#')) + { + next_line (file); + continue; } - if (*save_pos == '\t') { - file->pos = save_pos; - file->line_nr += extra_lines; + + /* colon field */ + { + char *chp = file->pos; + entry = new_table_entry (file, table_colon_entry); + next_line (file); + /* figure out how many fields */ + { + int nr_fields = 1; + char *tmpch = chp; + while (1) + { + tmpch = skip_to_separator (tmpch, "\\:"); + if (*tmpch == '\\') + { + /* eat the escaped character */ + char *cp = tmpch; + while (cp[1] != '\0') + { + cp[0] = cp[1]; + cp++; + } + cp[0] = '\0'; + tmpch++; + } + else if (*tmpch != ':') + break; + else + { + *tmpch = '\0'; + tmpch++; + nr_fields++; + } + } + set_nr_table_entry_fields (entry, nr_fields); + } + /* now parse them */ + { + int field_nr; + for (field_nr = 0; field_nr < entry->nr_fields; field_nr++) + { + chp = skip_spaces (chp); + entry->field[field_nr] = chp; + chp = skip_to_null (chp); + *back_spaces (entry->field[field_nr], chp) = '\0'; + chp++; + } } + break; } - } while (*file->pos != '\0' && *file->pos == '\t'); - if (file->pos[-1] == '\n') - file->pos[-1] = '\0'; - } - else - entry->annex = NULL; - /* return it */ - return entry; + } + ASSERT (entry == NULL || entry->field[entry->nr_fields] == NULL); + return entry; } - extern void -dump_table_entry(table_entry *entry, - int indent) +table_print_code (lf *file, + table_entry *entry) { - printf("(table_entry*)%p\n", entry); + int field_nr; + int nr = 0; + for (field_nr = 0; + field_nr < entry->nr_fields; + field_nr++) + { + char *chp = entry->field[field_nr]; + int in_bit_field = 0; + if (*chp == '#') + lf_indent_suppress(file); + while (*chp != '\0') + { + if (chp[0] == '{' + && !isspace(chp[1]) + && chp[1] != '\0') + { + in_bit_field = 1; + nr += lf_putchr(file, '_'); + } + else if (in_bit_field && chp[0] == ':') + { + nr += lf_putchr(file, '_'); + } + else if (in_bit_field && *chp == '}') + { + nr += lf_putchr(file, '_'); + in_bit_field = 0; + } + else + { + nr += lf_putchr(file, *chp); + } + chp++; + } + if (in_bit_field) + { + line_ref line = *entry->line; + line.line_nr += field_nr; + error (&line, "Bit field brace miss match\n"); + } + nr += lf_putchr(file, '\n'); + } +} - if (entry != NULL) { - int field; - char sep; - sep = ' '; - dumpf(indent, "(fields"); - for (field = 0; field < entry->nr_fields; field++) { - printf("%c%s", sep, entry->fields[field]); - sep = ':'; - } - printf(")\n"); - dumpf(indent, "(line_nr %d)\n", entry->line_nr); +void +dump_line_ref (lf *file, + char *prefix, + const line_ref *line, + char *suffix) +{ + lf_printf (file, "%s(line_ref*) 0x%lx", prefix, (long) line); + if (line != NULL) + { + lf_indent (file, +1); + lf_printf (file, "\n(line_nr %d)", line->line_nr); + lf_printf (file, "\n(file_name %s)", line->file_name); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); +} - dumpf(indent, "(file_name %s)\n", entry->file_name); - dumpf(indent, "(annex\n%s\n", entry->annex); - dumpf(indent, " )\n"); +static const char * +table_entry_type_to_str (table_entry_type type) +{ + switch (type) + { + case table_code_entry: return "code-entry"; + case table_colon_entry: return "colon-entry"; + } + return "*invalid*"; +} - } +void +dump_table_entry(lf *file, + char *prefix, + const table_entry *entry, + char *suffix) +{ + lf_printf (file, "%s(table_entry*) 0x%lx", prefix, (long) entry); + if (entry != NULL) + { + int field; + lf_indent (file, +1); + dump_line_ref (file, "\n(line ", entry->line, ")"); + lf_printf (file, "\n(type %s)", table_entry_type_to_str (entry->type)); + lf_printf (file, "\n(nr_fields %d)", entry->nr_fields); + lf_printf (file, "\n(fields"); + lf_indent (file, +1); + for (field = 0; field < entry->nr_fields; field++) + lf_printf (file, "\n\"%s\"", entry->field[field]); + lf_indent (file, -1); + lf_printf (file, ")"); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); } -extern void -table_entry_print_cpp_line_nr(lf *file, - table_entry *entry) +#ifdef MAIN +int +main(int argc, char **argv) { - lf_print__external_reference(file, entry->line_nr, entry->file_name); -} + table *t; + table_entry *entry; + lf *l; + int line_nr; + if (argc != 2) + { + printf("Usage: table <file>\n"); + exit (1); + } + t = table_open (argv[1]); + l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-table"); + + line_nr = 0; + do + { + char line[10]; + entry = table_read (t); + line_nr ++; + sprintf (line, "(%d ", line_nr); + dump_table_entry (l, line, entry, ")\n"); + } + while (entry != NULL); + + return 0; +} +#endif |