diff options
author | Stan Shebs <shebs@apple.com> | 1999-04-16 01:35:26 +0000 |
---|---|---|
committer | Stan Shebs <shebs@apple.com> | 1999-04-16 01:35:26 +0000 |
commit | 14cd51f7793a9ce07bc435069f57269450141363 (patch) | |
tree | 280a2da48f771d61be5b451ddbacdf9ef8e9ad13 /sim/igen | |
download | gdb-14cd51f7793a9ce07bc435069f57269450141363.tar.gz |
Initial revision
Diffstat (limited to 'sim/igen')
40 files changed, 17322 insertions, 0 deletions
diff --git a/sim/igen/ChangeLog b/sim/igen/ChangeLog new file mode 100644 index 00000000000..43ba1505e7e --- /dev/null +++ b/sim/igen/ChangeLog @@ -0,0 +1,998 @@ +Fri Dec 4 15:14:09 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c (main): Fix -Pitable=. + + * gen-engine.c (print_run_body): Prefix instruction_address. + +Wed Oct 28 18:12:43 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * Makefile.in (SIM_WARNINGS): Update to match ../common/aclocal.m4 + changes. + +Wed Aug 12 10:55:28 1998 Frank Ch. Eigler <fche@cygnus.com> + + * gen-icache.c (print_icache_extraction): #undef a generated + symbol before #define'ing it, to remove conflict with system + macros. + +Wed Jul 29 10:07:27 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * gen.c (gen_entry_expand_opcode): For conditional, fields. Fix + the extraction of the value from its source - both table and bit + cases were wrong. + +Tue Jul 28 11:19:43 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * ld-insn.c (parse_insn_word): For constant conditional strings, + encode their bit value. + + * ld-insn.c (parse_insn_word, parse_insn_words): Allow conditional + operands to refer to fields in earlier instruction words. + + * gen.c (sub_val): Replace field argument with val_last_pos. + (gen_entry_expand_opcode): Look in previous tables for a value for + a conditional field as well as the bits from the current table. + (insn_list_insert): Add sort key of instructions where + their operand fields have different conditionals. + (insn_field_cmp): New function. + +Sun Apr 26 15:31:55 1998 Tom Tromey <tromey@creche> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + * config.in: Ditto. + +Sun Apr 26 15:20:08 1998 Tom Tromey <tromey@cygnus.com> + + * acconfig.h: New file. + * configure.in: Reverted change of Apr 24; use sinclude again. + +Fri Apr 24 14:16:40 1998 Tom Tromey <tromey@creche> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + * config.in: Ditto. + +Fri Apr 24 11:19:33 1998 Tom Tromey <tromey@cygnus.com> + + * configure.in: Don't call sinclude. + +Fri Apr 24 19:45:00 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-icache.c (print_icache_extraction): Do not type cast + pointers. + + * ld-insn.c (load_insn_table): Terminate error with NL. + + * gen.c (insns_bit_useless): Perform unsigned bit comparisons. + + * filter.c (is_filtered_out, filter_parse): Pacify GCC, len is + unsigned. + +Wed Apr 22 14:27:39 1998 Michael Meissner <meissner@cygnus.com> + + * configure: Reconfigure to pick up ../common/aclocal.m4 changes + to suppress inlining by default. + +Tue Apr 21 01:37:54 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-icache.c (print_icache_extraction): When generating #define + force the expression to the correct type. + +Thu Apr 16 08:50:29 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * misc.c (name2i): strlen returns an unsigned. + +Tue Apr 14 19:04:28 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.h (struct igen_warn_options): Add unimplemented option. + * igen.c (main): Update + + * ld-insn.c (load_insn_table): Report unimplemented functions. + +Tue Apr 14 10:57:26 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * ld-insn.c (parse_insn_word): Treat `!' and `=' as valid + separator tokens when parsing a conditional. + + * igen.h (main): Add option -S so that suffix can be specified. + +Tue Apr 14 08:44:53 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.h (struct igen_trace_options): Add members insn_expansion + and insn_insertion. + + * igen.c (main): Add options -Gtrace-insn-expansion, + -Gtrace-insn-insertion and -Gtrace-all. + + * gen.c (gen_entry_expand_insns): Trace each instruction as it is + selected for expansion. + (gen_entry_expand_opcode): Trace each expanded instruction as it + is inserted into the table. + +Mon Apr 13 19:21:47 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * ld-insn.c (parse_insn_word): Parse conditional operators. + (parse_insn_word): Verify field conditionals. + + * ld-insn.h: Extend syntax to allow macros and field equality. + (struct insn_field_cond): Rename insn_field_exclusion, add type. + + * gen.c (gen_entry_expand_opcode): Check type of conditional. + (insns_bit_useless): Ditto. + + * ld-insn.c (parse_macro_record): New function. + +Mon Apr 13 22:37:47 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * ld-insn.h (enum insn_field_type): Add insn_field_invalid. + + * ld-insn.c (parse_insn_word): Check instruction field type + correctly initialized. + (print_insn_words): Ditto. + (insn_field_type_to_str): Ditto. + (dump_insn_field): Ditto. + + * gen.c (insns_bit_useless): Ditto. + +Fri Apr 3 18:08:16 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * gen.h, igen.c (print_include_inline, print_includes, + print_includes): New functions. Generate include list. For for + semantics et.al. generate CPP code to inline when + C_REVEALS_MODULE_P. + + * igen.c (gen_semantics_c): Call print_includes. + * gen-engine.c (gen_engine_c): Ditto. + +Sat Apr 4 21:09:11 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.h: (struct _igen_name_option): Replace with struct + igen_module_option. Contains both module prefix and suffix. + (INIT_OPTIONS): Initialize. + + * igen.c (main): Update -P option to fill in full module info. + (gen-engine.c, gen-icache.c, gen-itable.c, gen-semantics.c, + gen-support.c): Update. + +Sat Apr 4 02:15:35 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c (print_itrace): Use TRACE_ANY_P macro to determine if any + tracing is needed. + +Thu Mar 26 20:51:23 1998 Stu Grossman <grossman@bhuna.cygnus.co.uk> + + * table.c (table_push): Redo, using stdio. Fixes NT native + problem with <CRLF>=><LF> translation... + +Tue Mar 24 23:30:07 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-engine.c (print_run_body): Re-extract the CIA after + processing any events. + +Tue Mar 24 17:46:08 1998 Stu Grossman <grossman@bhuna.cygnus.co.uk> + + * Makefile.in: Get SHELL from configure. + * configure: Regenerate with autoconf 2.12.1 to fix shell issues for + NT native builds. + +Mon Mar 16 12:51:31 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c: Pass sim_cia to trace_prefix. + +Thu Feb 26 19:25:02 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * ld-insn.c (parse_function_record): Check models are valid. + (parse_function_record): Only discard function when no model is + common. + +Tue Feb 24 01:42:03 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-engine.c (print_run_body): Always wrap generated idecode + body in ENGINE_ISSUE_PREFIX_HOOK / ENGINE_ISSUE_POSTFIX_HOOK. + +Fri Feb 20 16:22:10 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * ld-insn.c (parse_function_record): When -Wnodiscard, suppress + discarded function warning. + + * igen.c (main): Clarify -Wnodiscard. + + * ld-insn.c (parse_function_record): For functions, allow use of + instruction style function model records + + * ld-insn.h (nr_function_model_fields): Define. + +Tue Feb 17 16:36:27 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c (print_itrace_prefix): Generate call to trace_prefix + instead of trace_one_insn. + (print_itrace): Generate trace_prefix call if any tracing enabled, + (print_itrace): Nest generated call to trace_generic inside + conditional for any tracing enabled. + (print_itrace_prefix): Do not pass PHASE to trace_prefix. + +Tue Feb 3 14:00:32 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-engine.c (print_run_body): Add bitsize suffix to IMEM macro. + * gen-icache.c (print_icache_body): Ditto. + * gen-idecode.c (print_idecode_ifetch): Ditto. + + * gen-icache.c (print_icache_body): Mark successive instruction + words as unused. + + * ld-insn.c (parse_insn_word): Only report insn-width problems + when warning enabled. + + * igen.h: Add flag for warning about invalid instruction widths. + * igen.c: Parse -Wwidth option. + + * gen-support.c (gen_support_h): Map instruction_word onto + <PREFIX>_instruction_word when needed. + (print_support_function_name): Use support prefix. + (gen_support_h): Ditto for <PREFIX>_idecode_issue. + +Sun Feb 1 11:08:48 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-support.c (gen_support_h): Generate new macro CPU_. + +Sat Jan 31 14:50:27 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-engine.c (gen_engine_h): Don't assume a model is present. + (gen_engine_c): Ditto. + + * igen.c (gen_run_c): Ditto. + + * gen-engine.c (print_run_body): Use CIA_GET & CIA_SET instead of + CPU_CIA. Parameterize with CPU argument. + +Fri Jan 30 09:09:39 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * gen.h (struct _gen_list): Replace processor with model. + + * igen.c (gen_idecode_h): Update. + (gen_run_c): For generated switch, use model->full_name. + + * gen.c (print_gen_entry_path): Ditto. + (make_table): Ditto. + (gen_entry_expand_insns): Ditto. + (make_gen_tables): Ditto. + + * igen.c (gen_run_c): Add extra argument `nr_cpus' to generated + function sim_engine_run. Pass argument on to engine_run. + + * gen-engine.c (print_engine_run_function_header): Add extra + argument `nr_cpus' to generated function engine_run. + (print_run_body): Fix SMP case. + + * gen-support.c (support_c_function): Call sim_engine_abort when + internal function fails to long jump. + +Wed Jan 21 18:00:22 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-semantics.c (print_semantic_body): Use GPR_SET to zero + hardwired register. + +Wed Dec 17 14:49:03 1997 Jeffrey A Law (law@cygnus.com) + + * gen-semantics.c (print_semantic_body): Fix handling of + hardwired zero register. + +Tue Dec 9 12:45:00 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.h (struct _igen_gen_options): Add member default_model. + + * igen.c (gen_run_c): Default to the first machine in the + multi-sim list. + (main): Add MODEL parameter to gen-multi-sim option. + + * gen.h (function_decl_type): Declare enum. + + * gen-engine.c (print_engine_run_function_header), gen-engine.h: + Make global, pass function_decl_type as argument. + (gen_engine_h, gen_engine_c): Update call. + + * gen-idecode.c (print_idecode_issue_function_header), + gen-idecode.h: Pass function_decl_type as argument. + + * igen.c (gen_idecode_h): For multi-sim, delcare global variable + idecode_issue. + + * igen.c (gen_run_c): For multi-sim, initialize globals + idecode_issue and engine_run. + +Fri Nov 14 10:51:44 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * ld-insn.c (parse_insn_model_record): Allow multiple model names + to be specified in a single instruction model record. + (dump_insn_model_entry): Update. + + * ld-insn.h (struct _insn_model_entry): Replace member name with + the filter names. Document syntax change. + +Wed Nov 12 15:45:40 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-engine.c (print_run_body): Add hooks for adding code before + and after an instruction has been issued. + +1997-11-04 Brendan Kehoe <brendan@lisa.cygnus.com> + + * gen-idecode.c (print_jump_until_stop_body): Use `#if 0' instead of + `#ifdef 0' around this. + +Tue Nov 4 08:18:29 1997 Michael Meissner <meissner@cygnus.com> + + * ld-decode.c (load_decode_table): Don't assume NULL is an integer + constant. + +Wed Oct 29 13:17:17 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * ld-insn.h: Document mnemonic string format. + +Tue Oct 28 10:50:35 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-icache.c (print_icache_extraction): Force result of atol to + unsigned. + + * ld-insn.c (parse_function_record): Separate handling of old and + ney fynction records. + (load_insn_table): For %s record, hack function name & type after + it has been parsed. + + * filter.h (filter_is_subset): Reverse argument names, wrong + order. + + * ld-insn.c (load_insn_table): Move include code to. + (parse_include_record): New function. Check for filtering of + include statement by both flags and models. + (load_insn_table): Check for model filtering of cache and model + records. + (parse_model_data_record): Check for model & flag filtering of + model data records. + (parse_function_record): Check for model & flag filtering of + function records. + + * ld-insn.h: Define record_filter_models_field. Add filter-models + field to all but instruction records. + (struct _function_entry, struct _cache_entry): Add models field. + (nr_function_fields): Make parm field mandatory. + +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 + cia.ip. Escape newlines at end of generated call to + sim_engine_abort. + +Tue Oct 14 11:13:27 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c (print_itrace): Output line-ref to igen source file when + generating trace statements. + (print_itrace_prefix, print_itrace_format): Escape newline at end + of each line of generated call to trace function. + +Mon Oct 13 11:27:31 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-support.c (gen_support_h): Generate #define NIA. Definition + dependant on gen-delayed-branch mode. + + * ld-insn.c (parse_insn_mnemonic_record): Check for opening and + closing double quote in mnemonic field. + (parse_option_record): Add gen-delayed-branch option. + +Wed Oct 8 13:10:16 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * gen.c (insn_list_insert): Missing \n in warning. + + * ld-insn.c (load_insn_table): Only notify of discarded + instrctions when warn.discard enabled. + + * igen.h: Add option.warn.discard, default enabled. + + * igen.c (main): Add -Wnodiscard option. + + * ld-insn.c (record_type): For old record type, check the number + of fields is correct. + (load_insn_table): Allow insn assembler and insn model records to + appear in any order. + (parse_insn_model_record): Rename from parse_insn_model_records. + Parse only one record. + (parse_insn_mnemonic_record): Rename from + parse_insn_mnemonic_records. Parse only one record. + +Tue Sep 23 15:52:06 1997 Felix Lee <flee@yin.cygnus.com> + + * gen-itable.c (gen_itable_h): [nr_itable_* + 1] to avoid + illegal zero-sized array. + (itable_print_set): likewise, avoid empty initializers. + +Mon Sep 22 18:49:07 1997 Felix Lee <flee@cygnus.com> + + * configure.in: i386-windows is a cross, so don't expect + libiberty to be there. + * configure: updated. + +Fri Sep 19 10:36:30 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c (print_function_name): Put the format name after the + function / instruction name, not before. + (print_itrace): Better format trace code. + +Tue Sep 16 11:01:07 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * gen.c (insns_bit_useless): Don't treat string fields restricted + to a range of values as useless. + +Mon Sep 15 15:47:21 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c (gen_run_c): Handle non-multi-sim case. + + * gen-support.c (gen_support_h): Define SD_ - to replace _SD. + Define CIA from cia. + +Thu Sep 11 10:27:39 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-semantics.c (print_semantic_body): Trace the instruction + after it has been validated. + (print_semantic_body): Count the instruction using sim-profile. + +Wed Sep 10 13:35:37 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-itable.c (gen_itable_h): Collect summary info on instruction + table when traversing it. + (gen_itable_h): Output an enum defining the max size of each of + the itable string members. + +Tue Sep 9 03:30:26 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c (gen_run_c): New function. Generate sim_engine_run that + looks at the currently selected architecture. + + * gen-engine.c, gen-idecode.c: Add multi-sim support - generate + one engine per model. + + * gen-semantics.c, gen-icache.c gen-support.c: + Update. + + * ld-insn.h, ld-insn-h (load_insn_table): Rewrite. table.h only + returns a line at a time. Parse multi-word instructions. Add + multi-sim support. + + * table.h, table.c: Simplify. Only parse a single line at a time. + ld-insn can handle the rest. + + * filter.h, filter.c (filter_parse, filter_add, filter_is_subset, + filter_is_common, filter_is_member, filter_next): New filter + operations. + (dump_filter): Ditto. + + * gen.h, gen.c: New file. Takes the insn table and turns it into + a set of decode tables and semantic functions. + + * ld-insn.c: Copy generator code from here. + * gen.c: To here. + +Fri Aug 8 11:43:45 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * misc.h (NZALLOC): Allocate an N element array of TYPE. + + * table.h, table.c: Simplify table parser so that it only + understands colon delimited lines and code blocks. + (table_read): Parse '{' ... '}' as a code block. + (table_print_code): New function, print out a code block to file. + (main): Add suport for standalone testing. + + * ld-insn.h, ld-insn.c: + + +Mon Sep 1 11:41:12 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-idecode.c (error_leaf_contains_multiple_insn): Make static. + (print_jump_definition, print_jump, print_jump_internal_function, + print_jump_insn, print_jump_until_stop_body): Delete, moved to + sim-engine.c + + * igen.c (print_itrace_format): Delete unused variable chp. + (gen-engine.h): Include. + + * table.c (current_file_name, current_line_entry, + current_line_entry): Make static. + +Wed Aug 6 12:31:17 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * configure.in: Define AR_FOR_BUILD, AR_FLAGS_FOR_BUILD, + RANLIB_FOR_BUILD and CFLAGS_FOR_BUILD. + * configure.in: Include simulator common/aclocal.m4. + * configure.in: Add --enable-sim-warnings option. + * configure: Re-generate. + + * Makefile.in: Use. + + * Makefile.in (tmp-filter): New rule. + (igen.o, tmp-table, tmp-ld-decode, tmp-ld-cache, tmp-ld-insn, + ld-decode.o, ld-cache.o, ld-insn.o): Fix dependencies. + + * gen.h, gen.c: New files. + + * Makefile.in (gen.o, tmp-gen): New rules, update all + dependencies. + +Tue Jun 24 11:46:45 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * ld-insn.c (load_insn_table): Accept %s as a function type. + +Thu Jun 5 17:14:32 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c (print_itrace_prefix): Move printing of insn prefix to + here. + (print_itrace_format): Drop printing of MY_NAME in instruction + trace. Printing of insn prefix moved. + (print_itrace): Ditto. + +Fri May 30 11:27:37 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-icache.c (print_icache_function_header): Pass + table_line_entry instead of separate file and line. + + * table.c (table_entry_read): Set assembler source file/line-nr to + the current not initial file. + (table_entry_read): Fix line numbering of source files. + + table.h (table_line_entry): New structure. Exactly specifies a + source file/line-nr. + (table_*_entry): Add this to all. + + table.c (table_entry_print_cpp_line_nr): Change to use values from + a table_line_entry struct. + (table_entry_read): Save table_line_entry in all structures read. + + gen-icache.c, gen-support.c, gen-idecode.c, gen-semantics.c, + gen-model.c: Update all references. + +Thu May 29 10:29:57 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c (print_my_defines): Define MY_NAME - a string. For + MY_PREFIX, undefine the name of the function incase some dumb + header defined it. it. + (print_itrace): Use MY_NAME not MY_PREFIX. + + * lf.c (lf_write): New function write an N character buffer to the + file. + + * igen.c (print_itrace): When available, use the assembler to + print the insn-trace. + (print_itrace_prefix): New function, print first part of call to + print_one_insn. + (print_itrace_format): New function, print fmt argument for + print_one_insn. + + * table.c (table_entry_read): Save any assembler lines instead of + discarding them. + +Wed May 28 09:55:29 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-icache.c (print_icache_body): Process immeds. + + * gen-semantics.c (print_semantic_body): When computing NIA, skip + any immed words that follow the instruction word. + + * ld-insn.c (parse_insn_format): Parse immeds appended to an + instruction. + + * igen.c (main): Allow any register to be specified as the zero + register. + (semantic_zero_reg): Global, index to zero register. + + * gen-semantics.c (print_semantic_body): Zero selected register. + +Tue May 27 14:12:32 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.h: Stop options and code gen type bit masks overlaping. + +Fri May 23 12:01:08 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-semantics.c (print_semantic_body): Incorrect test for + zero-r0 code. + +Fri May 16 14:32:31 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-semantics.c (print_semantic_body): Use common sim-engine + interface. + +Fri May 16 11:48:30 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-semantics.c (print_semantic_body): Add code to clear r0. + + * igen.c (main): Add new option zero-r0, which adds code to clear + GPR(0) each cycle. + +Wed May 7 12:31:30 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c (print_itrace): Fix so line-nr is passed to trace + function. + + * gen-idecode.c (print_idecode_validate): Correct FP code. + + * gen-support.c (gen_support_h): Always pass MY_INDEX to support + functions. + (print_support_function_name): Ditto. + +Tue May 6 06:12:04 1997 Mike Meissner <meissner@cygnus.com> + + * igen.c (print_itrace): Call trace_one_insn to trace + instructions, rather than doing it directly. + +Mon May 5 14:11:46 1997 Mike Meissner <meissner@cygnus.com> + + * gen-engine.c (engine_switch_leaf): Remove extra %s. + (print_engine_floating_point_unavailable): Wrap in #ifdef + UNUSED/#endif, until somebody uses it. + + * gen-idecode.c (error_leaf_contains_multiple_insn): Remove unused + variable. + (print_jump_until_stop_body): Wrap in #ifdef UNUSED/#endif, until + somebody uses it. + (print_idecode_validate): Use long formats to print long values. + + * gen-semantics.c (print_idecode_invalid): Set name to "unknown" + if we get an unexpected type. + +Fri May 2 13:28:06 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c (print_itrace): Pass SD as well as CPU to calls to + trace_printf. + + * gen-support.c (gen_support_h): Always pass sim_cia cia to + support functions. + (print_support_function_name): Ditto. + +Wed Apr 30 17:35:51 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * gen-support.c (support_c_function): Remove unnecessary memset of + cia. + * gen-semantics.c (print_semantic_body): Wasn't closing + generated comment. + +Tue Apr 29 11:11:12 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * ld-insn.c (load_insn_table): Report instructions that do not + have at least a format and name. + (insn_table_find_opcode_field): Check progress is being made. + + * gen-support.c (support_c_function): Report empty function body. + +Thu Apr 24 11:43:45 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * ld-insn.c (insn_table_expand_opcode): Allow reserved fields to + be broken up. + (insn_table_expand_insns): Allow special rules to apply to groups + of instructions when all members of the group match the special + mask/value. + + * gen-semantics.c (print_c_semantic): Ditto. + * igen.c (print_semantic_function_formal): Ditto. + (print_semantic_function_type): Ditto. + * igen.c (print_icache_function_formal): Ditto. + * gen-idecode.c (print_idecode_issue_function_body): Ditto. + + * gen-idecode.c (gen_idecode_h): Prepend the global_prefix to the + instruction_address type. + + * gen-semantics.c (print_semantic_body): Call cpu_error when an + unimplemented instruction is encountered - gives the interpreter + the chance to stop correctly. + +Wed Apr 23 20:06:36 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c (print_function_name): Allow dot's in instruction names. + +Tue Apr 22 21:46:28 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * igen.c (main), igen.h: Support new option - delayed-branch - + generate code to drive a delayed branch processor. + + * gen-idecode.c (gen_idecode_h): Define instruction_address type. + + * igen.c (print_icache_function_formal): Replace address_word with + instruction_address. + (print_semantic_function_formal): Ditto. + (print_semantic_function_type): Ditto. + * gen-idecode.c (print_idecode_issue_function_body): Ditto. + + * gen-semantics.c (print_semantic_body): Ditto. + (print_c_semantic): Ditto. + + * gen-support.c (support_c_function): Return a zeroed CIA instead + of just zero - works with any cia type. + + * igen.c (print_itrace): For delayed branch case, print just the + current instruction. + +Thu Apr 17 07:02:33 1997 Doug Evans <dje@canuck.cygnus.com> + + * igen.c (print_itrace): Use TRACE_FOO_P and trace_printf. + +Tue Apr 15 15:20:31 1997 Ian Lance Taylor <ian@cygnus.com> + + * Makefile.in (INSTALL): Set to @INSTALL@. + (INSTALL_XFORM, INSTALL_XFORM1): Remove. + +Mon Apr 14 16:29:34 1997 Ian Lance Taylor <ian@cygnus.com> + + * Makefile.in (INSTALL): Change install.sh to install-sh. + +Wed Apr 2 18:51:20 1997 Doug Evans <dje@canuck.cygnus.com> + + * gen-support.c (gen_support_c): sim-state.h renamed to sim-main.h. + * gen-idecode.c (gen_idecode_c): Likewise. + * igen.c (gen_semantics_c): Likewise. + +Mon Mar 24 10:10:08 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * gen-icache.c (print_icache_body): No longer define cpu/sd, + support.h now defines CPU/SD globally. + + * gen-model.c (gen_model_h): Ditto. + + * gen-idecode.c (print_idecode_issue_function_body): Ditto. + (print_jump): Ditto. + (print_jump_until_stop_body): Ditto. + (print_idecode_validate): Ditto. + + * gen-icache.c (print_icache_body): Ditto. + + * gen-semantics.c (print_semantic_body): Ditto. + + * igen.c (print_semantic_function_formal): Rename cpu to sim_cpu, + processor to cpu. + (print_icache_function_formal): Ditto. + + * gen-support.c (print_support_function_name): Include sd/cpu arg + in support function argument list. + (support_c_function): Generate code to cpu/sd from sd/cpu. + (gen_support_h): Define _SD the argument prefix for all support + functions. Define SD/CPU to determine sd/cpu from value of _SD + macro. + +Tue Mar 18 15:52:24 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * gen-support.c (gen_support_c): Update for renaming of engine to + sim-state. + + * igen.c: Ditto. + * gen-idecode.c (gen_idecode_c): Ditto. + +Mon Mar 17 15:17:07 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * ld-decode.c (load_decode_table): Rename slash to reserved. + (dump_decode_rule): Ditto. + + * ld-insn.c (parse_insn_format): Differentiate between a `/' - + reserved bit - and a `*' - wild card. + (parse_insn_format): Change is_slash to more informative reserved. + (dump_insn_field): Ditto. + (insn_field_is_constant): Ditto. + (insn_table_expand_opcode): Ditto. + + * gen-idecode.c (print_idecode_validate): Make check_mask and + check_val the correct integer size. + (print_idecode_validate): Fix reserved bit check for 64 bit + targets. + +Fri Mar 14 11:24:06 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * ld-insn.c (parse_insn_format): Accept '*' as an alternative of + `/' in bit fields. `/' denotes a wild bit. + +Fri Mar 7 18:20:38 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * igen.h, igen.c (main): New options. Control generation of + conditional issue and slot verification code. + +Fri Mar 7 18:17:25 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * gen-support.c (print_support_function_name): Prepend the global + name prefix when applicable. Provide #define to map the user + specified name the generated globaly unique one. + +Fri Mar 7 18:07:45 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * gen-idecode.c (print_idecode_validate): Wrap each of the checks + - reserved bits, floating point and slot validation - with a + #ifdef so that they are optional. + +Fri Mar 7 16:35:13 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * gen-idecode.c (error_leaf_contains_multiple_insn): New function + - report the error of a leaf node in the decision tree containing + several instructions. + (print_idecode_table_leaf): Detect a leaf with multiple instructions. + (print_idecode_switch_leaf): Ditto. + + * gen-semantics.h, gen-semantics.c (print_idecode_illegal, + print_idecode_invalid): Rename former to latter. Add argument so + that one function can generate all invalid instruction cases - + illegal, fp-unavailable, wrong-slot. + * gen-engine.c: Update. + + * gen-idecode.c: Use print_idecode_invalid to generate a function + call for cases when fp-unavailable and the slot is wrong. + + * gen-idecode.c (print_idecode_validate): New check, generate code + to verify that the instruction slot is correct. + + * igen.c (main): Simplify options. + +Wed Mar 5 09:55:55 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * igen.c (print_itrace): Remove source line reference for trace + code - let the user see the generated file. + (print_itrace): Print the trace code rather than reference a + macro. + +Tue Mar 4 17:31:55 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * igen.c (print_semantic_function_actual): Pass either the + processor - smp - or the engine - mono - into semantic functions. + Don't pass in both. + + * gen-icache.c (print_icache_body): Dependant on smp, derive + processor from engine or engine from processor, and hence ensuring + that both are defined in all semantic functions. + +Mon Mar 3 17:11:21 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * ld-insn.c (parse_insn_format): Make the width field optional. + If missing assume that the number of characters in the value + determines the number of bits in the field. + +Thu Feb 27 11:27:48 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * ld-insn.c (insn_table_expand_opcode): Replace assertion with + more useful error message. + +Tue Feb 25 16:43:27 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * misc.c (error): Output errors on stderr. + + * ld-insn.c (parse_insn_format): Skip any leading spaces. + Verify the width of instructions being parsed. + + * table.c (table_entry_read): Parse CPP's convention for + specifying original file name/line-nr. + +Wed Feb 19 12:30:28 1997 Andrew Cagney <cagney@critters.cygnus.com> + + * ld-insn.c (parse_insn_format): Allow trailing spaces in + instruction fields. + + * Makefile.in: Create using ../ppc/Makefile.in as a starting + point. + * configure.in: Ditto vis ../ppc/configure.in + +Mon Feb 17 10:44:18 1997 Andrew Cagney <cagney@critters.cygnus.com> + + * gen-support.c (gen_support_c): Always include engine.h instead + of cpu.h + * gen-idecode.c (gen_idecode_c): Ditto. + + * words.h (instruction_word): Remove instruction_word - now + generated by igen. + (address_word): New. Used by igen. + + * lf.c (lf_print_function_type_function): New, pass a function to + print out the type instead of a constant string. + + * igen.h, igen.c (print_semantic_function_formal, + SEMANTIC_FUNCTION_FORMAL): Relace macro with function. + (print_semantic_function_actual, SEMANTIC_FUNCTION_ACTUAL): Ditto. + (print_semantic_function_type, SEMANTIC_FUNCTION_TYPE): Ditto. + (print_icache_function_type, ICACHE_FUNCTION_TYPE): Ditto. + (print_icache_function_formal, ICACHE_FUNCTION_FORMAL): Ditto. + (print_icache_function_actual, ICACHE_FUNCTION_ACTUAL): Ditto. + * gen-idecode.c (print_idecode_table): Update. + (idecode_switch_leaf): Update. + (print_idecode_switch_function_header): Ditto. + (print_idecode_floating_point_unavailable): Ditto. + (print_idecode_issue_function_header): Ditto. + * igen.c (gen_icache_h): Ditto. + * gen-engine.c (print_engine_table): Ditto. + (engine_switch_leaf): Ditto. + * gen-support.c (print_support_function_name): Ditto. + * gen-semantics.c (print_semantic_function_header): Update. + Update. + * gen-icache.c (print_icache_function_header): Update. + (print_icache_function): Update. + (print_icache_internal_function_declaration): Update. + (print_icache_internal_function_definition): Update. + + * gen-idecode.c (gen_idecode_h): Drop including of idecode_*.h + files, will at some stage need to move it into support. + + * igen.h, igen.c (main): New option -e <engine> - generate a full + simulation engine. Previously this was the -d <idecode-file> + option. + * gen-engine.h, gen-engine.c: Copies of gen-idecode.*. Will need + to clean these up so that that call upon the updated gen-idecode + code. + + * gen-idecode.h, gen-idecode.c: Prune out any code not relevant to + generating a decode table. + + * Makefile.in (igen): Add dependencies for new gen-engine.* files. + + * igen.h, igen.c (main): New option -M - Control what is returned + by semantic functions - -1/NIA vs CIA+N/NIA. Add + generate_semantic_returning_modified_nia_only to igen_code enum. + * gen-semantics.c (print_semantic_body): As an alternative, make + NIA == -1 instead of CIA+insn_size by default. + + * igen.h, igen.c (main, global_name_prefix, global_uname_prefix): + New option -P <prefix> - Prepend all generated functions with the + specified prefix. + (gen_idecode_c): Adjust. + * gen-icache.c (print_icache_struct): Ditto. + * gen-support.c (gen_support_c): Ditto. + +Sun Feb 16 15:23:15 1997 Andrew Cagney <cagney@critters.cygnus.com> + + * igen.c (main): Correct usage. Missleading message about ucase + options dumping internal tables. -F now includes rather then + excludes instructions. + + * misc.h, misc.c (a2i): Make 64bit. + + * ld-insn.h (max_insn_bit_size, default_insn_bit_size): Increase + max to 64bits, expect trouble. Make the default 32 bits. + * gen-idecode.c (print_idecode_table): Change EXTRACTED* + et.al. macro's to use the insn_bit_size instead of assuming 32 + bits. + * gen-icache.c (print_icache_extraction): Ditto. + * gen-idecode.c (idecode_switch_start): Ditto. + * gen-idecode.c (gen_idecode_c): Ditto + + * igen.h (insn_specifying_widths), igen.c (main): New option -W. + Indicates that the instruction field of the table is specifying + bit widths instead of bit offsets. + * ld-insn.c (parse_insn_format): Parse instruction fields + specifying widths. + + * misc.c (a2i): Allow binary numbers to be specified using the + syntax 0bNNNN. + * ld-insn.c: Allow such numbers to appear in the instruction + format. + + * table.c (table_entry_read): Make // a valid comment character. + (table_entry_read): Skip lines containing a leading " - these may + eventually be used in a disasembler. + +Fri Feb 14 15:23:15 1997 Andrew Cagney <cagney@critters.cygnus.com> + + * filter.c, filter.h, gen-engine.c, gen-engine.h, gen-icache.c, + gen-icache.h, gen-idecode.c, gen-idecode.h, gen-itable.c, + gen-itable.h, gen-model.c, gen-model.h, gen-semantics.c, + gen-semantics.h, gen-support.c, gen-support.h, igen.c, igen.h, + ld-cache.c, ld-cache.h, ld-decode.c, ld-decode.h, ld-insn.c, + ld-insn.h, lf.c, lf.h, misc.c, misc.h, table.c, table.h: Copy in + from the ../ppc directory. + + * filter_host.c, filter_host.h: Copy in from the ../ppc directory + renaming from filter_filename.[hc] diff --git a/sim/igen/Makefile.in b/sim/igen/Makefile.in new file mode 100644 index 00000000000..0a1d25af8da --- /dev/null +++ b/sim/igen/Makefile.in @@ -0,0 +1,177 @@ +# +# This file is part of the program psim. +# +# Copyright (C) 1994-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. +# + +default: all + +VPATH = @srcdir@ +srcdir = @srcdir@ +srcroot = $(srcdir)/../.. + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +host_alias = @host_alias@ +target_alias = @target_alias@ +program_transform_name = @program_transform_name@ +bindir = @bindir@ +libdir = @libdir@ +tooldir = $(libdir)/$(target_alias) + +datadir = @datadir@ +mandir = @mandir@ +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = @infodir@ +includedir = @includedir@ + +SHELL = @SHELL@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +AR = @AR@ +CC = @CC@ +CFLAGS = @CFLAGS@ +RANLIB = @RANLIB@ + +AR_FOR_BUILD = @AR_FOR_BUILD@ +AR_FLAGS_FOR_BUILD = @AR_FLAGS_FOR_BUILD@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +RANLIB_FOR_BUILD = @RANLIB_FOR_BUILD@ + +SIM_WARNINGS = @build_warnings@ + +BISON = bison +MAKEINFO = makeinfo + +.NOEXPORT: +MAKEOVERRIDES= + +LIB_INCLUDES = -I$(srcdir)/../../include +INCLUDES = -I. -I$(srcdir) $(LIB_INCLUDES) + +LIBIBERTY_LIB = @LIBIBERTY_LIB@ + +BUILD_CFLAGS = $(CFLAGS_FOR_BUILD) $(SIM_WARNINGS) $(INCLUDES) -O0 +BUILD_LDFLAGS = + +all: igen +#all: tmp-filter tmp-table tmp-ld-insn tmp-ld-cache tmp-ld-decode tmp-gen + +.c.o: + $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $< + + +filter_filename.o: filter_filename.c filter_filename.h config.h ppc-config.h + +IGEN_OBJS=\ + table.o \ + lf.o misc.o \ + filter_host.o \ + ld-decode.o \ + ld-cache.o \ + filter.o \ + ld-insn.o \ + gen-model.o \ + gen-itable.o \ + gen-icache.o \ + gen-semantics.o \ + gen-idecode.o \ + gen-support.o \ + gen-engine.o \ + gen.o + +igen: igen.o $(IGEN_OBJS) + $(CC_FOR_BUILD) $(BUILD_LDFLAGS) -o igen igen.o $(IGEN_OBJS) $(LIBIBERTY_LIB) + +igen.o: igen.c misc.h filter_host.h lf.h table.h ld-decode.h ld-cache.h ld-insn.h filter.h gen-model.h gen-itable.h gen-icache.h gen-idecode.h gen-engine.h gen-semantics.h gen-support.h gen.h igen.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/igen.c + +tmp-table: table.c table.h misc.o lf.o filter_host.o + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-table -DMAIN $(srcdir)/table.c misc.o lf.o filter_host.o $(BUILD_LIBS) + +tmp-filter: filter.c filter.h lf.o misc.o filter_host.o + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-filter -DMAIN $(srcdir)/filter.c lf.o misc.o filter_host.o $(BUILD_LIBS) + +tmp-ld-decode: ld-decode.h ld-decode.c filter.o misc.o lf.o table.o filter_host.o gen.h igen.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-ld-decode -DMAIN $(srcdir)/ld-decode.c filter.o misc.o lf.o table.o filter_host.o $(BUILD_LIBS) + +tmp-ld-cache: ld-cache.c ld-cache.h ld-insn.o misc.o lf.o table.o filter_host.o gen.h igen.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-ld-cache -DMAIN $(srcdir)/ld-cache.c ld-insn.o filter.o misc.o lf.o table.o filter_host.o $(BUILD_LIBS) + +tmp-ld-insn: ld-insn.c ld-insn.h misc.o lf.o table.o filter_host.o filter.o gen.h igen.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-ld-insn -DMAIN $(srcdir)/ld-insn.c misc.o lf.o table.o filter_host.o filter.o $(BUILD_LIBS) + +tmp-gen: gen.c gen.h ld-insn.o ld-decode.o misc.o lf.o table.o filter_host.o filter.o gen.h igen.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-gen -DMAIN $(srcdir)/gen.c misc.o ld-insn.o ld-decode.o lf.o table.o filter_host.o filter.o $(BUILD_LIBS) + +filter_host.o: filter_host.c filter_host.h +table.o: table.c misc.h filter_host.h lf.h table.h +lf.o: lf.c misc.h filter_host.h lf.h +filter.o: filter.c misc.h lf.h table.h filter.h +ld-decode.o: ld-decode.c misc.h lf.h table.h ld-decode.h igen.h +ld-cache.o: ld-cache.c misc.h lf.h table.h ld-cache.h igen.h +ld-insn.o: ld-insn.c misc.h lf.h table.h ld-insn.h gen.h igen.h +gen-model.o: gen-model.c misc.h lf.h table.h gen-model.h ld-decode.h gen.h igen.h ld-insn.h +gen-itable.o: gen-itable.c misc.h lf.h table.h gen-itable.h ld-decode.h gen.h igen.h ld-insn.h gen.h filter.h +gen-icache.o: gen-icache.c misc.h lf.h table.h gen-icache.h ld-decode.h gen.h igen.h ld-insn.h gen-semantics.h gen-idecode.h filter.h +gen-semantics.o: gen-semantics.c misc.h lf.h table.h gen-semantics.h ld-decode.h gen.h igen.h ld-insn.h filter.h +gen-idecode.o: gen-idecode.c misc.h lf.h table.h gen-idecode.h gen-icache.h gen-semantics.h ld-decode.h gen.h igen.h ld-insn.h filter.h +gen-engine.o: gen-engine.c misc.h lf.h table.h gen-idecode.h gen-engine.h gen-icache.h gen-semantics.h ld-decode.h gen.h igen.h ld-insn.h filter.h +gen-support.o: gen-support.c misc.h lf.h table.h gen-support.h ld-decode.h gen.h igen.h ld-insn.h filter.h +gen.o: gen.c misc.h lf.h table.h gen-icache.h ld-decode.h gen.h igen.h ld-insn.h gen-semantics.h gen-idecode.h filter.h +misc.o: misc.c misc.h filter_host.h + + +tags etags: TAGS + +TAGS: + etags $(srcdir)/*.h $(srcdir)/*.c + +clean mostlyclean: + rm -f tmp-* *.[oasi] core igen + +distclean realclean: clean + rm -f TAGS Makefile config.cache config.status config.h defines.h stamp-h config.log + +maintainer-clean: distclean + rm -f *~ *.log ppc-config.h core *.core + +Makefile: Makefile.in config.status + CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) ./config.status + +config.h: stamp-h ; @true +stamp-h: config.in config.status + CONFIG_FILES= CONFIG_HEADERS=config.h:config.in $(SHELL) ./config.status + +config.status: configure + $(SHELL) ./config.status --recheck + +install: +# diff --git a/sim/igen/acconfig.h b/sim/igen/acconfig.h new file mode 100644 index 00000000000..f9b87a10c60 --- /dev/null +++ b/sim/igen/acconfig.h @@ -0,0 +1,15 @@ + +/* Define to 1 if NLS is requested. */ +#undef ENABLE_NLS + +/* Define as 1 if you have catgets and don't want to use GNU gettext. */ +#undef HAVE_CATGETS + +/* Define as 1 if you have gettext and don't want to use GNU gettext. */ +#undef HAVE_GETTEXT + +/* Define as 1 if you have the stpcpy function. */ +#undef HAVE_STPCPY + +/* Define if your locale.h file contains LC_MESSAGES. */ +#undef HAVE_LC_MESSAGES diff --git a/sim/igen/config.in b/sim/igen/config.in new file mode 100644 index 00000000000..4fcf519489a --- /dev/null +++ b/sim/igen/config.in @@ -0,0 +1,31 @@ +/* config.in. Generated automatically from configure.in by autoheader. */ + +/* Define if you have the <dirent.h> header file. */ +#undef HAVE_DIRENT_H + +/* Define if you have the <ndir.h> header file. */ +#undef HAVE_NDIR_H + +/* Define if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the <sys/dir.h> header file. */ +#undef HAVE_SYS_DIR_H + +/* Define if you have the <sys/ndir.h> header file. */ +#undef HAVE_SYS_NDIR_H + +/* Define if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H diff --git a/sim/igen/configure b/sim/igen/configure new file mode 100755 index 00000000000..2d4f4ec90fc --- /dev/null +++ b/sim/igen/configure @@ -0,0 +1,1806 @@ +#! /bin/sh + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +sim_inline="-DDEFAULT_INLINE=0" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# This file is derived from `gettext.m4'. The difference is that the +# included macros assume Cygnus-style source and build trees. + +# Macro to add for using GNU gettext. +# Ulrich Drepper <drepper@cygnus.com>, 1995. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 3 + + + + + +# Search path for a program which passes the given test. +# Ulrich Drepper <drepper@cygnus.com>, 1996. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 1 + + + +# Check whether LC_MESSAGES is available in <locale.h>. +# Ulrich Drepper <drepper@cygnus.com>, 1995. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 1 + + + +# Check to see if we're running under Cygwin32, without using +# AC_CANONICAL_*. If so, set output variable CYGWIN32 to "yes". +# Otherwise set it to "no". + + + +# Check to see if we're running under Win32, without using +# AC_CANONICAL_*. If so, set output variable EXEEXT to ".exe". +# Otherwise set it to "". + + + + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.12.2 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --enable-build-warnings[=LIST] Enable build-time compiler warnings" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.12.2" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=table.h + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:691: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:744: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:773: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:823: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:854: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext <<EOF +#line 864 "configure" +#include "confdefs.h" +main(){return(0);} +EOF +if { (eval echo configure:868: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:888: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:893: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:902: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:921: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + + + +# Check whether --enable-build-warnings or --disable-build-warnings was given. +if test "${enable_build_warnings+set}" = set; then + enableval="$enable_build_warnings" + build_warnings="-Wall -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations" +case "${enableval}" in + yes) ;; + no) build_warnings="-w";; + ,*) t=`echo "${enableval}" | sed -e "s/,/ /g"` + build_warnings="${build_warnings} ${t}";; + *,) t=`echo "${enableval}" | sed -e "s/,/ /g"` + build_warnings="${t} ${build_warnings}";; + *) build_warnings=`echo "${enableval}" | sed -e "s/,/ /g"`;; +esac +if test x"$silent" != x"yes" && test x"$build_warnings" != x""; then + echo "Setting warning flags = $build_warnings" 6>&1 +fi +else + build_warnings="" +fi + + +# Put a plausible default for CC_FOR_BUILD in Makefile. +if test "x$cross_compiling" = "xno" -a "x$host" != "xi386-windows"; then + AR_FOR_BUILD='$(AR)' + AR_FLAGS_FOR_BUILD='$(AR_FLAGS)' + CC_FOR_BUILD='$(CC)' + CFLAGS_FOR_BUILD='$(CFLAGS)' + RANLIB_FOR_BUILD='$(RANLIB)' + LIBIBERTY_LIB=../../libiberty/libiberty.a +else + AR_FOR_BUILD=${AR_FOR_BUILD-ar} + AR_FLAGS_FOR_BUILD=${AR_FLAGS_FOR_BUILD-rc} + CC_FOR_BUILD=${CC_FOR_BUILD-gcc} + CFLAGS_FOR_BUILD=${CFLAGS_FOR_BUILD-"-g"} + RANLIB_FOR_BUILD=${RANLIB_FOR_BUILD-ranlib} + LIBIBERTY_LIB= +fi + + +ac_aux_dir= +for ac_dir in `cd $srcdir;pwd`/../.. $srcdir/`cd $srcdir;pwd`/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in `cd $srcdir;pwd`/../.. $srcdir/`cd $srcdir;pwd`/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:1040: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 +echo "configure:1061: checking target system type" >&5 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 +echo "configure:1079: checking build system type" >&5 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + + +. ${srcdir}/../../bfd/configure.host + + + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1126: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext <<EOF +#line 1141 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1147: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext <<EOF +#line 1158 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1164: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext <<EOF +#line 1175 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1181: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +for ac_hdr in stdlib.h string.h strings.h sys/stat.h sys/types.h unistd.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1209: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1214 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1219: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 +echo "configure:1250: checking for $ac_hdr that defines DIR" >&5 +if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1255 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <$ac_hdr> +int main() { +DIR *dirp = 0; +; return 0; } +EOF +if { (eval echo configure:1263: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + ac_header_dirent=$ac_hdr; break +else + echo "$ac_t""no" 1>&6 +fi +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then +echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 +echo "configure:1288: checking for opendir in -ldir" >&5 +ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldir $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1296 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir(); + +int main() { +opendir() +; return 0; } +EOF +if { (eval echo configure:1307: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -ldir" +else + echo "$ac_t""no" 1>&6 +fi + +else +echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 +echo "configure:1329: checking for opendir in -lx" >&5 +ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lx $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1337 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir(); + +int main() { +opendir() +; return 0; } +EOF +if { (eval echo configure:1348: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -lx" +else + echo "$ac_t""no" 1>&6 +fi + +fi + + + + + + + + + + + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1383: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set) 2>&1 | grep ac_space` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS <<EOF +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.12.2" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile config.h:config.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS <<EOF + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@sim_environment@%$sim_environment%g +s%@sim_alignment@%$sim_alignment%g +s%@sim_assert@%$sim_assert%g +s%@sim_bitsize@%$sim_bitsize%g +s%@sim_endian@%$sim_endian%g +s%@sim_hostendian@%$sim_hostendian%g +s%@sim_float@%$sim_float%g +s%@sim_scache@%$sim_scache%g +s%@sim_default_model@%$sim_default_model%g +s%@sim_hw_cflags@%$sim_hw_cflags%g +s%@sim_hw_objs@%$sim_hw_objs%g +s%@sim_hw@%$sim_hw%g +s%@sim_inline@%$sim_inline%g +s%@sim_packages@%$sim_packages%g +s%@sim_regparm@%$sim_regparm%g +s%@sim_reserved_bits@%$sim_reserved_bits%g +s%@sim_smp@%$sim_smp%g +s%@sim_stdcall@%$sim_stdcall%g +s%@sim_xor_endian@%$sim_xor_endian%g +s%@build_warnings@%$build_warnings%g +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@CC@%$CC%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@CPP@%$CPP%g +s%@AR_FOR_BUILD@%$AR_FOR_BUILD%g +s%@AR_FLAGS_FOR_BUILD@%$AR_FLAGS_FOR_BUILD%g +s%@CC_FOR_BUILD@%$CC_FOR_BUILD%g +s%@CFLAGS_FOR_BUILD@%$CFLAGS_FOR_BUILD%g +s%@RANLIB_FOR_BUILD@%$RANLIB_FOR_BUILD%g +s%@LIBIBERTY_LIB@%$LIBIBERTY_LIB%g +s%@AR@%$AR%g +s%@RANLIB@%$RANLIB%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <<EOF + +CONFIG_FILES=\${CONFIG_FILES-"Makefile"} +EOF +cat >> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <<EOF + CONFIG_HEADERS="config.h:config.in" +EOF +cat >> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <<EOF + +EOF +cat >> $CONFIG_STATUS <<\EOF +case x$CONFIG_HEADERS in xconfig.h:config.in) echo > stamp-h ;; esac +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/sim/igen/configure.in b/sim/igen/configure.in new file mode 100644 index 00000000000..20836d9dec6 --- /dev/null +++ b/sim/igen/configure.in @@ -0,0 +1,52 @@ +dnl Process this file with autoconf to produce a configure script. +sinclude(../common/aclocal.m4) +AC_PREREQ(2.5)dnl +AC_INIT(table.h) + +AC_PROG_INSTALL +AC_PROG_CC + +SIM_AC_OPTION_WARNINGS + +# Put a plausible default for CC_FOR_BUILD in Makefile. +if test "x$cross_compiling" = "xno" -a "x$host" != "xi386-windows"; then + AR_FOR_BUILD='$(AR)' + AR_FLAGS_FOR_BUILD='$(AR_FLAGS)' + CC_FOR_BUILD='$(CC)' + CFLAGS_FOR_BUILD='$(CFLAGS)' + RANLIB_FOR_BUILD='$(RANLIB)' + LIBIBERTY_LIB=../../libiberty/libiberty.a +else + AR_FOR_BUILD=${AR_FOR_BUILD-ar} + AR_FLAGS_FOR_BUILD=${AR_FLAGS_FOR_BUILD-rc} + CC_FOR_BUILD=${CC_FOR_BUILD-gcc} + CFLAGS_FOR_BUILD=${CFLAGS_FOR_BUILD-"-g"} + RANLIB_FOR_BUILD=${RANLIB_FOR_BUILD-ranlib} + LIBIBERTY_LIB= +fi + + +AC_CONFIG_AUX_DIR(`cd $srcdir;pwd`/../..) +AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM + +. ${srcdir}/../../bfd/configure.host + +AC_CONFIG_HEADER(config.h:config.in) + +AC_CHECK_HEADERS(stdlib.h string.h strings.h sys/stat.h sys/types.h unistd.h) +AC_HEADER_DIRENT + +AC_SUBST(AR_FOR_BUILD) +AC_SUBST(AR_FLAGS_FOR_BUILD) +AC_SUBST(CC_FOR_BUILD) +AC_SUBST(CFLAGS_FOR_BUILD) +AC_SUBST(RANLIB_FOR_BUILD) +AC_SUBST(LIBIBERTY_LIB) + +AC_SUBST(AR) +AC_SUBST(CFLAGS) +AC_PROG_RANLIB + +AC_OUTPUT(Makefile, +[case x$CONFIG_HEADERS in xconfig.h:config.in) echo > stamp-h ;; esac]) diff --git a/sim/igen/filter.c b/sim/igen/filter.c new file mode 100644 index 00000000000..afc51889724 --- /dev/null +++ b/sim/igen/filter.c @@ -0,0 +1,355 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, 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 "config.h" + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#include "misc.h" +#include "lf.h" +#include "filter.h" + +struct _filter { + char *member; + filter *next; +}; + + +void +filter_parse (filter **filters, + const char *filt) +{ + while (strlen (filt) > 0) + { + filter *new_filter; + filter **last; + /* break out a member of the filter list */ + const char *flag = filt; + unsigned /*size_t*/ len; + filt = strchr (filt, ','); + if (filt == NULL) + { + filt = strchr (flag, '\0'); + len = strlen (flag); + } + else + { + len = filt - flag; + filt = filt + 1; + } + /* find an insertion point - sorted order */ + last = filters; + while (*last != NULL + && strncmp (flag, (*last)->member, len) > 0) + last = &(*last)->next; + if (*last != NULL + && strncmp (flag, (*last)->member, len) == 0 + && strlen ((*last)->member) == len) + continue; /* duplicate */ + /* create an entry for that member */ + new_filter = ZALLOC (filter); + new_filter->member = NZALLOC (char, len + 1); + strncpy (new_filter->member, flag, len); + /* insert it */ + new_filter->next = *last; + *last = new_filter; + } +} + + +void +filter_add (filter **set, + filter *add) +{ + while (add != NULL) + { + int cmp; + if (*set == NULL) + cmp = 1; /* set->member > add->member */ + else + cmp = strcmp ((*set)->member, add->member); + if (cmp > 0) + { + /* insert it here */ + filter *new = ZALLOC (filter); + new->member = NZALLOC (char, strlen (add->member) + 1); + strcpy (new->member, add->member); + new->next = *set; + *set = new; + add = add->next; + } + else if (cmp == 0) + { + /* already in set */ + add = add->next; + } + else /* cmp < 0 */ + { + /* not reached insertion point */ + set = &(*set)->next; + } + } +} + + +int +filter_is_subset (filter *superset, + filter *subset) +{ + while (1) + { + int cmp; + if (subset == NULL) + return 1; + if (superset == NULL) + return 0; /* subset isn't finished */ + cmp = strcmp (subset->member, superset->member); + if (cmp < 0) + return 0; /* not found */ + else if (cmp == 0) + subset = subset->next; /* found */ + else if (cmp > 0) + superset = superset->next; /* later in list? */ + } +} + + +int +filter_is_common (filter *l, + filter *r) +{ + while (1) + { + int cmp; + if (l == NULL) + return 0; + if (r == NULL) + return 0; + cmp = strcmp (l->member, r->member); + if (cmp < 0) + l = l->next; + else if (cmp == 0) + return 1; /* common member */ + else if (cmp > 0) + r = r->next; + } +} + + +int +filter_is_member (filter *filt, + const char *flag) +{ + int index = 1; + while (filt != NULL) + { + if (strcmp (flag, filt->member) == 0) + return index; + filt = filt->next; + index++; + } + return 0; +} + + +int +is_filtered_out (filter *filters, + const char *flags) +{ + while (strlen(flags) > 0) { + int present; + filter *filt = filters; + /* break the string up */ + char *end = strchr(flags, ','); + char *next; + unsigned /*size_t*/ len; + if (end == NULL) { + end = strchr(flags, '\0'); + next = end; + } + else { + next = end + 1; + } + len = end - flags; + /* check that it is present */ + present = 0; + filt = filters; + while (filt != NULL) { + if (strncmp(flags, filt->member, len) == 0 + && strlen(filt->member) == len) { + present = 1; + break; + } + filt = filt->next; + } + if (!present) + return 1; + flags = next; + } + return 0; +} + + +#if 0 +int +it_is (const char *flag, + const char *flags) +{ + int flag_len = strlen(flag); + while (*flags != '\0') { + if (!strncmp(flags, flag, flag_len) + && (flags[flag_len] == ',' || flags[flag_len] == '\0')) + return 1; + while (*flags != ',') { + if (*flags == '\0') + return 0; + flags++; + } + flags++; + } + return 0; +} +#endif + + +char * +filter_next (filter *set, + char *member) +{ + while (set != NULL) + { + if (strcmp (set->member, member) > 0) + return set->member; + set = set->next; + } + return NULL; +} + + +void +dump_filter (lf *file, + char *prefix, + filter *set, + char *suffix) +{ + char *member; + lf_printf (file, "%s", prefix); + member = filter_next (set, ""); + if (member != NULL) + { + while (1) + { + lf_printf (file, "%s", member); + member = filter_next (set, member); + if (member == NULL) + break; + lf_printf (file, ","); + } + } + lf_printf (file, "%s", suffix); +} + + +#ifdef MAIN +int +main(int argc, char **argv) +{ + filter *subset = NULL; + filter *superset = NULL; + lf *l; + int i; + if (argc < 2) { + printf("Usage: filter <subset> <filter> ...\n"); + exit (1); + } + + /* load the filter up */ + filter_parse (&subset, argv[1]); + for (i = 2; i < argc; i++) + filter_parse (&superset, argv[i]); + + /* dump various info */ + l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-filter"); +#if 0 + if (is_filtered_out (argv[1], superset)) + lf_printf (l, "excluded\n"); + else + lf_printf (l, "included\n"); +#endif + /* subset */ + { + dump_filter (l, "{", subset, " }"); + if (filter_is_subset (superset, subset)) + lf_printf (l, " subset of "); + else + lf_printf (l, " !subset of "); + dump_filter (l, "{", superset, " }"); + lf_printf (l, "\n"); + } + /* intersection */ + { + dump_filter (l, "{", subset, " }"); + if (filter_is_common (subset, superset)) + lf_printf (l, " intersects "); + else + lf_printf (l, " !intersects "); + dump_filter (l, "{", superset, " }"); + lf_printf (l, "\n"); + } + /* membership */ + { + filter *memb = subset; + while (memb != NULL) + { + lf_printf (l, "%s", memb->member); + if (filter_is_member (superset, memb->member)) + lf_printf (l, " in "); + else + lf_printf (l, " !in "); + dump_filter (l, "{", superset, " }"); + lf_printf (l, "\n"); + memb = memb->next; + } + } + /* addition */ + { + filter *add = NULL; + filter_add (&add, superset); + filter_add (&add, subset); + dump_filter (l, "{", add, " }"); + lf_printf (l, " = "); + dump_filter (l, "{", subset, " }"); + lf_printf (l, " + "); + dump_filter (l, "{", superset, " }"); + lf_printf (l, "\n"); + } + + return 0; +} +#endif diff --git a/sim/igen/filter.h b/sim/igen/filter.h new file mode 100644 index 00000000000..c85b8039bc9 --- /dev/null +++ b/sim/igen/filter.h @@ -0,0 +1,86 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, 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. + + */ + + +/* NB, an empty filter is NULL */ +typedef struct _filter filter; + + +/* parse the list merging any flags into the filter */ + +extern void filter_parse +(filter **filters, + const char *filt); + + +/* add the second filter to the first */ + +extern void filter_add +(filter **filters, + filter *add); + + + +/* returns true if SUB is a strict subset of SUPER. For an empty set + is a member of any set */ + +extern int filter_is_subset +(filter *superset, + filter *subset); + + +/* return true if there is at least one member common to the two + filters */ + +extern int filter_is_common +(filter *l, + filter *r); + + +/* returns the index (pos + 1) if the name is in the filter. */ + +extern int filter_is_member +(filter *set, + const char *flag); + + +/* returns true if one of the flags is not present in the filter. + === !filter_is_subset (filter_parse (NULL, flags), filters) */ +int is_filtered_out +(filter *filters, + const char *flags); + + +/* returns the next member of the filter set that follows MEMBER. + Member does not need to be an elememt of the filter set. Next of + "" is the first non-empty member */ +char *filter_next +(filter *set, + char *member); + + + +/* for debugging */ + +extern void dump_filter +(lf *file, + char *prefix, + filter *filt, + char *suffix); diff --git a/sim/igen/filter_host.c b/sim/igen/filter_host.c new file mode 100644 index 00000000000..de8c93fe439 --- /dev/null +++ b/sim/igen/filter_host.c @@ -0,0 +1,37 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, 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 "config.h" +#include "filter_host.h" + +/* Shorten traces by eliminating the directory component to filenames. */ +const char * +filter_filename (const char *filename) +{ + const char *p = filename; + const char *last = filename; + int ch; + + while ((ch = *p++) != '\0' && ch != ':') + if (ch == '/') + last = p; + + return last; +} diff --git a/sim/igen/filter_host.h b/sim/igen/filter_host.h new file mode 100644 index 00000000000..fdfa6bc03e1 --- /dev/null +++ b/sim/igen/filter_host.h @@ -0,0 +1,27 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-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. + + */ + +#ifndef _FILTER_HOST_H +#define _FILTER_HOST_H + +/* Remove directory part from filename */ +extern const char * +filter_filename(const char *filename); +#endif diff --git a/sim/igen/gen-engine.c b/sim/igen/gen-engine.c new file mode 100644 index 00000000000..4b6861ed97e --- /dev/null +++ b/sim/igen/gen-engine.c @@ -0,0 +1,807 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, 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 "misc.h" +#include "lf.h" +#include "table.h" +#include "filter.h" + +#include "igen.h" + +#include "ld-insn.h" +#include "ld-decode.h" + +#include "gen.h" + +#include "gen-idecode.h" +#include "gen-engine.h" +#include "gen-icache.h" +#include "gen-semantics.h" + + +static void +print_engine_issue_prefix_hook (lf *file) +{ + lf_printf (file, "\n"); + lf_indent_suppress (file); + lf_printf (file, "#if defined (%sENGINE_ISSUE_PREFIX_HOOK)\n", + options.module.global.prefix.l); + lf_printf (file, "%sENGINE_ISSUE_PREFIX_HOOK();\n", + options.module.global.prefix.l); + lf_indent_suppress (file); + lf_printf (file, "#endif\n"); + lf_printf (file, "\n"); +} + +static void +print_engine_issue_postfix_hook (lf *file) +{ + lf_printf (file, "\n"); + lf_indent_suppress (file); + lf_printf (file, "#if defined (%sENGINE_ISSUE_POSTFIX_HOOK)\n", + options.module.global.prefix.l); + lf_printf (file, "%sENGINE_ISSUE_POSTFIX_HOOK();\n", + options.module.global.prefix.l); + lf_indent_suppress (file); + lf_printf (file, "#endif\n"); + lf_printf (file, "\n"); +} + + +static void +print_run_body (lf *file, + gen_entry *table) +{ + /* Output the function to execute real code: + + Unfortunatly, there are multiple cases to consider vis: + + <icache> X <smp> + + Consequently this function is written in multiple different ways */ + + lf_printf (file, "{\n"); + lf_indent (file, +2); + if (!options.gen.smp) + { + lf_printf (file, "%sinstruction_address cia;\n", options.module.global.prefix.l); + } + lf_printf (file, "int current_cpu = next_cpu_nr;\n"); + + if (options.gen.icache) + { + lf_printf (file, "/* flush the icache of a possible break insn */\n"); + lf_printf (file, "{\n"); + lf_printf (file, " int cpu_nr;\n"); + lf_printf (file, " for (cpu_nr = 0; cpu_nr < nr_cpus; cpu_nr++)\n"); + lf_printf (file, " cpu_flush_icache (STATE_CPU (sd, cpu_nr));\n"); + lf_printf (file, "}\n"); + } + + if (!options.gen.smp) + { + + lf_putstr (file, " +/* CASE 1: NO SMP (with or with out instruction cache). + +In this case, we can take advantage of the fact that the current +instruction address (CIA) does not need to be read from / written to +the CPU object after the execution of an instruction. + +Instead, CIA is only saved when the main loop exits. This occures +when either sim_engine_halt or sim_engine_restart is called. Both of +these functions save the current instruction address before halting / +restarting the simulator. + +As a variation, there may also be support for an instruction cracking +cache. */ + +"); + + lf_putstr (file, "\n"); + lf_putstr (file, "/* prime the main loop */\n"); + lf_putstr (file, "SIM_ASSERT (current_cpu == 0);\n"); + lf_putstr (file, "SIM_ASSERT (nr_cpus == 1);\n"); + lf_putstr (file, "cia = CIA_GET (CPU);\n"); + + lf_putstr (file, "\n"); + lf_putstr (file, "while (1)\n"); + lf_putstr (file, " {\n"); + lf_indent (file, +4); + + lf_printf (file, "%sinstruction_address nia;\n", + options.module.global.prefix.l); + + lf_printf (file, "\n"); + if (!options.gen.icache) + { + lf_printf (file, "%sinstruction_word instruction_0 = IMEM%d (cia);\n", + options.module.global.prefix.l, + options.insn_bit_size); + print_engine_issue_prefix_hook (file); + print_idecode_body (file, table, "nia = "); + print_engine_issue_postfix_hook (file); + } + else + { + lf_putstr (file, "idecode_cache *cache_entry =\n"); + lf_putstr (file, " cpu_icache_entry (cpu, cia);\n"); + lf_putstr (file, "if (cache_entry->address == cia)\n"); + lf_putstr (file, " {\n"); + lf_indent (file, -4); + lf_putstr (file, "/* cache hit */\n"); + lf_putstr (file, "idecode_semantic *const semantic = cache_entry->semantic;\n"); + lf_putstr (file, "cia = semantic (cpu, cache_entry, cia);\n"); + /* tail */ + lf_indent (file, -4); + lf_putstr (file, " }\n"); + lf_putstr (file, "else\n"); + lf_putstr (file, " {\n"); + lf_indent (file, +4); + lf_putstr (file, "/* cache miss */\n"); + if (!options.gen.semantic_icache) + { + lf_putstr (file, "idecode_semantic *semantic;\n"); + } + lf_printf (file, "instruction_word instruction = IMEM%d (cia);\n", + options.insn_bit_size); + lf_putstr (file, "if (WITH_MON != 0)\n"); + lf_putstr (file, " mon_event (mon_event_icache_miss, cpu, cia);\n"); + if (options.gen.semantic_icache) + { + lf_putstr (file, "{\n"); + lf_indent (file, +2); + print_engine_issue_prefix_hook (file); + print_idecode_body (file, table, "nia ="); + print_engine_issue_postfix_hook (file); + lf_indent (file, -2); + lf_putstr (file, "}\n"); + } + else + { + print_engine_issue_prefix_hook (file); + print_idecode_body (file, table, "semantic ="); + lf_putstr (file, "nia = semantic (cpu, cache_entry, cia);\n"); + print_engine_issue_postfix_hook (file); + } + lf_indent (file, -4); + lf_putstr (file, " }\n"); + } + + /* update the cpu if necessary */ + switch (options.gen.nia) + { + case nia_is_cia_plus_one: + lf_printf (file, "\n"); + lf_printf (file, "/* Update the instruction address */\n"); + lf_printf (file, "cia = nia;\n"); + break; + case nia_is_void: + case nia_is_invalid: + ERROR ("engine gen when NIA complex"); + } + + /* events */ + lf_putstr (file, "\n"); + lf_putstr (file, "/* process any events */\n"); + lf_putstr (file, "if (sim_events_tick (sd))\n"); + lf_putstr (file, " {\n"); + lf_putstr (file, " CIA_SET (CPU, cia);\n"); + lf_putstr (file, " sim_events_process (sd);\n"); + lf_putstr (file, " cia = CIA_GET (CPU);\n"); + lf_putstr (file, " }\n"); + + lf_indent (file, -4); + lf_printf (file, " }\n"); + } + + if (options.gen.smp) + { + + lf_putstr (file, " +/* CASE 2: SMP (With or without ICACHE) + +The complexity here comes from needing to correctly halt the simulator +when it is aborted. For instance, if cpu0 requests a restart then +cpu1 will normally be the next cpu that is run. Cpu0 being restarted +after all the other CPU's and the event queue have been processed */ + +"); + + lf_putstr (file, "\n"); + lf_printf (file, "/* have ensured that the event queue is NOT next */\n"); + lf_printf (file, "SIM_ASSERT (current_cpu >= 0);\n"); + lf_printf (file, "SIM_ASSERT (current_cpu <= nr_cpus - 1);\n"); + lf_printf (file, "SIM_ASSERT (nr_cpus <= MAX_NR_PROCESSORS);\n"); + + lf_putstr (file, "\n"); + lf_putstr (file, "while (1)\n"); + lf_putstr (file, " {\n"); + lf_indent (file, +4); + lf_putstr (file, "sim_cpu *cpu = STATE_CPU (sd, current_cpu);\n"); + lf_putstr (file, "instruction_address cia = CIA_GET (cpu);\n"); + lf_putstr (file, "\n"); + + if (!options.gen.icache) + { + lf_printf (file, "instruction_word instruction_0 = IMEM%d (cia);\n", + options.insn_bit_size); + print_engine_issue_prefix_hook (file); + print_idecode_body (file, table, "cia ="); + lf_putstr (file, "CIA_SET (cpu, cia);\n"); + print_engine_issue_postfix_hook (file); + } + + if (options.gen.icache) + { + lf_putstr (file, "engine_cache *cache_entry =\n"); + lf_putstr (file, " cpu_icache_entry(processor, cia);\n"); + lf_putstr (file, "\n"); + lf_putstr (file, "if (cache_entry->address == cia) {\n"); + { + lf_indent (file, +2); + lf_putstr (file, "\n"); + lf_putstr (file, "/* cache hit */\n"); + lf_putstr (file, "engine_semantic *semantic = cache_entry->semantic;\n"); + lf_putstr (file, "cia = semantic(processor, cache_entry, cia);\n"); + /* tail */ + lf_putstr (file, "cpu_set_program_counter(processor, cia);\n"); + lf_putstr (file, "\n"); + lf_indent (file, -2); + } + lf_putstr (file, "}\n"); + lf_putstr (file, "else {\n"); + { + lf_indent (file, +2); + lf_putstr (file, "\n"); + lf_putstr (file, "/* cache miss */\n"); + if (!options.gen.semantic_icache) + { + lf_putstr (file, "engine_semantic *semantic;\n"); + } + lf_printf (file, "instruction_word instruction = IMEM%d (cia);\n", + options.insn_bit_size); + lf_putstr (file, "if (WITH_MON != 0)\n"); + lf_putstr (file, " mon_event(mon_event_icache_miss, processors[current_cpu], cia);\n"); + if (options.gen.semantic_icache) + { + lf_putstr (file, "{\n"); + lf_indent (file, +2); + print_engine_issue_prefix_hook (file); + print_idecode_body(file, table, "cia ="); + print_engine_issue_postfix_hook (file); + lf_indent (file, -2); + lf_putstr (file, "}\n"); + } + else + { + print_engine_issue_prefix_hook (file); + print_idecode_body(file, table, "semantic = "); + lf_putstr (file, "cia = semantic(processor, cache_entry, cia);\n"); + print_engine_issue_postfix_hook (file); + } + /* tail */ + lf_putstr (file, "cpu_set_program_counter(processor, cia);\n"); + lf_putstr (file, "\n"); + lf_indent (file, -2); + } + lf_putstr (file, "}\n"); + } + + lf_putstr (file, "\n"); + lf_putstr (file, "current_cpu += 1;\n"); + lf_putstr (file, "if (current_cpu == nr_cpus)\n"); + lf_putstr (file, " {\n"); + lf_putstr (file, " if (sim_events_tick (sd))\n"); + lf_putstr (file, " {\n"); + lf_putstr (file, " sim_events_process (sd);\n"); + lf_putstr (file, " }\n"); + lf_putstr (file, " current_cpu = 0;\n"); + lf_putstr (file, " }\n"); + + /* tail */ + lf_indent (file, -4); + lf_putstr (file, " }\n"); + } + + + lf_indent (file, -2); + lf_putstr (file, "}\n"); +} + + +/****************************************************************/ + +#if 0 +static void +print_jump (lf *file, + int is_tail) +{ + if (!options.gen.smp) + { + lf_putstr (file, "if (event_queue_tick (sd))\n"); + lf_putstr (file, " {\n"); + lf_putstr (file, " CPU_CIA (processor) = nia;\n"); + lf_putstr (file, " sim_events_process (sd);\n"); + lf_putstr (file, " }\n"); + lf_putstr (file, "}\n"); + } + + if (options.gen.smp) + { + if (is_tail) + lf_putstr (file, "cpu_set_program_counter(processor, nia);\n"); + lf_putstr (file, "current_cpu += 1;\n"); + lf_putstr (file, "if (current_cpu >= nr_cpus)\n"); + lf_putstr (file, " {\n"); + lf_putstr (file, " if (sim_events_tick (sd))\n"); + lf_putstr (file, " {\n"); + lf_putstr (file, " sim_events_process (sd);\n"); + lf_putstr (file, " }\n"); + lf_putstr (file, " current_cpu = 0;\n"); + lf_putstr (file, " }\n"); + lf_putstr (file, "processor = processors[current_cpu];\n"); + lf_putstr (file, "nia = cpu_get_program_counter(processor);\n"); + } + + if (options.gen.icache) + { + lf_putstr (file, "cache_entry = cpu_icache_entry(processor, nia);\n"); + lf_putstr (file, "if (cache_entry->address == nia) {\n"); + lf_putstr (file, " /* cache hit */\n"); + lf_putstr (file, " goto *cache_entry->semantic;\n"); + lf_putstr (file, "}\n"); + if (is_tail) { + lf_putstr (file, "goto cache_miss;\n"); + } + } + + if (!options.gen.icache && is_tail) + { + lf_printf (file, "goto engine;\n"); + } + +} +#endif + + +#if 0 +static void +print_jump_insn (lf *file, + insn_entry *instruction, + opcode_bits *expanded_bits, + opcode_field *opcodes, + cache_entry *cache_rules) +{ + insn_opcodes opcode_path; + + memset (&opcode_path, 0, sizeof (opcode_path)); + opcode_path.opcode = opcodes; + + /* what we are for the moment */ + lf_printf (file, "\n"); + print_my_defines (file, + instruction->name, + instruction->format_name, + expanded_bits); + + /* output the icache entry */ + if (options.gen.icache) + { + lf_printf (file, "\n"); + lf_indent (file, -1); + print_function_name (file, + instruction->name, + instruction->format_name, + NULL, + expanded_bits, + function_name_prefix_icache); + lf_printf (file, ":\n"); + lf_indent (file, +1); + lf_printf (file, "{\n"); + lf_indent (file, +2); + lf_putstr (file, "const unsigned_word cia = nia;\n"); + print_itrace (file, instruction, 1/*putting-value-in-cache*/); + print_idecode_validate (file, instruction, &opcode_path); + lf_printf (file, "\n"); + lf_printf (file, "{\n"); + lf_indent (file, +2); + print_icache_body (file, + instruction, + expanded_bits, + cache_rules, + 0, /*use_defines*/ + put_values_in_icache); + lf_printf (file, "cache_entry->address = nia;\n"); + lf_printf (file, "cache_entry->semantic = &&"); + print_function_name (file, + instruction->name, + instruction->format_name, + NULL, + expanded_bits, + function_name_prefix_semantics); + lf_printf (file, ";\n"); + if (options.gen.semantic_icache) + { + print_semantic_body (file, + instruction, + expanded_bits, + &opcode_path); + print_jump(file, 1/*is-tail*/); + } + else + { + lf_printf (file, "/* goto "); + print_function_name (file, + instruction->name, + instruction->format_name, + NULL, + expanded_bits, + function_name_prefix_semantics); + lf_printf (file, "; */\n"); + } + lf_indent (file, -2); + lf_putstr (file, "}\n"); + lf_indent (file, -2); + lf_printf (file, "}\n"); + } + + /* print the semantics */ + lf_printf (file, "\n"); + lf_indent (file, -1); + print_function_name (file, + instruction->name, + instruction->format_name, + NULL, + expanded_bits, + function_name_prefix_semantics); + lf_printf (file, ":\n"); + lf_indent (file, +1); + lf_printf (file, "{\n"); + lf_indent (file, +2); + lf_putstr (file, "const unsigned_word cia = nia;\n"); + print_icache_body (file, + instruction, + expanded_bits, + cache_rules, + (options.gen.direct_access + ? define_variables + : declare_variables), + (options.gen.icache + ? get_values_from_icache + : do_not_use_icache)); + print_semantic_body (file, + instruction, + expanded_bits, + &opcode_path); + if (options.gen.direct_access) + print_icache_body (file, + instruction, + expanded_bits, + cache_rules, + undef_variables, + (options.gen.icache + ? get_values_from_icache + : do_not_use_icache)); + print_jump(file, 1/*is tail*/); + lf_indent (file, -2); + lf_printf (file, "}\n"); +} +#endif + + +#if 0 +static void +print_jump_definition (lf *file, + gen_entry *entry, + int depth, + void *data) +{ + cache_entry *cache_rules = (cache_entry*)data; + if (entry->opcode_rule->with_duplicates) + { + ASSERT (entry->nr_insns == 1 + && entry->opcode == NULL + && entry->parent != NULL + && entry->parent->opcode != NULL); + ASSERT (entry->nr_insns == 1 + && entry->opcode == NULL + && entry->parent != NULL + && entry->parent->opcode != NULL + && entry->parent->opcode_rule != NULL); + print_jump_insn (file, + entry->insns->insn, + entry->expanded_bits, + entry->opcode, + cache_rules); + } + else + { + print_jump_insn (file, + entry->insns->insn, + NULL, + NULL, + cache_rules); + } +} +#endif + + +#if 0 +static void +print_jump_internal_function (lf *file, + function_entry *function, + void *data) +{ + if (function->is_internal) + { + lf_printf (file, "\n"); + lf_print__line_ref (file, function->line); + lf_indent (file, -1); + print_function_name (file, + function->name, + NULL, + NULL, + NULL, + (options.gen.icache + ? function_name_prefix_icache + : function_name_prefix_semantics)); + lf_printf (file, ":\n"); + lf_indent (file, +1); + lf_printf (file, "{\n"); + lf_indent (file, +2); + lf_printf (file, "const unsigned_word cia = nia;\n"); + table_print_code (file, function->code); + lf_print__internal_ref (file); + lf_printf (file, "error(\"Internal function must longjump\\n\");\n"); + lf_indent (file, -2); + lf_printf (file, "}\n"); + } +} +#endif + + +#if 0 +static void +print_jump_body (lf *file, + gen_entry *entry, + insn_table *isa, + cache_entry *cache_rules) +{ + lf_printf (file, "{\n"); + lf_indent (file, +2); + lf_putstr (file, "jmp_buf halt;\n"); + lf_putstr (file, "jmp_buf restart;\n"); + lf_putstr (file, "cpu *processor = NULL;\n"); + lf_putstr (file, "unsigned_word nia = -1;\n"); + lf_putstr (file, "instruction_word instruction = 0;\n"); + if (options.gen.icache) + { + lf_putstr (file, "engine_cache *cache_entry = NULL;\n"); + } + if (options.gen.smp) + { + lf_putstr (file, "int current_cpu = -1;\n"); + } + + /* all the switches and tables - they know about jumping */ + print_idecode_lookups (file, entry, cache_rules); + + /* start the simulation up */ + if (options.gen.icache) + { + lf_putstr (file, "\n"); + lf_putstr (file, "{\n"); + lf_putstr (file, " int cpu_nr;\n"); + lf_putstr (file, " for (cpu_nr = 0; cpu_nr < nr_cpus; cpu_nr++)\n"); + lf_putstr (file, " cpu_flush_icache(processors[cpu_nr]);\n"); + lf_putstr (file, "}\n"); + } + + lf_putstr (file, "\n"); + lf_putstr (file, "psim_set_halt_and_restart(system, &halt, &restart);\n"); + + lf_putstr (file, "\n"); + lf_putstr (file, "if (setjmp(halt))\n"); + lf_putstr (file, " return;\n"); + + lf_putstr (file, "\n"); + lf_putstr (file, "setjmp(restart);\n"); + + lf_putstr (file, "\n"); + if (!options.gen.smp) + { + lf_putstr (file, "processor = processors[0];\n"); + lf_putstr (file, "nia = cpu_get_program_counter(processor);\n"); + } + else + { + lf_putstr (file, "current_cpu = psim_last_cpu(system);\n"); + } + + if (!options.gen.icache) + { + lf_printf (file, "\n"); + lf_indent (file, -1); + lf_printf (file, "engine:\n"); + lf_indent (file, +1); + } + + print_jump(file, 0/*is_tail*/); + + if (options.gen.icache) + { + lf_indent (file, -1); + lf_printf (file, "cache_miss:\n"); + lf_indent (file, +1); + } + + print_engine_issue_prefix_hook (file); + lf_putstr (file, "instruction\n"); + lf_putstr (file, " = vm_instruction_map_read(cpu_instruction_map(processor),\n"); + lf_putstr (file, " processor, nia);\n"); + print_engine_issue_prefix_hook (file); + print_idecode_body (file, entry, "/*IGORE*/"); + print_engine_issue_postfix_hook (file); + + /* print out a table of all the internals functions */ + function_entry_traverse (file, isa->functions, + print_jump_internal_function, + NULL); + + /* print out a table of all the instructions */ + ERROR ("Use the list of semantic functions, not travere_tree"); + gen_entry_traverse_tree (file, entry, + 1, + NULL, /* start */ + print_jump_definition, /* leaf */ + NULL, /* end */ + cache_rules); + lf_indent (file, -2); + lf_printf (file, "}\n"); +} +#endif + + +/****************************************************************/ + + +void +print_engine_run_function_header (lf *file, + char *processor, + function_decl_type decl_type) +{ + int indent; + lf_printf (file, "\n"); + switch (decl_type) + { + case is_function_declaration: + lf_print__function_type (file, "void", "INLINE_ENGINE", "\n"); + break; + case is_function_definition: + lf_print__function_type (file, "void", "INLINE_ENGINE", " "); + break; + case is_function_variable: + lf_printf (file, "void (*"); + break; + } + indent = print_function_name (file, + "run", + NULL, /* format name */ + processor, + NULL, /* expanded bits */ + function_name_prefix_engine); + switch (decl_type) + { + case is_function_definition: + lf_putstr (file, "\n("); + indent = 1; + break; + case is_function_declaration: + indent += lf_printf (file, " ("); + break; + case is_function_variable: + lf_putstr (file, ")\n("); + indent = 1; + break; + } + lf_indent (file, +indent); + lf_printf (file, "SIM_DESC sd,\n"); + lf_printf (file, "int next_cpu_nr,\n"); + lf_printf (file, "int nr_cpus,\n"); + lf_printf (file, "int siggnal)"); + lf_indent (file, -indent); + switch (decl_type) + { + case is_function_definition: + lf_putstr (file, "\n"); + break; + case is_function_variable: + case is_function_declaration: + lf_putstr (file, ";\n"); + break; + } +} + + +void +gen_engine_h (lf *file, + gen_table *gen, + insn_table *isa, + cache_entry *cache_rules) +{ + gen_list *entry; + for (entry = gen->tables; entry != NULL; entry = entry->next) + { + print_engine_run_function_header (file, + (options.gen.multi_sim + ? entry->model->name + : NULL), + is_function_declaration); + } +} + + +void +gen_engine_c(lf *file, + gen_table *gen, + insn_table *isa, + cache_entry *cache_rules) +{ + gen_list *entry; + /* the intro */ + print_includes (file); + print_include_inline (file, options.module.semantics); + print_include (file, options.module.engine); + lf_printf (file, "\n"); + lf_printf (file, "#include \"sim-assert.h\"\n"); + lf_printf (file, "\n"); + print_idecode_globals (file); + lf_printf (file, "\n"); + + for (entry = gen->tables; entry != NULL; entry = entry->next) + { + switch (options.gen.code) + { + case generate_calls: + print_idecode_lookups (file, entry->table, cache_rules); + + /* output the main engine routine */ + print_engine_run_function_header (file, + (options.gen.multi_sim + ? entry->model->name + : NULL), + is_function_definition); + print_run_body (file, entry->table); + break; + + case generate_jumps: + ERROR ("Jumps currently unimplemented"); +#if 0 + print_engine_run_function_header (file, + entry->processor, + is_function_definition); + print_jump_body (file, entry->table, + isa, cache_rules); +#endif + break; + } + } +} diff --git a/sim/igen/gen-engine.h b/sim/igen/gen-engine.h new file mode 100644 index 00000000000..9dbd87abbd5 --- /dev/null +++ b/sim/igen/gen-engine.h @@ -0,0 +1,37 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-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. + + */ + +extern void gen_engine_h +(lf *file, + gen_table *gen, + insn_table *isa, + cache_entry *cache_rules); + +extern void gen_engine_c +(lf *file, + gen_table *gen, + insn_table *isa, + cache_entry *cache_rules); + +extern void print_engine_run_function_header +(lf *file, + char *processor, + function_decl_type decl_type); + diff --git a/sim/igen/gen-icache.c b/sim/igen/gen-icache.c new file mode 100644 index 00000000000..88d5d412288 --- /dev/null +++ b/sim/igen/gen-icache.c @@ -0,0 +1,859 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, 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 "misc.h" +#include "lf.h" +#include "table.h" +#include "filter.h" +#include "igen.h" + +#include "ld-insn.h" +#include "ld-decode.h" + +#include "gen.h" + +#include "gen-semantics.h" +#include "gen-idecode.h" +#include "gen-icache.h" + + + +static void +print_icache_function_header (lf *file, + const char *basename, + const char *format_name, + opcode_bits *expanded_bits, + int is_function_definition, + int nr_prefetched_words) +{ + lf_printf(file, "\n"); + lf_print__function_type_function (file, print_icache_function_type, + "EXTERN_ICACHE", " "); + print_function_name (file, + basename, format_name, NULL, + expanded_bits, + function_name_prefix_icache); + lf_printf (file, "\n("); + print_icache_function_formal (file, nr_prefetched_words); + lf_printf (file, ")"); + if (!is_function_definition) + lf_printf (file, ";"); + lf_printf (file, "\n"); +} + + +void +print_icache_declaration (lf *file, + insn_entry *insn, + opcode_bits *expanded_bits, + insn_opcodes *opcodes, + int nr_prefetched_words) +{ + print_icache_function_header (file, + insn->name, + insn->format_name, + expanded_bits, + 0/* is not function definition */, + nr_prefetched_words); +} + + + +static void +print_icache_extraction (lf *file, + const char *format_name, + cache_entry_type cache_type, + const char *entry_name, + const char *entry_type, + const char *entry_expression, + char *single_insn_field, + line_ref *line, + insn_field_entry *cur_field, + opcode_bits *expanded_bits, + icache_decl_type what_to_declare, + icache_body_type what_to_do) +{ + const char *expression; + opcode_bits *bits; + char *reason; + ASSERT (format_name != NULL); + ASSERT (entry_name != NULL); + + /* figure out exactly what should be going on here */ + switch (cache_type) + { + case scratch_value: + if ((what_to_do & put_values_in_icache) + || what_to_do == do_not_use_icache) + { + reason = "scratch"; + what_to_do = do_not_use_icache; + } + else + return; + break; + case compute_value: + if ((what_to_do & get_values_from_icache) + || what_to_do == do_not_use_icache) + { + reason = "compute"; + what_to_do = do_not_use_icache; + } + else + return; + break; + case cache_value: + if ((what_to_declare != undef_variables) + || !(what_to_do & put_values_in_icache)) + { + reason = "cache"; + what_to_declare = ((what_to_do & put_values_in_icache) + ? declare_variables + : what_to_declare); + } + else + return; + break; + } + + /* For the type, default to a simple unsigned */ + if (entry_type == NULL || strlen (entry_type) == 0) + entry_type = "unsigned"; + + /* look through the set of expanded sub fields to see if this field + has been given a constant value */ + for (bits = expanded_bits; + bits != NULL; + bits = bits->next) + { + if (bits->field == cur_field) + break; + } + + /* Define a storage area for the cache element */ + switch (what_to_declare) + { + case undef_variables: + /* We've finished with the #define value - destory it */ + lf_indent_suppress (file); + lf_printf (file, "#undef %s\n", entry_name); + return; + case define_variables: + /* Using direct access for this entry, clear any prior + definition, then define it */ + lf_indent_suppress (file); + lf_printf (file, "#undef %s\n", entry_name); + /* Don't type cast pointer types! */ + lf_indent_suppress (file); + if (strchr (entry_type, '*') != NULL) + lf_printf (file, "#define %s (", entry_name); + else + lf_printf (file, "#define %s ((%s) ", entry_name, entry_type); + break; + case declare_variables: + /* using variables to define the value */ + if (line != NULL) + lf_print__line_ref (file, line); + lf_printf (file, "%s const %s UNUSED = ", entry_type, entry_name); + break; + } + + + /* define a value for that storage area as determined by what is in + the cache */ + if (bits != NULL + && single_insn_field != NULL + && strcmp (entry_name, single_insn_field) == 0 + && strcmp (entry_name, cur_field->val_string) == 0 + && ((bits->opcode->is_boolean && bits->value == 0) + || (!bits->opcode->is_boolean))) + { + /* The cache rule is specifying what to do with a simple + instruction field. + + Because of instruction expansion, the field is either a + constant value or equal to the specified constant (boolean + comparison). (The latter indicated by bits->value == 0). + + The case of a field not being equal to the specified boolean + value is handled later. */ + expression = "constant field"; + ASSERT (bits->field == cur_field); + if (bits->opcode->is_boolean) + { + ASSERT (bits->value == 0); + lf_printf (file, "%d", bits->opcode->boolean_constant); + } + else if (bits->opcode->last < bits->field->last) + { + lf_printf (file, "%d", + bits->value << (bits->field->last - bits->opcode->last)); + } + else + { + lf_printf (file, "%d", bits->value); + } + } + else if (bits != NULL + && single_insn_field != NULL + && strncmp (entry_name, + single_insn_field, + strlen (single_insn_field)) == 0 + && strncmp (entry_name + strlen (single_insn_field), + "_is_", + strlen ("_is_")) == 0 + && ((bits->opcode->is_boolean + && ((unsigned) atol (entry_name + strlen (single_insn_field) + strlen ("_is_")) + == bits->opcode->boolean_constant)) + || (!bits->opcode->is_boolean))) + { + /* The cache rule defines an entry for the comparison between a + single instruction field and a constant. The value of the + comparison in someway matches that of the opcode field that + was made constant through expansion. */ + expression = "constant compare"; + if (bits->opcode->is_boolean) + { + lf_printf (file, "%d /* %s == %d */", + bits->value == 0, + single_insn_field, + bits->opcode->boolean_constant); + } + else if (bits->opcode->last < bits->field->last) + { + lf_printf (file, "%d /* %s == %d */", + (atol (entry_name + strlen (single_insn_field) + strlen ("_is_")) + == (bits->value << (bits->field->last - bits->opcode->last))), + single_insn_field, + (bits->value << (bits->field->last - bits->opcode->last))); + } + else + { + lf_printf (file, "%d /* %s == %d */", + (atol (entry_name + strlen (single_insn_field) + strlen ("_is_")) + == bits->value), + single_insn_field, + bits->value); + } + } + else + { + /* put the field in the local variable, possibly also enter it + into the cache */ + expression = "extraction"; + /* handle the cache */ + if ((what_to_do & get_values_from_icache) + || (what_to_do & put_values_in_icache)) + { + lf_printf (file, "cache_entry->crack.%s.%s", + format_name, + entry_name); + if (what_to_do & put_values_in_icache) /* also put it in the cache? */ + { + lf_printf (file, " = "); + } + } + if ((what_to_do & put_values_in_icache) + || what_to_do == do_not_use_icache) + { + if (cur_field != NULL) + { + if (entry_expression != NULL && strlen (entry_expression) > 0) + error (line, "Instruction field entry with nonempty expression\n"); + if (cur_field->first == 0 && cur_field->last == options.insn_bit_size - 1) + lf_printf (file, "(instruction_%d)", + cur_field->word_nr); + else if (cur_field->last == options.insn_bit_size - 1) + lf_printf (file, "MASKED%d (instruction_%d, %d, %d)", + options.insn_bit_size, + cur_field->word_nr, + i2target (options.hi_bit_nr, cur_field->first), + i2target (options.hi_bit_nr, cur_field->last)); + else + lf_printf (file, "EXTRACTED%d (instruction_%d, %d, %d)", + options.insn_bit_size, + cur_field->word_nr, + i2target (options.hi_bit_nr, cur_field->first), + i2target (options.hi_bit_nr, cur_field->last)); + } + else + { + lf_printf (file, "%s", entry_expression); + } + } + } + + switch (what_to_declare) + { + case define_variables: + lf_printf (file, ")"); + break; + case undef_variables: + break; + case declare_variables: + lf_printf (file, ";"); + break; + } + + ASSERT (reason != NULL && expression != NULL); + lf_printf (file, " /* %s - %s */\n", reason, expression); +} + + +void +print_icache_body (lf *file, + insn_entry *instruction, + opcode_bits *expanded_bits, + cache_entry *cache_rules, + icache_decl_type what_to_declare, + icache_body_type what_to_do, + int nr_prefetched_words) +{ + /* extract instruction fields */ + lf_printf (file, "/* Extraction: %s\n", instruction->name); + lf_printf (file, " "); + switch (what_to_declare) + { + case define_variables: + lf_printf (file, "#define"); + break; + case declare_variables: + lf_printf (file, "declare"); + break; + case undef_variables: + lf_printf (file, "#undef"); + break; + } + lf_printf (file, " "); + switch (what_to_do) + { + case get_values_from_icache: + lf_printf (file, "get-values-from-icache"); + break; + case put_values_in_icache: + lf_printf (file, "put-values-in-icache"); + break; + case both_values_and_icache: + lf_printf (file, "get-values-from-icache|put-values-in-icache"); + break; + case do_not_use_icache: + lf_printf (file, "do-not-use-icache"); + break; + } + lf_printf (file, "\n "); + print_insn_words (file, instruction); + lf_printf(file, " */\n"); + + /* pass zero - fetch from memory any missing instructions. + + Some of the instructions will have already been fetched (in the + instruction array), others will still need fetching. */ + switch (what_to_do) + { + case get_values_from_icache: + break; + case put_values_in_icache: + case both_values_and_icache: + case do_not_use_icache: + { + int word_nr; + switch (what_to_declare) + { + case undef_variables: + break; + case define_variables: + case declare_variables: + for (word_nr = nr_prefetched_words; + word_nr < instruction->nr_words; + word_nr++) + { + /* FIXME - should be using print_icache_extraction? */ + lf_printf (file, "%sinstruction_word instruction_%d UNUSED = ", + options.module.global.prefix.l, + word_nr); + lf_printf (file, "IMEM%d_IMMED (cia, %d)", + options.insn_bit_size, word_nr); + lf_printf (file, ";\n"); + } + } + } + } + + /* if putting the instruction words in the cache, define references + for them */ + if (options.gen.insn_in_icache) { + /* FIXME: is the instruction_word type correct? */ + print_icache_extraction (file, + instruction->format_name, + cache_value, + "insn", /* name */ + "instruction_word", /* type */ + "instruction", /* expression */ + NULL, /* origin */ + NULL, /* line */ + NULL, NULL, + what_to_declare, + what_to_do); + } + lf_printf(file, "\n"); + + /* pass one - process instruction fields. + + If there is no cache rule, the default is to enter the field into + the cache */ + { + insn_word_entry *word; + for (word = instruction->words; + word != NULL; + word = word->next) + { + insn_field_entry *cur_field; + for (cur_field = word->first; + cur_field->first < options.insn_bit_size; + cur_field = cur_field->next) + { + if (cur_field->type == insn_field_string) + { + cache_entry *cache_rule; + cache_entry_type value_type = cache_value; + line_ref *value_line = instruction->line; + /* check the cache table to see if it contains a rule + overriding the default cache action for an + instruction field */ + for (cache_rule = cache_rules; + cache_rule != NULL; + cache_rule = cache_rule->next) + { + if (filter_is_subset (instruction->field_names, + cache_rule->original_fields) + && strcmp (cache_rule->name, cur_field->val_string) == 0) + { + value_type = cache_rule->entry_type; + value_line = cache_rule->line; + if (value_type == compute_value) + { + options.warning (cache_rule->line, + "instruction field of type `compute' changed to `cache'\n"); + cache_rule->entry_type = cache_value; + } + break; + } + } + /* Define an entry for the field within the + instruction */ + print_icache_extraction (file, + instruction->format_name, + value_type, + cur_field->val_string, /* name */ + NULL, /* type */ + NULL, /* expression */ + cur_field->val_string, /* insn field */ + value_line, + cur_field, + expanded_bits, + what_to_declare, + what_to_do); + } + } + } + } + + /* pass two - any cache fields not processed above */ + { + cache_entry *cache_rule; + for (cache_rule = cache_rules; + cache_rule != NULL; + cache_rule = cache_rule->next) + { + if (filter_is_subset (instruction->field_names, + cache_rule->original_fields) + && !filter_is_member (instruction->field_names, + cache_rule->name)) + { + char *single_field = filter_next (cache_rule->original_fields, ""); + if (filter_next (cache_rule->original_fields, single_field) != NULL) + single_field = NULL; + print_icache_extraction (file, + instruction->format_name, + cache_rule->entry_type, + cache_rule->name, + cache_rule->type, + cache_rule->expression, + single_field, + cache_rule->line, + NULL, /* cur_field */ + expanded_bits, + what_to_declare, + what_to_do); + } + } + } + + lf_print__internal_ref (file); +} + + + +typedef struct _form_fields form_fields; +struct _form_fields { + char *name; + filter *fields; + form_fields *next; +}; + +static form_fields * +insn_table_cache_fields (insn_table *isa) +{ + form_fields *forms = NULL; + insn_entry *insn; + for (insn = isa->insns; + insn != NULL; + insn = insn->next) { + form_fields **form = &forms; + while (1) + { + if (*form == NULL) + { + /* new format name, add it */ + form_fields *new_form = ZALLOC (form_fields); + new_form->name = insn->format_name; + filter_add (&new_form->fields, insn->field_names); + *form = new_form; + break; + } + else if (strcmp ((*form)->name, insn->format_name) == 0) + { + /* already present, add field names to the existing list */ + filter_add (&(*form)->fields, insn->field_names); + break; + } + form = &(*form)->next; + } + } + return forms; +} + + + +extern void +print_icache_struct (lf *file, + insn_table *isa, + cache_entry *cache_rules) +{ + /* Create a list of all the different instruction formats with their + corresponding field names. */ + form_fields *formats = insn_table_cache_fields (isa); + + lf_printf (file, "\n"); + lf_printf (file, "#define WITH_%sIDECODE_CACHE_SIZE %d\n", + options.module.global.prefix.u, + (options.gen.icache ? options.gen.icache_size : 0)); + lf_printf (file, "\n"); + + /* create an instruction cache if being used */ + if (options.gen.icache) { + lf_printf (file, "typedef struct _%sidecode_cache {\n", + options.module.global.prefix.l); + lf_indent (file, +2); + { + form_fields *format; + lf_printf (file, "unsigned_word address;\n"); + lf_printf (file, "void *semantic;\n"); + lf_printf (file, "union {\n"); + lf_indent (file, +2); + for (format = formats; + format != NULL; + format = format->next) + { + lf_printf (file, "struct {\n"); + lf_indent (file, +2); + { + cache_entry *cache_rule; + char *field; + /* space for any instruction words */ + if (options.gen.insn_in_icache) + lf_printf (file, "instruction_word insn[%d];\n", isa->max_nr_words); + /* define an entry for any applicable cache rules */ + for (cache_rule = cache_rules; + cache_rule != NULL; + cache_rule = cache_rule->next) + { + /* nb - sort of correct - should really check against + individual instructions */ + if (filter_is_subset (format->fields, cache_rule->original_fields)) + { + char *memb; + lf_printf (file, "%s %s;", + (cache_rule->type == NULL + ? "unsigned" + : cache_rule->type), + cache_rule->name); + lf_printf (file, " /*"); + for (memb = filter_next (cache_rule->original_fields, ""); + memb != NULL; + memb = filter_next (cache_rule->original_fields, memb)) + { + lf_printf (file, " %s", memb); + } + lf_printf (file, " */\n"); + } + } + /* define an entry for any fields not covered by a cache rule */ + for (field = filter_next (format->fields, ""); + field != NULL; + field = filter_next (format->fields, field)) + { + cache_entry *cache_rule; + int found_rule = 0; + for (cache_rule = cache_rules; + cache_rule != NULL; + cache_rule = cache_rule->next) + { + if (strcmp (cache_rule->name, field) == 0) + { + found_rule = 1; + break; + } + } + if (!found_rule) + lf_printf (file, "unsigned %s; /* default */\n", field); + } + } + lf_indent (file, -2); + lf_printf (file, "} %s;\n", format->name); + } + lf_indent (file, -2); + lf_printf (file, "} crack;\n"); + } + lf_indent (file, -2); + lf_printf (file, "} %sidecode_cache;\n", options.module.global.prefix.l); + } + else + { + /* alernativly, since no cache, emit a dummy definition for + idecode_cache so that code refering to the type can still compile */ + lf_printf(file, "typedef void %sidecode_cache;\n", + options.module.global.prefix.l); + } + lf_printf (file, "\n"); +} + + + +static void +print_icache_function (lf *file, + insn_entry *instruction, + opcode_bits *expanded_bits, + insn_opcodes *opcodes, + cache_entry *cache_rules, + int nr_prefetched_words) +{ + int indent; + + /* generate code to enter decoded instruction into the icache */ + lf_printf(file, "\n"); + lf_print__function_type_function (file, print_icache_function_type, + "EXTERN_ICACHE", "\n"); + indent = print_function_name (file, + instruction->name, + instruction->format_name, + NULL, + expanded_bits, + function_name_prefix_icache); + indent += lf_printf (file, " "); + lf_indent (file, +indent); + lf_printf (file, "("); + print_icache_function_formal (file, nr_prefetched_words); + lf_printf (file, ")\n"); + lf_indent (file, -indent); + + /* function header */ + lf_printf (file, "{\n"); + lf_indent (file, +2); + + print_my_defines (file, + instruction->name, + instruction->format_name, + expanded_bits); + print_itrace (file, instruction, 1/*putting-value-in-cache*/); + + print_idecode_validate (file, instruction, opcodes); + + lf_printf (file, "\n"); + lf_printf (file, "{\n"); + lf_indent (file, +2); + if (options.gen.semantic_icache) + lf_printf (file, "unsigned_word nia;\n"); + print_icache_body (file, + instruction, + expanded_bits, + cache_rules, + (options.gen.direct_access + ? define_variables + : declare_variables), + (options.gen.semantic_icache + ? both_values_and_icache + : put_values_in_icache), + nr_prefetched_words); + + lf_printf (file, "\n"); + lf_printf (file, "cache_entry->address = cia;\n"); + lf_printf (file, "cache_entry->semantic = "); + print_function_name (file, + instruction->name, + instruction->format_name, + NULL, + expanded_bits, + function_name_prefix_semantics); + lf_printf (file, ";\n"); + lf_printf (file, "\n"); + + if (options.gen.semantic_icache) { + lf_printf (file, "/* semantic routine */\n"); + print_semantic_body (file, + instruction, + expanded_bits, + opcodes); + lf_printf (file, "return nia;\n"); + } + + if (!options.gen.semantic_icache) + { + lf_printf (file, "/* return the function proper */\n"); + lf_printf (file, "return "); + print_function_name (file, + instruction->name, + instruction->format_name, + NULL, + expanded_bits, + function_name_prefix_semantics); + lf_printf (file, ";\n"); + } + + if (options.gen.direct_access) + { + print_icache_body (file, + instruction, + expanded_bits, + cache_rules, + undef_variables, + (options.gen.semantic_icache + ? both_values_and_icache + : put_values_in_icache), + nr_prefetched_words); + } + + lf_indent (file, -2); + lf_printf (file, "}\n"); + lf_indent (file, -2); + lf_printf (file, "}\n"); +} + + +void +print_icache_definition (lf *file, + insn_entry *insn, + opcode_bits *expanded_bits, + insn_opcodes *opcodes, + cache_entry *cache_rules, + int nr_prefetched_words) +{ + print_icache_function (file, + insn, + expanded_bits, + opcodes, + cache_rules, + nr_prefetched_words); +} + + + +void +print_icache_internal_function_declaration (lf *file, + function_entry *function, + void *data) +{ + ASSERT (options.gen.icache); + if (function->is_internal) + { + lf_printf (file, "\n"); + lf_print__function_type_function (file, print_icache_function_type, + "INLINE_ICACHE", "\n"); + print_function_name (file, + function->name, + NULL, + NULL, + NULL, + function_name_prefix_icache); + lf_printf (file, "\n("); + print_icache_function_formal (file, 0); + lf_printf (file, ");\n"); + } +} + + +void +print_icache_internal_function_definition (lf *file, + function_entry *function, + void *data) +{ + ASSERT (options.gen.icache); + if (function->is_internal) + { + lf_printf (file, "\n"); + lf_print__function_type_function (file, print_icache_function_type, + "INLINE_ICACHE", "\n"); + print_function_name (file, + function->name, + NULL, + NULL, + NULL, + function_name_prefix_icache); + lf_printf (file, "\n("); + print_icache_function_formal (file, 0); + lf_printf (file, ")\n"); + lf_printf (file, "{\n"); + lf_indent (file, +2); + lf_printf (file, "/* semantic routine */\n"); + if (options.gen.semantic_icache) + { + lf_print__line_ref (file, function->code->line); + table_print_code (file, function->code); + lf_printf (file, "error (\"Internal function must longjump\\n\");\n"); + lf_printf (file, "return 0;\n"); + } + else + { + lf_printf (file, "return "); + print_function_name (file, + function->name, + NULL, + NULL, + NULL, + function_name_prefix_semantics); + lf_printf (file, ";\n"); + } + + lf_print__internal_ref (file); + lf_indent (file, -2); + lf_printf (file, "}\n"); + } +} diff --git a/sim/igen/gen-icache.h b/sim/igen/gen-icache.h new file mode 100644 index 00000000000..34c73f62276 --- /dev/null +++ b/sim/igen/gen-icache.h @@ -0,0 +1,81 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-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. + + */ + + + +/* Output code to manipulate the instruction cache: either create it + or reference it */ + +typedef enum { + declare_variables, + define_variables, + undef_variables, +} icache_decl_type; + +typedef enum { + do_not_use_icache = 0, + get_values_from_icache = 0x1, + put_values_in_icache = 0x2, + both_values_and_icache = 0x3, +} icache_body_type; + +extern void print_icache_body +(lf *file, + insn_entry *instruction, + opcode_bits *expanded_bits, + cache_entry *cache_rules, + icache_decl_type what_to_declare, + icache_body_type what_to_do, + int nr_prefetched_words); + + +/* Output an instruction cache decode function */ + +extern void print_icache_declaration +(lf *file, + insn_entry *insn, + opcode_bits *expanded_bits, + insn_opcodes *opcodes, + int nr_prefetched_words); + +extern void print_icache_definition +(lf *file, + insn_entry *insn, + opcode_bits *expanded_bits, + insn_opcodes *opcodes, + cache_entry *cache_rules, + int nr_prefetched_words); + + +/* Output an instruction cache support function */ + +extern function_entry_handler print_icache_internal_function_declaration; +extern function_entry_handler print_icache_internal_function_definition; + + +/* Output the instruction cache table data structure */ + +extern void print_icache_struct +(lf *file, + insn_table *instructions, + cache_entry *cache_rules); + + +/* Output a single instructions decoder */ diff --git a/sim/igen/gen-idecode.c b/sim/igen/gen-idecode.c new file mode 100644 index 00000000000..a670e3d289b --- /dev/null +++ b/sim/igen/gen-idecode.c @@ -0,0 +1,1391 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, 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 "misc.h" +#include "lf.h" +#include "table.h" +#include "filter.h" +#include "igen.h" + +#include "ld-insn.h" +#include "ld-decode.h" + +#include "gen.h" + +#include "gen-idecode.h" +#include "gen-icache.h" +#include "gen-semantics.h" + + + +static void +lf_print_opcodes (lf *file, + gen_entry *table) +{ + if (table != NULL) + { + while (1) + { + ASSERT (table->opcode != NULL); + 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 +print_idecode_ifetch (lf *file, + int previous_nr_prefetched_words, + int current_nr_prefetched_words) +{ + int word_nr; + for (word_nr = previous_nr_prefetched_words; + word_nr < current_nr_prefetched_words; + word_nr ++) + { + lf_printf (file, "instruction_word instruction_%d = IMEM%d_IMMED (cia, %d);\n", + word_nr, options.insn_bit_size, word_nr); + + } +} + + + +/****************************************************************/ + + +static void +lf_print_table_name (lf *file, + gen_entry *table) +{ + lf_printf (file, "idecode_table"); + lf_print_opcodes (file, table); +} + + + +static void +print_idecode_table (lf *file, + gen_entry *entry, + const char *result) +{ + lf_printf (file, "/* prime the search */\n"); + lf_printf (file, "idecode_table_entry *table = "); + lf_print_table_name (file, entry); + lf_printf (file, ";\n"); + lf_printf (file, "int opcode = EXTRACTED%d (instruction, %d, %d);\n", + options.insn_bit_size, + i2target (options.hi_bit_nr, entry->opcode->first), + i2target (options.hi_bit_nr, entry->opcode->last)); + lf_printf (file, "idecode_table_entry *table_entry = table + opcode;\n"); + + lf_printf (file, "\n"); + lf_printf (file, "/* iterate until a leaf */\n"); + lf_printf (file, "while (1) {\n"); + lf_printf (file, " signed shift = table_entry->shift;\n"); + lf_printf (file, "if (shift == function_entry) break;\n"); + lf_printf (file, " if (shift >= 0) {\n"); + 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, " >> shift);\n"); + lf_printf (file, " table_entry = table + opcode;\n"); + lf_printf (file, " }\n"); + lf_printf (file, " else {\n"); + lf_printf (file, " /* must be a boolean */\n"); + lf_printf (file, " ASSERT(table_entry->shift == boolean_entry);\n"); + lf_printf (file, " opcode = ((instruction & table_entry->mask)\n"); + lf_printf (file, " != table_entry->value);\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_printf (file, " }\n"); + lf_printf (file, "}\n"); + + lf_printf (file, "\n"); + lf_printf (file, "/* call the leaf code */\n"); + if (options.gen.code == generate_jumps) + { + lf_printf (file, "goto *table_entry->function_or_table;\n"); + } + else + { + lf_printf (file, "%s ", result); + if (options.gen.icache) + { + lf_printf (file, "(((idecode_icache*)table_entry->function_or_table)\n"); + lf_printf (file, " ("); + print_icache_function_actual (file, 1); + lf_printf (file, "));\n"); + } + else + { + lf_printf (file, "((idecode_semantic*)table_entry->function_or_table)\n"); + lf_printf (file, " ("); + print_semantic_function_actual (file, 1); + lf_printf (file, ");\n"); + } + } +} + + +static void +print_idecode_table_start (lf *file, + gen_entry *table, + int depth, + void *data) +{ + ASSERT (depth == 0); + /* start of the table */ + if (table->opcode_rule->gen == array_gen) + { + lf_printf (file, "\n"); + lf_printf (file, "static idecode_table_entry "); + lf_print_table_name (file, table); + lf_printf (file, "[] = {\n"); + } +} + +static void +print_idecode_table_leaf (lf *file, + gen_entry *entry, + int depth, + void *data) +{ + gen_entry *master_entry; + ASSERT (entry->parent != NULL); + ASSERT (depth == 0); + if (entry->combined_parent == NULL) + master_entry = entry; + else + master_entry = entry->combined_parent; + + /* add an entry to the table */ + if (entry->parent->opcode_rule->gen == array_gen) + { + lf_printf (file, " /*%d*/ { ", entry->opcode_nr); + if (entry->opcode == NULL) + { + ASSERT (entry->nr_insns == 1); + /* table leaf entry */ + lf_printf (file, "function_entry, 0, 0, "); + if (options.gen.code == generate_jumps) + { + lf_printf (file, "&&"); + } + print_function_name (file, + entry->insns->insn->name, + entry->insns->insn->format_name, + NULL, + master_entry->expanded_bits, + (options.gen.icache + ? function_name_prefix_icache + : function_name_prefix_semantics)); + } + else if (entry->opcode_rule->gen == switch_gen + || entry->opcode_rule->gen == goto_switch_gen + || entry->opcode_rule->gen == padded_switch_gen) + { + /* table calling switch statement */ + lf_printf (file, "function_entry, 0, 0, "); + if (options.gen.code == generate_jumps) + { + lf_printf (file, "&&"); + } + lf_print_table_name (file, entry); + } + else if (entry->opcode->is_boolean) + { + /* table `calling' boolean table */ + lf_printf (file, "boolean_entry, "); + lf_printf (file, "MASK32(%d, %d), ", + i2target (options.hi_bit_nr, entry->opcode->first), + i2target (options.hi_bit_nr, entry->opcode->last)); + lf_printf (file, "INSERTED32(%d, %d, %d), ", + entry->opcode->boolean_constant, + i2target (options.hi_bit_nr, entry->opcode->first), + i2target (options.hi_bit_nr, entry->opcode->last)); + lf_print_table_name (file, entry); + } + else + { + /* table `calling' another table */ + lf_printf (file, "%d, ", options.insn_bit_size - entry->opcode->last - 1); + lf_printf (file, "MASK%d(%d,%d), ", + options.insn_bit_size, + i2target (options.hi_bit_nr, entry->opcode->first), + i2target (options.hi_bit_nr, entry->opcode->last)); + lf_printf (file, "0, "); + lf_print_table_name (file, entry); + } + lf_printf (file, " },\n"); + } +} + +static void +print_idecode_table_end (lf *file, + gen_entry *table, + int depth, + void *data) +{ + ASSERT (depth == 0); + if (table->opcode_rule->gen == array_gen) { + lf_printf (file, "};\n"); + } +} + +/****************************************************************/ + + +static void +print_goto_switch_name (lf *file, + gen_entry *entry) +{ + lf_printf (file, "case_"); + if (entry->opcode == NULL) + { + print_function_name (file, + entry->insns->insn->name, + entry->insns->insn->format_name, + NULL, + entry->expanded_bits, + (options.gen.icache + ? function_name_prefix_icache + : function_name_prefix_semantics)); + } + else + { + lf_print_table_name(file, entry); + } +} + +static void +print_goto_switch_table_leaf (lf *file, + gen_entry *entry, + int depth, + void *data) +{ + ASSERT (entry->parent != NULL); + ASSERT (depth == 0); + ASSERT (entry->parent->opcode_rule->gen == goto_switch_gen); + ASSERT (entry->parent->opcode); + + lf_printf (file, "/* %d */ &&", entry->opcode_nr); + if (entry->combined_parent != NULL) + print_goto_switch_name (file, entry->combined_parent); + else + print_goto_switch_name (file, entry); + lf_printf (file, ",\n"); +} + +static void +print_goto_switch_break (lf *file, + gen_entry *entry) +{ + lf_printf (file, "goto break_"); + lf_print_table_name (file, entry->parent); + lf_printf (file, ";\n"); +} + + +static void +print_goto_switch_table (lf *file, + gen_entry *table) +{ + lf_printf (file, "const static void *"); + lf_print_table_name (file, table); + lf_printf (file, "[] = {\n"); + lf_indent (file, +2); + gen_entry_traverse_tree (file, table, + 0, + NULL/*start*/, + print_goto_switch_table_leaf, + NULL/*end*/, + NULL/*data*/); + lf_indent (file, -2); + lf_printf (file, "};\n"); +} + + +void print_idecode_switch +(lf *file, + gen_entry *table, + const char *result); + +static void +print_idecode_switch_start (lf *file, + gen_entry *table, + int depth, + void *data) +{ + /* const char *result = data; */ + ASSERT (depth == 0); + ASSERT (table->opcode_rule->gen == switch_gen + || table->opcode_rule->gen == goto_switch_gen + || table->opcode_rule->gen == padded_switch_gen); + + if (table->opcode->is_boolean + || table->opcode_rule->gen == switch_gen + || table->opcode_rule->gen == padded_switch_gen) + { + lf_printf (file, "switch (EXTRACTED%d (instruction_%d, %d, %d))\n", + options.insn_bit_size, + table->opcode_rule->word_nr, + i2target (options.hi_bit_nr, table->opcode->first), + i2target (options.hi_bit_nr, table->opcode->last)); + lf_indent (file, +2); + lf_printf (file, "{\n"); + } + else if (table->opcode_rule->gen == goto_switch_gen) + { + if (table->parent != NULL + && (table->parent->opcode_rule->gen == switch_gen + || table->parent->opcode_rule->gen == goto_switch_gen + || table->parent->opcode_rule->gen == padded_switch_gen)) + { + lf_printf (file, "{\n"); + lf_indent (file, +2); + } + print_goto_switch_table (file, table); + lf_printf (file, "ASSERT (EXTRACTED%d (instruction_%d, %d, %d)\n", + options.insn_bit_size, + table->opcode->word_nr, + i2target (options.hi_bit_nr, table->opcode->first), + i2target (options.hi_bit_nr, table->opcode->last)); + lf_printf (file, " < (sizeof ("); + lf_print_table_name (file, table); + lf_printf (file, ") / sizeof(void*)));\n"); + lf_printf (file, "goto *"); + lf_print_table_name (file, table); + lf_printf (file, "[EXTRACTED%d (instruction_%d, %d, %d)];\n", + options.insn_bit_size, + table->opcode->word_nr, + i2target (options.hi_bit_nr, table->opcode->first), + i2target (options.hi_bit_nr, table->opcode->last)); + } + else + { + ASSERT("bad switch" == NULL); + } +} + + +static void +print_idecode_switch_leaf (lf *file, + gen_entry *entry, + int depth, + void *data) +{ + const char *result = data; + ASSERT (entry->parent != NULL); + ASSERT (depth == 0); + ASSERT (entry->parent->opcode_rule->gen == switch_gen + || entry->parent->opcode_rule->gen == goto_switch_gen + || entry->parent->opcode_rule->gen == padded_switch_gen); + ASSERT (entry->parent->opcode); + + /* skip over any instructions combined into another entry */ + if (entry->combined_parent != NULL) + return; + + if (entry->parent->opcode->is_boolean + && entry->opcode_nr == 0) + { + /* case: boolean false target */ + lf_printf (file, "case %d:\n", entry->parent->opcode->boolean_constant); + } + else if (entry->parent->opcode->is_boolean + && entry->opcode_nr != 0) + { + /* case: boolean true case */ + lf_printf (file, "default:\n"); + } + else if (entry->parent->opcode_rule->gen == switch_gen + || entry->parent->opcode_rule->gen == padded_switch_gen) + { + /* case: <opcode-nr> - switch */ + gen_entry *cob; + for (cob = entry; cob != NULL; cob = cob->combined_next) + lf_printf (file, "case %d:\n", cob->opcode_nr); + } + else if (entry->parent->opcode_rule->gen == goto_switch_gen) + { + /* case: <opcode-nr> - goto-switch */ + print_goto_switch_name (file, entry); + lf_printf (file, ":\n"); + } + else + { + ERROR ("bad switch"); + } + lf_printf (file, " {\n"); + lf_indent (file, +4); + { + if (entry->opcode == NULL) + { + /* switch calling leaf */ + ASSERT (entry->nr_insns == 1); + print_idecode_ifetch (file, entry->nr_prefetched_words, + entry->insns->semantic->nr_prefetched_words); + switch (options.gen.code) + { + case generate_jumps: + lf_printf (file, "goto "); + break; + case generate_calls: + lf_printf (file, "%s", result); + break; + } + print_function_name (file, + entry->insns->insn->name, + entry->insns->insn->format_name, + NULL, + entry->expanded_bits, + (options.gen.icache + ? function_name_prefix_icache + : function_name_prefix_semantics)); + if (options.gen.code == generate_calls) + { + lf_printf (file, " ("); + print_semantic_function_actual (file, entry->insns->semantic->nr_prefetched_words); + lf_printf (file, ")"); + } + lf_printf (file, ";\n"); + } + else if (entry->opcode_rule->gen == switch_gen + || entry->opcode_rule->gen == goto_switch_gen + || entry->opcode_rule->gen == padded_switch_gen) + { + /* switch calling switch */ + lf_printf (file, "{\n"); + lf_indent (file, +2); + print_idecode_ifetch (file, entry->parent->nr_prefetched_words, + entry->nr_prefetched_words); + print_idecode_switch (file, entry, result); + lf_indent (file, -2); + lf_printf (file, "}\n"); + } + else + { + /* switch looking up a table */ + lf_printf (file, "{\n"); + lf_indent (file, +2); + print_idecode_ifetch (file, entry->parent->nr_prefetched_words, + entry->nr_prefetched_words); + print_idecode_table (file, entry, result); + lf_indent (file, -2); + lf_printf (file, "}\n"); + } + if (entry->parent->opcode->is_boolean + || entry->parent->opcode_rule->gen == switch_gen + || entry->parent->opcode_rule->gen == padded_switch_gen) + { + lf_printf (file, "break;\n"); + } + else if (entry->parent->opcode_rule->gen == goto_switch_gen) + { + print_goto_switch_break(file, entry); + } + else + { + ERROR ("bad switch"); + } + } + lf_indent (file, -4); + lf_printf (file, " }\n"); +} + + +static void +print_idecode_switch_illegal (lf *file, + const char *result) +{ + lf_indent (file, +2); + print_idecode_invalid (file, result, invalid_illegal); + lf_printf (file, "break;\n"); + lf_indent (file, -2); +} + +static void +print_idecode_switch_end (lf *file, + gen_entry *table, + int depth, + void *data) +{ + const char *result = data; + ASSERT (depth == 0); + ASSERT (table->opcode_rule->gen == switch_gen + || table->opcode_rule->gen == goto_switch_gen + || table->opcode_rule->gen == padded_switch_gen); + ASSERT (table->opcode); + + if (table->opcode->is_boolean) + { + lf_printf (file, "}\n"); + lf_indent (file, -2); + } + else if (table->opcode_rule->gen == switch_gen + || table->opcode_rule->gen == padded_switch_gen) + { + lf_printf (file, "default:\n"); + lf_indent (file, +2); + if (table->nr_entries == table->opcode->nr_opcodes) + { + print_sim_engine_abort (file, "Internal error - bad switch generated"); + lf_printf (file, "%sNULL_CIA;\n", result); + lf_printf (file, "break;\n"); + } + else + { + print_idecode_switch_illegal (file, result); + } + lf_indent (file, -2); + lf_printf (file, "}\n"); + lf_indent (file, -2); + } + else if (table->opcode_rule->gen == goto_switch_gen) + { + lf_printf (file, "illegal_"); + lf_print_table_name (file, table); + lf_printf (file, ":\n"); + print_idecode_invalid (file, result, invalid_illegal); + lf_printf (file, "break_"); + lf_print_table_name(file, table); + lf_printf (file, ":;\n"); + if (table->parent != NULL + && (table->parent->opcode_rule->gen == switch_gen + || table->parent->opcode_rule->gen == goto_switch_gen + || table->parent->opcode_rule->gen == padded_switch_gen)) + { + lf_indent (file, -2); + lf_printf (file, "}\n"); + } + } + else + { + ERROR ("bad switch"); + } +} + + +void +print_idecode_switch (lf *file, + gen_entry *table, + const char *result) +{ + gen_entry_traverse_tree (file, table, + 0, + print_idecode_switch_start, + print_idecode_switch_leaf, + print_idecode_switch_end, + (void*)result); +} + + +static void +print_idecode_switch_function_header (lf *file, + gen_entry *table, + int is_function_definition, + int nr_prefetched_words) +{ + lf_printf (file, "\n"); + if (options.gen.code == generate_calls) + { + lf_printf (file, "static "); + if (options.gen.icache) + { + lf_printf (file, "idecode_semantic *"); + } + else + { + lf_printf (file, "unsigned_word"); + } + if (is_function_definition) + { + lf_printf (file, "\n"); + } + else + { + lf_printf (file, " "); + } + lf_print_table_name (file, table); + lf_printf (file, "\n("); + print_icache_function_formal (file, nr_prefetched_words); + lf_printf (file, ")"); + if (!is_function_definition) + { + lf_printf (file, ";"); + } + lf_printf (file, "\n"); + } + if (options.gen.code == generate_jumps && is_function_definition) + { + lf_indent (file, -1); + lf_print_table_name (file, table); + lf_printf (file, ":\n"); + lf_indent (file, +1); + } +} + + +static void +idecode_declare_if_switch (lf *file, + gen_entry *table, + int depth, + void *data) +{ + if ((table->opcode_rule->gen == switch_gen + || table->opcode_rule->gen == goto_switch_gen + || table->opcode_rule->gen == padded_switch_gen) + && table->parent != NULL /* don't declare the top one yet */ + && table->parent->opcode_rule->gen == array_gen) + { + print_idecode_switch_function_header (file, + table, + 0/*isnt function definition*/, + 0); + } +} + + +static void +idecode_expand_if_switch (lf *file, + gen_entry *table, + int depth, + void *data) +{ + if ((table->opcode_rule->gen == switch_gen + || table->opcode_rule->gen == goto_switch_gen + || table->opcode_rule->gen == padded_switch_gen) + && table->parent != NULL /* don't expand the top one yet */ + && table->parent->opcode_rule->gen == array_gen) + { + print_idecode_switch_function_header(file, + table, + 1/*is function definition*/, + 0); + if (options.gen.code == generate_calls) + { + lf_printf (file, "{\n"); + lf_indent (file, +2); + } + print_idecode_switch(file, table, "return"); + if (options.gen.code == generate_calls) + { + lf_indent (file, -2); + lf_printf (file, "}\n"); + } + } +} + + +/****************************************************************/ + + +void +print_idecode_lookups (lf *file, + gen_entry *table, + cache_entry *cache_rules) +{ + int depth; + + /* output switch function declarations where needed by tables */ + gen_entry_traverse_tree (file, table, + 1, + idecode_declare_if_switch, /* START */ + NULL, NULL, + NULL); + + /* output tables where needed */ + for (depth = gen_entry_depth (table); + depth > 0; + depth--) + { + gen_entry_traverse_tree (file, table, + 1-depth, + print_idecode_table_start, + print_idecode_table_leaf, + print_idecode_table_end, + NULL); + } + + /* output switch functions where needed */ + gen_entry_traverse_tree (file, table, + 1, + idecode_expand_if_switch, /* START */ + NULL, NULL, + NULL); +} + + +void +print_idecode_body (lf *file, + gen_entry *table, + const char *result) +{ + if (table->opcode_rule->gen == switch_gen + || table->opcode_rule->gen == goto_switch_gen + || table->opcode_rule->gen == padded_switch_gen) + { + print_idecode_switch (file, table, result); + } + else + { + print_idecode_table (file, table, result); + } +} + + +/****************************************************************/ + +#if 0 +static void +print_jump (lf *file, + int is_tail) +{ + if (is_tail) + { + lf_putstr (file, "if (keep_running != NULL && !*keep_running)\n"); + lf_putstr (file, " cpu_halt(cpu, nia, was_continuing, 0/*na*/);\n"); + } + + if (!options.generate_smp) + { + lf_putstr (file, "if (WITH_EVENTS) {\n"); + lf_putstr (file, " if (event_queue_tick(events)) {\n"); + lf_putstr (file, " cpu_set_program_counter(cpu, nia);\n"); + lf_putstr (file, " event_queue_process(events);\n"); + lf_putstr (file, " nia = cpu_get_program_counter(cpu);\n"); + lf_putstr (file, " }\n"); + lf_putstr (file, "}\n"); + } + + if (options.generate_smp) + { + if (is_tail) + { + lf_putstr (file, "cpu_set_program_counter(cpu, nia);\n"); + } + lf_putstr (file, "if (WITH_EVENTS) {\n"); + lf_putstr (file, " current_cpu += 1;\n"); + lf_putstr (file, " if (current_cpu >= nr_cpus) {\n"); + lf_putstr (file, " if (event_queue_tick(events)) {\n"); + lf_putstr (file, " event_queue_process(events);\n"); + lf_putstr (file, " }\n"); + lf_putstr (file, " current_cpu = 0;\n"); + lf_putstr (file, " }\n"); + lf_putstr (file, "}\n"); + lf_putstr (file, "else {\n"); + lf_putstr (file, " current_cpu = (current_cpu + 1) % nr_cpus;\n"); + lf_putstr (file, "}\n"); + lf_putstr (file, "cpu = cpus[current_cpu];\n"); + lf_putstr (file, "nia = cpu_get_program_counter(cpu);\n"); + } + + if (options.gen.icache) + { + lf_putstr (file, "cache_entry = cpu_icache_entry(cpu, nia);\n"); + lf_putstr (file, "if (cache_entry->address == nia) {\n"); + lf_putstr (file, " /* cache hit */\n"); + lf_putstr (file, " goto *cache_entry->semantic;\n"); + lf_putstr (file, "}\n"); + if (is_tail) + { + lf_putstr (file, "goto cache_miss;\n"); + } + } + + if (!options.gen.icache && is_tail) + { + lf_printf (file, "goto idecode;\n"); + } + +} +#endif + + + +#if 0 +static void +print_jump_insn (lf *file, + insn_entry *instruction, + insn_bits *expanded_bits, + opcode_field *opcodes, + cache_entry *cache_rules) +{ + + /* what we are for the moment */ + lf_printf (file, "\n"); + print_my_defines (file, expanded_bits, instruction->name); + + /* output the icache entry */ + if (options.gen.icache) + { + lf_printf (file, "\n"); + lf_indent (file, -1); + print_function_name (file, + instruction->name, + expanded_bits, + function_name_prefix_icache); + lf_printf (file, ":\n"); + lf_indent (file, +1); + lf_printf (file, "{\n"); + lf_indent (file, +2); + lf_putstr (file, "const unsigned_word cia = nia;\n"); + print_itrace (file, instruction, 1/*putting-value-in-cache*/); + print_idecode_validate (file, instruction, opcodes); + lf_printf (file, "\n"); + lf_printf (file, "{\n"); + lf_indent (file, +2); + print_icache_body (file, + instruction, + expanded_bits, + cache_rules, + 0, /*use_defines*/ + put_values_in_icache); + lf_printf (file, "cache_entry->address = nia;\n"); + lf_printf (file, "cache_entry->semantic = &&"); + print_function_name (file, + instruction->name, + expanded_bits, + function_name_prefix_semantics); + lf_printf (file, ";\n"); + if (options.gen.semantic_icache) + { + print_semantic_body (file, + instruction, + expanded_bits, + opcodes); + print_jump (file, 1/*is-tail*/); + } + else + { + lf_printf (file, "/* goto "); + print_function_name (file, + instruction->name, + expanded_bits, + function_name_prefix_semantics); + lf_printf (file, "; */\n"); + } + lf_indent (file, -2); + lf_putstr (file, "}\n"); + lf_indent (file, -2); + lf_printf (file, "}\n"); + } + + /* print the semantics */ + lf_printf (file, "\n"); + lf_indent (file, -1); + print_function_name (file, + instruction->name, + expanded_bits, + function_name_prefix_semantics); + lf_printf (file, ":\n"); + lf_indent (file, +1); + lf_printf (file, "{\n"); + lf_indent (file, +2); + lf_putstr (file, "const unsigned_word cia = nia;\n"); + print_icache_body (file, + instruction, + expanded_bits, + cache_rules, + (options.gen.direct_access + ? define_variables + : declare_variables), + (options.gen.icache + ? get_values_from_icache + : do_not_use_icache)); + print_semantic_body (file, + instruction, + expanded_bits, + opcodes); + if (options.gen.direct_access) + print_icache_body (file, + instruction, + expanded_bits, + cache_rules, + undef_variables, + (options.gen.icache + ? get_values_from_icache + : do_not_use_icache)); + print_jump (file, 1/*is tail*/); + lf_indent (file, -2); + lf_printf (file, "}\n"); +} +#endif + + +#if 0 +static void +print_jump_definition (lf *file, + gen_entry *entry, + insn_entry *insn, + int depth, + void *data) +{ + cache_entry *cache_rules = (cache_entry*)data; + if (options.generate_expanded_instructions) + { + ASSERT (entry->nr_insns == 1 + && entry->opcode == NULL + && entry->parent != NULL + && entry->parent->opcode != NULL); + ASSERT (entry->nr_insns == 1 + && entry->opcode == NULL + && entry->parent != NULL + && entry->parent->opcode != NULL + && entry->parent->opcode_rule != NULL); + print_jump_insn (file, + entry->insns->words[0]->insn, + entry->expanded_bits, + entry->opcode, + cache_rules); + } + else + { + print_jump_insn (file, + instruction->words[0]->insn, + NULL, + NULL, + cache_rules); + } +} +#endif + +#if 0 +static void +print_jump_internal_function (lf *file, + gen_entry *table, + function_entry *function, + void *data) +{ + if (function->is_internal) + { + lf_printf (file, "\n"); + lf_print__line_ref (file, function->line); + lf_indent (file, -1); + print_function_name (file, + function->name, + NULL, + (options.gen.icache + ? function_name_prefix_icache + : function_name_prefix_semantics)); + lf_printf (file, ":\n"); + lf_indent (file, +1); + lf_printf (file, "{\n"); + lf_indent (file, +2); + lf_printf (file, "const unsigned_word cia = nia;\n"); + table_print_code (file, function->code); + lf_print__internal_ref (file); + print_sim_engine_abort (file, "Internal function must longjump"); + lf_indent (file, -2); + lf_printf (file, "}\n"); + } +} +#endif + + + +#if 0 +static void +print_jump_until_stop_body(lf *file, + insn_table *table, + cache_table *cache_rules) +{ + lf_printf (file, "{\n"); + lf_indent (file, +2); + lf_putstr (file, "jmp_buf halt;\n"); + lf_putstr (file, "jmp_buf restart;\n"); + lf_putstr (file, "sim_cpu *cpu = NULL;\n"); + lf_putstr (file, "unsigned_word nia = -1;\n"); + lf_putstr (file, "instruction_word instruction = 0;\n"); + if ((code & generate_with_icache)) { + lf_putstr (file, "idecode_cache *cache_entry = NULL;\n"); + } + if (generate_smp) { + lf_putstr (file, "int current_cpu = -1;\n"); + } + + /* all the switches and tables - they know about jumping */ + print_idecode_lookups(file, table, cache_rules); + + /* start the simulation up */ + if ((code & generate_with_icache)) { + lf_putstr (file, "\n"); + lf_putstr (file, "{\n"); + lf_putstr (file, " int cpu_nr;\n"); + lf_putstr (file, " for (cpu_nr = 0; cpu_nr < nr_cpus; cpu_nr++)\n"); + lf_putstr (file, " cpu_flush_icache(cpus[cpu_nr]);\n"); + lf_putstr (file, "}\n"); + } + + lf_putstr (file, "\n"); + lf_putstr (file, "psim_set_halt_and_restart(system, &halt, &restart);\n"); + + lf_putstr (file, "\n"); + lf_putstr (file, "if (setjmp(halt))\n"); + lf_putstr (file, " return;\n"); + + lf_putstr (file, "\n"); + lf_putstr (file, "setjmp(restart);\n"); + + lf_putstr (file, "\n"); + if (!generate_smp) { + lf_putstr (file, "cpu = cpus[0];\n"); + lf_putstr (file, "nia = cpu_get_program_counter(cpu);\n"); + } + else { + lf_putstr (file, "current_cpu = psim_last_cpu(system);\n"); + } + + if (!(code & generate_with_icache)) { + lf_printf (file, "\n"); + lf_indent (file, -1); + lf_printf (file, "idecode:\n"); + lf_indent (file, +1); + } + + print_jump(file, 0/*is_tail*/); + + if ((code & generate_with_icache)) { + lf_indent (file, -1); + lf_printf (file, "cache_miss:\n"); + lf_indent (file, +1); + } + + lf_putstr (file, "instruction\n"); + lf_putstr (file, " = vm_instruction_map_read(cpu_instruction_map(cpu),\n"); + lf_putstr (file, " cpu, nia);\n"); + print_idecode_body(file, table, "/*IGORE*/"); + + /* print out a table of all the internals functions */ + insn_table_traverse_function(table, + file, NULL, + print_jump_internal_function); + + /* print out a table of all the instructions */ + if (generate_expanded_instructions) + insn_table_traverse_tree(table, + file, cache_rules, + 1, + NULL, /* start */ + print_jump_definition, /* leaf */ + NULL, /* end */ + NULL); /* padding */ + else + insn_table_traverse_insn(table, + file, cache_rules, + print_jump_definition); + lf_indent (file, -2); + lf_printf (file, "}\n"); +} +#endif + +/****************************************************************/ + + + +/* 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 */ + +void +print_idecode_validate (lf *file, + insn_entry *instruction, + insn_opcodes *opcode_paths) +{ + /* 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 */ + { + int nr_checks = 0; + int word_nr; + lf_printf (file, "\n"); + lf_indent_suppress (file); + lf_printf (file, "#if defined (WITH_RESERVED_BITS)\n"); + lf_printf (file, "/* validate: "); + print_insn_words (file, instruction); + lf_printf (file, " */\n"); + for (word_nr = 0; word_nr < instruction->nr_words; word_nr++) + { + insn_uint check_mask = 0; + insn_uint check_val = 0; + insn_word_entry *word = instruction->word[word_nr]; + int bit_nr; + + /* form check_mask/check_val containing what needs to be checked + in the instruction */ + for (bit_nr = 0; bit_nr < options.insn_bit_size; bit_nr++) + { + insn_bit_entry *bit = word->bit[bit_nr]; + insn_field_entry *field = bit->field; + + /* Make space for the next bit */ + check_mask <<= 1; + check_val <<= 1; + + /* Only need to validate constant (and reserved) + bits. Skip any others */ + if (field->type != insn_field_int + && field->type != insn_field_reserved) + continue; + + /* Look through the list of opcode paths that lead to this + instruction. See if any have failed to check the + relevant bit */ + if (opcode_paths != NULL) + { + insn_opcodes *entry; + for (entry = opcode_paths; + entry != NULL; + entry = entry->next) + { + opcode_field *opcode; + for (opcode = entry->opcode; + opcode != NULL; + opcode = opcode->parent) + { + if (opcode->word_nr == word_nr + && opcode->first <= bit_nr + && opcode->last >= bit_nr) + /* we've decoded on this bit */ + break; + } + if (opcode == NULL) + /* the bit wasn't decoded on */ + break; + } + if (entry == NULL) + /* all the opcode paths decoded on BIT_NR, no need + to check it */ + continue; + } + + check_mask |= 1; + check_val |= bit->value; + } + + /* if any bits not checked by opcode tables, output code to check them */ + if (check_mask) + { + if (nr_checks == 0) + { + lf_printf (file, "if (WITH_RESERVED_BITS)\n"); + lf_printf (file, " {\n"); + lf_indent (file, +4); + } + nr_checks ++; + if (options.insn_bit_size > 32) + { + lf_printf (file, "if ((instruction_%d\n", word_nr); + lf_printf (file, " & UNSIGNED64 (0x%08lx%08lx))\n", + (unsigned long)(check_mask >> 32), + (unsigned long)(check_mask)); + lf_printf (file, " != UNSIGNED64 (0x%08lx%08lx))\n", + (unsigned long)(check_val >> 32), + (unsigned long)(check_val)); + } + else + { + lf_printf (file, "if ((instruction_%d & 0x%08lx) != 0x%08lx)\n", + word_nr, + (unsigned long)(check_mask), + (unsigned long)(check_val)); + } + lf_indent (file, +2); + print_idecode_invalid (file, "return", invalid_illegal); + lf_indent (file, -2); + } + } + if (nr_checks > 0) + { + lf_indent (file, -4); + lf_printf (file, " }\n"); + } + lf_indent_suppress(file); + lf_printf (file, "#endif\n"); + } + + /* 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 (filter_is_member (instruction->flags, "f")) + { + lf_printf (file, "\n"); + lf_indent_suppress (file); + lf_printf (file, "#if defined(CURRENT_FLOATING_POINT)\n"); + lf_printf (file, "/* Validate: FP hardware exists */\n"); + lf_printf (file, "if (CURRENT_FLOATING_POINT != HARD_FLOATING_POINT) {\n"); + lf_indent (file, +2); + print_idecode_invalid (file, "return", invalid_illegal); + lf_indent (file, -2); + lf_printf (file, "}\n"); + lf_indent_suppress (file); + lf_printf (file, "#endif\n"); + } + } + + /* 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 (filter_is_member (instruction->flags, "f")) + { + lf_printf (file, "\n"); + lf_indent_suppress (file); + lf_printf (file, "#if defined(IS_FP_AVAILABLE)\n"); + lf_printf (file, "/* Validate: FP available according to cpu */\n"); + lf_printf (file, "if (!IS_FP_AVAILABLE) {\n"); + lf_indent (file, +2); + print_idecode_invalid (file, "return", invalid_fp_unavailable); + lf_indent (file, -2); + lf_printf (file, "}\n"); + lf_indent_suppress (file); + lf_printf (file, "#endif\n"); + } + } + + /* Validate: Validate Instruction in correct slot + + Some architectures place restrictions on the slot that an + instruction can be issued in */ + + { + if (filter_is_member (instruction->options, "s") + || options.gen.slot_verification) + { + lf_printf (file, "\n"); + lf_indent_suppress (file); + lf_printf (file, "#if defined(IS_WRONG_SLOT)\n"); + lf_printf (file, "/* Validate: Instruction issued in correct slot */\n"); + lf_printf (file, "if (IS_WRONG_SLOT) {\n"); + lf_indent (file, +2); + print_idecode_invalid (file, "return", invalid_wrong_slot); + lf_indent (file, -2); + lf_printf (file, "}\n"); + lf_indent_suppress (file); + lf_printf (file, "#endif\n"); + } + } + +} + + +/****************************************************************/ + + +void +print_idecode_issue_function_header (lf *file, + const char *processor, + function_decl_type decl_type, + int nr_prefetched_words) +{ + int indent; + lf_printf (file, "\n"); + switch (decl_type) + { + case is_function_declaration: + lf_print__function_type_function (file, print_semantic_function_type, + "INLINE_IDECODE", + " "); + break; + case is_function_definition: + lf_print__function_type_function (file, print_semantic_function_type, + "INLINE_IDECODE", + "\n"); + break; + case is_function_variable: + print_semantic_function_type (file); + lf_printf (file, " (*"); + break; + } + indent = print_function_name (file, + "issue", + NULL, + processor, + NULL, + function_name_prefix_idecode); + switch (decl_type) + { + case is_function_definition: + indent += lf_printf (file, " ("); + break; + case is_function_declaration: + lf_putstr (file, "\n("); + indent = 1; + break; + case is_function_variable: + lf_putstr (file, ")\n("); + indent = 1; + break; + } + lf_indent (file, +indent); + print_semantic_function_formal (file, nr_prefetched_words); + lf_putstr (file, ")"); + lf_indent (file, -indent); + switch (decl_type) + { + case is_function_definition: + lf_printf (file, "\n"); + break; + case is_function_declaration: + case is_function_variable: + lf_putstr (file, ";\n"); + break; + } +} + + + +void +print_idecode_globals (lf *file) +{ + lf_printf (file, "enum {\n"); + lf_printf (file, " /* greater or equal to zero => table */\n"); + lf_printf (file, " function_entry = -1,\n"); + lf_printf (file, " boolean_entry = -2,\n"); + lf_printf (file, "};\n"); + lf_printf (file, "\n"); + lf_printf (file, "typedef struct _idecode_table_entry {\n"); + lf_printf (file, " int shift;\n"); + lf_printf (file, " unsigned%d mask;\n", options.insn_bit_size); + lf_printf (file, " unsigned%d value;\n", options.insn_bit_size); + lf_printf (file, " void *function_or_table;\n"); + lf_printf (file, "} idecode_table_entry;\n"); +} diff --git a/sim/igen/gen-idecode.h b/sim/igen/gen-idecode.h new file mode 100644 index 00000000000..c660904602d --- /dev/null +++ b/sim/igen/gen-idecode.h @@ -0,0 +1,50 @@ +/* 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. + + */ + +void print_idecode_issue_function_header +(lf *file, + const char *processor, + function_decl_type decl_type, + int nr_prefetched_words); + +void print_idecode_globals +(lf *file); + +void print_idecode_lookups +(lf *file, + gen_entry *table, + cache_entry *cache_rules); + +void print_idecode_body +(lf *file, + gen_entry *table, + const char *result); + + + +/* 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 */ + +extern void print_idecode_validate +(lf *file, + insn_entry *instruction, + insn_opcodes *opcode_paths); diff --git a/sim/igen/gen-itable.c b/sim/igen/gen-itable.c new file mode 100644 index 00000000000..c3e90535683 --- /dev/null +++ b/sim/igen/gen-itable.c @@ -0,0 +1,317 @@ +/* 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 "misc.h" +#include "lf.h" +#include "table.h" +#include "filter.h" +#include "igen.h" + +#include "ld-insn.h" +#include "ld-decode.h" + +#include "gen.h" + +#include "gen-itable.h" + +#ifndef NULL +#define NULL 0 +#endif + + + +typedef struct _itable_info { + int sizeof_form; + int sizeof_name; + int sizeof_file; +} itable_info; + + +static void +itable_h_insn (lf *file, + insn_table *entry, + insn_entry *instruction, + void *data) +{ + int len; + itable_info *info = data; + lf_print__line_ref (file, instruction->line); + lf_printf (file, " "); + print_function_name (file, + instruction->name, + instruction->format_name, + NULL, + NULL, + function_name_prefix_itable); + lf_printf (file, ",\n"); + /* update summary info */ + len = strlen (instruction->format_name); + if (info->sizeof_form <= len) + info->sizeof_form = len + 1; + len = strlen (instruction->name); + if (info->sizeof_name <= len) + info->sizeof_name = len + 1; + len = strlen (filter_filename (instruction->line->file_name)); + if (info->sizeof_file <= len) + info->sizeof_file = len + 1; +} + + +/* print the list of all the different options */ + +static void +itable_print_enum (lf *file, + filter *set, + char *name) +{ + char *elem; + lf_printf (file, "typedef enum {\n"); + lf_indent (file, +2); + for (elem = filter_next (set, ""); + elem != NULL; + elem = filter_next (set, elem)) + { + lf_printf (file, "%sitable_%s_%s,\n", + options.module.itable.prefix.l, name, elem); + if (strlen (options.module.itable.prefix.l) > 0) + { + lf_indent_suppress (file); + lf_printf (file, "#define itable_%s_%s %sitable_%s_%s\n", + name, elem, options.module.itable.prefix.l, name, elem); + } + } + lf_printf (file, "nr_%sitable_%ss,\n", options.module.itable.prefix.l, name); + + lf_indent (file, -2); + lf_printf (file, "} %sitable_%ss;\n", options.module.itable.prefix.l, name); + if (strlen (options.module.itable.prefix.l) > 0) + { + lf_indent_suppress (file); + lf_printf (file, "#define itable_%ss %sitable_%ss\n", + name, options.module.itable.prefix.l, name); + lf_indent_suppress (file); + lf_printf (file, "#define nr_itable_%ss nr_%sitable_%ss\n", + name, options.module.itable.prefix.l, name); + } +} + +/* print an array of the option names as strings */ + +static void +itable_print_names (lf *file, + filter *set, + char *name) +{ + char *elem; + lf_printf (file, "const char *%sitable_%s_names[nr_%sitable_%ss + 1] = {\n", + options.module.itable.prefix.l, name, + options.module.itable.prefix.l, name); + lf_indent (file, +2); + for (elem = filter_next (set, ""); + elem != NULL; + elem = filter_next (set, elem)) + { + lf_printf (file, "\"%s\",\n", elem); + } + lf_printf (file, "0,\n"); + lf_indent (file, -2); + lf_printf (file, "};\n"); +} + +extern void +gen_itable_h (lf *file, + insn_table *isa) +{ + itable_info *info = ZALLOC (itable_info); + + /* output an enumerated type for each instruction */ + lf_printf (file, "typedef enum {\n"); + insn_table_traverse_insn (file, isa, itable_h_insn, info); + lf_printf (file, " nr_%sitable_entries,\n", options.module.itable.prefix.l); + lf_printf (file, "} %sitable_index;\n", options.module.itable.prefix.l); + lf_printf (file, "\n"); + + /* output an enumeration type for each flag */ + itable_print_enum (file, isa->flags, "flag"); + lf_printf (file, "extern const char *%sitable_flag_names[];\n", + options.module.itable.prefix.l); + lf_printf (file, "\n"); + + /* output an enumeration of all the possible options */ + itable_print_enum (file, isa->options, "option"); + lf_printf (file, "extern const char *%sitable_option_names[];\n", + options.module.itable.prefix.l); + lf_printf (file, "\n"); + + /* output an enumeration of all the processor models */ + itable_print_enum (file, isa->model->processors, "processor"); + lf_printf (file, "extern const char *%sitable_processor_names[];\n", + options.module.itable.prefix.l); + lf_printf (file, "\n"); + + /* output the table that contains the actual instruction info */ + lf_printf (file, "typedef struct _%sitable_instruction_info {\n", + options.module.itable.prefix.l); + lf_printf (file, " %sitable_index nr;\n", options.module.itable.prefix.l); + lf_printf (file, " char *format;\n"); + lf_printf (file, " char *form;\n"); + lf_printf (file, " char *flags;\n"); + + /* nr_itable_* may be zero, so we add 1 to avoid an + illegal zero-sized array. */ + lf_printf (file, " char flag[nr_%sitable_flags + 1];\n", + options.module.itable.prefix.l); + lf_printf (file, " char *options;\n"); + lf_printf (file, " char option[nr_%sitable_options + 1];\n", + options.module.itable.prefix.l); + lf_printf (file, " char *processors;\n"); + lf_printf (file, " char processor[nr_%sitable_processors + 1];\n", + options.module.itable.prefix.l); + lf_printf (file, " char *name;\n"); + lf_printf (file, " char *file;\n"); + lf_printf (file, " int line_nr;\n"); + lf_printf (file, "} %sitable_info;\n", options.module.itable.prefix.l); + lf_printf (file, "\n"); + lf_printf (file, "extern %sitable_info %sitable[nr_%sitable_entries];\n", + options.module.itable.prefix.l, options.module.itable.prefix.l, + options.module.itable.prefix.l); + if (strlen (options.module.itable.prefix.l) > 0) + { + lf_indent_suppress (file); + lf_printf (file, "#define itable %sitable\n", + options.module.itable.prefix.l); + } + lf_printf (file, "\n"); + + /* output an enum defining the max size of various itable members */ + lf_printf (file, "enum {\n"); + lf_printf (file, " sizeof_%sitable_form = %d,\n", + options.module.itable.prefix.l, info->sizeof_form); + lf_printf (file, " sizeof_%sitable_name = %d,\n", + options.module.itable.prefix.l, info->sizeof_name); + lf_printf (file, " sizeof_%sitable_file = %d,\n", + options.module.itable.prefix.l, info->sizeof_file); + lf_printf (file, "};\n"); +} + + +/****************************************************************/ + +static void +itable_print_set (lf *file, + filter *set, + filter *members) +{ + char *elem; + lf_printf (file, "\""); + elem = filter_next (members, ""); + if (elem != NULL) + { + while (1) + { + lf_printf (file, "%s", elem); + elem = filter_next (members, elem); + if (elem == NULL) + break; + lf_printf (file, ","); + } + } + lf_printf (file, "\",\n"); + + lf_printf(file, "{"); + for (elem = filter_next (set, ""); + elem != NULL; + elem = filter_next (set, elem)) + { + if (filter_is_member (members, elem)) + { + lf_printf (file, " 1,"); + } + else + { + lf_printf (file, " 0,"); + } + + } + /* always print a dummy element, to avoid empty initializers. */ + lf_printf(file, " 99 },\n"); +} + + +static void +itable_c_insn (lf *file, + insn_table *isa, + insn_entry *instruction, + void *data) +{ + lf_printf (file, "{ "); + lf_indent (file, +2); + print_function_name (file, + instruction->name, + instruction->format_name, + NULL, + NULL, + function_name_prefix_itable); + lf_printf (file, ",\n"); + lf_printf (file, "\""); + print_insn_words (file, instruction); + lf_printf (file, "\",\n"); + lf_printf (file, "\"%s\",\n", instruction->format_name); + + itable_print_set (file, isa->flags, instruction->flags); + itable_print_set (file, isa->options, instruction->options); + itable_print_set (file, isa->model->processors, instruction->processors); + + lf_printf(file, "\"%s\",\n", instruction->name); + lf_printf(file, "\"%s\",\n", + filter_filename (instruction->line->file_name)); + lf_printf(file, "%d,\n", instruction->line->line_nr); + lf_printf(file, "},\n"); + lf_indent (file, -2); +} + + +extern void +gen_itable_c (lf *file, + insn_table *isa) +{ + /* leader */ + lf_printf(file, "#include \"%sitable.h\"\n", options.module.itable.prefix.l); + lf_printf(file, "\n"); + + /* FIXME - output model data??? */ + /* FIXME - output assembler data??? */ + + /* output the flag, option and processor name tables */ + itable_print_names (file, isa->flags, "flag"); + itable_print_names (file, isa->options, "option"); + itable_print_names (file, isa->model->processors, "processor"); + + /* output the table that contains the actual instruction info */ + lf_printf (file, "%sitable_info %sitable[nr_%sitable_entries] = {\n", + options.module.itable.prefix.l, + options.module.itable.prefix.l, + options.module.itable.prefix.l); + insn_table_traverse_insn (file, isa, itable_c_insn, NULL); + + lf_printf(file, "};\n"); +} diff --git a/sim/igen/gen-itable.h b/sim/igen/gen-itable.h new file mode 100644 index 00000000000..36c8659c7b8 --- /dev/null +++ b/sim/igen/gen-itable.h @@ -0,0 +1,30 @@ +/* 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. + + */ + + +/* Output a table of all the instructions */ + +extern void gen_itable_h +(lf *file, + insn_table *table); + +extern void gen_itable_c +(lf *file, + insn_table *table); diff --git a/sim/igen/gen-model.c b/sim/igen/gen-model.c new file mode 100644 index 00000000000..dcb300a59ef --- /dev/null +++ b/sim/igen/gen-model.c @@ -0,0 +1,416 @@ +/* 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 "misc.h" +#include "lf.h" +#include "table.h" + +#include "filter.h" + +#include "ld-decode.h" +#include "ld-insn.h" + +#include "gen-model.h" + +#ifndef NULL +#define NULL 0 +#endif + + +#if 0 +static void +model_c_or_h_data(insn_table *table, + lf *file, + table_entry *data) +{ + if (data->annex) { + table_entry_print_cpp_line_nr(file, data->annex_line); + lf_print__c_code(file, data->annex); + lf_print__internal_reference(file); + lf_printf(file, "\n"); + } +} + +static void +model_c_or_h_function(insn_table *entry, + lf *file, + table_entry *function, + char *prefix) +{ + if (function->fields[function_type] == NULL + || function->fields[function_type][0] == '\0') { + error("Model function type not specified for %s", function->fields[function_name]); + } + lf_printf(file, "\n"); + lf_print_function_type(file, function->fields[function_type], prefix, " "); + lf_printf(file, "%s\n(%s);\n", + function->fields[function_name], + function->fields[function_param]); + lf_printf(file, "\n"); +} + +void +gen_model_h(insn_table *table, lf *file) +{ + insn *insn_ptr; + model *model_ptr; + insn *macro; + char *name; + int model_create_p = 0; + int model_init_p = 0; + int model_halt_p = 0; + int model_mon_info_p = 0; + int model_mon_info_free_p = 0; + + for(macro = model_macros; macro; macro = macro->next) { + model_c_or_h_data(table, file, macro->file_entry); + } + + lf_printf(file, "typedef enum _model_enum {\n"); + lf_printf(file, " MODEL_NONE,\n"); + for (model_ptr = models; model_ptr; model_ptr = model_ptr->next) { + lf_printf(file, " MODEL_%s,\n", model_ptr->name); + } + lf_printf(file, " nr_models\n"); + lf_printf(file, "} model_enum;\n"); + lf_printf(file, "\n"); + + lf_printf(file, "#define DEFAULT_MODEL MODEL_%s\n", (models) ? models->name : "NONE"); + lf_printf(file, "\n"); + + lf_printf(file, "typedef struct _model_data model_data;\n"); + lf_printf(file, "typedef struct _model_time model_time;\n"); + lf_printf(file, "\n"); + + lf_printf(file, "extern model_enum current_model;\n"); + lf_printf(file, "extern const char *model_name[ (int)nr_models ];\n"); + lf_printf(file, "extern const char *const *const model_func_unit_name[ (int)nr_models ];\n"); + lf_printf(file, "extern const model_time *const model_time_mapping[ (int)nr_models ];\n"); + lf_printf(file, "\n"); + + for(insn_ptr = model_functions; insn_ptr; insn_ptr = insn_ptr->next) { + model_c_or_h_function(table, file, insn_ptr->file_entry, "INLINE_MODEL"); + name = insn_ptr->file_entry->fields[function_name]; + if (strcmp (name, "model_create") == 0) + model_create_p = 1; + else if (strcmp (name, "model_init") == 0) + model_init_p = 1; + else if (strcmp (name, "model_halt") == 0) + model_halt_p = 1; + else if (strcmp (name, "model_mon_info") == 0) + model_mon_info_p = 1; + else if (strcmp (name, "model_mon_info_free") == 0) + model_mon_info_free_p = 1; + } + + if (!model_create_p) { + lf_print_function_type(file, "model_data *", "INLINE_MODEL", " "); + lf_printf(file, "model_create\n"); + lf_printf(file, "(sim_cpu *cpu);\n"); + lf_printf(file, "\n"); + } + + if (!model_init_p) { + lf_print_function_type(file, "void", "INLINE_MODEL", " "); + lf_printf(file, "model_init\n"); + lf_printf(file, "(model_data *model_ptr);\n"); + lf_printf(file, "\n"); + } + + if (!model_halt_p) { + lf_print_function_type(file, "void", "INLINE_MODEL", " "); + lf_printf(file, "model_halt\n"); + lf_printf(file, "(model_data *model_ptr);\n"); + lf_printf(file, "\n"); + } + + if (!model_mon_info_p) { + lf_print_function_type(file, "model_print *", "INLINE_MODEL", " "); + lf_printf(file, "model_mon_info\n"); + lf_printf(file, "(model_data *model_ptr);\n"); + lf_printf(file, "\n"); + } + + if (!model_mon_info_free_p) { + lf_print_function_type(file, "void", "INLINE_MODEL", " "); + lf_printf(file, "model_mon_info_free\n"); + lf_printf(file, "(model_data *model_ptr,\n"); + lf_printf(file, " model_print *info_ptr);\n"); + lf_printf(file, "\n"); + } + + lf_print_function_type(file, "void", "INLINE_MODEL", " "); + lf_printf(file, "model_set\n"); + lf_printf(file, "(const char *name);\n"); +} + +/****************************************************************/ + +typedef struct _model_c_passed_data model_c_passed_data; +struct _model_c_passed_data { + lf *file; + model *model_ptr; +}; + +static void +model_c_insn(insn_table *entry, + lf *phony_file, + void *data, + insn *instruction, + int depth) +{ + model_c_passed_data *data_ptr = (model_c_passed_data *)data; + lf *file = data_ptr->file; + char *current_name = data_ptr->model_ptr->printable_name; + table_model_entry *model_ptr = instruction->file_entry->model_first; + + while (model_ptr) { + if (model_ptr->fields[insn_model_name] == current_name) { + lf_printf(file, " { %-*s }, /* %s */\n", + max_model_fields_len, + model_ptr->fields[insn_model_fields], + instruction->file_entry->fields[insn_name]); + return; + } + + model_ptr = model_ptr->next; + } + + lf_printf(file, " { %-*s }, /* %s */\n", + max_model_fields_len, + data_ptr->model_ptr->insn_default, + instruction->file_entry->fields[insn_name]); +} + +static void +model_c_function(insn_table *table, + lf *file, + table_entry *function, + const char *prefix) +{ + if (function->fields[function_type] == NULL + || function->fields[function_type][0] == '\0') + { + error("Model function return type not specified for %s", + function->fields[function_name]); + } + else + { + lf_printf(file, "\n"); + lf_print_function_type(file, function->fields[function_type], prefix, "\n"); + lf_printf(file, "%s(%s)\n", + function->fields[function_name], + function->fields[function_param]); + } + lf_printf(file, "{\n"); + if (function->annex) + { + lf_indent(file, +2); + table_entry_print_cpp_line_nr(file, function->annex_line); + lf_print__c_code(file, function->annex); + lf_indent(file, -2); + } + lf_printf(file, "}\n"); + lf_print__internal_reference(file); + lf_printf(file, "\n"); +} + +void +gen_model_c(insn_table *table, lf *file) +{ + insn *insn_ptr; + model *model_ptr; + char *name; + int model_create_p = 0; + int model_init_p = 0; + int model_halt_p = 0; + int model_mon_info_p = 0; + int model_mon_info_free_p = 0; + + lf_printf(file, "\n"); + lf_printf(file, "#include \"cpu.h\"\n"); + lf_printf(file, "#include \"mon.h\"\n"); + lf_printf(file, "\n"); + lf_printf(file, "#ifdef HAVE_STDLIB_H\n"); + lf_printf(file, "#include <stdlib.h>\n"); + lf_printf(file, "#endif\n"); + lf_printf(file, "\n"); + + for(insn_ptr = model_data; insn_ptr; insn_ptr = insn_ptr->next) { + model_c_or_h_data(table, file, insn_ptr->file_entry); + } + + for(insn_ptr = model_static; insn_ptr; insn_ptr = insn_ptr->next) { + model_c_or_h_function(table, file, insn_ptr->file_entry, "/*h*/STATIC"); + } + + for(insn_ptr = model_internal; insn_ptr; insn_ptr = insn_ptr->next) { + model_c_or_h_function(table, file, insn_ptr->file_entry, "STATIC_INLINE_MODEL"); + } + + for(insn_ptr = model_static; insn_ptr; insn_ptr = insn_ptr->next) { + model_c_function(table, file, insn_ptr->file_entry, "/*c*/STATIC"); + } + + for(insn_ptr = model_internal; insn_ptr; insn_ptr = insn_ptr->next) { + model_c_function(table, file, insn_ptr->file_entry, "STATIC_INLINE_MODEL"); + } + + for(insn_ptr = model_functions; insn_ptr; insn_ptr = insn_ptr->next) { + model_c_function(table, file, insn_ptr->file_entry, "INLINE_MODEL"); + name = insn_ptr->file_entry->fields[function_name]; + if (strcmp (name, "model_create") == 0) + model_create_p = 1; + else if (strcmp (name, "model_init") == 0) + model_init_p = 1; + else if (strcmp (name, "model_halt") == 0) + model_halt_p = 1; + else if (strcmp (name, "model_mon_info") == 0) + model_mon_info_p = 1; + else if (strcmp (name, "model_mon_info_free") == 0) + model_mon_info_free_p = 1; + } + + if (!model_create_p) { + lf_print_function_type(file, "model_data *", "INLINE_MODEL", "\n"); + lf_printf(file, "model_create(sim_cpu *cpu)\n"); + lf_printf(file, "{\n"); + lf_printf(file, " return (model_data *)0;\n"); + lf_printf(file, "}\n"); + lf_printf(file, "\n"); + } + + if (!model_init_p) { + lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); + lf_printf(file, "model_init(model_data *model_ptr)\n"); + lf_printf(file, "{\n"); + lf_printf(file, "}\n"); + lf_printf(file, "\n"); + } + + if (!model_halt_p) { + lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); + lf_printf(file, "model_halt(model_data *model_ptr)\n"); + lf_printf(file, "{\n"); + lf_printf(file, "}\n"); + lf_printf(file, "\n"); + } + + if (!model_mon_info_p) { + lf_print_function_type(file, "model_print *", "INLINE_MODEL", "\n"); + lf_printf(file, "model_mon_info(model_data *model_ptr)\n"); + lf_printf(file, "{\n"); + lf_printf(file, " return (model_print *)0;\n"); + lf_printf(file, "}\n"); + lf_printf(file, "\n"); + } + + if (!model_mon_info_free_p) { + lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); + lf_printf(file, "model_mon_info_free(model_data *model_ptr,\n"); + lf_printf(file, " model_print *info_ptr)\n"); + lf_printf(file, "{\n"); + lf_printf(file, "}\n"); + lf_printf(file, "\n"); + } + + lf_printf(file, "/* Insn functional unit info */\n"); + for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { + model_c_passed_data data; + + lf_printf(file, "static const model_time model_time_%s[] = {\n", model_ptr->name); + data.file = file; + data.model_ptr = model_ptr; + insn_table_traverse_insn(table, + NULL, (void *)&data, + model_c_insn); + + lf_printf(file, "};\n"); + lf_printf(file, "\n"); + lf_printf(file, "\f\n"); + } + + lf_printf(file, "#ifndef _INLINE_C_\n"); + lf_printf(file, "const model_time *const model_time_mapping[ (int)nr_models ] = {\n"); + lf_printf(file, " (const model_time *const)0,\n"); + for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { + lf_printf(file, " model_time_%s,\n", model_ptr->name); + } + lf_printf(file, "};\n"); + lf_printf(file, "#endif\n"); + lf_printf(file, "\n"); + + lf_printf(file, "\f\n"); + lf_printf(file, "/* map model enumeration into printable string */\n"); + lf_printf(file, "#ifndef _INLINE_C_\n"); + lf_printf(file, "const char *model_name[ (int)nr_models ] = {\n"); + lf_printf(file, " \"NONE\",\n"); + for (model_ptr = models; model_ptr; model_ptr = model_ptr->next) { + lf_printf(file, " \"%s\",\n", model_ptr->printable_name); + } + lf_printf(file, "};\n"); + lf_printf(file, "#endif\n"); + lf_printf(file, "\n"); + + lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); + lf_printf(file, "model_set(const char *name)\n"); + lf_printf(file, "{\n"); + if (models) { + lf_printf(file, " model_enum model;\n"); + lf_printf(file, " for(model = MODEL_%s; model < nr_models; model++) {\n", models->name); + lf_printf(file, " if(strcmp(name, model_name[model]) == 0) {\n"); + lf_printf(file, " current_model = model;\n"); + lf_printf(file, " return;\n"); + lf_printf(file, " }\n"); + lf_printf(file, " }\n"); + lf_printf(file, "\n"); + lf_printf(file, " error(\"Unknown model '%%s', Models which are known are:%%s\n\",\n"); + lf_printf(file, " name,\n"); + lf_printf(file, " \""); + for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { + lf_printf(file, "\\n\\t%s", model_ptr->printable_name); + } + lf_printf(file, "\");\n"); + } else { + lf_printf(file, " error(\"No models are currently known about\");\n"); + } + + lf_printf(file, "}\n"); +} + +#endif + + + +void +gen_model_h (lf *file, + insn_table *table) +{ + lf_print__this_file_is_empty (file, "suffering bit rot"); +} + + +void +gen_model_c (lf *file, + insn_table *table) +{ + lf_print__this_file_is_empty (file, "suffering bit rot"); +} diff --git a/sim/igen/gen-model.h b/sim/igen/gen-model.h new file mode 100644 index 00000000000..4188e1b2225 --- /dev/null +++ b/sim/igen/gen-model.h @@ -0,0 +1,29 @@ +/* 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. + + */ + + + +extern void gen_model_h +(lf *file, + insn_table *isa); + +extern void gen_model_c +(lf *file, + insn_table *isa); diff --git a/sim/igen/gen-semantics.c b/sim/igen/gen-semantics.c new file mode 100644 index 00000000000..3acd6d802e0 --- /dev/null +++ b/sim/igen/gen-semantics.c @@ -0,0 +1,390 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, 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 "misc.h" +#include "lf.h" +#include "table.h" +#include "filter.h" +#include "igen.h" + +#include "ld-insn.h" +#include "ld-decode.h" + +#include "gen.h" + +#include "gen-semantics.h" +#include "gen-icache.h" +#include "gen-idecode.h" + + +static void +print_semantic_function_header (lf *file, + const char *basename, + const char *format_name, + opcode_bits *expanded_bits, + int is_function_definition, + int nr_prefetched_words) +{ + int indent; + lf_printf(file, "\n"); + lf_print__function_type_function (file, print_semantic_function_type, + "EXTERN_SEMANTICS", + (is_function_definition ? "\n" : " ")); + indent = print_function_name (file, + basename, + format_name, + NULL, + expanded_bits, + function_name_prefix_semantics); + if (is_function_definition) + { + indent += lf_printf (file, " "); + lf_indent (file, +indent); + } + else + { + lf_printf (file, "\n"); + } + lf_printf (file, "("); + lf_indent (file, +1); + print_semantic_function_formal (file, nr_prefetched_words); + lf_indent (file, -1); + lf_printf (file, ")"); + if (is_function_definition) + { + lf_indent (file, -indent); + } + else + { + lf_printf (file, ";"); + } + lf_printf (file, "\n"); +} + +void +print_semantic_declaration (lf *file, + insn_entry *insn, + opcode_bits *expanded_bits, + insn_opcodes *opcodes, + int nr_prefetched_words) +{ + print_semantic_function_header (file, + insn->name, + insn->format_name, + expanded_bits, + 0/* is not function definition*/, + nr_prefetched_words); +} + + + +/* generate the semantics.c file */ + + +void +print_idecode_invalid (lf *file, + const char *result, + invalid_type type) +{ + const char *name; + switch (type) + { + default: name = "unknown"; break; + case invalid_illegal: name = "illegal"; break; + case invalid_fp_unavailable: name = "fp_unavailable"; break; + case invalid_wrong_slot: name = "wrong_slot"; break; + } + if (options.gen.code == generate_jumps) + { + lf_printf (file, "goto %s_%s;\n", + (options.gen.icache ? "icache" : "semantic"), + name); + } + else if (options.gen.icache) + { + lf_printf (file, "%s %sicache_%s (", result, options.module.global.prefix.l, name); + print_icache_function_actual (file, 0); + lf_printf (file, ");\n"); + } + else + { + lf_printf (file, "%s %ssemantic_%s (", result, options.module.global.prefix.l, name); + print_semantic_function_actual (file, 0); + lf_printf (file, ");\n"); + } +} + + +void +print_semantic_body (lf *file, + insn_entry *instruction, + opcode_bits *expanded_bits, + insn_opcodes *opcodes) +{ + /* validate the instruction, if a cache this has already been done */ + if (!options.gen.icache) + { + print_idecode_validate (file, instruction, opcodes); + } + + print_itrace (file, instruction, 0/*put_value_in_cache*/); + + /* generate the instruction profile call - this is delayed until + after the instruction has been verified. The count macro + generated is prefixed by ITABLE_PREFIX */ + { + lf_printf (file, "\n"); + lf_indent_suppress (file); + lf_printf (file, "#if defined (%sPROFILE_COUNT_INSN)\n", + options.module.itable.prefix.u); + lf_printf (file, "%sPROFILE_COUNT_INSN (CPU, CIA, MY_INDEX);\n", + options.module.itable.prefix.u); + lf_indent_suppress (file); + lf_printf (file, "#endif\n"); + } + + /* generate the model call - this is delayed until after the + instruction has been verified */ + { + lf_printf (file, "\n"); + lf_indent_suppress (file); + lf_printf (file, "#if defined (WITH_MON)\n"); + lf_printf (file, "/* monitoring: */\n"); + lf_printf (file, "if (WITH_MON & MONITOR_INSTRUCTION_ISSUE)\n"); + lf_printf (file, " mon_issue ("); + print_function_name (file, + instruction->name, + instruction->format_name, + NULL, + NULL, + function_name_prefix_itable); + lf_printf (file, ", cpu, cia);\n"); + lf_indent_suppress (file); + lf_printf (file, "#endif\n"); + lf_printf (file, "\n"); + } + + /* determine the new instruction address */ + { + lf_printf(file, "/* keep the next instruction address handy */\n"); + if (options.gen.nia == nia_is_invalid) + { + lf_printf(file, "nia = %sINVALID_INSTRUCTION_ADDRESS;\n", + options.module.global.prefix.u); + } + else + { + int nr_immeds = instruction->nr_words - 1; + if (options.gen.delayed_branch) + { + if (nr_immeds > 0) + { + lf_printf (file, "cia.dp += %d * %d; %s\n", + options.insn_bit_size / 8, nr_immeds, + "/* skip dp immeds */"); + } + lf_printf (file, "nia.ip = cia.dp; %s\n", + "/* instruction pointer */"); + lf_printf (file, "nia.dp = cia.dp + %d; %s\n", + options.insn_bit_size / 8, + "/* delayed-slot pointer */"); + } + else + { + if (nr_immeds > 0) + { + lf_printf (file, "nia = cia + %d * (%d + 1); %s\n", + options.insn_bit_size / 8, nr_immeds, + "/* skip immeds as well */"); + + } + else + { + lf_printf (file, "nia = cia + %d;\n", + options.insn_bit_size / 8); + } + } + } + } + + /* if conditional, generate code to verify that the instruction + should be issued */ + if (filter_is_member (instruction->options, "c") + || options.gen.conditional_issue) + { + lf_printf (file, "\n"); + lf_printf (file, "/* execute only if conditional passes */\n"); + lf_printf (file, "if (IS_CONDITION_OK)\n"); + lf_printf (file, " {\n"); + lf_indent (file, +4); + /* FIXME - need to log a conditional failure */ + } + + /* Architecture expects a REG to be zero. Instead of having to + check every read to see if it is refering to that REG just zap it + at the start of every instruction */ + if (options.gen.zero_reg) + { + lf_printf (file, "\n"); + lf_printf (file, "/* Architecture expects REG to be zero */\n"); + lf_printf (file, "GPR_SET(%d, 0);\n", options.gen.zero_reg_nr); + } + + /* generate the code (or at least something */ + lf_printf (file, "\n"); + lf_printf (file, "/* semantics: */\n"); + if (instruction->code != NULL) + { + /* true code */ + lf_printf (file, "{\n"); + lf_indent (file, +2); + lf_print__line_ref (file, instruction->code->line); + table_print_code (file, instruction->code); + lf_indent (file, -2); + lf_printf (file, "}\n"); + lf_print__internal_ref (file); + } + else if (filter_is_member (instruction->options, "nop")) + { + lf_print__internal_ref (file); + } + else + { + const char *prefix = "sim_engine_abort ("; + int indent = strlen (prefix); + /* abort so it is implemented now */ + lf_print__line_ref (file, instruction->line); + lf_printf (file, "%sSD, CPU, cia, \\\n", prefix); + lf_indent (file, +indent); + lf_printf (file, "\"%s:%d:0x%%08lx:%%s unimplemented\\n\", \\\n", + filter_filename (instruction->line->file_name), + instruction->line->line_nr); + lf_printf (file, "(long) CIA, \\\n"); + lf_printf (file, "%sitable[MY_INDEX].name);\n", + options.module.itable.prefix.l); + lf_indent (file, -indent); + lf_print__internal_ref (file); + } + + /* Close off the conditional execution */ + if (filter_is_member (instruction->options, "c") + || options.gen.conditional_issue) + { + lf_indent (file, -4); + lf_printf (file, " }\n"); + } +} + +static void +print_c_semantic (lf *file, + insn_entry *instruction, + opcode_bits *expanded_bits, + insn_opcodes *opcodes, + cache_entry *cache_rules, + int nr_prefetched_words) +{ + + lf_printf (file, "{\n"); + lf_indent (file, +2); + + print_my_defines (file, + instruction->name, + instruction->format_name, + expanded_bits); + lf_printf (file, "\n"); + print_icache_body (file, + instruction, + expanded_bits, + cache_rules, + (options.gen.direct_access + ? define_variables + : declare_variables), + (options.gen.icache + ? get_values_from_icache + : do_not_use_icache), + nr_prefetched_words); + + lf_printf (file, "%sinstruction_address nia;\n", options.module.global.prefix.l); + print_semantic_body (file, + instruction, + expanded_bits, + opcodes); + lf_printf (file, "return nia;\n"); + + /* generate something to clean up any #defines created for the cache */ + if (options.gen.direct_access) + { + print_icache_body (file, + instruction, + expanded_bits, + cache_rules, + undef_variables, + (options.gen.icache + ? get_values_from_icache + : do_not_use_icache), + nr_prefetched_words); + } + + lf_indent (file, -2); + lf_printf (file, "}\n"); +} + +static void +print_c_semantic_function (lf *file, + insn_entry *instruction, + opcode_bits *expanded_bits, + insn_opcodes *opcodes, + cache_entry *cache_rules, + int nr_prefetched_words) +{ + /* build the semantic routine to execute the instruction */ + print_semantic_function_header (file, + instruction->name, + instruction->format_name, + expanded_bits, + 1/*is-function-definition*/, + nr_prefetched_words); + print_c_semantic (file, + instruction, + expanded_bits, + opcodes, + cache_rules, + nr_prefetched_words); +} + +void +print_semantic_definition (lf *file, + insn_entry *insn, + opcode_bits *expanded_bits, + insn_opcodes *opcodes, + cache_entry *cache_rules, + int nr_prefetched_words) +{ + print_c_semantic_function (file, + insn, + expanded_bits, + opcodes, + cache_rules, + nr_prefetched_words); +} + + diff --git a/sim/igen/gen-semantics.h b/sim/igen/gen-semantics.h new file mode 100644 index 00000000000..869d1eddde4 --- /dev/null +++ b/sim/igen/gen-semantics.h @@ -0,0 +1,104 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-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. + + */ + + +/* Creates the files semantics.[hc]. + + The generated file semantics contains functions that implement the + operations required to model a single target processor instruction. + + Several different variations on the semantics file can be created: + + o uncached + + No instruction cache exists. The semantic function + needs to generate any required values locally. + + o cached - separate cracker and semantic + + Two independant functions are created. Firstly the + function that cracks an instruction entering it into a + cache and secondly the semantic function propper that + uses the cache. + + o cached - semantic + cracking semantic + + The function that cracks the instruction and enters + all values into the cache also contains a copy of the + semantic code (avoiding the need to call both the + cracker and the semantic function when there is a + cache miss). + + For each of these general forms, several refinements can occure: + + o do/don't duplicate/expand semantic functions + + As a consequence of decoding an instruction, the + decoder, as part of its table may have effectivly made + certain of the variable fields in an instruction + constant. Separate functions for each of the + alternative values for what would have been treated as + a variable part can be created. + + o use cache struct directly. + + When a cracking cache is present, the semantic + functions can be generated to either hold intermediate + cache values in local variables or always refer to the + contents of the cache directly. */ + + + + + + +extern void print_semantic_declaration +(lf *file, + insn_entry *insn, + opcode_bits *bits, + insn_opcodes *opcodes, + int nr_prefetched_words); + +extern void print_semantic_definition +(lf *file, + insn_entry *insn, + opcode_bits *bits, + insn_opcodes *opcodes, + cache_entry *cache_rules, + int nr_prefetched_words); + + +typedef enum { + invalid_illegal, + invalid_fp_unavailable, + invalid_wrong_slot, +} invalid_type; + +extern void print_idecode_invalid +(lf *file, + const char *result, + invalid_type type); + +extern void print_semantic_body +(lf *file, + insn_entry *instruction, + opcode_bits *expanded_bits, + insn_opcodes *opcodes); + diff --git a/sim/igen/gen-support.c b/sim/igen/gen-support.c new file mode 100644 index 00000000000..93efaa74f72 --- /dev/null +++ b/sim/igen/gen-support.c @@ -0,0 +1,219 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, 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 "misc.h" +#include "lf.h" +#include "table.h" +#include "filter.h" + +#include "igen.h" + +#include "ld-insn.h" +#include "ld-decode.h" + +#include "gen.h" + +#include "gen-semantics.h" +#include "gen-support.h" + +static void +print_support_function_name (lf *file, + function_entry *function, + int is_function_definition) +{ + if (function->is_internal) + { + lf_print__function_type_function (file, print_semantic_function_type, + "INLINE_SUPPORT", + (is_function_definition ? "\n" : " ")); + print_function_name (file, + function->name, + NULL, + NULL, + NULL, + function_name_prefix_semantics); + lf_printf (file, "\n("); + lf_indent (file, +1); + print_semantic_function_formal (file, 0); + lf_indent (file, -1); + lf_printf (file, ")"); + if (!is_function_definition) + lf_printf (file, ";"); + lf_printf (file, "\n"); + } + else + { + /* map the name onto a globally valid name */ + if (!is_function_definition + && strcmp (options.module.support.prefix.l, "") != 0) + { + lf_indent_suppress (file); + lf_printf (file, "#define %s %s%s\n", + function->name, + options.module.support.prefix.l, + function->name); + } + lf_print__function_type (file, + function->type, + "INLINE_SUPPORT", + (is_function_definition ? "\n" : " ")); + lf_printf (file, "%s%s\n(", + options.module.support.prefix.l, + function->name); + if (options.gen.smp) + lf_printf (file, + "sim_cpu *cpu, %sinstruction_address cia, int MY_INDEX", + options.module.support.prefix.l); + else + lf_printf (file, + "SIM_DESC sd, %sinstruction_address cia, int MY_INDEX", + options.module.support.prefix.l); + if (function->param != NULL + && strlen (function->param) > 0) + lf_printf (file, ", %s", function->param); + lf_printf (file, ")%s", (is_function_definition ? "\n" : ";\n")); + } +} + + +static void +support_h_function (lf *file, + function_entry *function, + void *data) +{ + ASSERT (function->type != NULL); + print_support_function_name (file, + function, + 0/*!is_definition*/); + lf_printf(file, "\n"); +} + + +extern void +gen_support_h (lf *file, + insn_table *table) +{ + /* output the definition of `SD_'*/ + if (options.gen.smp) + { + lf_printf(file, "#define SD CPU_STATE (cpu)\n"); + lf_printf(file, "#define CPU cpu\n"); + lf_printf(file, "#define CPU_ cpu\n"); + } + else + { + lf_printf(file, "#define SD sd\n"); + lf_printf(file, "#define CPU (STATE_CPU (sd, 0))\n"); + lf_printf(file, "#define CPU_ sd\n"); + } + + lf_printf(file, "#define CIA_ cia\n"); + if (options.gen.delayed_branch) + { + lf_printf(file, "#define CIA cia.ip\n"); + lf_printf(file, "/* #define NIA nia.dp -- do not define, ambigious */\n"); + } + else + { + lf_printf(file, "#define CIA cia\n"); + lf_printf(file, "#define NIA nia\n"); + } + lf_printf(file, "\n"); + + lf_printf(file, "#define SD_ CPU_, CIA_, MY_INDEX\n"); + lf_printf(file, "#define _SD SD_ /* deprecated */\n"); + lf_printf(file, "\n"); + + /* Map <PREFIX>_instruction_word and <PREFIX>_idecode_issue onto the + shorter instruction_word and idecode_issue. Map defined here as, + name space problems are created when the name is defined in + idecode.h */ + if (strcmp (options.module.idecode.prefix.l, "") != 0) + { + lf_indent_suppress (file); + lf_printf (file, "#define %s %s%s\n", + "instruction_word", + options.module.idecode.prefix.l, + "instruction_word"); + lf_printf (file, "\n"); + lf_indent_suppress (file); + lf_printf (file, "#define %s %s%s\n", + "idecode_issue", + options.module.idecode.prefix.l, + "idecode_issue"); + lf_printf (file, "\n"); + } + + /* output a declaration for all functions */ + function_entry_traverse (file, table->functions, + support_h_function, + NULL); + lf_printf(file, "\n"); + lf_printf(file, "#if defined(SUPPORT_INLINE)\n"); + lf_printf(file, "# if ((SUPPORT_INLINE & INCLUDE_MODULE)\\\n"); + lf_printf(file, " && (SUPPORT_INLINE & INCLUDED_BY_MODULE))\n"); + lf_printf(file, "# include \"%ssupport.c\"\n", options.module.support.prefix.l); + lf_printf(file, "# endif\n"); + lf_printf(file, "#endif\n"); +} + +static void +support_c_function (lf *file, + function_entry *function, + void *data) +{ + ASSERT (function->type != NULL); + print_support_function_name (file, + function, + 1/*!is_definition*/); + lf_printf (file, "{\n"); + lf_indent (file, +2); + if (function->code == NULL) + error (function->line, + "Function without body (or null statement)"); + lf_print__line_ref (file, function->code->line); + table_print_code (file, function->code); + if (function->is_internal) + { + lf_printf (file, "sim_engine_abort (SD, CPU, cia, \"Internal function must longjump\\n\");\n"); + lf_printf (file, "return cia;\n"); + } + lf_indent (file, -2); + lf_printf (file, "}\n"); + lf_print__internal_ref (file); + lf_printf (file, "\n"); +} + + +void +gen_support_c (lf *file, + insn_table *table) +{ + lf_printf(file, "#include \"sim-main.h\"\n"); + lf_printf(file, "#include \"%sidecode.h\"\n", options.module.idecode.prefix.l); + lf_printf(file, "#include \"%sitable.h\"\n", options.module.itable.prefix.l); + lf_printf(file, "#include \"%ssupport.h\"\n", options.module.support.prefix.l); + lf_printf(file, "\n"); + + /* output a definition (c-code) for all functions */ + function_entry_traverse (file, table->functions, + support_c_function, + NULL); +} diff --git a/sim/igen/gen-support.h b/sim/igen/gen-support.h new file mode 100644 index 00000000000..301f1ae0d1c --- /dev/null +++ b/sim/igen/gen-support.h @@ -0,0 +1,29 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, 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. + + */ + + +extern void gen_support_h +(lf *file, + insn_table *table); + +extern void gen_support_c +(lf *file, + insn_table *table); + diff --git a/sim/igen/gen.c b/sim/igen/gen.c new file mode 100644 index 00000000000..de886190665 --- /dev/null +++ b/sim/igen/gen.c @@ -0,0 +1,1765 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-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. + + */ + + +#include "misc.h" +#include "lf.h" +#include "table.h" +#include "filter.h" + +#include "igen.h" +#include "ld-insn.h" +#include "ld-decode.h" +#include "gen.h" + +static insn_uint +sub_val (insn_uint val, + int val_last_pos, + int first_pos, + int last_pos) +{ + return ((val >> (val_last_pos - last_pos)) + & (((insn_uint)1 << (last_pos - first_pos + 1)) - 1)); +} + +static void +update_depth (lf *file, + gen_entry *entry, + int depth, + void *data) +{ + int *max_depth = (int*)data; + if (*max_depth < depth) + *max_depth = depth; +} + + +int +gen_entry_depth (gen_entry *table) +{ + int depth = 0; + gen_entry_traverse_tree (NULL, + table, + 1, + NULL, /*start*/ + update_depth, + NULL, /*end*/ + &depth); /* data */ + return depth; +} + + +static void +print_gen_entry_path (line_ref *line, + gen_entry *table, + error_func *print) +{ + if (table->parent == NULL) + { + if (table->top->model != NULL) + print (line, "%s", table->top->model->name); + else + print (line, ""); + } + else + { + print_gen_entry_path (line, table->parent, print); + print (NULL, ".%d", table->opcode_nr); + } +} + +static void +print_gen_entry_insns (gen_entry *table, + error_func *print, + char *first_message, + char *next_message) +{ + insn_list *i; + char *message; + message = first_message; + for (i = table->insns; i != NULL; i = i->next) + { + insn_entry *insn = i->insn; + print_gen_entry_path (insn->line, table, print); + print (NULL, ": %s.%s %s\n", + insn->format_name, + insn->name, + message); + if (next_message != NULL) + message = next_message; + } +} + +/* same as strcmp */ +static int +insn_field_cmp (insn_word_entry *l, insn_word_entry *r) +{ + while (1) + { + int bit_nr; + if (l == NULL && r == NULL) + return 0; /* all previous fields the same */ + if (l == NULL) + return -1; /* left shorter than right */ + if (r == NULL) + return +1; /* left longer than right */ + for (bit_nr = 0; + bit_nr < options.insn_bit_size; + bit_nr++) + { + if (l->bit[bit_nr]->field->type != insn_field_string) + continue; + if (r->bit[bit_nr]->field->type != insn_field_string) + continue; + if (l->bit[bit_nr]->field->conditions == NULL) + continue; + if (r->bit[bit_nr]->field->conditions == NULL) + continue; + if (0) + printf ("%s%s%s VS %s%s%s\n", + l->bit[bit_nr]->field->val_string, + l->bit[bit_nr]->field->conditions->test == insn_field_cond_eq ? "=" : "!", + l->bit[bit_nr]->field->conditions->string, + r->bit[bit_nr]->field->val_string, + r->bit[bit_nr]->field->conditions->test == insn_field_cond_eq ? "=" : "!", + r->bit[bit_nr]->field->conditions->string); + if (l->bit[bit_nr]->field->conditions->test == insn_field_cond_eq + && r->bit[bit_nr]->field->conditions->test == insn_field_cond_eq) + { + if (l->bit[bit_nr]->field->conditions->type == insn_field_cond_field + && r->bit[bit_nr]->field->conditions->type == insn_field_cond_field) + /* somewhat arbitrary */ + { + int cmp = strcmp (l->bit[bit_nr]->field->conditions->string, + r->bit[bit_nr]->field->conditions->string); + if (cmp != 0) + return cmp; + else + continue; + } + if (l->bit[bit_nr]->field->conditions->type == insn_field_cond_field) + return +1; + if (r->bit[bit_nr]->field->conditions->type == insn_field_cond_field) + return -1; + /* The case of both fields having constant values should have + already have been handled because such fields are converted + into normal constant fields. */ + continue; + } + if (l->bit[bit_nr]->field->conditions->test == insn_field_cond_eq) + return +1; /* left = only */ + if (r->bit[bit_nr]->field->conditions->test == insn_field_cond_eq) + return -1; /* right = only */ + /* FIXME: Need to some what arbitrarily order conditional lists */ + continue; + } + l = l->next; + r = r->next; + } +} + +/* same as strcmp */ +static int +insn_word_cmp (insn_word_entry *l, insn_word_entry *r) +{ + while (1) + { + int bit_nr; + if (l == NULL && r == NULL) + return 0; /* all previous fields the same */ + if (l == NULL) + return -1; /* left shorter than right */ + if (r == NULL) + return +1; /* left longer than right */ + for (bit_nr = 0; + bit_nr < options.insn_bit_size; + bit_nr++) + { + if (l->bit[bit_nr]->mask < r->bit[bit_nr]->mask) + return -1; + if (l->bit[bit_nr]->mask > r->bit[bit_nr]->mask) + return 1; + if (l->bit[bit_nr]->value < r->bit[bit_nr]->value) + return -1; + if (l->bit[bit_nr]->value > r->bit[bit_nr]->value) + return 1; + } + l = l->next; + r = r->next; + } +} + +/* same as strcmp */ +static int +opcode_bit_cmp (opcode_bits *l, + opcode_bits *r) +{ + if (l == NULL && r == NULL) + return 0; /* all previous bits the same */ + if (l == NULL) + return -1; /* left shorter than right */ + if (r == NULL) + return +1; /* left longer than right */ + /* most significant word */ + if (l->field->word_nr < r->field->word_nr) + return +1; /* left has more significant word */ + if (l->field->word_nr > r->field->word_nr) + return -1; /* right has more significant word */ + /* most significant bit? */ + if (l->first < r->first) + return +1; /* left as more significant bit */ + if (l->first > r->first) + return -1; /* right as more significant bit */ + /* nr bits? */ + if (l->last < r->last) + return +1; /* left as less bits */ + if (l->last > r->last) + return -1; /* right as less bits */ + /* value? */ + if (l->value < r->value) + return -1; + if (l->value > r->value) + return 1; + return 0; +} + + +/* same as strcmp */ +static int +opcode_bits_cmp (opcode_bits *l, + opcode_bits *r) +{ + while (1) + { + int cmp; + if (l == NULL && r == NULL) + return 0; /* all previous bits the same */ + cmp = opcode_bit_cmp (l, r); + if (cmp != 0) + return cmp; + l = l->next; + r = r->next; + } +} + +/* same as strcmp */ +static opcode_bits * +new_opcode_bits (opcode_bits *old_bits, + int value, + int first, + int last, + insn_field_entry *field, + opcode_field *opcode) +{ + opcode_bits *new_bits = ZALLOC (opcode_bits); + new_bits->field = field; + new_bits->value = value; + new_bits->first = first; + new_bits->last = last; + new_bits->opcode = opcode; + + if (old_bits != NULL) + { + opcode_bits *new_list; + opcode_bits **last = &new_list; + new_list = new_opcode_bits (old_bits->next, + old_bits->value, + old_bits->first, + old_bits->last, + old_bits->field, + old_bits->opcode); + while (*last != NULL) + { + int cmp = opcode_bit_cmp (new_bits, *last); + if (cmp < 0) /* new < new_list */ + { + break; + } + if (cmp == 0) + { + ERROR ("Duplicated insn bits in list"); + } + last = &(*last)->next; + } + new_bits->next = *last; + *last = new_bits; + return new_list; + } + else + { + return new_bits; + } +} + + + + +typedef enum { + merge_duplicate_insns, + report_duplicate_insns, +} duplicate_insn_actions; + +static insn_list * +insn_list_insert (insn_list **cur_insn_ptr, + int *nr_insns, + insn_entry *insn, + opcode_bits *expanded_bits, + opcode_field *opcodes, + int nr_prefetched_words, + duplicate_insn_actions duplicate_action) +{ + /* insert it according to the order of the fields & bits */ + for (; (*cur_insn_ptr) != NULL; cur_insn_ptr = &(*cur_insn_ptr)->next) + { + int cmp; + + /* key#1 sort according to the constant fields of each instruction */ + cmp = insn_word_cmp (insn->words, (*cur_insn_ptr)->insn->words); + if (cmp < 0) + break; + else if (cmp > 0) + continue; + + /* key#2 sort according to the expanded bits of each instruction */ + cmp = opcode_bits_cmp (expanded_bits, (*cur_insn_ptr)->expanded_bits); + if (cmp < 0) + break; + else if (cmp > 0) + continue; + + /* key#3 sort according to the non-constant fields of each instruction */ + cmp = insn_field_cmp (insn->words, (*cur_insn_ptr)->insn->words); + if (cmp < 0) + break; + else if (cmp > 0) + continue; + + /* duplicate keys, report problem */ + switch (duplicate_action) + { + case report_duplicate_insns: + /* It would appear that we have two instructions with the + same constant field values across all words and bits. + This error can also occure when insn_field_cmp() is + failing to differentiate between two instructions that + differ only in their conditional fields. */ + warning (insn->line, + "Two instructions with identical constant fields\n"); + error ((*cur_insn_ptr)->insn->line, + "Location of duplicate instruction\n"); + case merge_duplicate_insns: + /* Add the opcode path to the instructions list */ + if (opcodes != NULL) + { + insn_opcodes **last = &(*cur_insn_ptr)->opcodes; + while (*last != NULL) + { + last = &(*last)->next; + } + (*last) = ZALLOC (insn_opcodes); + (*last)->opcode = opcodes; + } + /* Use the larger nr_prefetched_words */ + if ((*cur_insn_ptr)->nr_prefetched_words < nr_prefetched_words) + (*cur_insn_ptr)->nr_prefetched_words = nr_prefetched_words; + return (*cur_insn_ptr); + } + + } + + /* create a new list entry and insert it */ + { + insn_list *new_insn = ZALLOC (insn_list); + new_insn->insn = insn; + new_insn->expanded_bits = expanded_bits; + new_insn->next = (*cur_insn_ptr); + new_insn->nr_prefetched_words = nr_prefetched_words; + if (opcodes != NULL) + { + new_insn->opcodes = ZALLOC (insn_opcodes); + new_insn->opcodes->opcode = opcodes; + } + (*cur_insn_ptr) = new_insn; + } + + *nr_insns += 1; + + return (*cur_insn_ptr); +} + + +extern void +gen_entry_traverse_tree (lf *file, + gen_entry *table, + int depth, + gen_entry_handler *start, + gen_entry_handler *leaf, + gen_entry_handler *end, + void *data) +{ + gen_entry *entry; + + ASSERT (table != NULL); + ASSERT (table->opcode != NULL); + ASSERT (table->nr_entries > 0); + ASSERT (table->entries != 0); + + /* prefix */ + if (start != NULL && depth >= 0) + { + start (file, table, depth, data); + } + /* infix leaves */ + for (entry = table->entries; + entry != NULL; + entry = entry->sibling) + { + if (entry->entries != NULL && depth != 0) + { + gen_entry_traverse_tree (file, entry, depth + 1, + start, leaf, end, data); + } + else if (depth >= 0) + { + if (leaf != NULL) + { + leaf (file, entry, depth, data); + } + } + } + /* postfix */ + if (end != NULL && depth >= 0) + { + end (file, table, depth, data); + } +} + + + +/* create a list element containing a single gen_table entry */ + +static gen_list * +make_table (insn_table *isa, + decode_table *rules, + model_entry *model) +{ + insn_entry *insn; + gen_list *entry = ZALLOC (gen_list); + entry->table = ZALLOC (gen_entry); + entry->table->top = entry; + entry->model = model; + entry->isa = isa; + for (insn = isa->insns; insn != NULL; insn = insn->next) + { + if (model == NULL + || insn->processors == NULL + || filter_is_member (insn->processors, model->name)) + { + insn_list_insert (&entry->table->insns, + &entry->table->nr_insns, + insn, + NULL, /* expanded_bits - none yet */ + NULL, /* opcodes - none yet */ + 0, /* nr_prefetched_words - none yet */ + report_duplicate_insns); + } + } + entry->table->opcode_rule = rules; + return entry; +} + + +gen_table * +make_gen_tables (insn_table *isa, + decode_table *rules) +{ + gen_table *gen = ZALLOC (gen_table); + gen->isa = isa; + gen->rules = rules; + if (options.gen.multi_sim) + { + gen_list **last = &gen->tables; + model_entry *model; + filter *processors; + if (options.model_filter != NULL) + processors = options.model_filter; + else + processors = isa->model->processors; + for (model = isa->model->models; + model != NULL; + model = model->next) + { + if (filter_is_member (processors, model->name)) + { + *last = make_table (isa, rules, model); + last = &(*last)->next; + } + } + } + else + { + gen->tables = make_table (isa, rules, NULL); + } + return gen; +} + + +/****************************************************************/ + +#if 0 +typedef enum { + field_is_not_constant = 0, + field_constant_int = 1, + field_constant_reserved = 2, + field_constant_string = 3 +} constant_field_types; + +static constant_field_types +insn_field_is_constant (insn_field *field, + decode_table *rule) +{ + switch (field->type) + { + case insn_field_int: + /* field is an integer */ + return field_constant_int; + case insn_field_reserved: + /* field is `/' and treating that as a constant */ + if (rule->with_zero_reserved) + return field_constant_reserved; + else + return field_is_not_constant; + case insn_field_wild: + return field_is_not_constant; /* never constant */ + case insn_field_string: + /* field, though variable, is on the list of forced constants */ + if (filter_is_member (rule->constant_field_names, field->val_string)) + return field_constant_string; + else + return field_is_not_constant; + } + ERROR ("Internal error"); + return field_is_not_constant; +} +#endif + + +/****************************************************************/ + + +/* Is the bit, according to the decode rule, identical across all the + instructions? */ +static int +insns_bit_useless (insn_list *insns, + decode_table *rule, + int bit_nr) +{ + insn_list *entry; + int value = -1; + int is_useless = 1; /* cleared if something actually found */ + + /* check the instructions for some constant value in at least one of + the bit fields */ + for (entry = insns; entry != NULL; entry = entry->next) + { + insn_word_entry *word = entry->insn->word[rule->word_nr]; + insn_bit_entry *bit = word->bit[bit_nr]; + switch (bit->field->type) + { + case insn_field_invalid: + ASSERT (0); + break; + case insn_field_wild: + case insn_field_reserved: + /* neither useless or useful - ignore */ + break; + case insn_field_int: + switch (rule->search) + { + case decode_find_strings: + /* an integer isn't a string */ + return 1; + case decode_find_constants: + case decode_find_mixed: + /* an integer is useful if its value isn't the same + between all instructions. The first time through the + value is saved, the second time through (if the + values differ) it is marked as useful. */ + if (value < 0) + value = bit->value; + else if (value != bit->value) + is_useless = 0; + break; + } + break; + case insn_field_string: + switch (rule->search) + { + case decode_find_strings: + /* at least one string, keep checking */ + is_useless = 0; + break; + case decode_find_constants: + case decode_find_mixed: + if (filter_is_member (rule->constant_field_names, + bit->field->val_string)) + /* a string field forced to constant? */ + is_useless = 0; + else if (rule->search == decode_find_constants) + /* the string field isn't constant */ + return 1; + break; + } + } + } + + /* Given only one constant value has been found, check through all + the instructions to see if at least one conditional makes it + usefull */ + if (value >= 0 && is_useless) + { + for (entry = insns; entry != NULL; entry = entry->next) + { + insn_word_entry *word = entry->insn->word[rule->word_nr]; + insn_bit_entry *bit = word->bit[bit_nr]; + switch (bit->field->type) + { + case insn_field_invalid: + ASSERT (0); + break; + case insn_field_wild: + case insn_field_reserved: + case insn_field_int: + /* already processed */ + break; + case insn_field_string: + switch (rule->search) + { + case decode_find_strings: + case decode_find_constants: + /* already processed */ + break; + case decode_find_mixed: + /* string field with conditions. If this condition + eliminates the value then the compare is useful */ + if (bit->field->conditions != NULL) + { + insn_field_cond *condition; + int shift = bit->field->last - bit_nr; + for (condition = bit->field->conditions; + condition != NULL; + condition = condition->next) + { + switch (condition->type) + { + case insn_field_cond_value: + switch (condition->test) + { + case insn_field_cond_ne: + if (((condition->value >> shift) & 1) + == (unsigned) value) + /* conditional field excludes the + current value */ + is_useless = 0; + break; + case insn_field_cond_eq: + if (((condition->value >> shift) & 1) + != (unsigned) value) + /* conditional field requires the + current value */ + is_useless = 0; + break; + } + break; + case insn_field_cond_field: + /* are these handled separatly? */ + break; + } + } + } + } + } + } + } + + return is_useless; +} + + +/* go through a gen-table's list of instruction formats looking for a + range of bits that meet the decode table RULEs requirements */ + +static opcode_field * +gen_entry_find_opcode_field (insn_list *insns, + decode_table *rule, + int string_only) +{ + opcode_field curr_opcode; + ASSERT (rule != NULL); + + memset (&curr_opcode, 0, sizeof (curr_opcode)); + curr_opcode.word_nr = rule->word_nr; + curr_opcode.first = rule->first; + curr_opcode.last = rule->last; + + /* Try to reduce the size of first..last in accordance with the + decode rules */ + + while (curr_opcode.first <= rule->last) + { + if (insns_bit_useless (insns, rule, curr_opcode.first)) + curr_opcode.first ++; + else + break; + } + while (curr_opcode.last >= rule->first) + { + if (insns_bit_useless (insns, rule, curr_opcode.last)) + curr_opcode.last --; + else + break; + } + + +#if 0 + for (entry = insns; entry != NULL; entry = entry->next) + { + insn_word_entry *fields = entry->insn->word[rule->word_nr]; + opcode_field new_opcode; + + ASSERT (fields != NULL); + + /* 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->bit[new_opcode.first], rule) + != field_constant_string)) + && (string_only + || (insn_field_is_constant(fields->bit[new_opcode.first], rule) + == field_is_not_constant))) + { + int new_first = fields->bit[new_opcode.first]->last + 1; + ASSERT (new_first > new_opcode.first); + new_opcode.first = new_first; + } + ASSERT(new_opcode.first > rule->last + || (string_only + && insn_field_is_constant(fields->bit[new_opcode.first], + rule) == field_constant_string) + || (!string_only + && insn_field_is_constant(fields->bit[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->bit[new_opcode.last], + rule) != field_constant_string) + && (string_only + || !insn_field_is_constant(fields->bit[new_opcode.last], + rule))) + { + int new_last = fields->bit[new_opcode.last]->first - 1; + ASSERT (new_last < new_opcode.last); + new_opcode.last = new_last; + } + ASSERT(new_opcode.last < rule->first + || (string_only + && insn_field_is_constant(fields->bit[new_opcode.last], + rule) == field_constant_string) + || (!string_only + && insn_field_is_constant(fields->bit[new_opcode.last], + rule))); + + /* now see if our current opcode needs expanding to include the + interesting fields within this instruction */ + 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; + + } +#endif + + /* did the final opcode field end up being empty? */ + if (curr_opcode.first > curr_opcode.last) + { + return NULL; + } + ASSERT (curr_opcode.last >= rule->first); + ASSERT (curr_opcode.first <= rule->last); + ASSERT (curr_opcode.first <= curr_opcode.last); + + /* Ensure that, for the non string only case, the opcode includes + the range forced_first .. forced_last */ + 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; + } + + /* For the string only case, force just the lower bound (so that the + shift can be eliminated) */ + if (string_only + && rule->force_last == options.insn_bit_size - 1) + { + curr_opcode.last = options.insn_bit_size - 1; + } + + /* handle any special cases */ + switch (rule->type) + { + case normal_decode_rule: + /* let the above apply */ + curr_opcode.nr_opcodes = + (1 << (curr_opcode.last - curr_opcode.first + 1)); + break; + case boolean_rule: + curr_opcode.is_boolean = 1; + curr_opcode.boolean_constant = rule->constant; + curr_opcode.nr_opcodes = 2; + break; + } + + { + opcode_field *new_field = ZALLOC (opcode_field); + memcpy (new_field, &curr_opcode, sizeof (opcode_field)); + return new_field; + } +} + + +static void +gen_entry_insert_insn (gen_entry *table, + insn_entry *old_insn, + int new_word_nr, + int new_nr_prefetched_words, + int new_opcode_nr, + opcode_bits *new_bits) +{ + gen_entry **entry = &table->entries; + + /* find the new table for this entry */ + while ((*entry) != NULL && (*entry)->opcode_nr < new_opcode_nr) + { + entry = &(*entry)->sibling; + } + + if ((*entry) == NULL || (*entry)->opcode_nr != new_opcode_nr) + { + /* insert the missing entry */ + gen_entry *new_entry = ZALLOC (gen_entry); + new_entry->sibling = (*entry); + (*entry) = new_entry; + table->nr_entries++; + /* fill it in */ + new_entry->top = table->top; + new_entry->opcode_nr = new_opcode_nr; + new_entry->word_nr = new_word_nr; + new_entry->expanded_bits = new_bits; + new_entry->opcode_rule = table->opcode_rule->next; + new_entry->parent = table; + new_entry->nr_prefetched_words = new_nr_prefetched_words; + } + /* ASSERT new_bits == cur_entry bits */ + ASSERT ((*entry) != NULL && (*entry)->opcode_nr == new_opcode_nr); + insn_list_insert (&(*entry)->insns, + &(*entry)->nr_insns, + old_insn, + NULL, /* expanded_bits - only in final list */ + NULL, /* opcodes - only in final list */ + new_nr_prefetched_words, /* for this table */ + report_duplicate_insns); +} + + +static void +gen_entry_expand_opcode (gen_entry *table, + insn_entry *instruction, + int bit_nr, + int opcode_nr, + opcode_bits *bits) +{ + if (bit_nr > table->opcode->last) + { + /* Only include the hardwired bit information with an entry IF + that entry (and hence its functions) are being duplicated. */ + if (options.trace.insn_expansion) + { + print_gen_entry_path (table->opcode_rule->line, table, notify); + notify (NULL, ": insert %d - %s.%s%s\n", + opcode_nr, + instruction->format_name, + instruction->name, + (table->opcode_rule->with_duplicates ? " (duplicated)" : "")); + } + if (table->opcode_rule->with_duplicates) + { + gen_entry_insert_insn (table, instruction, + table->opcode->word_nr, + table->nr_prefetched_words, + opcode_nr, bits); + } + else + { + gen_entry_insert_insn (table, instruction, + table->opcode->word_nr, + table->nr_prefetched_words, + opcode_nr, NULL); + } + } + else + { + insn_word_entry *word = instruction->word[table->opcode->word_nr]; + insn_field_entry *field = word->bit[bit_nr]->field; + 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; + switch (field->type) + { + case insn_field_int: + { + int val; + val = sub_val (field->val_int, field->last, + first_pos, last_pos); + gen_entry_expand_opcode (table, instruction, + last_pos + 1, + ((opcode_nr << width) | val), + bits); + break; + } + default: + { + if (field->type == insn_field_reserved) + gen_entry_expand_opcode (table, instruction, + last_pos + 1, + ((opcode_nr << width)), + bits); + else + { + int val; + int last_val = (table->opcode->is_boolean + ? 2 + : (1 << width)); + for (val = 0; val < last_val; val++) + { + /* check to see if the value has been precluded + (by a conditional) in some way */ + int is_precluded; + insn_field_cond *condition; + for (condition = field->conditions, is_precluded = 0; + condition != NULL && !is_precluded; + condition = condition->next) + { + switch (condition->type) + { + case insn_field_cond_value: + { + int value = sub_val (condition->value, field->last, + first_pos, last_pos); + switch (condition->test) + { + case insn_field_cond_ne: + if (value == val) + is_precluded = 1; + break; + case insn_field_cond_eq: + if (value != val) + is_precluded = 1; + break; + } + break; + } + case insn_field_cond_field: + { + int value; + opcode_bits *bit; + gen_entry *t; + /* Try to find a value for the + conditional by looking back through + the previously defined bits for one + that covers the designated + conditional field */ + for (bit = bits; + bit != NULL; + bit = bit->next) + { + if (bit->field->word_nr == condition->field->word_nr + && bit->first <= condition->field->first + && bit->last >= condition->field->last) + { + /* the bit field fully specified + the conditional field's value */ + value = sub_val (bit->value, bit->last, + condition->field->first, + condition->field->last); + } + } + /* Try to find a value by looking + through this and previous tables */ + if (bit == NULL) + { + for (t = table; + t->parent != NULL; + t = t->parent) + { + if (t->parent->opcode->word_nr == condition->field->word_nr + && t->parent->opcode->first <= condition->field->first + && t->parent->opcode->last >= condition->field->last) + { + /* the table entry fully + specified the condition + field's value */ + /* extract the field's value + from the opcode */ + value = sub_val (t->opcode_nr, t->parent->opcode->last, + condition->field->first, condition->field->last); + /* this is a requirement of + a conditonal field + refering to another field */ + ASSERT ((condition->field->first - condition->field->last) + == (first_pos - last_pos)); +printf ("value=%d, opcode_nr=%d, last=%d, [%d..%d]\n", + value, t->opcode_nr, t->parent->opcode->last, condition->field->first, condition->field->last); + } + } + } + if (bit == NULL && t == NULL) + error (instruction->line, + "Conditional `%s' of field `%s' isn't expanded", + condition->string, field->val_string); + switch (condition->test) + { + case insn_field_cond_ne: + if (value == val) + is_precluded = 1; + break; + case insn_field_cond_eq: + if (value != val) + is_precluded = 1; + break; + } + break; + } + } + } + if (!is_precluded) + { + /* Only add additional hardwired bit + information if the entry is not going to + later be combined */ + if (table->opcode_rule->with_combine) + { + gen_entry_expand_opcode (table, instruction, + last_pos + 1, + ((opcode_nr << width) | val), + bits); + } + else + { + opcode_bits *new_bits = new_opcode_bits (bits, val, + first_pos, last_pos, + field, + table->opcode); + gen_entry_expand_opcode (table, instruction, + last_pos + 1, + ((opcode_nr << width) | val), + new_bits); + } + } + } + } + } + } + } +} + +static void +gen_entry_insert_expanding (gen_entry *table, + insn_entry *instruction) +{ + gen_entry_expand_opcode (table, + instruction, + table->opcode->first, + 0, + table->expanded_bits); +} + + +static int +insns_match_format_names (insn_list *insns, + filter *format_names) +{ + if (format_names != NULL) + { + insn_list *i; + for (i = insns; i != NULL; i = i->next) + { + if ( i->insn->format_name != NULL + && !filter_is_member (format_names, i->insn->format_name)) + return 0; + } + } + return 1; +} + +static int +table_matches_path (gen_entry *table, + decode_path_list *paths) +{ + if (paths == NULL) + return 1; + while (paths != NULL) + { + gen_entry *entry = table; + decode_path *path = paths->path; + while (1) + { + if (entry == NULL && path == NULL) + return 1; + if (entry == NULL || path == NULL) + break; + if (entry->opcode_nr != path->opcode_nr) + break; + entry = entry->parent; + path = path->parent; + } + paths = paths->next; + } + return 0; +} + + +static int +insns_match_conditions (insn_list *insns, + decode_cond *conditions) +{ + if (conditions != NULL) + { + insn_list *i; + for (i = insns; i != NULL; i = i->next) + { + decode_cond *cond; + for (cond = conditions; cond != NULL; cond = cond->next) + { + int bit_nr; + if (i->insn->nr_words <= cond->word_nr) + return 0; + for (bit_nr = 0; bit_nr < options.insn_bit_size; bit_nr++) + { + if (!cond->mask[bit_nr]) + continue; + if (!i->insn->word[cond->word_nr]->bit[bit_nr]->mask) + return 0; + if ((i->insn->word[cond->word_nr]->bit[bit_nr]->value + == cond->value[bit_nr]) + == !cond->is_equal) + return 0; + } + } + } + } + return 1; +} + +static int +insns_match_nr_words (insn_list *insns, + int nr_words) +{ + insn_list *i; + for (i = insns; i != NULL; i = i->next) + { + if (i->insn->nr_words < nr_words) + return 0; + } + return 1; +} + +static int +insn_list_cmp (insn_list *l, + insn_list *r) +{ + while (1) + { + insn_entry *insn; + if (l == NULL && r == NULL) + return 0; + if (l == NULL) + return -1; + if (r == NULL) + return 1; + if (l->insn != r->insn) + return -1; /* somewhat arbitrary at present */ + /* skip this insn */ + insn = l->insn; + while (l != NULL && l->insn == insn) + l = l->next; + while (r != NULL && r->insn == insn) + r = r->next; + } +} + + + +static void +gen_entry_expand_insns (gen_entry *table) +{ + decode_table *opcode_rule; + + ASSERT(table->nr_insns >= 1); + + /* determine a valid opcode */ + for (opcode_rule = table->opcode_rule; + opcode_rule != NULL; + opcode_rule = opcode_rule->next) + { + char *discard_reason; + if (table->top->model != NULL + && opcode_rule->model_names != NULL + && !filter_is_member (opcode_rule->model_names, + table->top->model->name)) + { + /* the rule isn't applicable to this processor */ + discard_reason = "wrong model"; + } + else if (table->nr_insns == 1 && opcode_rule->conditions == NULL) + { + /* for safety, require a pre-codition when attempting to + apply a rule to a single instruction */ + discard_reason = "need pre-condition when nr-insn == 1"; + } + else if (table->nr_insns == 1 && !opcode_rule->with_duplicates) + { + /* Little point in expanding a single instruction when we're + not duplicating the semantic functions that this table + calls */ + discard_reason = "need duplication with nr-insns == 1"; + } + else if (!insns_match_format_names (table->insns, opcode_rule->format_names)) + { + discard_reason = "wrong format name"; + } + else if (!insns_match_nr_words (table->insns, opcode_rule->word_nr + 1)) + { + discard_reason = "wrong nr words"; + } + else if (!table_matches_path (table, opcode_rule->paths)) + { + discard_reason = "path failed"; + } + else if (!insns_match_conditions (table->insns, opcode_rule->conditions)) + { + discard_reason = "condition failed"; + } + else + { + discard_reason = "no opcode field"; + table->opcode = + gen_entry_find_opcode_field (table->insns, + opcode_rule, + table->nr_insns == 1/*string-only*/ + ); + if (table->opcode != NULL) + { + table->opcode_rule = opcode_rule; + break; + } + } + + if (options.trace.rule_rejection) + { + print_gen_entry_path (opcode_rule->line, table, notify); + notify (NULL, ": rule discarded - %s\n", discard_reason); + } + } + + /* did we find anything */ + if (opcode_rule == NULL) + { + /* the decode table failed, this set of instructions haven't + been uniquely identified */ + if (table->nr_insns > 1) + { + print_gen_entry_insns (table, warning, + "was not uniquely decoded", + "decodes to the same entry"); + error (NULL, ""); + } + return; + } + + /* Determine the number of words that must have been prefetched for + this table to function */ + if (table->parent == NULL) + table->nr_prefetched_words = table->opcode_rule->word_nr + 1; + else if (table->opcode_rule->word_nr + 1 > table->parent->nr_prefetched_words) + table->nr_prefetched_words = table->opcode_rule->word_nr + 1; + else + table->nr_prefetched_words = table->parent->nr_prefetched_words; + + /* back link what we found to its parent */ + if (table->parent != NULL) + { + ASSERT(table->parent->opcode != NULL); + table->opcode->parent = table->parent->opcode; + } + + /* report the rule being used to expand the instructions */ + if (options.trace.rule_selection) + { + print_gen_entry_path (table->opcode_rule->line, table, notify); + notify (NULL, + ": decode - word %d, bits [%d..%d] in [%d..%d], opcodes %d, entries %d\n", + table->opcode->word_nr, + i2target (options.hi_bit_nr, table->opcode->first), + i2target (options.hi_bit_nr, table->opcode->last), + i2target (options.hi_bit_nr, table->opcode_rule->first), + i2target (options.hi_bit_nr, table->opcode_rule->last), + table->opcode->nr_opcodes, + table->nr_entries); + } + + /* expand the raw instructions according to the opcode */ + { + insn_list *entry; + for (entry = table->insns; entry != NULL; entry = entry->next) + { + if (options.trace.insn_expansion) + { + print_gen_entry_path (table->opcode_rule->line, table, notify); + notify (NULL, ": expand - %s.%s\n", + entry->insn->format_name, + entry->insn->name); + } + gen_entry_insert_expanding (table, entry->insn); + } + } + + /* dump the results */ + if (options.trace.entries) + { + gen_entry *entry; + for (entry = table->entries; entry != NULL; entry = entry->sibling) + { + insn_list *l; + print_gen_entry_path (table->opcode_rule->line, entry, notify); + notify (NULL, ": %d - entries %d -", + entry->opcode_nr, + entry->nr_insns); + for (l = entry->insns; l != NULL; l = l->next) + notify (NULL, " %s.%s", l->insn->format_name, l->insn->name); + notify (NULL, "\n"); + } + } + + /* perform a combine pass if needed */ + if (table->opcode_rule->with_combine) + { + gen_entry *entry; + for (entry = table->entries; entry != NULL; entry = entry->sibling) + { + if (entry->combined_parent == NULL) + { + gen_entry **last = &entry->combined_next; + gen_entry *alt; + for (alt = entry->sibling; alt != NULL; alt = alt->sibling) + { + if (alt->combined_parent == NULL + && insn_list_cmp (entry->insns, alt->insns) == 0) + { + alt->combined_parent = entry; + *last = alt; + last = &alt->combined_next; + } + } + } + } + if (options.trace.combine) + { + int nr_unique = 0; + gen_entry *entry; + for (entry = table->entries; entry != NULL; entry = entry->sibling) + { + if (entry->combined_parent == NULL) + { + insn_list *l; + gen_entry *duplicate; + nr_unique++; + print_gen_entry_path (table->opcode_rule->line, entry, notify); + for (duplicate = entry->combined_next; + duplicate != NULL; + duplicate = duplicate->combined_next) + { + notify (NULL, "+%d", duplicate->opcode_nr); + } + notify (NULL, ": entries %d -", entry->nr_insns); + for (l = entry->insns; l != NULL; l = l->next) + { + notify (NULL, " %s.%s", + l->insn->format_name, + l->insn->name); + } + notify (NULL, "\n"); + } + } + print_gen_entry_path (table->opcode_rule->line, table, notify); + notify (NULL, ": combine - word %d, bits [%d..%d] in [%d..%d], opcodes %d, entries %d, unique %d\n", + table->opcode->word_nr, + i2target (options.hi_bit_nr, table->opcode->first), + i2target (options.hi_bit_nr, table->opcode->last), + i2target (options.hi_bit_nr, table->opcode_rule->first), + i2target (options.hi_bit_nr, table->opcode_rule->last), + table->opcode->nr_opcodes, + table->nr_entries, + nr_unique); + } + } + + /* Check that the rule did more than re-arange the order of the + instructions */ + { + gen_entry *entry; + for (entry = table->entries; entry != NULL; entry = entry->sibling) + { + if (entry->combined_parent == NULL) + { + if (insn_list_cmp (table->insns, entry->insns) == 0) + { + print_gen_entry_path (table->opcode_rule->line, table, warning); + warning (NULL, ": Applying rule just copied all instructions\n"); + print_gen_entry_insns (entry, warning, "Copied", NULL); + error (NULL, ""); + } + } + } + } + + /* if some form of expanded table, fill in the missing dots */ + switch (table->opcode_rule->gen) + { + case padded_switch_gen: + case array_gen: + case goto_switch_gen: + if (!table->opcode->is_boolean) + { + gen_entry **entry = &table->entries; + gen_entry *illegals = NULL; + gen_entry **last_illegal = &illegals; + int opcode_nr = 0; + while (opcode_nr < table->opcode->nr_opcodes) + { + if ((*entry) == NULL || (*entry)->opcode_nr != opcode_nr) + { + /* missing - insert it under our feet at *entry */ + gen_entry_insert_insn (table, + table->top->isa->illegal_insn, + table->opcode->word_nr, + 0, /* nr_prefetched_words == 0 for invalid */ + opcode_nr, NULL); + ASSERT ((*entry) != NULL); + ASSERT ((*entry)->opcode_nr == opcode_nr); + (*last_illegal) = *entry; + (*last_illegal)->combined_parent = illegals; + last_illegal = &(*last_illegal)->combined_next; + } + entry = &(*entry)->sibling; + opcode_nr++; + } + /* oops, will have pointed the first illegal insn back to + its self. Fix this */ + if (illegals != NULL) + illegals->combined_parent = NULL; + } + break; + case switch_gen: + case invalid_gen: + /* ignore */ + break; + } + + /* and do the same for the newly created sub entries but *only* + expand entries that haven't been combined. */ + { + gen_entry *entry; + for (entry = table->entries; entry != NULL; entry = entry->sibling) + { + if (entry->combined_parent == NULL) + { + gen_entry_expand_insns (entry); + } + } + } +} + +void +gen_tables_expand_insns (gen_table *gen) +{ + gen_list *entry; + for (entry = gen->tables; entry != NULL; entry = entry->next) + { + gen_entry_expand_insns (entry->table); + } +} + + +/* create a list of all the semantic functions that need to be + generated. Eliminate any duplicates. Verify that the decode stage + worked. */ + +static void +make_gen_semantics_list (lf *file, + gen_entry *entry, + int depth, + void *data) +{ + gen_table *gen = (gen_table*) data; + insn_list *insn; + /* Not interested in an entrie that have been combined into some + other entry at the same level */ + if (entry->combined_parent != NULL) + return; + + /* a leaf should contain exactly one instruction. If not the decode + stage failed. */ + ASSERT (entry->nr_insns == 1); + + /* Enter this instruction into the list of semantic functions. */ + insn = insn_list_insert (&gen->semantics, &gen->nr_semantics, + entry->insns->insn, + entry->expanded_bits, + entry->parent->opcode, + entry->insns->nr_prefetched_words, + merge_duplicate_insns); + /* point the table entry at the real semantic function */ + ASSERT (insn != NULL); + entry->insns->semantic = insn; +} + + +void +gen_tables_expand_semantics (gen_table *gen) +{ + gen_list *entry; + for (entry = gen->tables; entry != NULL; entry = entry->next) + { + gen_entry_traverse_tree (NULL, + entry->table, + 1, /* depth */ + NULL, /* start-handler */ + make_gen_semantics_list, /* leaf-handler */ + NULL, /* end-handler */ + gen); /* data */ + } +} + + + +#ifdef MAIN + + +static void +dump_opcode_field (lf *file, + char *prefix, + opcode_field *field, + char *suffix, + int levels) +{ + lf_printf (file, "%s(opcode_field *) 0x%lx", prefix, (long) field); + if (levels && field != NULL) { + lf_indent (file, +1); + lf_printf (file, "\n(first %d)", field->first); + lf_printf (file, "\n(last %d)", field->last); + lf_printf (file, "\n(nr_opcodes %d)", field->nr_opcodes); + lf_printf (file, "\n(is_boolean %d)", field->is_boolean); + lf_printf (file, "\n(boolean_constant %d)", field->boolean_constant); + dump_opcode_field(file, "\n(parent ", field->parent, ")", levels - 1); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); +} + + +static void +dump_opcode_bits (lf *file, + char *prefix, + opcode_bits *bits, + char *suffix, + int levels) +{ + lf_printf (file, "%s(opcode_bits *) 0x%lx", prefix, (long) bits); + + if (levels && bits != NULL) + { + lf_indent (file, +1); + lf_printf (file, "\n(value %d)", bits->value); + dump_opcode_field (file, "\n(opcode ", bits->opcode, ")", 0); + dump_insn_field (file, "\n(field ", bits->field, ")"); + dump_opcode_bits (file, "\n(next ", bits->next, ")", levels - 1); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); +} + + + +static void +dump_insn_list (lf *file, + char *prefix, + insn_list *entry, + char *suffix) +{ + lf_printf (file, "%s(insn_list *) 0x%lx", prefix, (long) entry); + + if (entry != NULL) { + lf_indent (file, +1); + dump_insn_entry (file, "\n(insn ", entry->insn, ")"); + lf_printf (file, "\n(next 0x%lx)", (long) entry->next); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); +} + + +static void +dump_insn_word_entry_list_entries (lf *file, + char *prefix, + insn_list *entry, + char *suffix) +{ + lf_printf (file, "%s", prefix); + while (entry != NULL) + { + dump_insn_list (file, "\n(", entry, ")"); + entry = entry->next; + } + lf_printf (file, "%s", suffix); +} + + +static void +dump_gen_entry (lf *file, + char *prefix, + gen_entry *table, + char *suffix, + int levels) +{ + + lf_printf (file, "%s(gen_entry *) 0x%lx", prefix, (long) table); + + if (levels && table != NULL) { + + lf_indent (file, +1); + lf_printf (file, "\n(opcode_nr %d)", table->opcode_nr); + lf_printf (file, "\n(word_nr %d)", table->word_nr); + dump_opcode_bits (file, "\n(expanded_bits ", table->expanded_bits, ")", -1); + lf_printf (file, "\n(nr_insns %d)", table->nr_insns); + dump_insn_word_entry_list_entries (file, "\n(insns ", table->insns, ")"); + dump_decode_rule (file, "\n(opcode_rule ", table->opcode_rule, ")"); + dump_opcode_field (file, "\n(opcode ", table->opcode, ")", 0); + lf_printf (file, "\n(nr_entries %d)", table->nr_entries); + dump_gen_entry (file, "\n(entries ", table->entries, ")", table->nr_entries); + dump_gen_entry (file, "\n(sibling ", table->sibling, ")", levels - 1); + dump_gen_entry (file, "\n(parent ", table->parent, ")", 0); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); +} + +static void +dump_gen_list (lf *file, + char *prefix, + gen_list *entry, + char *suffix, + int levels) +{ + while (entry != NULL) + { + lf_printf (file, "%s(gen_list *) 0x%lx", prefix, (long) entry); + dump_gen_entry (file, "\n(", entry->table, ")", levels); + lf_printf (file, "\n(next (gen_list *) 0x%lx)", (long) entry->next); + lf_printf (file, "%s", suffix); + } +} + + +static void +dump_gen_table (lf *file, + char *prefix, + gen_table *gen, + char *suffix, + int levels) +{ + lf_printf (file, "%s(gen_table *) 0x%lx", prefix, (long) gen); + lf_printf (file, "\n(isa (insn_table *) 0x%lx)", (long) gen->isa); + lf_printf (file, "\n(rules (decode_table *) 0x%lx)", (long) gen->rules); + dump_gen_list (file, "\n(", gen->tables, ")", levels); + lf_printf (file, "%s", suffix); +} + + +igen_options options; + +int +main (int argc, + char **argv) +{ + decode_table *decode_rules; + insn_table *instructions; + gen_table *gen; + lf *l; + + if (argc != 7) + error (NULL, "Usage: insn <filter-in> <hi-bit-nr> <insn-bit-size> <widths> <decode-table> <insn-table>\n"); + + INIT_OPTIONS (options); + + filter_parse (&options.flags_filter, argv[1]); + + options.hi_bit_nr = a2i(argv[2]); + options.insn_bit_size = a2i(argv[3]); + options.insn_specifying_widths = a2i(argv[4]); + ASSERT(options.hi_bit_nr < options.insn_bit_size); + + instructions = load_insn_table (argv[6], NULL); + decode_rules = load_decode_table (argv[5]); + gen = make_gen_tables (instructions, decode_rules); + + gen_tables_expand_insns (gen); + + l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-ld-insn"); + + dump_gen_table (l, "(", gen, ")\n", -1); + return 0; +} + +#endif diff --git a/sim/igen/gen.h b/sim/igen/gen.h new file mode 100644 index 00000000000..884e27711e4 --- /dev/null +++ b/sim/igen/gen.h @@ -0,0 +1,227 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, 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 struct _opcode_field opcode_field; +struct _opcode_field { + int word_nr; + int first; + int last; + int is_boolean; + int nr_opcodes; + unsigned boolean_constant; + opcode_field *parent; +}; + +typedef struct _opcode_bits opcode_bits; +struct _opcode_bits { + int value; + int first; + int last; + insn_field_entry *field; + opcode_field *opcode; + opcode_bits *next; +}; + +typedef struct _insn_opcodes insn_opcodes; +struct _insn_opcodes { + opcode_field *opcode; + insn_opcodes *next; +}; + +typedef struct _insn_list insn_list; +struct _insn_list { + /* the instruction */ + insn_entry *insn; + /* list of non constant bits that have been made constant */ + opcode_bits *expanded_bits; + /* list of the various opcode field paths used to reach this + instruction */ + insn_opcodes *opcodes; + /* number of prefetched words for this instruction */ + int nr_prefetched_words; + /* The semantic function list_entry corresponding to this insn */ + insn_list *semantic; + /* linked list */ + insn_list *next; +}; + +/* forward */ +typedef struct _gen_list gen_list; + +typedef struct _gen_entry gen_entry; +struct _gen_entry { + + /* as an entry in a table */ + int word_nr; + int opcode_nr; + gen_entry *sibling; + opcode_bits *expanded_bits; + gen_entry *parent; /* parent has the opcode* data */ + + /* as a table containing entries */ + decode_table *opcode_rule; + opcode_field *opcode; + int nr_prefetched_words; + int nr_entries; + gen_entry *entries; + + /* as both an entry and a table */ + int nr_insns; + insn_list *insns; + + /* if siblings are being combined */ + gen_entry *combined_next; + gen_entry *combined_parent; + + /* our top-of-tree */ + gen_list *top; +}; + + +struct _gen_list { + model_entry *model; + insn_table *isa; + gen_entry *table; + gen_list *next; +}; + + +typedef struct _gen_table gen_table; +struct _gen_table { + /* list of all the instructions */ + insn_table *isa; + /* list of all the semantic functions */ + decode_table *rules; + /* list of all the generated instruction tables */ + gen_list *tables; + /* list of all the semantic functions */ + int nr_semantics; + insn_list *semantics; +}; + + +extern gen_table *make_gen_tables +(insn_table *isa, + decode_table *rules); + + +extern void gen_tables_expand_insns +(gen_table *gen); + +extern void gen_tables_expand_semantics +(gen_table *gen); + +extern int gen_entry_depth +(gen_entry *table); + + + +/* Traverse the created data structure */ + +typedef void gen_entry_handler +(lf *file, + gen_entry *entry, + int depth, + void *data); + +extern void gen_entry_traverse_tree +(lf *file, + gen_entry *table, + int depth, + gen_entry_handler *start, + gen_entry_handler *leaf, + gen_entry_handler *end, + void *data); + + + +/* Misc functions - actually in igen.c */ + + +/* Cache functions: */ + +extern int print_icache_function_formal +(lf *file, int nr_prefetched_words); + +extern int print_icache_function_actual +(lf *file, int nr_prefetched_words); + +extern int print_icache_function_type +(lf *file); + +extern int print_semantic_function_formal +(lf *file, int nr_prefetched_words); + +extern int print_semantic_function_actual +(lf *file, int nr_prefetched_words); + +extern int print_semantic_function_type +(lf *file); + +extern int print_idecode_function_formal +(lf *file, int nr_prefetched_words); + +extern int print_idecode_function_actual +(lf *file, int nr_prefetched_words); + +typedef enum { + function_name_prefix_semantics, + function_name_prefix_idecode, + function_name_prefix_itable, + function_name_prefix_icache, + function_name_prefix_engine, + function_name_prefix_none +} lf_function_name_prefixes; + +typedef enum { + is_function_declaration = 0, + is_function_definition = 1, + is_function_variable, +} function_decl_type; + +extern int print_function_name +(lf *file, + const char *basename, + const char *format_name, + const char *model_name, + opcode_bits *expanded_bits, + lf_function_name_prefixes prefix); + +extern void print_my_defines +(lf *file, + const char *basename, + const char *format_name, + opcode_bits *expanded_bits); + +extern void print_itrace +(lf *file, + insn_entry *insn, + int idecode); + +extern void print_sim_engine_abort +(lf *file, + const char *message); + + +extern void print_include (lf *file, igen_module module); +extern void print_include_inline (lf *file, igen_module module); +extern void print_includes (lf *file); + diff --git a/sim/igen/igen.c b/sim/igen/igen.c new file mode 100644 index 00000000000..094f0cd43bb --- /dev/null +++ b/sim/igen/igen.c @@ -0,0 +1,1621 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, 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 <getopt.h> + +#include "misc.h" +#include "lf.h" +#include "table.h" +#include "config.h" +#include "filter.h" + +#include "igen.h" + +#include "ld-insn.h" +#include "ld-decode.h" +#include "ld-cache.h" + +#include "gen.h" + +#include "gen-model.h" +#include "gen-icache.h" +#include "gen-itable.h" +#include "gen-idecode.h" +#include "gen-semantics.h" +#include "gen-engine.h" +#include "gen-support.h" +#include "gen-engine.h" + + +/****************************************************************/ + + +/* Semantic functions */ + +int +print_semantic_function_formal (lf *file, + int nr_prefetched_words) +{ + int nr = 0; + int word_nr; + if (options.gen.icache || nr_prefetched_words < 0) + { + nr += lf_printf (file, "SIM_DESC sd,\n"); + nr += lf_printf (file, "%sidecode_cache *cache_entry,\n", + options.module.global.prefix.l); + nr += lf_printf (file, "%sinstruction_address cia", + options.module.global.prefix.l); + } + else if (options.gen.smp) + { + nr += lf_printf (file, "sim_cpu *cpu,\n"); + for (word_nr = 0; word_nr < nr_prefetched_words; word_nr++) + { + nr += lf_printf (file, "%sinstruction_word instruction_%d,\n", + options.module.global.prefix.l, + word_nr); + } + nr += lf_printf (file, "%sinstruction_address cia", + options.module.global.prefix.l); + } + else + { + nr += lf_printf (file, "SIM_DESC sd,\n"); + for (word_nr = 0; word_nr < nr_prefetched_words; word_nr++) + { + nr += lf_printf (file, "%sinstruction_word instruction_%d,\n", + options.module.global.prefix.l, + word_nr); + } + nr += lf_printf (file, "%sinstruction_address cia", + options.module.global.prefix.l); + } + return nr; +} + +int +print_semantic_function_actual (lf *file, + int nr_prefetched_words) +{ + int nr = 0; + int word_nr; + if (options.gen.icache || nr_prefetched_words < 0) + { + nr += lf_printf (file, "sd, cache_entry, cia"); + } + else + { + if (options.gen.smp) + nr += lf_printf (file, "cpu"); + else + nr += lf_printf (file, "sd"); + for (word_nr = 0; word_nr < nr_prefetched_words; word_nr++) + nr += lf_printf (file, ", instruction_%d", word_nr); + nr += lf_printf (file, ", cia"); + } + return nr; +} + +int +print_semantic_function_type (lf *file) +{ + int nr = 0; + nr += lf_printf (file, "%sinstruction_address", + options.module.global.prefix.l); + return nr; +} + + +/* Idecode functions */ + +int +print_icache_function_formal (lf *file, + int nr_prefetched_words) +{ + int nr = 0; + int word_nr; + if (options.gen.smp) + nr += lf_printf (file, "sim_cpu *cpu,\n"); + else + nr += lf_printf (file, "SIM_DESC sd,\n"); + for (word_nr = 0; word_nr < nr_prefetched_words; word_nr++) + nr += lf_printf (file, " %sinstruction_word instruction_%d,\n", + options.module.global.prefix.l, word_nr); + nr += lf_printf (file, " %sinstruction_address cia,\n", + options.module.global.prefix.l); + nr += lf_printf (file, " %sidecode_cache *cache_entry", + options.module.global.prefix.l); + return nr; +} + +int +print_icache_function_actual (lf *file, + int nr_prefetched_words) +{ + int nr = 0; + int word_nr; + if (options.gen.smp) + nr += lf_printf (file, "cpu"); + else + nr += lf_printf (file, "sd"); + for (word_nr = 0; word_nr < nr_prefetched_words; word_nr++) + nr += lf_printf (file, ", instruction_%d", word_nr); + nr += lf_printf (file, ", cia, cache_entry"); + return nr; +} + +int +print_icache_function_type (lf *file) +{ + int nr; + if (options.gen.semantic_icache) + { + nr = print_semantic_function_type (file); + } + else + { + nr = lf_printf (file, "%sidecode_semantic *", + options.module.global.prefix.l); + } + return nr; +} + + +/* Function names */ + +static int +print_opcode_bits (lf *file, + opcode_bits *bits) +{ + int nr = 0; + if (bits == NULL) + return nr; + nr += lf_putchr (file, '_'); + nr += lf_putstr (file, bits->field->val_string); + if (bits->opcode->is_boolean && bits->value == 0) + nr += lf_putint (file, bits->opcode->boolean_constant); + else if (!bits->opcode->is_boolean) { + if (bits->opcode->last < bits->field->last) + nr += lf_putint (file, bits->value << (bits->field->last - bits->opcode->last)); + else + nr += lf_putint (file, bits->value); + } + nr += print_opcode_bits (file, bits->next); + return nr; +} + +static int +print_c_name (lf *file, + const char *name) +{ + int nr = 0; + const char *pos; + for (pos = name; *pos != '\0'; pos++) + { + switch (*pos) + { + case '/': + case '-': + break; + case ' ': + case '.': + nr += lf_putchr (file, '_'); + break; + default: + nr += lf_putchr (file, *pos); + break; + } + } + return nr; +} + +extern int +print_function_name (lf *file, + const char *basename, + const char *format_name, + const char *model_name, + opcode_bits *expanded_bits, + lf_function_name_prefixes prefix) +{ + int nr = 0; + /* the prefix */ + switch (prefix) + { + case function_name_prefix_semantics: + nr += lf_printf (file, "%s", options.module.semantics.prefix.l); + nr += lf_printf (file, "semantic_"); + break; + case function_name_prefix_idecode: + nr += lf_printf (file, "%s", options.module.idecode.prefix.l); + nr += lf_printf (file, "idecode_"); + break; + case function_name_prefix_itable: + nr += lf_printf (file, "%sitable_", options.module.itable.prefix.l); + break; + case function_name_prefix_icache: + nr += lf_printf (file, "%s", options.module.icache.prefix.l); + nr += lf_printf (file, "icache_"); + break; + case function_name_prefix_engine: + nr += lf_printf (file, "%s", options.module.engine.prefix.l); + nr += lf_printf (file, "engine_"); + default: + break; + } + + if (model_name != NULL) + { + nr += print_c_name (file, model_name); + nr += lf_printf (file, "_"); + } + + /* the function name */ + nr += print_c_name (file, basename); + + /* the format name if available */ + if (format_name != NULL) + { + nr += lf_printf (file, "_"); + nr += print_c_name (file, format_name); + } + + /* the suffix */ + nr += print_opcode_bits (file, expanded_bits); + + return nr; +} + + +void +print_my_defines (lf *file, + const char *basename, + const char *format_name, + opcode_bits *expanded_bits) +{ + /* #define MY_INDEX xxxxx */ + lf_indent_suppress (file); + lf_printf (file, "#undef MY_INDEX\n"); + lf_indent_suppress (file); + lf_printf (file, "#define MY_INDEX "); + print_function_name (file, + basename, format_name, NULL, + NULL, + function_name_prefix_itable); + lf_printf (file, "\n"); + /* #define MY_PREFIX xxxxxx */ + lf_indent_suppress (file); + lf_printf (file, "#undef "); + print_function_name (file, + basename, format_name, NULL, + expanded_bits, + function_name_prefix_none); + lf_printf (file, "\n"); + lf_indent_suppress (file); + lf_printf (file, "#undef MY_PREFIX\n"); + lf_indent_suppress (file); + lf_printf (file, "#define MY_PREFIX "); + print_function_name (file, + basename, format_name, NULL, + expanded_bits, + function_name_prefix_none); + lf_printf (file, "\n"); + /* #define MY_NAME xxxxxx */ + lf_indent_suppress (file); + lf_indent_suppress (file); + lf_printf (file, "#undef MY_NAME\n"); + lf_indent_suppress (file); + lf_printf (file, "#define MY_NAME \""); + print_function_name (file, + basename, format_name, NULL, + expanded_bits, + function_name_prefix_none); + lf_printf (file, "\"\n"); +} + + +static int +print_itrace_prefix (lf *file) +{ + const char *prefix = "trace_prefix ("; + int indent = strlen (prefix); + lf_printf (file, "%sSD, CPU, cia, CIA, TRACE_LINENUM_P (CPU), \\\n", prefix); + lf_indent (file, +indent); + lf_printf (file, "%sitable[MY_INDEX].file, \\\n", options.module.itable.prefix.l); + lf_printf (file, "%sitable[MY_INDEX].line_nr, \\\n", options.module.itable.prefix.l); + lf_printf (file, "\""); + return indent; +} + + +static void +print_itrace_format (lf *file, + insn_mnemonic_entry *assembler) +{ + /* pass=1 is fmt string; pass=2 is arguments */ + int pass; + /* print the format string */ + for (pass = 1; pass <= 2; pass++) + { + const char *chp = assembler->format; + chp++; /* skip the leading quote */ + /* write out the format/args */ + while (*chp != '\0') + { + if (chp[0] == '\\' && (chp[1] == '<' || chp[1] == '>')) + { + if (pass == 1) + lf_putchr (file, chp[1]); + chp += 2; + } + else if (chp[0] == '<' || chp[0] == '%') + { + /* parse [ "%" ... ] "<" [ func "#" ] param ">" */ + const char *fmt; + const char *func; + int strlen_func; + const char *param; + int strlen_param; + /* the "%" ... "<" format */ + fmt = chp; + while (chp[0] != '<' && chp[0] != '\0') + chp++; + if (chp[0] != '<') + error (assembler->line, "Missing `<' after `%%'\n"); + chp++; + /* [ "func" # ] OR "param" */ + func = chp; + param = chp; + while (chp[0] != '>' && chp[0] != '#' && chp[0] != '\0') + chp++; + strlen_func = chp - func; + if (chp[0] == '#') + { + chp++; + param = chp; + while (chp[0] != '>' && chp[0] != '\0') + chp++; + } + strlen_param = chp - param; + if (chp[0] != '>') + error (assembler->line, "Missing closing `>' in assembler string\n"); + chp++; + /* now process it */ + if (pass == 2) + lf_printf (file, ", \\\n"); + if (strncmp (fmt, "<", 1) == 0) + /* implicit long int format */ + { + if (pass == 1) + lf_printf (file, "%%ld"); + else + { + lf_printf (file, "(long) "); + lf_write (file, param, strlen_param); + } + } + else if (strncmp (fmt, "%<", 2) == 0) + /* explicit format */ + { + if (pass == 1) + lf_printf (file, "%%"); + else + lf_write (file, param, strlen_param); + } + else if (strncmp (fmt, "%s<", 3) == 0) + /* string format */ + { + if (pass == 1) + lf_printf (file, "%%s"); + else + { + lf_printf (file, "%sstr_", options.module.global.prefix.l); + lf_write (file, func, strlen_func); + lf_printf (file, " (SD_, "); + lf_write (file, param, strlen_param); + lf_printf (file, ")"); + } + } + else if (strncmp (fmt, "%lx<", 4) == 0) + /* simple hex */ + { + if (pass == 1) + lf_printf (file, "%%lx"); + else + { + lf_printf (file, "(unsigned long) "); + lf_write (file, param, strlen_param); + } + } + else if (strncmp (fmt, "%08lx<", 6) == 0) + /* simple hex */ + { + if (pass == 1) + lf_printf (file, "%%08lx"); + else + { + lf_printf (file, "(unsigned long) "); + lf_write (file, param, strlen_param); + } + } + else + error (assembler->line, "Unknown assembler string format\n"); + } + else + { + if (pass == 1) + lf_putchr (file, chp[0]); + chp += 1; + } + } + } + lf_printf (file, ");\n"); +} + + +void +print_itrace (lf *file, + insn_entry *insn, + int idecode) +{ + /* NB: Here we escape each EOLN. This is so that the the compiler + treats a trace function call as a single line. Consequently any + errors in the line are refered back to the same igen assembler + source line */ + const char *phase = (idecode) ? "DECODE" : "INSN"; + lf_printf (file, "\n"); + lf_indent_suppress (file); + lf_printf (file, "#if defined (WITH_TRACE)\n"); + lf_printf (file, "/* generate a trace prefix if any tracing enabled */\n"); + lf_printf (file, "if (TRACE_ANY_P (CPU))\n"); + lf_printf (file, " {\n"); + lf_indent (file, +4); + { + if (insn->mnemonics != NULL) + { + insn_mnemonic_entry *assembler = insn->mnemonics; + int is_first = 1; + do + { + if (assembler->condition != NULL) + { + int indent; + lf_printf (file, "%sif (%s)\n", + is_first ? "" : "else ", + assembler->condition); + lf_indent (file, +2); + lf_print__line_ref (file, assembler->line); + indent = print_itrace_prefix (file); + print_itrace_format (file, assembler); + lf_print__internal_ref (file); + lf_indent (file, -indent); + lf_indent (file, -2); + if (assembler->next == NULL) + error (assembler->line, "Missing final unconditional assembler\n"); + } + else + { + int indent; + if (!is_first) + { + lf_printf (file, "else\n"); + lf_indent (file, +2); + } + lf_print__line_ref (file, assembler->line); + indent = print_itrace_prefix (file); + print_itrace_format (file, assembler); + lf_print__internal_ref (file); + lf_indent (file, -indent); + if (!is_first) + lf_indent (file, -2); + if (assembler->next != NULL) + error (assembler->line, "Unconditional assembler is not last\n"); + } + is_first = 0; + assembler = assembler->next; + } + while (assembler != NULL); + } + else + { + int indent; + lf_indent (file, +2); + lf_print__line_ref (file, insn->line); + indent = print_itrace_prefix (file); + lf_printf (file, "%%s\", \\\n"); + lf_printf (file, "itable[MY_INDEX].name);\n"); + lf_print__internal_ref (file); + lf_indent (file, -indent); + lf_indent (file, -2); + } + lf_printf (file, "/* trace the instruction execution if enabled */\n"); + lf_printf (file, "if (TRACE_%s_P (CPU))\n", phase); + lf_printf (file, " trace_generic (SD, CPU, TRACE_%s_IDX, \" %%s\", itable[MY_INDEX].name);\n", phase); + } + lf_indent (file, -4); + lf_printf (file, " }\n"); + lf_indent_suppress (file); + lf_printf (file, "#endif\n"); +} + + +void +print_sim_engine_abort (lf *file, + const char *message) +{ + lf_printf (file, "sim_engine_abort (SD, CPU, cia, "); + lf_printf (file, "\"%s\"", message); + lf_printf (file, ");\n"); +} + + +void +print_include (lf *file, + igen_module module) +{ + lf_printf (file, "#include \"%s%s.h\"\n", module.prefix.l, module.suffix.l); +} + +void +print_include_inline (lf *file, + igen_module module) +{ + lf_printf (file, "#if C_REVEALS_MODULE_P (%s_INLINE)\n", module.suffix.u); + lf_printf (file, "#include \"%s%s.c\"\n", module.prefix.l, module.suffix.l); + lf_printf (file, "#else\n"); + print_include (file, module); + lf_printf (file, "#endif\n"); + lf_printf (file, "\n"); +} + +void +print_includes (lf *file) +{ + lf_printf (file, "\n"); + lf_printf (file, "#include \"sim-inline.c\"\n"); + lf_printf (file, "\n"); + print_include_inline (file, options.module.itable); + print_include_inline (file, options.module.idecode); + print_include_inline (file, options.module.support); +} + + +/****************************************************************/ + + +static void +gen_semantics_h (lf *file, + insn_list *semantics, + int max_nr_words) +{ + int word_nr; + insn_list *semantic; + for (word_nr = -1; word_nr <= max_nr_words; word_nr++) + { + lf_printf (file, "typedef "); + print_semantic_function_type (file); + lf_printf (file, " %sidecode_semantic", + options.module.global.prefix.l); + if (word_nr >= 0) + lf_printf (file, "_%d", word_nr); + lf_printf (file, "\n("); + lf_indent (file, +1); + print_semantic_function_formal (file, word_nr); + lf_indent (file, -1); + lf_printf (file, ");\n"); + lf_printf (file, "\n"); + } + switch (options.gen.code) + { + case generate_calls: + for (semantic = semantics; semantic != NULL; semantic = semantic->next) + { + /* Ignore any special/internal instructions */ + if (semantic->insn->nr_words == 0) + continue; + print_semantic_declaration (file, + semantic->insn, + semantic->expanded_bits, + semantic->opcodes, + semantic->nr_prefetched_words); + } + break; + case generate_jumps: + lf_print__this_file_is_empty (file, "generating jumps"); + break; + } +} + + +static void +gen_semantics_c (lf *file, + insn_list *semantics, + cache_entry *cache_rules) +{ + if (options.gen.code == generate_calls) + { + insn_list *semantic; + print_includes (file); + print_include (file, options.module.semantics); + lf_printf (file, "\n"); + + for (semantic = semantics; semantic != NULL; semantic = semantic->next) + { + /* Ignore any special/internal instructions */ + if (semantic->insn->nr_words == 0) + continue; + print_semantic_definition (file, + semantic->insn, + semantic->expanded_bits, + semantic->opcodes, + cache_rules, + semantic->nr_prefetched_words); + } + } + else + { + lf_print__this_file_is_empty (file, "generating jump engine"); + } +} + + +/****************************************************************/ + + +static void +gen_icache_h (lf *file, + insn_list *semantic, + function_entry *functions, + int max_nr_words) +{ + int word_nr; + for (word_nr = 0; word_nr <= max_nr_words; word_nr++) + { + lf_printf (file, "typedef "); + print_icache_function_type(file); + lf_printf (file, " %sidecode_icache_%d\n(", + options.module.global.prefix.l, + word_nr); + print_icache_function_formal(file, word_nr); + lf_printf (file, ");\n"); + lf_printf (file, "\n"); + } + if (options.gen.code == generate_calls + && options.gen.icache) + { + function_entry_traverse (file, functions, + print_icache_internal_function_declaration, + NULL); + while (semantic != NULL) + { + print_icache_declaration (file, + semantic->insn, + semantic->expanded_bits, + semantic->opcodes, + semantic->nr_prefetched_words); + semantic = semantic->next; + } + } + else + { + lf_print__this_file_is_empty (file, "generating jump engine"); + } +} + +static void +gen_icache_c (lf *file, + insn_list *semantic, + function_entry *functions, + cache_entry *cache_rules) +{ + /* output `internal' invalid/floating-point unavailable functions + where needed */ + if (options.gen.code == generate_calls + && options.gen.icache) + { + 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, "#include \"icache.h\"\n"); + lf_printf (file, "#include \"support.h\"\n"); + lf_printf (file, "\n"); + function_entry_traverse (file, functions, + print_icache_internal_function_definition, + NULL); + lf_printf (file, "\n"); + while (semantic != NULL) + { + print_icache_definition (file, + semantic->insn, + semantic->expanded_bits, + semantic->opcodes, + cache_rules, + semantic->nr_prefetched_words); + semantic = semantic->next; + } + } + else + { + lf_print__this_file_is_empty (file, "generating jump engine"); + } +} + + +/****************************************************************/ + + +static void +gen_idecode_h (lf *file, + gen_table *gen, + insn_table *insns, + cache_entry *cache_rules) +{ + lf_printf (file, "typedef unsigned%d %sinstruction_word;\n", + options.insn_bit_size, options.module.global.prefix.l); + if (options.gen.delayed_branch) + { + lf_printf (file, "typedef struct _%sinstruction_address {\n", + options.module.global.prefix.l); + lf_printf (file, " address_word ip; /* instruction pointer */\n"); + lf_printf (file, " address_word dp; /* delayed-slot pointer */\n"); + lf_printf (file, "} %sinstruction_address;\n", options.module.global.prefix.l); + } + else + { + lf_printf (file, "typedef address_word %sinstruction_address;\n", + options.module.global.prefix.l); + + } + if (options.gen.nia == nia_is_invalid + && strlen (options.module.global.prefix.u) > 0) + { + lf_indent_suppress (file); + lf_printf (file, "#define %sINVALID_INSTRUCTION_ADDRESS ", + options.module.global.prefix.u); + lf_printf (file, "INVALID_INSTRUCTION_ADDRESS\n"); + } + lf_printf (file, "\n"); + print_icache_struct (file, insns, cache_rules); + lf_printf (file, "\n"); + if (options.gen.icache) + { + ERROR ("FIXME - idecode with icache suffering from bit-rot"); + } + else + { + gen_list *entry; + for (entry = gen->tables; entry != NULL; entry = entry->next) + { + print_idecode_issue_function_header (file, + (options.gen.multi_sim + ? entry->model->name + : NULL), + is_function_declaration, + 1/*ALWAYS ONE WORD*/); + } + if (options.gen.multi_sim) + { + print_idecode_issue_function_header (file, + NULL, + is_function_variable, + 1/*ALWAYS ONE WORD*/); + } + } +} + + +static void +gen_idecode_c (lf *file, + gen_table *gen, + insn_table *isa, + cache_entry *cache_rules) +{ + /* the intro */ + print_includes (file); + print_include_inline (file, options.module.semantics); + lf_printf (file, "\n"); + + print_idecode_globals (file); + lf_printf (file, "\n"); + + switch (options.gen.code) + { + case generate_calls: + { + gen_list *entry; + for (entry = gen->tables; entry != NULL; entry = entry->next) + { + print_idecode_lookups (file, entry->table, cache_rules); + + /* output the main idecode routine */ + if (!options.gen.icache) + { + print_idecode_issue_function_header (file, + (options.gen.multi_sim + ? entry->model->name + : NULL), + 1/*is definition*/, + 1/*ALWAYS ONE WORD*/); + lf_printf (file, "{\n"); + lf_indent (file, +2); + lf_printf (file, "%sinstruction_address nia;\n", + options.module.global.prefix.l); + print_idecode_body (file, entry->table, "nia ="); + lf_printf (file, "return nia;"); + lf_indent (file, -2); + lf_printf (file, "}\n"); + } + } + break; + } + case generate_jumps: + { + lf_print__this_file_is_empty (file, "generating a jump engine"); + break; + } + } +} + + +/****************************************************************/ + + +static void +gen_run_c (lf *file, + gen_table *gen) +{ + gen_list *entry; + lf_printf (file, "#include \"sim-main.h\"\n"); + lf_printf (file, "#include \"engine.h\"\n"); + lf_printf (file, "#include \"idecode.h\"\n"); + lf_printf (file, "#include \"bfd.h\"\n"); + lf_printf (file, "\n"); + + if (options.gen.multi_sim) + { + print_idecode_issue_function_header (file, NULL, is_function_variable, 1); + lf_printf (file, "\n"); + print_engine_run_function_header (file, NULL, is_function_variable); + lf_printf (file, "\n"); + } + + lf_printf (file, "void\n"); + lf_printf (file, "sim_engine_run (SIM_DESC sd,\n"); + lf_printf (file, " int next_cpu_nr,\n"); + lf_printf (file, " int nr_cpus,\n"); + lf_printf (file, " int siggnal)\n"); + lf_printf (file, "{\n"); + lf_indent (file, +2); + if (options.gen.multi_sim) + { + lf_printf (file, "int mach;\n"); + lf_printf (file, "if (STATE_ARCHITECTURE (sd) == NULL)\n"); + lf_printf (file, " mach = 0;\n"); + lf_printf (file, "else\n"); + lf_printf (file, " mach = STATE_ARCHITECTURE (sd)->mach;\n"); + lf_printf (file, "switch (mach)\n"); + lf_printf (file, " {\n"); + lf_indent (file, +2); + for (entry = gen->tables; entry != NULL; entry = entry->next) + { + if (options.gen.default_model != NULL + && (strcmp (entry->model->name, options.gen.default_model) == 0 + || strcmp (entry->model->full_name, options.gen.default_model) == 0)) + lf_printf (file, "default:\n"); + lf_printf (file, "case bfd_mach_%s:\n", entry->model->full_name); + lf_indent (file, +2); + print_function_name (file, + "issue", + NULL, /* format name */ + NULL, /* NO processor */ + NULL, /* expanded bits */ + function_name_prefix_idecode); + lf_printf (file, " = "); + print_function_name (file, + "issue", + NULL, /* format name */ + entry->model->name, + NULL, /* expanded bits */ + function_name_prefix_idecode); + lf_printf (file, ";\n"); + print_function_name (file, + "run", + NULL, /* format name */ + NULL, /* NO processor */ + NULL, /* expanded bits */ + function_name_prefix_engine); + lf_printf (file, " = "); + print_function_name (file, + "run", + NULL, /* format name */ + entry->model->name, + NULL, /* expanded bits */ + function_name_prefix_engine); + lf_printf (file, ";\n"); + lf_printf (file, "break;\n"); + lf_indent (file, -2); + } + if (options.gen.default_model == NULL) + { + lf_printf (file, "default:\n"); + lf_indent (file, +2); + lf_printf (file, "sim_engine_abort (sd, NULL, NULL_CIA,\n"); + lf_printf (file, " \"sim_engine_run - unknown machine\");\n"); + lf_printf (file, "break;\n"); + lf_indent (file, -2); + } + lf_indent (file, -2); + lf_printf (file, " }\n"); + } + print_function_name (file, + "run", + NULL, /* format name */ + NULL, /* NO processor */ + NULL, /* expanded bits */ + function_name_prefix_engine); + lf_printf (file, " (sd, next_cpu_nr, nr_cpus, siggnal);\n"); + lf_indent (file, -2); + lf_printf (file, "}\n"); +} + +/****************************************************************/ + +static gen_table * +do_gen (insn_table *isa, + decode_table *decode_rules) +{ + gen_table *gen; + if (decode_rules == NULL) + error (NULL, "Must specify a decode table\n"); + if (isa == NULL) + error (NULL, "Must specify an instruction table\n"); + if (decode_table_max_word_nr (decode_rules) > 0) + options.gen.multi_word = decode_table_max_word_nr (decode_rules); + gen = make_gen_tables (isa, decode_rules); + gen_tables_expand_insns (gen); + gen_tables_expand_semantics (gen); + return gen; +} + +/****************************************************************/ + +igen_options options; + +int +main (int argc, + char **argv, + char **envp) +{ + cache_entry *cache_rules = NULL; + lf_file_references file_references = lf_include_references; + decode_table *decode_rules = NULL; + insn_table *isa = NULL; + gen_table *gen = NULL; + char *real_file_name = NULL; + int is_header = 0; + int ch; + lf *standard_out = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "igen"); + + INIT_OPTIONS (); + + if (argc == 1) + { + printf ("Usage:\n"); + printf ("\n"); + printf (" igen <config-opts> ... <input-opts>... <output-opts>...\n"); + printf ("\n"); + printf ("Config options:\n"); + printf ("\n"); + printf (" -B <bit-size>\n"); + printf ("\t Set the number of bits in an instruction (depreciated).\n"); + printf ("\t This option can now be set directly in the instruction table.\n"); + printf ("\n"); + printf (" -D <data-structure>\n"); + printf ("\t Dump the specified data structure to stdout. Valid structures include:\n"); + printf ("\t processor-names - list the names of all the processors (models)\n"); + printf ("\n"); + printf (" -F <filter-list>\n"); + printf ("\t Filter out any instructions with a non-empty flags field that contains\n"); + printf ("\t a flag not listed in the <filter-list>.\n"); + printf ("\n"); + printf (" -H <high-bit>\n"); + 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 <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 ("\t all models.).\n"); + printf ("\n"); + printf (" -N <nr-cpus>\n"); + printf ("\t Generate a simulator supporting <nr-cpus>\n"); + printf ("\t Specify `-N 0' to disable generation of the SMP. Specifying `-N 1' will\n"); + printf ("\t still generate an SMP enabled simulator but will only support one CPU.\n"); + printf ("\n"); + printf (" -T <mechanism>\n"); + printf ("\t Override the decode mechanism specified by the decode rules\n"); + printf ("\n"); + printf (" -P <prefix>\n"); + printf ("\t Prepend global names (except itable) with the string <prefix>.\n"); + printf ("\t Specify -P <module>=<prefix> to set a specific <module>'s prefix.\n"); + printf ("\n"); + printf (" -S <suffix>\n"); + printf ("\t Replace a global name (suffix) (except itable) with the string <suffix>.\n"); + printf ("\t Specify -S <module>=<suffix> to change a specific <module>'s name (suffix).\n"); + printf ("\n"); + printf (" -Werror\n"); + printf ("\t Make warnings errors\n"); + printf (" -Wnodiscard\n"); + printf ("\t Suppress warnings about discarded functions and instructions\n"); + printf (" -Wnowidth\n"); + printf ("\t Suppress warnings about instructions with invalid widths\n"); + printf (" -Wnounimplemented\n"); + printf ("\t Suppress warnings about unimplemented instructions\n"); + printf ("\n"); + printf (" -G [!]<gen-option>\n"); + printf ("\t Any of the following options:\n"); + printf ("\n"); + printf ("\t decode-duplicate - Override the decode rules, forcing the duplication of\n"); + printf ("\t semantic functions\n"); + printf ("\t decode-combine - Combine any duplicated entries within a table\n"); + printf ("\t decode-zero-reserved - Override the decode rules, forcing reserved bits to be\n"); + printf ("\t treated as zero.\n"); + printf ("\t decode-switch-is-goto - Overfide the padded-switch code type as a goto-switch\n"); + printf ("\n"); + printf ("\t gen-conditional-issue - conditionally issue each instruction\n"); + 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[=<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[=MODEL] - generate multiple simulators - one per model\n"); + printf ("\t If specified MODEL is made the default architecture.\n"); + printf ("\t By default, a single simulator that will\n"); + printf ("\t execute any instruction is generated\n"); + printf ("\t gen-multi-word - generate code allowing for multi-word insns\n"); + printf ("\t gen-semantic-icache - include semantic code in cracking functions\n"); + printf ("\t gen-slot-verification - perform slot verification as part of decode\n"); + printf ("\t gen-nia-invalid - NIA defaults to nia_invalid\n"); + printf ("\t gen-nia-void - do not compute/return NIA\n"); + printf ("\n"); + printf ("\t trace-combine - report combined entries a rule application\n"); + printf ("\t trace-entries - report entries after a rules application\n"); + printf ("\t trace-rule-rejection - report each rule as rejected\n"); + printf ("\t trace-rule-selection - report each rule as selected\n"); + printf ("\t trace-insn-insertion - report each instruction as it is inserted into a decode table\n"); + printf ("\t trace-rule-expansion - report each instruction as it is expanded (before insertion into a decode table)\n"); + printf ("\t trace-all - enable all trace options\n"); + printf ("\n"); + printf ("\t field-widths - instruction formats specify widths (depreciated)\n"); + printf ("\t By default, an instruction format specifies bit\n"); + printf ("\t positions\n"); + printf ("\t This option can now be set directly in the\n"); + printf ("\t instruction table\n"); + printf ("\t jumps - use jumps instead of function calls\n"); + printf ("\t omit-line-numbers - do not include line number information in the output\n"); + printf ("\n"); + printf ("Input options:\n"); + printf ("\n"); + printf (" -k <cache-rules> (depreciated)\n"); + printf (" -o <decode-rules>\n"); + printf (" -i <instruction-table>\n"); + printf ("\n"); + printf ("Output options:\n"); + printf ("\n"); + printf (" -x Perform expansion (required)\n"); + printf (" -n <real-name> Specify the real name of the next output file\n"); + printf (" -h Generate the header (.h) file rather than the body (.c)\n"); + printf (" -c <output-file> output icache\n"); + printf (" -d <output-file> output idecode\n"); + printf (" -e <output-file> output engine\n"); + printf (" -f <output-file> output support functions\n"); + printf (" -m <output-file> output model\n"); + printf (" -r <output-file> output multi-sim run\n"); + printf (" -s <output-file> output schematic\n"); + printf (" -t <output-file> output itable\n"); + } + + while ((ch = getopt(argc, argv, + "B:D:F:G:H:I:M:N:P:T:W:o:k:i:n:hc:d:e:m:r:s:t:f:x")) + != -1) + { + fprintf (stderr, " -%c ", ch); + if (optarg) + fprintf (stderr, "%s ", optarg); + fprintf (stderr, "\\\n"); + + switch(ch) + { + + case 'M': + filter_parse (&options.model_filter, optarg); + break; + + case 'D': + if (strcmp (optarg, "processor-names")) + { + char *processor; + for (processor = filter_next (options.model_filter, ""); + processor != NULL; + processor = filter_next (options.model_filter, processor)) + lf_printf (standard_out, "%s\n", processor); + } + else + error (NULL, "Unknown data structure %s, not dumped\n", optarg); + break; + + case 'F': + filter_parse (&options.flags_filter, optarg); + break; + + case 'I': + { + table_include **dir = &options.include; + while ((*dir) != NULL) + dir = &(*dir)->next; + (*dir) = ZALLOC (table_include); + (*dir)->dir = strdup (optarg); + } + break; + + case 'B': + options.insn_bit_size = a2i (optarg); + if (options.insn_bit_size <= 0 + || options.insn_bit_size > max_insn_bit_size) + { + error (NULL, "Instruction bitsize must be in range 1..%d\n", + max_insn_bit_size); + } + if (options.hi_bit_nr != options.insn_bit_size - 1 + && options.hi_bit_nr != 0) + { + error (NULL, "Conflict betweem hi-bit-nr and insn-bit-size\n"); + } + break; + + case 'H': + options.hi_bit_nr = a2i (optarg); + if (options.hi_bit_nr != options.insn_bit_size - 1 + && options.hi_bit_nr != 0) + { + error (NULL, "Conflict between hi-bit-nr and insn-bit-size\n"); + } + break; + + case 'N': + options.gen.smp = a2i (optarg); + break; + + case 'P': + case 'S': + { + igen_module *names; + igen_name *name; + char *chp; + chp = strchr (optarg, '='); + if (chp == NULL) + { + names = &options.module.global; + chp = optarg; + } + else + { + chp = chp + 1; /* skip `=' */ + names = NULL; + if (strncmp (optarg, "global=", chp - optarg) == 0) + { + names = &options.module.global; + } + if (strncmp (optarg, "engine=", chp - optarg) == 0) + { + names = &options.module.engine; + } + if (strncmp (optarg, "icache=", chp - optarg) == 0) + { + names = &options.module.icache; + } + if (strncmp (optarg, "idecode=", chp - optarg) == 0) + { + names = &options.module.idecode; + } + if (strncmp (optarg, "itable=", chp - optarg) == 0) + { + names = &options.module.itable; + } + if (strncmp (optarg, "semantics=", chp - optarg) == 0) + { + names = &options.module.semantics; + } + if (strncmp (optarg, "support=", chp - optarg) == 0) + { + names = &options.module.support; + } + if (names == NULL) + { + error (NULL, "Prefix `%s' unreconized\n", optarg); + } + } + switch (ch) + { + case 'P': + name = &names->prefix; + break; + case 'S': + name = &names->suffix; + break; + } + name->u = strdup (chp); + name->l = strdup (chp); + chp = name->u; + while (*chp) { + if (islower(*chp)) + *chp = toupper(*chp); + chp++; + } + if (name == &options.module.global.prefix) + { + options.module.engine.prefix = options.module.global.prefix; + options.module.icache.prefix = options.module.global.prefix; + options.module.idecode.prefix = options.module.global.prefix; + /* options.module.itable.prefix = options.module.global.prefix; */ + options.module.semantics.prefix = options.module.global.prefix; + options.module.support.prefix = options.module.global.prefix; + } + if (name == &options.module.global.suffix) + { + options.module.engine.suffix = options.module.global.suffix; + options.module.icache.suffix = options.module.global.suffix; + options.module.idecode.suffix = options.module.global.suffix; + /* options.module.itable.suffix = options.module.global.suffix; */ + options.module.semantics.suffix = options.module.global.suffix; + options.module.support.suffix = options.module.global.suffix; + } + break; + } + + case 'W': + { + if (strcmp (optarg, "error") == 0) + options.warning = error; + else if (strcmp (optarg, "nodiscard") == 0) + options.warn.discard = 0; + else if (strcmp (optarg, "discard") == 0) + options.warn.discard = 1; + else if (strcmp (optarg, "nowidth") == 0) + options.warn.width = 0; + else if (strcmp (optarg, "width") == 0) + options.warn.width = 1; + else if (strcmp (optarg, "nounimplemented") == 0) + options.warn.unimplemented = 0; + else if (strcmp (optarg, "unimplemented") == 0) + options.warn.unimplemented = 1; + else + error (NULL, "Unknown -W argument `%s'\n", optarg); + break; + } + + + case 'G': + { + 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); + options.gen.icache = enable_p; + break; + 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 (strncmp (argp, "gen-multi-sim", strlen ("gen-multi-sim")) == 0) + { + char *arg = &argp[strlen ("gen-multi-sim")]; + switch (arg[0]) + { + case '=': + options.gen.multi_sim = enable_p; + options.gen.default_model = arg + 1; + if (! filter_is_member (options.model_filter, options.gen.default_model)) + error (NULL, "multi-sim model %s unknown\n", options.gen.default_model); + break; + case '\0': + options.gen.multi_sim = enable_p; + options.gen.default_model = NULL; + break; + default: + error (NULL, "Expecting -Ggen-multi-sim or -Ggen-multi-sim=<MODEL>\n"); + break; + } + } + 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-all") == 0) + { + memset (&options.trace, enable_p, sizeof (options.trace)); + } + 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, "trace-insn-insertion") == 0) + { + options.trace.insn_insertion = enable_p; + } + else if (strcmp (argp, "trace-insn-expansion") == 0) + { + options.trace.insn_expansion = 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) + error (NULL, "illegal-instruction missing from insn table\n"); + break; + + case 'x': + gen = do_gen (isa, decode_rules); + break; + + case 'o': + decode_rules = load_decode_table (optarg); + break; + + case 'k': + if (isa != NULL) + error (NULL, "Cache file must appear before the insn file\n"); + cache_rules = load_cache_table (optarg); + break; + + case 'n': + real_file_name = strdup(optarg); + break; + + case 'h': + is_header = 1; + break; + + case 'c': + case 'd': + case 'e': + case 'f': + case 'm': + case 'r': + case 's': + case 't': + { + lf *file = lf_open(optarg, real_file_name, file_references, + (is_header ? lf_is_h : lf_is_c), + argv[0]); + if (gen == NULL && ch != 't' && ch != 'm' && ch != 'f') + { + options.warning (NULL, "Explicitly generate tables with -x option\n"); + gen = do_gen (isa, decode_rules); + } + lf_print__file_start(file); + switch (ch) + { + case 'm': + if (is_header) + gen_model_h (file, isa); + else + gen_model_c (file, isa); + break; + case 't': + if (is_header) + gen_itable_h (file, isa); + else + gen_itable_c (file, isa); + break; + case 'f': + if (is_header) + gen_support_h (file, isa); + else + gen_support_c (file, isa); + break; + case 'r': + if (is_header) + options.warning (NULL, "-hr option ignored\n"); + else + gen_run_c (file, gen); + break; + case 's': + if(is_header) + gen_semantics_h (file, gen->semantics, isa->max_nr_words); + else + gen_semantics_c (file, gen->semantics, isa->caches); + break; + case 'd': + if (is_header) + gen_idecode_h (file, gen, isa, cache_rules); + else + gen_idecode_c (file, gen, isa, cache_rules); + break; + case 'e': + if (is_header) + gen_engine_h (file, gen, isa, cache_rules); + else + gen_engine_c (file, gen, isa, cache_rules); + break; + case 'c': + if (is_header) + gen_icache_h (file, + gen->semantics, + isa->functions, + isa->max_nr_words); + else + gen_icache_c (file, + gen->semantics, + isa->functions, + cache_rules); + break; + } + lf_print__file_finish(file); + lf_close(file); + is_header = 0; + } + real_file_name = NULL; + break; + default: + ERROR ("Bad switch"); + } + } + return (0); +} diff --git a/sim/igen/igen.h b/sim/igen/igen.h new file mode 100644 index 00000000000..bdfdb833ef5 --- /dev/null +++ b/sim/igen/igen.h @@ -0,0 +1,234 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, 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. + + */ + +/* code-generation options: */ + +typedef enum { + + /* Transfer control to an instructions semantic code using the the + standard call/return mechanism */ + + generate_calls, + + /* Transfer control to an instructions semantic code using + (computed) goto's instead of the more conventional call/return + mechanism */ + + generate_jumps, + +} igen_code; + +typedef enum { + nia_is_cia_plus_one, + nia_is_void, + nia_is_invalid, +} igen_nia; + + + +typedef struct _igen_gen_options igen_gen_options; +struct _igen_gen_options { + int direct_access; + int semantic_icache; + int insn_in_icache; + int conditional_issue; + int slot_verification; + int delayed_branch; + + /* If zeroing a register, which one? */ + int zero_reg; + int zero_reg_nr; + + /* should multiple simulators be generated? */ + int multi_sim; + + /* name of the default multi-sim model */ + char *default_model; + + /* should the simulator support multi word instructions and if so, + what is the max nr of words. */ + int multi_word; + + /* SMP? Should the generated code include SMP support (>0) and if + so, for how many processors? */ + int smp; + + /* how should the next instruction address be computed? */ + igen_nia nia; + + /* nr of instructions in the decoded instruction cache */ + int icache; + int icache_size; + + /* see above */ + igen_code code; +}; + + +typedef struct _igen_trace_options igen_trace_options; +struct _igen_trace_options { + int rule_selection; + int rule_rejection; + int insn_insertion; + int insn_expansion; + int entries; + int combine; +}; + +typedef struct _igen_name { + char *u; + char *l; +} igen_name; +typedef struct _igen_module { + igen_name prefix; + igen_name suffix; +} igen_module; + +typedef struct _igen_module_options { + igen_module global; + igen_module engine; + igen_module icache; + igen_module idecode; + igen_module itable; + igen_module semantics; + igen_module support; +} igen_module_options; + +typedef struct _igen_decode_options igen_decode_options ; +struct _igen_decode_options { + + /* Combine tables? Should the generator make a second pass through + each generated table looking for any sub-entries that contain the + same instructions. Those entries being merged into a single + table */ + int combine; + + /* Instruction expansion? Should the semantic code for each + instruction, when the oportunity arrises, be expanded according + to the variable opcode files that the instruction decode process + renders constant */ + int duplicate; + + /* Treat reserved fields as constant (zero) instead of ignoring + their value when determining decode tables */ + int zero_reserved; + + /* Convert any padded switch rules into goto_switch */ + int switch_as_goto; + + /* Force all tables to be generated with this lookup mechanism */ + char *overriding_gen; +}; + + +typedef struct _igen_warn_options igen_warn_options; +struct _igen_warn_options { + + /* Issue warning about discarded instructions */ + int discard; + + /* Issue warning about invalid instruction widths */ + int width; + + /* Issue warning about unimplemented instructions */ + int unimplemented; + +}; + + + +typedef struct _igen_options igen_options; +struct _igen_options { + + /* What does the instruction look like - bit ordering, size, widths or + offesets */ + int hi_bit_nr; + int insn_bit_size; + int insn_specifying_widths; + + /* what should global names be prefixed with? */ + igen_module_options module; + + /* See above for options and flags */ + igen_gen_options gen; + + /* See above for trace options */ + igen_trace_options trace; + + /* See above for include options */ + table_include *include; + + /* See above for decode options */ + igen_decode_options decode; + + /* Filter set to be used on the flag field of the instruction table */ + filter *flags_filter; + + /* See above for warn options */ + igen_warn_options warn; + + /* Be more picky about the input */ + error_func (*warning); + + /* Model (processor) set - like flags_filter. Used to select the + specific ISA within a processor family. */ + filter *model_filter; + + /* Format name set */ + filter *format_name_filter; +}; + +extern igen_options options; + +/* default options - hopefully backward compatible */ \ +#define INIT_OPTIONS() \ +do { \ + memset (&options, 0, sizeof options); \ + memset (&options.warn, -1, sizeof (options.warn)); \ + options.hi_bit_nr = 0; \ + options.insn_bit_size = default_insn_bit_size; \ + options.insn_specifying_widths = 0; \ + options.module.global.prefix.u = ""; \ + options.module.global.prefix.l = ""; \ + /* the prefixes */ \ + options.module.engine = options.module.global; \ + options.module.icache = options.module.global; \ + options.module.idecode = options.module.global; \ + options.module.itable = options.module.global; \ + options.module.semantics = options.module.global; \ + options.module.support = options.module.global; \ + /* the suffixes */ \ + options.module.engine.suffix.l = "engine"; \ + options.module.engine.suffix.u = "ENGINE"; \ + options.module.icache.suffix.l = "icache"; \ + options.module.icache.suffix.u = "ICACHE"; \ + options.module.idecode.suffix.l = "idecode"; \ + options.module.idecode.suffix.u = "IDECODE"; \ + options.module.itable.suffix.l = "itable"; \ + options.module.itable.suffix.u = "ITABLE"; \ + options.module.semantics.suffix.l = "semantics"; \ + options.module.semantics.suffix.u = "SEMANTICS"; \ + options.module.support.suffix.l = "support"; \ + options.module.support.suffix.u = "SUPPORT"; \ + /* misc stuff */ \ + options.gen.code = generate_calls; \ + options.gen.icache_size = 1024; \ + options.warning = warning; \ +} while (0) diff --git a/sim/igen/ld-cache.c b/sim/igen/ld-cache.c new file mode 100644 index 00000000000..63bd111ac2e --- /dev/null +++ b/sim/igen/ld-cache.c @@ -0,0 +1,114 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, 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 "misc.h" +#include "lf.h" +#include "table.h" +#include "filter.h" +#include "igen.h" + +#include "ld-insn.h" +#include "ld-cache.h" + +#ifndef NULL +#define NULL 0 +#endif + + +enum { + ca_type, + ca_field_name, + ca_derived_name, + ca_type_def, + ca_expression, + nr_cache_rule_fields, +}; + +static const name_map cache_type_map[] = { + { "cache", cache_value }, + { "compute", compute_value }, + { "scratch", scratch_value }, + { NULL, 0 }, +}; + + +cache_entry * +load_cache_table (char *file_name) +{ + cache_entry *cache = NULL; + cache_entry **last = &cache; + table *file = table_open (file_name); + table_entry *entry; + while ((entry = table_read (file)) != NULL) + { + cache_entry *new_rule = ZALLOC (cache_entry); + new_rule->line = entry->line; + new_rule->entry_type = name2i (entry->field[ca_type], cache_type_map); + new_rule->name = entry->field[ca_derived_name]; + filter_parse (&new_rule->original_fields, + entry->field[ca_field_name]); + new_rule->type = entry->field[ca_type_def]; + /* expression is the concatenation of the remaining fields */ + if (entry->nr_fields > ca_expression) + { + int len = 0; + int chi; + for (chi = ca_expression; chi < entry->nr_fields; chi++) + { + len += strlen (" : ") + strlen (entry->field[chi]); + } + new_rule->expression = NZALLOC (char, len); + strcpy (new_rule->expression, entry->field[ca_expression]); + for (chi = ca_expression + 1; chi < entry->nr_fields; chi++) + { + strcat (new_rule->expression, " : "); + strcat (new_rule->expression, entry->field[chi]); + } + } + /* insert it */ + *last = new_rule; + last = &new_rule->next; + } + return cache; +} + + + +#ifdef MAIN + +igen_options options; + +int +main(int argc, char **argv) +{ + cache_entry *rules = NULL; + lf *l; + + if (argc != 2) + error (NULL, "Usage: cache <cache-file>\n"); + + rules = load_cache_table (argv[1]); + l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-ld-insn"); + dump_cache_entries (l, "(", rules, ")\n"); + + return 0; +} +#endif diff --git a/sim/igen/ld-cache.h b/sim/igen/ld-cache.h new file mode 100644 index 00000000000..fb81e6a3b39 --- /dev/null +++ b/sim/igen/ld-cache.h @@ -0,0 +1,66 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, 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. + + */ + + + +/* For backward compatibility only - load a standalone cache macro table */ + +/* Instruction unpacking: + + Once the instruction has been decoded, the register (and other) + fields within the instruction need to be extracted. + + The table that follows determines how each field should be treated. + Importantly it considers the case where the extracted field is to + be used immediatly or stored in an instruction cache. + + <type> + + Indicates what to do with the cache entry. If a cache is to be + used. SCRATCH and CACHE values are defined when a cache entry is + being filled while CACHE and COMPUTE values are defined in the + semantic code. + + Zero marks the end of the table. More importantly 1. indicates + that the entry is valid and can be cached. 2. indicates that that + the entry is valid but can not be cached. + + <field_name> + + The field name as given in the instruction spec. + + <derived_name> + + A new name for <field_name> once it has been extracted from the + instruction (and possibly stored in the instruction cache). + + <type> + + String specifying the storage type for <new_name> (the extracted + field>. + + <expression> + + Specifies how to get <new_name> from <old_name>. If null, old and + new name had better be the same. */ + + +extern cache_entry *load_cache_table +(char *file_name); diff --git a/sim/igen/ld-decode.c b/sim/igen/ld-decode.c new file mode 100644 index 00000000000..baea404d5a9 --- /dev/null +++ b/sim/igen/ld-decode.c @@ -0,0 +1,404 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, 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. + + */ + +/* load the opcode stat structure */ + +#include "misc.h" +#include "lf.h" +#include "table.h" +#include "filter.h" + +#include "igen.h" + +#include "ld-decode.h" + +#ifndef NULL +#define NULL 0 +#endif + + +static const name_map decode_type_map[] = { + { "normal", normal_decode_rule }, + { "boolean", boolean_rule }, + { NULL, normal_decode_rule }, +}; + +static const name_map decode_gen_map[] = { + { "array", array_gen }, + { "switch", switch_gen }, + { "padded-switch", padded_switch_gen }, + { "goto-switch", goto_switch_gen }, + { NULL, -1 }, +}; + +static const name_map decode_reserved_map[] = { + { "zero-reserved", 1 }, + { NULL, 0 }, +}; + +static const name_map decode_duplicates_map[] = { + { "duplicate", 1 }, + { NULL, 0 }, +}; + +static const name_map decode_combine_map[] = { + { "combine", 1 }, + { NULL, 0 }, +}; + +static const name_map decode_search_map[] = { + { "constants", decode_find_constants }, + { "mixed", decode_find_mixed }, + { "strings", decode_find_strings }, + { NULL, decode_find_mixed }, +}; + + +static void +set_bits (int bit[max_insn_bit_size], + unsigned64 value) +{ + int bit_nr; + for (bit_nr = 0; bit_nr < max_insn_bit_size; bit_nr++) + { + if (bit_nr < options.insn_bit_size) + bit[bit_nr] = (value >> (options.insn_bit_size - bit_nr - 1)) & 1; + else + bit[bit_nr] = 0; + } +} + +decode_table * +load_decode_table(char *file_name) +{ + table *file = table_open (file_name); + table_entry *entry; + decode_table *table = NULL; + decode_table **curr_rule = &table; + while ((entry = table_read (file)) != NULL) + { + char *decode_options = entry->field[decode_options_field]; + decode_table *new_rule = ZALLOC (decode_table); + if (entry->nr_fields < min_nr_decode_fields) + error (entry->line, "Missing decode table fields\n"); + new_rule->line = entry->line; + + /* the options field */ + new_rule->type = name2i (decode_options, decode_type_map); + if (options.decode.overriding_gen != NULL) + new_rule->gen = name2i (options.decode.overriding_gen, decode_gen_map); + else + new_rule->gen = name2i (decode_options, decode_gen_map); + if (new_rule->gen == padded_switch_gen + && options.decode.switch_as_goto) + new_rule->gen = goto_switch_gen; + if (options.decode.zero_reserved) + new_rule->with_zero_reserved = 1; + else + new_rule->with_zero_reserved = name2i (decode_options, decode_reserved_map); + if (options.decode.duplicate) + new_rule->with_duplicates = 1; + else + new_rule->with_duplicates = name2i (decode_options, decode_duplicates_map); + if (options.decode.combine) + new_rule->with_combine = 1; + else + new_rule->with_combine = name2i (decode_options, decode_combine_map); + if (new_rule->type == boolean_rule) + { + char *chp = decode_options; + while (*chp != '\0') + { + if (isdigit (*chp)) + { + new_rule->constant = a2i (chp); + break; + } + chp = skip_to_separator (chp, ","); + chp = skip_spaces (chp); + } + } + + /* First and last */ + if (entry->nr_fields > decode_first_field + && strlen (entry->field[decode_first_field]) > 0) + { + new_rule->first = target_a2i (options.hi_bit_nr, + entry->field[decode_first_field]); + if (new_rule->first < 0 || new_rule->first >= options.insn_bit_size) + error (new_rule->line, "First field out of range\n"); + } + else + new_rule->first = 0; + if (entry->nr_fields > decode_last_field + && strlen (entry->field[decode_last_field]) > 0) + { + new_rule->last = target_a2i (options.hi_bit_nr, + entry->field[decode_last_field]); + if (new_rule->last < 0 || new_rule->last >= options.insn_bit_size) + error (new_rule->line, "Last field out of range\n"); + } + else + new_rule->last = options.insn_bit_size - 1; + if (new_rule->first > new_rule->last) + error (new_rule->line, "First must preceed last\n"); + + /* force first/last, with default values based on first/last */ + if (entry->nr_fields > decode_force_first_field + && strlen (entry->field[decode_force_first_field]) > 0) + { + new_rule->force_first = target_a2i (options.hi_bit_nr, + entry->field[decode_force_first_field]); + if (new_rule->force_first < new_rule->first + || new_rule->force_first > new_rule->last + 1) + error (new_rule->line, "Force first out of range\n"); + } + else + new_rule->force_first = new_rule->last + 1; + if (entry->nr_fields > decode_force_last_field + && strlen (entry->field[decode_force_last_field]) > 0) + { + new_rule->force_last = target_a2i (options.hi_bit_nr, + entry->field[decode_force_last_field]); + if (new_rule->force_last > new_rule->last + || new_rule->force_last < new_rule->first - 1) + error (new_rule->line, "Force-last out of range\n"); + } + else + new_rule->force_last = new_rule->first - 1; + + /* fields to be treated as constant */ + if (entry->nr_fields > decode_constant_field_names_field) + filter_parse (&new_rule->constant_field_names, + entry->field[decode_constant_field_names_field]); + + /* applicable word nr */ + if (entry->nr_fields > decode_word_nr_field) + new_rule->word_nr = a2i (entry->field[decode_word_nr_field]); + + /* required instruction format names */ + if (entry->nr_fields > decode_format_names_field) + filter_parse (&new_rule->format_names, + entry->field[decode_format_names_field]); + + /* required processor models */ + if (entry->nr_fields > decode_model_names_field) + filter_parse (&new_rule->model_names, + entry->field[decode_model_names_field]); + + /* required paths */ + if (entry->nr_fields > decode_paths_field + && strlen (entry->field[decode_paths_field]) > 0) + { + decode_path_list **last = &new_rule->paths; + char *chp = entry->field[decode_paths_field]; + do + { + (*last) = ZALLOC (decode_path_list); + /* extra root/zero entry */ + (*last)->path = ZALLOC (decode_path); + do + { + decode_path *entry = ZALLOC (decode_path); + entry->opcode_nr = a2i (chp); + entry->parent = (*last)->path; + (*last)->path = entry; + chp = skip_digits (chp); + chp = skip_spaces (chp); + } + while (*chp == '.'); + last = &(*last)->next; + } + while (*chp == ','); + if (*chp != '\0') + error (entry->line, "Invalid path field\n"); + } + + /* collect up the list of optional special conditions applicable + to the rule */ + { + int field_nr = nr_decode_fields; + while (entry->nr_fields > field_nr) + { + decode_cond *cond = ZALLOC (decode_cond); + decode_cond **last; + if (entry->nr_fields > field_nr + decode_cond_mask_field) + set_bits (cond->mask, a2i (entry->field[field_nr + decode_cond_mask_field])); + if (entry->nr_fields > field_nr + decode_cond_value_field) + { + if (entry->field[field_nr + decode_cond_value_field][0] == '!') + { + cond->is_equal = 0; + set_bits (cond->value, a2i (entry->field[field_nr + decode_cond_value_field] + 1)); + } + else + { + cond->is_equal = 1; + set_bits (cond->value, a2i (entry->field[field_nr + decode_cond_value_field])); + } + } + if (entry->nr_fields > field_nr + decode_cond_word_nr_field) + cond->word_nr = a2i (entry->field[field_nr + decode_cond_word_nr_field]); + field_nr += nr_decode_cond_fields; + /* insert it */ + last = &new_rule->conditions; + while (*last != NULL) + last = &(*last)->next; + *last = cond; + } + } + *curr_rule = new_rule; + curr_rule = &new_rule->next; + } + return table; +} + + +int +decode_table_max_word_nr (decode_table *entry) +{ + int max_word_nr = 0; + while (entry != NULL) + { + decode_cond *cond; + if (entry->word_nr > max_word_nr) + max_word_nr = entry->word_nr; + for (cond = entry->conditions; cond != NULL; cond = cond->next) + { + if (cond->word_nr > max_word_nr) + max_word_nr = cond->word_nr; + } + entry = entry->next; + } + return max_word_nr; +} + + + +static void +dump_decode_cond (lf *file, + char *prefix, + decode_cond *cond, + char *suffix) +{ + lf_printf (file, "%s(decode_cond *) 0x%lx", prefix, (long) cond); + if (cond != NULL) + { + lf_indent (file, +1); + lf_printf (file, "\n(word_nr %d)", cond->word_nr); + lf_printf (file, "\n(mask 0x%lx)", (long) cond->mask); + lf_printf (file, "\n(value 0x%lx)", (long) cond->value); + lf_printf (file, "\n(is_equal 0x%lx)", (long) cond->is_equal); + lf_printf (file, "\n(next (decode_cond *) 0%lx)", (long) cond->next); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); +} + + +static void +dump_decode_conds (lf *file, + char *prefix, + decode_cond *cond, + char *suffix) +{ + lf_printf (file, "%s(decode_cond *) 0x%lx", prefix, (long) cond); + while (cond != NULL) + { + dump_decode_cond (file, "\n(", cond, ")"); + cond = cond->next; + } + lf_printf (file, "%s", suffix); +} + + +void +dump_decode_rule (lf *file, + char *prefix, + decode_table *rule, + char *suffix) +{ + lf_printf (file, "%s(decode_table *) 0x%lx", prefix, (long) rule); + if (rule != NULL) + { + lf_indent (file, +1); + dump_line_ref (file, "\n(line ", rule->line, ")"); + lf_printf (file, "\n(type %s)", i2name(rule->type, decode_type_map)); + lf_printf (file, "\n(gen %s)", i2name(rule->gen, decode_gen_map)); + lf_printf (file, "\n(first %d)", rule->first); + lf_printf (file, "\n(last %d)", rule->last); + lf_printf (file, "\n(force_first %d)", rule->force_first); + lf_printf (file, "\n(force_last %d)", rule->force_last); + dump_filter (file, "\n(constant_field_names \"", rule->constant_field_names, "\")"); + lf_printf (file, "\n(constant 0x%x)", rule->constant); + lf_printf (file, "\n(word_nr %d)", rule->word_nr); + lf_printf (file, "\n(with_zero_reserved %d)", rule->with_zero_reserved); + lf_printf (file, "\n(with_duplicates %d)", rule->with_duplicates); + lf_printf (file, "\n(with_combine %d)", rule->with_combine); + dump_filter (file, "\n(format_names \"", rule->format_names, "\")"); + dump_filter (file, "\n(model_names \"", rule->model_names, "\")"); + dump_decode_conds (file, "\n(conditions ", rule->conditions, ")"); + lf_printf (file, "\n(next 0x%lx)", (long) rule->next); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); +} + + +#ifdef MAIN + +static void +dump_decode_rules (lf *file, + char *prefix, + decode_table *rule, + char *suffix) +{ + lf_printf (file, "%s", prefix); + while (rule != NULL) + { + lf_indent (file, +1); + dump_decode_rule (file, "\n(", rule, ")"); + lf_indent (file, -1); + rule = rule->next; + } + lf_printf (file, "%s", suffix); +} + +igen_options options; + +int +main(int argc, char **argv) +{ + lf *l; + decode_table *rules; + + INIT_OPTIONS (options); + + if (argc != 3) + error (NULL, "Usage: decode <decode-file> <hi-bit-nr>\n"); + + options.hi_bit_nr = a2i (argv[2]); + rules = load_decode_table (argv[1]); + l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-ld-insn"); + dump_decode_rules (l, "(rules ", rules, ")\n"); + + return 0; +} +#endif diff --git a/sim/igen/ld-decode.h b/sim/igen/ld-decode.h new file mode 100644 index 00000000000..b24a231266a --- /dev/null +++ b/sim/igen/ld-decode.h @@ -0,0 +1,235 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, 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. + + */ + +/* Instruction decode table: + + <decode-rule> ::= + { <option> } + ":" [ <first> ] + ":" [ <last> ] + ":" [ <force-first> ] + ":" [ <force-last> ] + ":" [ <constant-field-names> ] + ":" [ <word-nr> ] + ":" [ <format-names> ] + ":" [ <model-names> ] + ":" [ <constant> ] + ":" [ <path> { "," <path> } ] + { ":" <special-mask> + ":" [ "!" ] <special-value> + ":" <word-nr> } + <nl> + ; + + + <path> ::= <int> "," <int> ;; + + <option> ::= + <reserved-options> + | <code-options> + | <optimize-options> + | <decode-options> + | <constant> + | <search-options> + ; + + <reserved-options> ::= "zero-reserved" ; + <gen-options> ::= "array" | "switch" | "padded-switch" | "goto-switch" ; + <optimize-options> ::= "duplicate" | "combine" + <decode-options> ::= "normal" | "boolean" ; + <search-options> ::= "constants" | "variables" | "mixed" + + Ignore the below: + + + The instruction decode table contains rules that dictate how igen + is going to firstly break down the opcode table and secondly + + The table that follows is used by gen to construct a decision tree + that can identify each possible instruction. Gen then outputs this + decision tree as (according to config) a table or switch statement + as the function idecode. + + In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS + determines of the semantic functions themselves should be expanded + in a similar way. + + <first> + <last> + + Range of bits (within the instruction) that should be searched for + an instruction field. Within such ranges, gen looks for opcodes + (constants), registers (strings) and reserved bits (slash) and + according to the rules that follows includes or excludes them from + a possible instruction field. + + <force_first> + <force_last> + + If an instruction field was found, enlarge the field size so that + it is forced to at least include bits starting from <force_first> + (<force_last>). To stop this occuring, use <force_first> = <last> + + 1 and <force_last> = <first> - 1. + + <force_reserved> + + Treat `/' (reserved) fields as a constant (zero) instead of + variable when looking for an instruction field. + + <force_expansion> + + Treat any contained register (string) fields as constant when + determining the instruction field. For the instruction decode (and + controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of + what would otherwize be non constant bits of an instruction. + + <use_switch> + + Should this table be expanded using a switch statement (val 1) and + if so, should it be padded with entries so as to force the compiler + to generate a jump table (val 2). Or a branch table (val 3). + + <special_mask> + <special_value> + <special_rule> + <special_constant> + + Special rule to fine tune how specific (or groups) of instructions + are expanded. The applicability of the rule is determined by + + <special_mask> != 0 && (instruction> & <special_mask>) == <special_value> + + Where <instruction> is obtained by looking only at constant fields + with in an instructions spec. When determining an expansion, the + rule is only considered when a node contains a single instruction. + <special_rule> can be any of: + + 0: for this instruction, expand by earlier rules + 1: expand bits <force_low> .. <force_hi> only + 2: boolean expansion of only zero/non-zero cases + 3: boolean expansion of equality of special constant + + */ + + +typedef enum { + normal_decode_rule, + boolean_rule, +} decode_special_type; + + +typedef enum { + invalid_gen, + array_gen, + switch_gen, + padded_switch_gen, + goto_switch_gen, +} decode_gen_type; + + +enum { + decode_cond_mask_field, + decode_cond_value_field, + decode_cond_word_nr_field, + nr_decode_cond_fields, +}; + +typedef struct _decode_path decode_path; +struct _decode_path { + int opcode_nr; + decode_path *parent; +}; + +typedef struct _decode_path_list decode_path_list; +struct _decode_path_list { + decode_path *path; + decode_path_list *next; +}; + + +typedef struct _decode_cond decode_cond; +struct _decode_cond { + int word_nr; + int mask[max_insn_bit_size]; + int value[max_insn_bit_size]; + int is_equal; + decode_cond *next; +}; + +typedef enum { + decode_find_mixed, + decode_find_constants, + decode_find_strings, +} decode_search_type; + +enum { + decode_options_field, + decode_first_field, + decode_last_field, + decode_force_first_field, + decode_force_last_field, + decode_constant_field_names_field, + decode_word_nr_field, + decode_format_names_field, + decode_model_names_field, + decode_paths_field, + nr_decode_fields, + min_nr_decode_fields = decode_last_field + 1, +}; + + +typedef struct _decode_table decode_table; +struct _decode_table { + line_ref *line; + decode_special_type type; + decode_gen_type gen; + decode_search_type search; + int first; + int last; + int force_first; + int force_last; + filter *constant_field_names; + int word_nr; + /* if a boolean */ + unsigned constant; + /* options */ + int with_zero_reserved; + int with_duplicates; + int with_combine; + /* conditions on the rule being applied */ + decode_path_list *paths; + filter *format_names; + filter *model_names; + decode_cond *conditions; + decode_table *next; +}; + + +extern decode_table *load_decode_table +(char *file_name); + +extern int decode_table_max_word_nr +(decode_table *rule); + +extern void dump_decode_rule +(lf *file, + char *prefix, + decode_table *rule, + char *suffix); diff --git a/sim/igen/ld-insn.c b/sim/igen/ld-insn.c new file mode 100644 index 00000000000..f812199e749 --- /dev/null +++ b/sim/igen/ld-insn.c @@ -0,0 +1,1829 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, 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 "misc.h" +#include "lf.h" +#include "table.h" +#include "filter.h" +#include "igen.h" +#include "ld-insn.h" + +static insn_word_entry * +parse_insn_word (line_ref *line, + char *string, + int word_nr) +{ + char *chp; + insn_word_entry *word = ZALLOC (insn_word_entry); + + /* create a leading sentinal */ + word->first = ZALLOC (insn_field_entry); + word->first->first = -1; + word->first->last = -1; + word->first->width = 0; + + /* and a trailing sentinal */ + word->last = ZALLOC (insn_field_entry); + word->last->first = options.insn_bit_size; + word->last->last = options.insn_bit_size; + word->last->width = 0; + + /* link them together */ + word->first->next = word->last; + word->last->prev = word->first; + + /* now work through the formats */ + chp = skip_spaces (string); + + while (*chp != '\0') { + char *start_pos; + int strlen_pos; + char *start_val; + int strlen_val; + insn_field_entry *new_field; + + /* create / link in the new field */ + new_field = ZALLOC (insn_field_entry); + new_field->next = word->last; + new_field->prev = word->last->prev; + new_field->next->prev = new_field; + new_field->prev->next = new_field; + new_field->word_nr = word_nr; + + /* break out the first field (if present) */ + start_pos = chp; + chp = skip_to_separator (chp, ".,!"); + strlen_pos = back_spaces (start_pos, chp) - start_pos; + + /* break out the second field (if present) */ + if (*chp != '.') + { + /* assume what was specified was the value (and not the start + position). Assume the value length implicitly specifies + the number of bits */ + start_val = start_pos; + strlen_val = strlen_pos; + start_pos = ""; + strlen_pos = 0; + } + else + { + chp++; /* skip `.' */ + chp = skip_spaces (chp); + start_val = chp; + if (*chp == '/' || *chp == '*') + { + do + { + chp++; + } + while (*chp == '/' || *chp == '*'); + } + else if (isalpha(*start_val)) + { + do + { + chp++; + } + while (isalnum(*chp) || *chp == '_'); + } + else if (isdigit(*start_val)) + { + do { + chp++; + } + while (isalnum(*chp)); + } + strlen_val = chp - start_val; + chp = skip_spaces (chp); + } + if (strlen_val == 0) + error (line, "Empty value field\n"); + + /* break out any conditional fields - { [ "!" | "=" [ <value> | <field-name> } */ + while (*chp == '!' || *chp == '=') + { + char *start; + char *end; + int len; + insn_field_cond *new_cond = ZALLOC (insn_field_cond); + + /* determine the conditional test */ + switch (*chp) + { + case '=': + new_cond->test = insn_field_cond_eq; + break; + case '!': + new_cond->test = insn_field_cond_ne; + break; + default: + ASSERT (0); + } + + /* save the value */ + chp++; + chp = skip_spaces (chp); + start = chp; + chp = skip_to_separator (chp, "+,:!="); + end = back_spaces (start, chp); + len = end - start; + if (len == 0) + error (line, "Missing or invalid conditional value\n"); + new_cond->string = NZALLOC (char, len + 1); + strncpy (new_cond->string, start, len); + + /* determine the conditional type */ + if (isdigit (*start)) + { + /* [ "!" | "=" ] <value> */ + new_cond->type = insn_field_cond_value; + new_cond->value = a2i (new_cond->string); + } + else + { + /* [ "!" | "=" ] <field> - check field valid */ + new_cond->type = insn_field_cond_field; + /* new_cond->field is determined in later */ + } + + /* Only a single `=' is permitted. */ + if ((new_cond->test == insn_field_cond_eq + && new_field->conditions != NULL) + || (new_field->conditions != NULL + && new_field->conditions->test == insn_field_cond_eq)) + error (line, "Only single conditional when `=' allowed\n"); + + /* insert it */ + { + insn_field_cond **last = &new_field->conditions; + while (*last != NULL) + last = &(*last)->next; + *last = new_cond; + } + } + + /* NOW verify that the field was finished */ + if (*chp == ',') + { + chp = skip_spaces (chp + 1); + if (*chp == '\0') + error (line, "empty field\n"); + } + else if (*chp != '\0') + { + error (line, "Missing field separator\n"); + } + + /* copy the value */ + new_field->val_string = NZALLOC (char, strlen_val+1); + strncpy (new_field->val_string, start_val, strlen_val); + if (isdigit (new_field->val_string[0])) + { + if (strlen_pos == 0) + { + /* when the length/pos field is omited, an integer field + is always binary */ + unsigned64 val = 0; + int i; + for (i = 0; i < strlen_val; i++) + { + if (new_field->val_string[i] != '0' + && new_field->val_string[i] != '1') + error (line, "invalid binary field %s\n", + new_field->val_string); + val = (val << 1) + (new_field->val_string[i] == '1'); + } + new_field->val_int = val; + new_field->type = insn_field_int; + } + else + { + new_field->val_int = a2i (new_field->val_string); + new_field->type = insn_field_int; + } + } + else if (new_field->val_string[0] == '/') + { + new_field->type = insn_field_reserved; + } + else if (new_field->val_string[0] == '*') + { + new_field->type = insn_field_wild; + } + else + { + new_field->type = insn_field_string; + if (filter_is_member (word->field_names, new_field->val_string)) + error (line, "Field name %s is duplicated\n", new_field->val_string); + filter_parse (&word->field_names, new_field->val_string); + } + if (new_field->type != insn_field_string + && new_field->conditions != NULL) + error (line, "Conditionals can only be applied to named fields\n"); + + /* the copy the position */ + new_field->pos_string = NZALLOC (char, strlen_pos + 1); + strncpy (new_field->pos_string, start_pos, strlen_pos); + if (strlen_pos == 0) + { + new_field->first = new_field->prev->last + 1; + if (new_field->first == 0 /* first field */ + && *chp == '\0' /* no further fields */ + && new_field->type == insn_field_string) + { + /* A single string without any position, assume that it + represents the entire instruction word */ + new_field->width = options.insn_bit_size; + } + else + { + /* No explicit width/position, assume value implicitly + supplies the width */ + new_field->width = strlen_val; + } + new_field->last = new_field->first + new_field->width - 1; + if (new_field->last >= options.insn_bit_size) + error (line, "Bit position %d exceed instruction bit size (%d)\n", + new_field->last, options.insn_bit_size); + } + else if (options.insn_specifying_widths) + { + new_field->first = new_field->prev->last + 1; + new_field->width = a2i(new_field->pos_string); + new_field->last = new_field->first + new_field->width - 1; + if (new_field->last >= options.insn_bit_size) + error (line, "Bit position %d exceed instruction bit size (%d)\n", + new_field->last, options.insn_bit_size); + } + else + { + new_field->first = target_a2i(options.hi_bit_nr, + new_field->pos_string); + new_field->last = new_field->next->first - 1; /* guess */ + new_field->width = new_field->last - new_field->first + 1; /* guess */ + new_field->prev->last = new_field->first - 1; /*fix*/ + new_field->prev->width = new_field->first - new_field->prev->first; /*fix*/ + } + } + + /* fiddle first/last so that the sentinals disapear */ + ASSERT(word->first->last < 0); + ASSERT(word->last->first >= options.insn_bit_size); + word->first = word->first->next; + word->last = word->last->prev; + + /* check that the last field goes all the way to the last bit */ + if (word->last->last != options.insn_bit_size - 1) + { + if (options.warn.width) + options.warning (line, "Instruction format is not %d bits wide\n", + options.insn_bit_size); + word->last->last = options.insn_bit_size - 1; + } + + /* now go over this again, pointing each bit position at a field + record */ + { + insn_field_entry *field; + for (field = word->first; + field->last < options.insn_bit_size; + field = field->next) + { + int i; + for (i = field->first; i <= field->last; i++) + { + word->bit[i] = ZALLOC (insn_bit_entry); + word->bit[i]->field = field; + switch (field->type) + { + case insn_field_invalid: + ASSERT (0); + break; + case insn_field_int: + word->bit[i]->mask = 1; + word->bit[i]->value = ((field->val_int + & ((insn_uint)1 << (field->last - i))) + != 0); + case insn_field_reserved: + case insn_field_wild: + case insn_field_string: + /* if we encounter a constant conditional, encode + their bit value. */ + if (field->conditions != NULL + && field->conditions->test == insn_field_cond_eq + && field->conditions->type == insn_field_cond_value) + { + word->bit[i]->mask = 1; + word->bit[i]->value = ((field->conditions->value + & ((insn_uint)1 << (field->last - i))) + != 0); + } + break; + } + } + } + } + + return word; +} + + +static void +parse_insn_words (insn_entry *insn, + char *formats) +{ + insn_word_entry **last_word = &insn->words; + char *chp; + + /* now work through the formats */ + insn->nr_words = 0; + chp = formats; + + while (1) + { + char *start_pos; + char *end_pos; + int strlen_pos; + char *format; + insn_word_entry *new_word; + + /* skip leading spaces */ + chp = skip_spaces (chp); + + /* break out the format */ + start_pos = chp; + chp = skip_to_separator (chp, "+"); + end_pos = back_spaces (start_pos, chp); + strlen_pos = end_pos - start_pos; + + /* check that something was there */ + if (strlen_pos == 0) + error (insn->line, "missing or empty instruction format\n"); + + /* parse the field */ + format = NZALLOC (char, strlen_pos + 1); + strncpy (format, start_pos, strlen_pos); + new_word = parse_insn_word (insn->line, format, insn->nr_words); + insn->nr_words++; + if (filter_is_common (insn->field_names, new_word->field_names)) + error (insn->line, "Field name duplicated between two words\n"); + filter_add (&insn->field_names, new_word->field_names); + + /* insert it */ + *last_word = new_word; + last_word = &new_word->next; + + /* last format? */ + if (*chp == '\0') + break; + ASSERT (*chp == '+'); + chp++; + } + + /* create a quick access array (indexed by word) of the same structure */ + { + int i; + insn_word_entry *word; + insn->word = NZALLOC (insn_word_entry *, insn->nr_words + 1); + for (i = 0, word = insn->words; + i < insn->nr_words; + i++, word = word->next) + insn->word[i] = word; + } + + /* Go over all fields that have conditionals refering to other + fields. Link the fields up. Verify that the two fields have the + same size. Verify that the two fields are different */ + { + int i; + for (i = 0; i < insn->nr_words; i++) + { + insn_word_entry *word = insn->word[i]; + insn_field_entry *f; + for (f = word->first; + f->last < options.insn_bit_size; + f = f->next) + { + insn_field_cond *cond; + for (cond = f->conditions; + cond != NULL; + cond = cond->next) + { + if (cond->type == insn_field_cond_field) + { + int j; + if (strcmp (cond->string, f->val_string) == 0) + error (insn->line, + "Conditional `%s' of field `%s' refers to its self\n", + cond->string, f->val_string); + for (j = 0; j <= i && cond->field == NULL; j++) + { + insn_word_entry *refered_word = insn->word[j]; + insn_field_entry *refered_field; + for (refered_field = refered_word->first; + refered_field != NULL && cond->field == NULL; + refered_field = refered_field->next) + { + if (refered_field->type == insn_field_string + && strcmp (refered_field->val_string, cond->string) == 0) + { + /* found field being refered to by conditonal */ + cond->field = refered_field; + /* check refered to and this field are + the same size */ + if (f->width != refered_field->width) + error (insn->line, + "Conditional `%s' of field `%s' should be of size %s\n", + cond->string, f->val_string, refered_field->width); + } + } + } + if (cond->field == NULL) + error (insn->line, + "Conditional `%s' of field `%s' not yet defined\n", + cond->string, f->val_string); + } + } + } + } + } + +} + +typedef enum { + unknown_record = 0, + insn_record, /* default */ + code_record, + cache_record, + compute_record, + scratch_record, + option_record, + string_function_record, + function_record, + internal_record, + define_record, + include_record, + model_processor_record, + model_macro_record, + model_data_record, + model_static_record, + model_function_record, + model_internal_record, +} insn_record_type; + +static const name_map insn_type_map[] = { + { "option", option_record }, + { "cache", cache_record }, + { "compute", compute_record }, + { "scratch", scratch_record }, + { "define", define_record }, + { "include", include_record }, + { "%s", string_function_record }, + { "function", function_record }, + { "internal", internal_record }, + { "model", model_processor_record }, + { "model-macro", model_macro_record }, + { "model-data", model_data_record }, + { "model-static", model_static_record }, + { "model-internal", model_internal_record }, + { "model-function", model_function_record }, + { NULL, insn_record }, +}; + + +static int +record_is_old (table_entry *entry) +{ + if (entry->nr_fields > record_type_field + && strlen (entry->field[record_type_field]) == 0) + return 1; + return 0; +} + +static insn_record_type +record_type (table_entry *entry) +{ + switch (entry->type) + { + case table_code_entry: + return code_record; + + case table_colon_entry: + if (record_is_old (entry)) + { + /* old-format? */ + if (entry->nr_fields > old_record_type_field) + { + int i = name2i (entry->field[old_record_type_field], + insn_type_map); + return i; + } + else + { + return unknown_record; + } + } + else if (entry->nr_fields > record_type_field + && entry->field[0][0] == '\0') + { + /* new-format? */ + int i = name2i (entry->field[record_type_field], + insn_type_map); + return i; + } + else + return insn_record; /* default */ + } + return unknown_record; +} + +static int +record_prefix_is (table_entry *entry, + char ch, + int nr_fields) +{ + if (entry->type != table_colon_entry) + return 0; + if (entry->nr_fields < nr_fields) + return 0; + if (entry->field[0][0] != ch && ch != '\0') + return 0; + return 1; +} + +static table_entry * +parse_model_data_record (insn_table *isa, + table *file, + table_entry *record, + int nr_fields, + model_data **list) +{ + table_entry *model_record = record; + table_entry *code_record = NULL; + model_data *new_data; + if (record->nr_fields < nr_fields) + error (record->line, "Incorrect number of fields\n"); + record = table_read (file); + if (record->type == table_code_entry) + { + code_record = record; + record = table_read (file); + } + /* create the new data record */ + new_data = ZALLOC (model_data); + new_data->line = model_record->line; + filter_parse (&new_data->flags, + model_record->field[record_filter_flags_field]); + new_data->entry = model_record; + new_data->code = code_record; + /* append it if not filtered out */ + if (!is_filtered_out (options.flags_filter, + model_record->field[record_filter_flags_field]) + && !is_filtered_out (options.model_filter, + model_record->field[record_filter_models_field])) + { + while (*list != NULL) + list = &(*list)->next; + *list = new_data; + } + return record; +} + + +typedef enum { + insn_bit_size_option = 1, + insn_specifying_widths_option, + hi_bit_nr_option, + flags_filter_option, + model_filter_option, + multi_sim_option, + format_names_option, + gen_delayed_branch, + unknown_option, +} option_names; + +static const name_map option_map[] = { + { "insn-bit-size", insn_bit_size_option }, + { "insn-specifying-widths", insn_specifying_widths_option }, + { "hi-bit-nr", hi_bit_nr_option }, + { "flags-filter", flags_filter_option }, + { "model-filter", model_filter_option }, + { "multi-sim", multi_sim_option }, + { "format-names", format_names_option }, + { "gen-delayed-branch", gen_delayed_branch }, + { NULL, unknown_option }, +}; + +static table_entry * +parse_include_record (table *file, + table_entry *record) +{ + /* parse the include record */ + if (record->nr_fields < nr_include_fields) + error (record->line, "Incorrect nr fields for include record\n"); + /* process it */ + if (!is_filtered_out (options.flags_filter, + record->field[record_filter_flags_field]) + && !is_filtered_out (options.model_filter, + record->field[record_filter_models_field])) + { + table_push (file, record->line, options.include, + record->field[include_filename_field]); + } + /* nb: can't read next record until after the file has been pushed */ + record = table_read (file); + return record; +} + + +static table_entry * +parse_option_record (table *file, + table_entry *record) +{ + table_entry *option_record; + /* parse the option record */ + option_record = record; + if (record->nr_fields < nr_option_fields) + error (record->line, "Incorrect nr of fields for option record\n"); + record = table_read (file); + /* process it */ + if (!is_filtered_out (options.flags_filter, + option_record->field[record_filter_flags_field]) + && !is_filtered_out (options.model_filter, + option_record->field[record_filter_models_field])) + { + char *name = option_record->field[option_name_field]; + option_names option = name2i (name, option_map); + char *value = option_record->field[option_value_field]; + switch (option) + { + case insn_bit_size_option: + { + options.insn_bit_size = a2i (value); + if (options.insn_bit_size < 0 + || options.insn_bit_size > max_insn_bit_size) + error (option_record->line, "Instruction bit size out of range\n"); + if (options.hi_bit_nr != options.insn_bit_size - 1 + && options.hi_bit_nr != 0) + error (option_record->line, "insn-bit-size / hi-bit-nr conflict\n"); + break; + } + case insn_specifying_widths_option: + { + options.insn_specifying_widths = a2i (value); + break; + } + case hi_bit_nr_option: + { + options.hi_bit_nr = a2i (value); + if (options.hi_bit_nr != 0 + && options.hi_bit_nr != options.insn_bit_size - 1) + error (option_record->line, "hi-bit-nr / insn-bit-size conflict\n"); + break; + } + case flags_filter_option: + { + filter_parse (&options.flags_filter, value); + break; + } + case model_filter_option: + { + filter_parse (&options.model_filter, value); + break; + } + case multi_sim_option: + { + options.gen.multi_sim = a2i (value); + break; + } + case format_names_option: + { + filter_parse (&options.format_name_filter, value); + break; + } + case gen_delayed_branch: + { + options.gen.delayed_branch = a2i (value); + break; + } + case unknown_option: + { + error (option_record->line, "Unknown option - %s\n", name); + break; + } + } + } + return record; +} + + +static table_entry * +parse_function_record (table *file, + table_entry *record, + function_entry **list, + function_entry **list_entry, + int is_internal, + model_table *model) +{ + function_entry *new_function; + new_function = ZALLOC (function_entry); + new_function->line = record->line; + new_function->is_internal = is_internal; + /* parse the function header */ + if (record_is_old (record)) + { + if (record->nr_fields < nr_old_function_fields) + error (record->line, "Missing fields from (old) function record\n"); + new_function->type = record->field[old_function_typedef_field]; + new_function->type = record->field[old_function_typedef_field]; + if (record->nr_fields > old_function_param_field) + new_function->param = record->field[old_function_param_field]; + new_function->name = record->field[old_function_name_field]; + } + else + { + if (record->nr_fields < nr_function_fields) + error (record->line, "Missing fields from function record\n"); + filter_parse (&new_function->flags, + record->field[record_filter_flags_field]); + filter_parse (&new_function->models, + record->field[record_filter_models_field]); + new_function->type = record->field[function_typedef_field]; + new_function->param = record->field[function_param_field]; + new_function->name = record->field[function_name_field]; + } + record = table_read (file); + /* parse any function-model records */ + while (record != NULL + && record_prefix_is (record, '*', nr_function_model_fields)) + { + char *model_name = record->field[function_model_name_field] + 1; /*skip `*'*/ + filter_parse (&new_function->models, model_name); + if (!filter_is_subset (model->processors, new_function->models)) + { + error (record->line, "machine model `%s' undefined\n", model_name); + } + record = table_read (file); + } + /* parse the function body */ + if (record->type == table_code_entry) + { + new_function->code = record; + record = table_read (file); + } + /* insert it */ + if (!filter_is_subset (options.flags_filter, new_function->flags)) + { + if (options.warn.discard) + notify (new_function->line, "Discarding function %s - filter flags\n", + new_function->name); + } + else if (new_function->models != NULL + && !filter_is_common (options.model_filter, new_function->models)) + { + if (options.warn.discard) + notify (new_function->line, "Discarding function %s - filter models\n", + new_function->name); + } + else + { + while (*list != NULL) + list = &(*list)->next; + *list = new_function; + if (list_entry != NULL) + *list_entry = new_function; + } + /* done */ + return record; +} + +static void +parse_insn_model_record (table *file, + table_entry *record, + insn_entry *insn, + model_table *model) +{ + insn_model_entry **last_insn_model; + insn_model_entry *new_insn_model = ZALLOC (insn_model_entry); + /* parse it */ + new_insn_model->line = record->line; + if (record->nr_fields > insn_model_unit_data_field) + new_insn_model->unit_data = record->field[insn_model_unit_data_field]; + new_insn_model->insn = insn; + /* parse the model names, verify that all were defined */ + new_insn_model->names = NULL; + filter_parse (&new_insn_model->names, + record->field[insn_model_name_field] + 1 /*skip `*'*/); + if (new_insn_model->names == NULL) + { + /* No processor names - a generic model entry, enter it into all + the non-empty fields */ + int index; + for (index = 0; index < model->nr_models; index++) + if (insn->model[index] == 0) + { + insn->model[index] = new_insn_model; + } + /* also add the complete processor set to this processor's set */ + filter_add (&insn->processors, model->processors); + } + else + { + /* Find the corresponding master model record for each name so + that they can be linked in. */ + int index; + char *name = ""; + while (1) + { + name = filter_next (new_insn_model->names, name); + if (name == NULL) break; + index = filter_is_member (model->processors, name) - 1; + if (index < 0) + { + error (new_insn_model->line, + "machine model `%s' undefined\n", name); + } + /* store it in the corresponding model array entry */ + if (insn->model[index] != NULL + && insn->model[index]->names != NULL) + { + warning (new_insn_model->line, + "machine model `%s' previously defined\n", name); + error (insn->model[index]->line, "earlier definition\n"); + } + insn->model[index] = new_insn_model; + /* also add the name to the instructions processor set as an + alternative lookup mechanism */ + filter_parse (&insn->processors, name); + } + } +#if 0 + /* for some reason record the max length of any + function unit field */ + int len = strlen (insn_model_ptr->field[insn_model_fields]); + if (model->max_model_fields_len < len) + model->max_model_fields_len = len; +#endif + /* link it in */ + last_insn_model = &insn->models; + while ((*last_insn_model) != NULL) + last_insn_model = &(*last_insn_model)->next; + *last_insn_model = new_insn_model; +} + + +static void +parse_insn_mnemonic_record (table *file, + table_entry *record, + insn_entry *insn) +{ + insn_mnemonic_entry **last_insn_mnemonic; + insn_mnemonic_entry *new_insn_mnemonic = ZALLOC (insn_mnemonic_entry); + /* parse it */ + new_insn_mnemonic->line = record->line; + ASSERT (record->nr_fields > insn_mnemonic_format_field); + new_insn_mnemonic->format = record->field[insn_mnemonic_format_field]; + ASSERT (new_insn_mnemonic->format[0] == '"'); + if (new_insn_mnemonic->format[strlen (new_insn_mnemonic->format) - 1] != '"') + error (new_insn_mnemonic->line, "Missing closing double quote in mnemonic field\n"); + if (record->nr_fields > insn_mnemonic_condition_field) + new_insn_mnemonic->condition = record->field[insn_mnemonic_condition_field]; + new_insn_mnemonic->insn = insn; + /* insert it */ + last_insn_mnemonic = &insn->mnemonics; + while ((*last_insn_mnemonic) != NULL) + last_insn_mnemonic = &(*last_insn_mnemonic)->next; + insn->nr_mnemonics++; + *last_insn_mnemonic = new_insn_mnemonic; +} + + +static table_entry * +parse_macro_record (table *file, + table_entry *record) +{ +#if 1 + error (record->line, "Macros are not implemented"); +#else + /* parse the define record */ + if (record->nr_fields < nr_define_fields) + error (record->line, "Incorrect nr fields for define record\n"); + /* process it */ + if (!is_filtered_out (options.flags_filter, + record->field[record_filter_flags_field]) + && !is_filtered_out (options.model_filter, + record->field[record_filter_models_field])) + { + table_define (file, + record->line, + record->field[macro_name_field], + record->field[macro_args_field], + record->field[macro_expr_field]); + } + record = table_read (file); +#endif + return record; +} + + +insn_table * +load_insn_table (char *file_name, + cache_entry *cache) +{ + table *file = table_open (file_name); + table_entry *record = table_read (file); + + insn_table *isa = ZALLOC (insn_table); + model_table *model = ZALLOC (model_table); + + isa->model = model; + isa->caches = cache; + + while (record != NULL) + { + + switch (record_type (record)) + { + + case include_record: + { + record = parse_include_record (file, record); + break; + } + + case option_record: + { + if (isa->insns != NULL) + error (record->line, "Option after first instruction\n"); + record = parse_option_record (file, record); + break; + } + + case string_function_record: + { + function_entry *function = NULL; + record = parse_function_record (file, record, + &isa->functions, + &function, + 0/*is-internal*/, + model); + /* convert a string function record into an internal function */ + if (function != NULL) + { + char *name = NZALLOC (char, + (strlen ("str_") + + strlen (function->name) + + 1)); + strcat (name, "str_"); + strcat (name, function->name); + function->name = name; + function->type = "const char *"; + } + break; + } + + case function_record: /* function record */ + { + record = parse_function_record (file, record, + &isa->functions, + NULL, + 0/*is-internal*/, + model); + break; + } + + case internal_record: + { + /* only insert it into the function list if it is unknown */ + function_entry *function = NULL; + record = parse_function_record (file, record, + &isa->functions, + &function, + 1/*is-internal*/, + model); + /* check what was inserted to see if a pseudo-instruction + entry also needs to be created */ + if (function != NULL) + { + insn_entry **insn = NULL; + if (strcmp (function->name, "illegal") == 0) + { + /* illegal function save it away */ + if (isa->illegal_insn != NULL) + { + warning (function->line, + "Multiple illegal instruction definitions\n"); + error (isa->illegal_insn->line, + "Location of first illegal instruction\n"); + } + else + insn = &isa->illegal_insn; + } + if (insn != NULL) + { + *insn = ZALLOC (insn_entry); + (*insn)->line = function->line; + (*insn)->name = function->name; + (*insn)->code = function->code; + } + } + break; + } + + case scratch_record: /* cache macro records */ + case cache_record: + case compute_record: + { + cache_entry *new_cache; + /* parse the cache record */ + if (record->nr_fields < nr_cache_fields) + error (record->line, + "Incorrect nr of fields for scratch/cache/compute record\n"); + /* create it */ + new_cache = ZALLOC (cache_entry); + new_cache->line = record->line; + filter_parse (&new_cache->flags, + record->field[record_filter_flags_field]); + filter_parse (&new_cache->models, + record->field[record_filter_models_field]); + new_cache->type = record->field[cache_typedef_field]; + new_cache->name = record->field[cache_name_field]; + filter_parse (&new_cache->original_fields, + record->field[cache_original_fields_field]); + new_cache->expression = record->field[cache_expression_field]; + /* insert it but only if not filtered out */ + if (!filter_is_subset (options.flags_filter, new_cache->flags)) + { + notify (new_cache->line, "Discarding cache entry %s - filter flags\n", + new_cache->name); + } + else if (is_filtered_out (options.model_filter, + record->field[record_filter_models_field])) + { + notify (new_cache->line, "Discarding cache entry %s - filter models\n", + new_cache->name); + } + else + { + cache_entry **last; + last = &isa->caches; + while (*last != NULL) + last = &(*last)->next; + *last = new_cache; + } + /* advance things */ + record = table_read (file); + break; + } + + /* model records */ + case model_processor_record: + { + model_entry *new_model; + /* parse the model */ + if (record->nr_fields < nr_model_processor_fields) + error (record->line, "Incorrect nr of fields for model record\n"); + if (isa->insns != NULL) + error (record->line, "Model appears after first instruction\n"); + new_model = ZALLOC (model_entry); + filter_parse (&new_model->flags, + record->field[record_filter_flags_field]); + new_model->line = record->line; + new_model->name = record->field[model_name_field]; + new_model->full_name = record->field[model_full_name_field]; + new_model->unit_data = record->field[model_unit_data_field]; + /* only insert it if not filtered out */ + if (!filter_is_subset (options.flags_filter, new_model->flags)) + { + notify (new_model->line, "Discarding processor model %s - filter flags\n", + new_model->name); + } + else if (is_filtered_out (options.model_filter, + record->field[record_filter_models_field])) + { + notify (new_model->line, "Discarding processor model %s - filter models\n", + new_model->name); + } + else if (filter_is_member (model->processors, new_model->name)) + { + error (new_model->line, "Duplicate processor model %s\n", + new_model->name); + } + else + { + model_entry **last; + last = &model->models; + while (*last != NULL) + last = &(*last)->next; + *last = new_model; + /* count it */ + model->nr_models ++; + filter_parse (&model->processors, new_model->name); + } + /* advance things */ + record = table_read (file); + } + break; + + case model_macro_record: + record = parse_model_data_record (isa, file, record, + nr_model_macro_fields, + &model->macros); + break; + + case model_data_record: + record = parse_model_data_record (isa, file, record, + nr_model_data_fields, + &model->data); + break; + + case model_static_record: + record = parse_function_record (file, record, + &model->statics, + NULL, + 0/*is internal*/, + model); + break; + + case model_internal_record: + record = parse_function_record (file, record, + &model->internals, + NULL, + 1/*is internal*/, + model); + break; + + case model_function_record: + record = parse_function_record (file, record, + &model->functions, + NULL, + 0/*is internal*/, + model); + break; + + case insn_record: /* instruction records */ + { + insn_entry *new_insn; + char *format; + /* parse the instruction */ + if (record->nr_fields < nr_insn_fields) + error (record->line, "Incorrect nr of fields for insn record\n"); + new_insn = ZALLOC (insn_entry); + new_insn->line = record->line; + filter_parse (&new_insn->flags, + record->field[record_filter_flags_field]); + /* save the format field. Can't parse it until after the + filter-out checks. Could be filtered out because the + format is invalid */ + format = record->field[insn_word_field]; + new_insn->format_name = record->field[insn_format_name_field]; + if (options.format_name_filter != NULL + && !filter_is_member (options.format_name_filter, + new_insn->format_name)) + error (new_insn->line, "Unreconized instruction format name `%s'\n", + new_insn->format_name); + filter_parse (&new_insn->options, + record->field[insn_options_field]); + new_insn->name = record->field[insn_name_field]; + record = table_read (file); + /* Parse any model/assember records */ + new_insn->nr_models = model->nr_models; + new_insn->model = NZALLOC (insn_model_entry*, model->nr_models + 1); + while (record != NULL) + { + if (record_prefix_is (record, '*', nr_insn_model_fields)) + parse_insn_model_record (file, record, new_insn, model); + else if (record_prefix_is (record, '"', nr_insn_mnemonic_fields)) + parse_insn_mnemonic_record (file, record, new_insn); + else + break; + /* advance */ + record = table_read (file); + } + /* Parse the code record */ + if (record != NULL && record->type == table_code_entry) + { + new_insn->code = record; + record = table_read (file); + } + else if (options.warn.unimplemented) + notify (new_insn->line, "unimplemented\n"); + /* insert it */ + if (!filter_is_subset (options.flags_filter, new_insn->flags)) + { + if (options.warn.discard) + notify (new_insn->line, + "Discarding instruction %s (flags-filter)\n", + new_insn->name); + } + else if (new_insn->processors != NULL + && options.model_filter != NULL + && !filter_is_common (options.model_filter, + new_insn->processors)) + { + /* only discard an instruction based in the processor + model when both the instruction and the options are + nonempty */ + if (options.warn.discard) + notify (new_insn->line, + "Discarding instruction %s (processor-model)\n", + new_insn->name); + } + else + { + insn_entry **last; + /* finish the parsing */ + parse_insn_words (new_insn, format); + /* append it */ + last = &isa->insns; + while (*last) + last = &(*last)->next; + *last = new_insn; + /* update global isa counters */ + isa->nr_insns ++; + if (isa->max_nr_words < new_insn->nr_words) + isa->max_nr_words = new_insn->nr_words; + filter_add (&isa->flags, new_insn->flags); + filter_add (&isa->options, new_insn->options); + } + break; + } + + case define_record: + record = parse_macro_record (file, record); + break; + + case unknown_record: + case code_record: + error (record->line, "Unknown or unexpected entry\n"); + + + } + } + return isa; +} + + +void +print_insn_words (lf *file, + insn_entry *insn) +{ + insn_word_entry *word = insn->words; + if (word != NULL) + { + while (1) + { + insn_field_entry *field = word->first; + while (1) + { + if (options.insn_specifying_widths) + lf_printf (file, "%d.", field->width); + else + lf_printf (file, "%d.", i2target (options.hi_bit_nr, field->first)); + switch (field->type) + { + case insn_field_invalid: + ASSERT (0); + break; + case insn_field_int: + lf_printf (file, "0x%lx", (long) field->val_int); + break; + case insn_field_reserved: + lf_printf (file, "/"); + break; + case insn_field_wild: + lf_printf (file, "*"); + break; + case insn_field_string: + lf_printf (file, "%s", field->val_string); + break; + } + if (field == word->last) + break; + field = field->next; + lf_printf (file, ","); + } + word = word->next; + if (word == NULL) + break; + lf_printf (file, "+"); + } + } +} + + + +void +function_entry_traverse (lf *file, + function_entry *functions, + function_entry_handler *handler, + void *data) +{ + function_entry *function; + for (function = functions; function != NULL; function = function->next) + { + handler (file, function, data); + } +} + +void +insn_table_traverse_insn (lf *file, + insn_table *isa, + insn_entry_handler *handler, + void *data) +{ + insn_entry *insn; + for (insn = isa->insns; insn != NULL; insn = insn->next) + { + handler (file, isa, insn, data); + } +} + + +static void +dump_function_entry (lf *file, + char *prefix, + function_entry *entry, + char *suffix) +{ + lf_printf (file, "%s(function_entry *) 0x%lx", prefix, (long) entry); + if (entry != NULL) + { + dump_line_ref (file, "\n(line ", entry->line, ")"); + dump_filter (file, "\n(flags ", entry->flags, ")"); + lf_printf (file, "\n(type \"%s\")", entry->type); + lf_printf (file, "\n(name \"%s\")", entry->name); + lf_printf (file, "\n(param \"%s\")", entry->param); + dump_table_entry (file, "\n(code ", entry->code, ")"); + lf_printf (file, "\n(is_internal %d)", entry->is_internal); + lf_printf (file, "\n(next 0x%lx)", (long) entry->next); + } + lf_printf (file, "%s", suffix); +} + +static void +dump_function_entries (lf *file, + char *prefix, + function_entry *entry, + char *suffix) +{ + lf_printf (file, "%s", prefix); + lf_indent (file, +1); + while (entry != NULL) + { + dump_function_entry (file, "\n(", entry, ")"); + entry = entry->next; + } + lf_indent (file, -1); + lf_printf (file, "%s", suffix); +} + +static char * +cache_entry_type_to_str (cache_entry_type type) +{ + switch (type) + { + case scratch_value: return "scratch"; + case cache_value: return "cache"; + case compute_value: return "compute"; + } + ERROR ("Bad switch"); + return 0; +} + +static void +dump_cache_entry (lf *file, + char *prefix, + cache_entry *entry, + char *suffix) +{ + lf_printf (file, "%s(cache_entry *) 0x%lx", prefix, (long) entry); + if (entry != NULL) + { + dump_line_ref (file, "\n(line ", entry->line, ")"); + dump_filter (file, "\n(flags ", entry->flags, ")"); + lf_printf (file, "\n(entry_type \"%s\")", cache_entry_type_to_str (entry->entry_type)); + lf_printf (file, "\n(name \"%s\")", entry->name); + dump_filter (file, "\n(original_fields ", entry->original_fields, ")"); + lf_printf (file, "\n(type \"%s\")", entry->type); + lf_printf (file, "\n(expression \"%s\")", entry->expression); + lf_printf (file, "\n(next 0x%lx)", (long) entry->next); + } + lf_printf (file, "%s", suffix); +} + +void +dump_cache_entries (lf *file, + char *prefix, + cache_entry *entry, + char *suffix) +{ + lf_printf (file, "%s", prefix); + lf_indent (file, +1); + while (entry != NULL) + { + dump_cache_entry (file, "\n(", entry, ")"); + entry = entry->next; + } + lf_indent (file, -1); + lf_printf (file, "%s", suffix); +} + +static void +dump_model_data (lf *file, + char *prefix, + model_data *entry, + char *suffix) +{ + lf_printf (file, "%s(model_data *) 0x%lx", prefix, (long) entry); + if (entry != NULL) + { + lf_indent (file, +1); + dump_line_ref (file, "\n(line ", entry->line, ")"); + dump_filter (file, "\n(flags ", entry->flags, ")"); + dump_table_entry (file, "\n(entry ", entry->entry, ")"); + dump_table_entry (file, "\n(code ", entry->code, ")"); + lf_printf (file, "\n(next 0x%lx)", (long) entry->next); + lf_indent (file, -1); + } + lf_printf (file, "%s", prefix); +} + +static void +dump_model_datas (lf *file, + char *prefix, + model_data *entry, + char *suffix) +{ + lf_printf (file, "%s", prefix); + lf_indent (file, +1); + while (entry != NULL) + { + dump_model_data (file, "\n(", entry, ")"); + entry = entry->next; + } + lf_indent (file, -1); + lf_printf (file, "%s", suffix); +} + +static void +dump_model_entry (lf *file, + char *prefix, + model_entry *entry, + char *suffix) +{ + lf_printf (file, "%s(model_entry *) 0x%lx", prefix, (long) entry); + if (entry != NULL) + { + lf_indent (file, +1); + dump_line_ref (file, "\n(line ", entry->line, ")"); + dump_filter (file, "\n(flags ", entry->flags, ")"); + lf_printf (file, "\n(name \"%s\")", entry->name); + lf_printf (file, "\n(full_name \"%s\")", entry->full_name); + lf_printf (file, "\n(unit_data \"%s\")", entry->unit_data); + lf_printf (file, "\n(next 0x%lx)", (long) entry->next); + lf_indent (file, -1); + } + lf_printf (file, "%s", prefix); +} + +static void +dump_model_entries (lf *file, + char *prefix, + model_entry *entry, + char *suffix) +{ + lf_printf (file, "%s", prefix); + lf_indent (file, +1); + while (entry != NULL) + { + dump_model_entry (file, "\n(", entry, ")"); + entry = entry->next; + } + lf_indent (file, -1); + lf_printf (file, "%s", suffix); +} + + +static void +dump_model_table (lf *file, + char *prefix, + model_table *entry, + char *suffix) +{ + lf_printf (file, "%s(model_table *) 0x%lx", prefix, (long) entry); + if (entry != NULL) + { + lf_indent (file, +1); + dump_filter (file, "\n(processors ", entry->processors, ")"); + lf_printf (file, "\n(nr_models %d)", entry->nr_models); + dump_model_entries (file, "\n(models ", entry->models, ")"); + dump_model_datas (file, "\n(macros ", entry->macros, ")"); + dump_model_datas (file, "\n(data ", entry->data, ")"); + dump_function_entries (file, "\n(statics ", entry->statics, ")"); + dump_function_entries (file, "\n(internals ", entry->functions, ")"); + dump_function_entries (file, "\n(functions ", entry->functions, ")"); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); +} + + +static char * +insn_field_type_to_str (insn_field_type type) +{ + switch (type) + { + case insn_field_invalid: ASSERT (0); return "(invalid)"; + case insn_field_int: return "int"; + case insn_field_reserved: return "reserved"; + case insn_field_wild: return "wild"; + case insn_field_string: return "string"; + } + ERROR ("bad switch"); + return 0; +} + +void +dump_insn_field (lf *file, + char *prefix, + insn_field_entry *field, + char *suffix) +{ + char *sep = " "; + lf_printf (file, "%s(insn_field_entry *) 0x%lx", prefix, (long) field); + if (field != NULL) + { + lf_indent (file, +1); + lf_printf (file, "%s(first %d)", sep, field->first); + lf_printf (file, "%s(last %d)", sep, field->last); + lf_printf (file, "%s(width %d)", sep, field->width); + lf_printf (file, "%s(type %s)", sep, insn_field_type_to_str (field->type)); + switch (field->type) + { + case insn_field_invalid: + ASSERT (0); + break; + case insn_field_int: + lf_printf (file, "%s(val 0x%lx)", sep, (long) field->val_int); + break; + case insn_field_reserved: + /* nothing output */ + break; + case insn_field_wild: + /* nothing output */ + break; + case insn_field_string: + lf_printf (file, "%s(val \"%s\")", sep, field->val_string); + break; + } + lf_printf (file, "%s(next 0x%lx)", sep, (long) field->next); + lf_printf (file, "%s(prev 0x%lx)", sep, (long) field->prev); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); +} + +void +dump_insn_word_entry (lf *file, + char *prefix, + insn_word_entry *word, + char *suffix) +{ + lf_printf (file, "%s(insn_word_entry *) 0x%lx", prefix, (long) word); + if (word != NULL) + { + int i; + insn_field_entry *field; + lf_indent (file, +1); + lf_printf (file, "\n(first 0x%lx)", (long) word->first); + lf_printf (file, "\n(last 0x%lx)", (long) word->last); + lf_printf (file, "\n(bit"); + for (i = 0; i < options.insn_bit_size; i++) + lf_printf (file, "\n ((value %d) (mask %d) (field 0x%lx))", + word->bit[i]->value, word->bit[i]->mask, (long) word->bit[i]->field); + lf_printf (file, ")"); + for (field = word->first; field != NULL; field = field->next) + dump_insn_field (file, "\n(", field, ")"); + dump_filter (file, "\n(field_names ", word->field_names, ")"); + lf_printf (file, "\n(next 0x%lx)", (long) word->next); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); +} + +static void +dump_insn_word_entries (lf *file, + char *prefix, + insn_word_entry *word, + char *suffix) +{ + lf_printf (file, "%s", prefix); + while (word != NULL) + { + dump_insn_word_entry (file, "\n(", word, ")"); + word = word->next; + } + lf_printf (file, "%s", suffix); +} + +static void +dump_insn_model_entry (lf *file, + char *prefix, + insn_model_entry *model, + char *suffix) +{ + lf_printf (file, "%s(insn_model_entry *) 0x%lx", prefix, (long) model); + if (model != NULL) + { + lf_indent (file, +1); + dump_line_ref (file, "\n(line ", model->line, ")"); + dump_filter (file, "\n(names ", model->names, ")"); + lf_printf (file, "\n(full_name \"%s\")", model->full_name); + lf_printf (file, "\n(unit_data \"%s\")", model->unit_data); + lf_printf (file, "\n(insn (insn_entry *) 0x%lx)", (long) model->insn); + lf_printf (file, "\n(next (insn_model_entry *) 0x%lx)", + (long) model->next); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); +} + +static void +dump_insn_model_entries (lf *file, + char *prefix, + insn_model_entry *model, + char *suffix) +{ + lf_printf (file, "%s", prefix); + while (model != NULL) + { + dump_insn_model_entry (file, "\n", model, ""); + model = model->next; + } + lf_printf (file, "%s", suffix); +} + + +static void +dump_insn_mnemonic_entry (lf *file, + char *prefix, + insn_mnemonic_entry *mnemonic, + char *suffix) +{ + lf_printf (file, "%s(insn_mnemonic_entry *) 0x%lx", prefix, (long) mnemonic); + if (mnemonic != NULL) + { + lf_indent (file, +1); + dump_line_ref (file, "\n(line ", mnemonic->line, ")"); + lf_printf (file, "\n(format \"%s\")", mnemonic->format); + lf_printf (file, "\n(condition \"%s\")", mnemonic->condition); + lf_printf (file, "\n(insn (insn_entry *) 0x%lx)", + (long) mnemonic->insn); + lf_printf (file, "\n(next (insn_mnemonic_entry *) 0x%lx)", + (long) mnemonic->next); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); +} + +static void +dump_insn_mnemonic_entries (lf *file, + char *prefix, + insn_mnemonic_entry *mnemonic, + char *suffix) +{ + lf_printf (file, "%s", prefix); + while (mnemonic != NULL) + { + dump_insn_mnemonic_entry (file, "\n", mnemonic, ""); + mnemonic = mnemonic->next; + } + lf_printf (file, "%s", suffix); +} + +void +dump_insn_entry (lf *file, + char *prefix, + insn_entry *entry, + char *suffix) +{ + lf_printf (file, "%s(insn_entry *) 0x%lx", prefix, (long) entry); + if (entry != NULL) + { + int i; + lf_indent (file, +1); + dump_line_ref (file, "\n(line ", entry->line, ")"); + dump_filter (file, "\n(flags ", entry->flags, ")"); + lf_printf (file, "\n(nr_words %d)", entry->nr_words); + dump_insn_word_entries (file, "\n(words ", entry->words, ")"); + lf_printf (file, "\n(word"); + for (i = 0; i < entry->nr_models; i++) + lf_printf (file, " 0x%lx", (long) entry->word[i]); + lf_printf (file, ")"); + dump_filter (file, "\n(field_names ", entry->field_names, ")"); + lf_printf (file, "\n(format_name \"%s\")", entry->format_name); + dump_filter (file, "\n(options ", entry->options, ")"); + lf_printf (file, "\n(name \"%s\")", entry->name); + lf_printf (file, "\n(nr_models %d)", entry->nr_models); + dump_insn_model_entries (file, "\n(models ", entry->models, ")"); + lf_printf (file, "\n(model"); + for (i = 0; i < entry->nr_models; i++) + lf_printf (file, " 0x%lx", (long) entry->model[i]); + lf_printf (file, ")"); + dump_filter (file, "\n(processors ", entry->processors, ")"); + dump_insn_mnemonic_entries (file, "\n(mnemonics ", entry->mnemonics, ")"); + dump_table_entry (file, "\n(code ", entry->code, ")"); + lf_printf (file, "\n(next 0x%lx)", (long) entry->next); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); +} + +static void +dump_insn_entries (lf *file, + char *prefix, + insn_entry *entry, + char *suffix) +{ + lf_printf (file, "%s", prefix); + lf_indent (file, +1); + while (entry != NULL) + { + dump_insn_entry (file, "\n(", entry, ")"); + entry = entry->next; + } + lf_indent (file, -1); + lf_printf (file, "%s", suffix); +} + + + +void +dump_insn_table (lf *file, + char *prefix, + insn_table *isa, + char *suffix) +{ + lf_printf (file, "%s(insn_table *) 0x%lx", prefix, (long) isa); + if (isa != NULL) + { + lf_indent (file, +1); + dump_cache_entries (file, "\n(caches ", isa->caches, ")"); + lf_printf (file, "\n(nr_insns %d)", isa->nr_insns); + lf_printf (file, "\n(max_nr_words %d)", isa->max_nr_words); + dump_insn_entries (file, "\n(insns ", isa->insns, ")"); + dump_function_entries (file, "\n(functions ", isa->functions, ")"); + dump_insn_entry (file, "\n(illegal_insn ", isa->illegal_insn, ")"); + dump_model_table (file, "\n(model ", isa->model, ")"); + dump_filter (file, "\n(flags ", isa->flags, ")"); + dump_filter (file, "\n(options ", isa->options, ")"); + lf_indent (file, -1); + } + lf_printf (file, "%s", suffix); +} + +#ifdef MAIN + +igen_options options; + +int +main (int argc, char **argv) +{ + insn_table *isa; + lf *l; + + INIT_OPTIONS (options); + + if (argc == 3) + filter_parse (&options.flags_filter, argv[2]); + else if (argc != 2) + error (NULL, "Usage: insn <insn-table> [ <filter-in> ]\n"); + + isa = load_insn_table (argv[1], NULL); + l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-ld-insn"); + dump_insn_table (l, "(isa ", isa, ")\n"); + + return 0; +} + +#endif diff --git a/sim/igen/ld-insn.h b/sim/igen/ld-insn.h new file mode 100644 index 00000000000..5f9d240bd56 --- /dev/null +++ b/sim/igen/ld-insn.h @@ -0,0 +1,703 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998 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: + + All non instruction records have the format: + + <...> ::= + ":" <record-name> + ":" <filter-flags> + ":" <filter-models> + ":" ... + + */ + +enum { + record_type_field = 1, + old_record_type_field = 2, + record_filter_flags_field = 2, + record_filter_models_field = 3, +}; + + +/* Include: + + Include the specified file. + + <include> ::= + ":" "include" + ":" <filter-flags> + ":" <filter-models> + ":" <filename> + <nl> + ; + + */ + +enum { + include_filename_field = 4, + nr_include_fields, +}; + + + +/* 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> + ":" <filter-models> + ":" <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 = 4, + option_value_field, + nr_option_fields, +}; + + + +/* Macro definitions: + + <insn-macro> ::= + ":" "define" + ":" <filter-flags> + ":" <filter-models> + ":" <name> + ":" <arg-list> + ":" <expression> + <nl> + ; + + <arg-list> ::= + [ <name> { "," <arg-list> } ] + ; + + */ + + +enum { + macro_name_field = 4, + macro_args_field, + macro_expr_field, + nr_macro_fields, +}; + + + +/* Functions and internal routins: + + NB: <filter-models> and <function-models> are equivalent. + + + <function> ::= + ":" "function" + <function-spec> + ; + + <internal> ::= + ":" "internal" + <function-spec> + ; + + <format> ::= + ":" ( "%s" | ... ) + <function-spec> + ; + + <function-model> ::= + "*" [ <processor-list> ] + ":" + <nl> + ; + + <function-spec> ::= + ":" <filter-flags> + ":" <filter-models> + ":" <typedef> + ":" <name> + [ ":" <parameter-list> ] + <nl> + [ <function-model> ] + <code-block> + ; + + */ + +enum { + function_typedef_field = 4, + function_name_field, + function_param_field, + nr_function_fields, +}; + +enum { + function_model_name_field = 0, + nr_function_model_fields = 1, +}; + +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 = 5, /* parameter-list is optional */ +}; + + +typedef struct _function_entry function_entry; +struct _function_entry { + line_ref *line; + filter *flags; + filter *models; + 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> + ":" <filter-models> + ":" <typedef> + ":" <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_typedef_field = 4, + cache_name_field, + cache_original_fields_field, + cache_expression_field, + nr_cache_fields, +}; + +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; + filter *models; + cache_entry_type entry_type; + char *name; + filter *original_fields; + char *type; + char *expression; + cache_entry *next; +}; + + + +/* Model specs: + + <model-processor> ::= + ":" "model" + ":" <filter-flags> + ":" <filter-models> + ":" <processor> + ":" <BFD-processor> + ":" <function-unit-data> + <nl> + ; + + <model-macro> ::= + ":" "model-macro" + ":" <filter-flags> + ":" <filter-models> + <nl> + <code-block> + ; + + <model-data> ::= + ":" "model-data" + ":" <filter-flags> + ":" <filter-models> + <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 = 4, + nr_model_data_fields = 4, + nr_model_static_fields = nr_function_fields, + nr_model_internal_fields = nr_function_fields, + nr_model_function_fields = nr_function_fields, +}; + +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 = 4, + model_full_name_field, + model_unit_data_field, + nr_model_processor_fields, +}; + +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-field> ::= + ( <binary-value-implying-width> + | <field-name-implying-width> + | [ <start-or-width> "." ] <field> + ) + { [ "!" | "=" ] [ <value> | <field-name> ] } + ; + + <field> ::= + { "*" }+ + | { "/" }+ + | <field-name> + | "0x" <hex-value> + | "0b" <binary-value> + | "0" <octal-value> + | <integer-value> ; + +*/ + +typedef enum _insn_field_cond_type { + insn_field_cond_value, + insn_field_cond_field, +} insn_field_cond_type; +typedef enum _insn_field_cond_test { + insn_field_cond_eq, + insn_field_cond_ne, +} insn_field_cond_test; +typedef struct _insn_field_cond insn_field_cond; +struct _insn_field_cond { + insn_field_cond_type type; + insn_field_cond_test test; + insn_uint value; + struct _insn_field_entry *field; + char *string; + insn_field_cond *next; +}; + + +typedef enum _insn_field_type { + insn_field_invalid, + 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_cond *conditions; + 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 and other data for the code modeling the + instruction unit. + + <insn-model> ::= + "*" [ <processor-list> ] + ":" [ <function-unit-data> ] + <nl> + ; + + <processor-list> ::= + <processor> { "," <processor>" } + ; + + If the <processor-list> is empty, 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; + filter *names; + 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> + ; + + An assembler mnemonic string has the syntax: + + <assembler-mnemonic> ::= + ( [ "%" <format-spec> ] "<" <func> [ "#" <param-list> ] ">" + | "%%" + | <other-letter> + )+ + + Where, for instance, the text is translated into a printf format + and argument pair: + + "<FUNC>" : "%ld", (long) FUNC + "%<FUNC>..." : "%...", FUNC + "%s<FUNC>" : "%s", <%s>FUNC (SD_, FUNC) + "%s<FUNC#P1,P2>" : "%s", <%s>FUNC (SD_, P1,P2) + "%lx<FUNC>" : "%lx", (unsigned long) FUNC + "%08lx<FUNC>" : "%08lx", (unsigned long) FUNC + + And "<%s>FUNC" denotes a function declared using the "%s" record + specifier. + + + + ; + + */ + +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/lf.c b/sim/igen/lf.c new file mode 100644 index 00000000000..1b4a5f136ec --- /dev/null +++ b/sim/igen/lf.c @@ -0,0 +1,418 @@ +/* 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 <stdarg.h> +#include <ctype.h> + +#include "config.h" +#include "misc.h" +#include "lf.h" + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +struct _lf { + FILE *stream; + int line_nr; /* nr complete lines written, curr line is line_nr+1 */ + int indent; + int line_blank; + const char *name; + const char *program; + lf_file_references references; + lf_file_type type; +}; + + +lf * +lf_open (char *name, + char *real_name, + lf_file_references references, + lf_file_type type, + const char *program) +{ + /* create a file object */ + lf *new_lf = ZALLOC(lf); + ASSERT (new_lf != NULL); + new_lf->references = references; + new_lf->type = type; + new_lf->name = (real_name == NULL ? name : real_name); + new_lf->program = program; + /* attach to stdout if pipe */ + if (!strcmp(name, "-")) { + new_lf->stream = stdout; + } + else { + /* create a new file */ + new_lf->stream = fopen(name, "w"); + if (new_lf->stream == NULL) { + perror(name); + exit(1); + } + } + return new_lf; +} + + +void +lf_close(lf *file) +{ + if (file->stream != stdout) { + if (fclose(file->stream)) { + perror("lf_close.fclose"); + exit(1); + } + free(file); + } +} + + +int +lf_putchr(lf *file, + const char chr) +{ + int nr = 0; + if (chr == '\n') { + file->line_nr += 1; + file->line_blank = 1; + } + else if (file->line_blank) { + int pad; + for (pad = file->indent; pad > 0; pad--) + putc(' ', file->stream); + nr += file->indent; + file->line_blank = 0; + } + putc(chr, file->stream); + nr += 1; + return nr; +} + +int +lf_write (lf *file, + const char *string, + int strlen_string) +{ + int nr = 0; + int i; + for (i = 0; i < strlen_string; i++) + nr += lf_putchr (file, string[i]); + return nr; +} + + +void +lf_indent_suppress(lf *file) +{ + file->line_blank = 0; +} + + +int +lf_putstr(lf *file, + const char *string) +{ + int nr = 0; + const char *chp; + if (string != NULL) { + for (chp = string; *chp != '\0'; chp++) { + nr += lf_putchr(file, *chp); + } + } + return nr; +} + +static int +do_lf_putunsigned(lf *file, + unsigned u) +{ + int nr = 0; + if (u > 0) { + nr += do_lf_putunsigned(file, u / 10); + nr += lf_putchr(file, (u % 10) + '0'); + } + return nr; +} + + +int +lf_putint(lf *file, + int decimal) +{ + int nr = 0; + if (decimal == 0) + nr += lf_putchr(file, '0'); + else if (decimal < 0) { + nr += lf_putchr(file, '-'); + nr += do_lf_putunsigned(file, -decimal); + } + else if (decimal > 0) { + nr += do_lf_putunsigned(file, decimal); + } + else + ASSERT(0); + return nr; +} + + +int +lf_printf (lf *file, + const char *fmt, + ...) +{ + int nr = 0; + char buf[1024]; + va_list ap; + + va_start (ap, fmt); + vsprintf (buf, fmt, ap); + /* FIXME - this is really stuffed but so is vsprintf() on a sun! */ + ASSERT (strlen (buf) < sizeof (buf)); + nr += lf_putstr (file, buf); + va_end(ap); + return nr; +} + + +int +lf_print__line_ref (lf *file, + line_ref *line) +{ + return lf_print__external_ref (file, line->line_nr, line->file_name); +} + +int +lf_print__external_ref (lf *file, + int line_nr, + const char *file_name) +{ + int nr = 0; + switch (file->references) + { + case lf_include_references: + lf_indent_suppress(file); + nr += lf_putstr (file, "#line "); + nr += lf_putint (file, line_nr); + nr += lf_putstr (file, " \""); + nr += lf_putstr (file, file_name); + nr += lf_putstr (file, "\"\n"); + break; + case lf_omit_references: + nr += lf_putstr (file, "/* "); + nr += lf_putstr (file, file_name); + nr += lf_putstr (file, ":"); + nr += lf_putint (file, line_nr); + nr += lf_putstr (file, "*/\n"); + break; + } + return nr; +} + +int +lf_print__internal_ref (lf *file) +{ + int nr = 0; + nr += lf_print__external_ref (file, file->line_nr+2, file->name); + /* line_nr == last_line, want to number from next */ + return nr; +} + +void +lf_indent (lf *file, int delta) +{ + file->indent += delta; +} + + +int +lf_print__gnu_copyleft (lf *file) +{ + int nr = 0; + switch (file->type) { + case lf_is_c: + case lf_is_h: + nr += lf_printf(file, "\ +/* This file is part of the program psim. + + Copyright (C) 1994-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. + + -- + + This file was generated by the program %s */ +", filter_filename(file->program)); + break; + default: + ASSERT(0); + break; + } + return nr; +} + + +int +lf_putbin(lf *file, int decimal, int width) +{ + int nr = 0; + int bit; + ASSERT(width > 0); + for (bit = 1 << (width-1); bit != 0; bit >>= 1) { + if (decimal & bit) + nr += lf_putchr(file, '1'); + else + nr += lf_putchr(file, '0'); + } + return nr; +} + +int +lf_print__this_file_is_empty(lf *file, + const char *reason) +{ + int nr = 0; + switch (file->type) { + case lf_is_c: + case lf_is_h: + nr += lf_printf (file, + "/* This generated file (%s) is intentionally left blank", + file->name); + if (reason != NULL) + nr += lf_printf (file, " - %s", reason); + nr += lf_printf (file, " */\n"); + break; + default: + ERROR ("Bad switch"); + } + return nr; +} + +int +lf_print__ucase_filename(lf *file) +{ + int nr = 0; + const char *chp = file->name; + while (*chp != '\0') { + char ch = *chp; + if (islower(ch)) { + nr += lf_putchr(file, toupper(ch)); + } + else if (ch == '.') + nr += lf_putchr(file, '_'); + else + nr += lf_putchr(file, ch); + chp++; + } + return nr; +} + +int +lf_print__file_start(lf *file) +{ + int nr = 0; + switch (file->type) { + case lf_is_h: + case lf_is_c: + nr += lf_print__gnu_copyleft(file); + nr += lf_printf(file, "\n"); + nr += lf_printf(file, "#ifndef "); + nr += lf_print__ucase_filename(file); + nr += lf_printf(file, "\n"); + nr += lf_printf(file, "#define "); + nr += lf_print__ucase_filename(file); + nr += lf_printf(file, "\n"); + nr += lf_printf(file, "\n"); + break; + default: + ASSERT(0); + } + return nr; +} + + +int +lf_print__file_finish(lf *file) +{ + int nr = 0; + switch (file->type) { + case lf_is_h: + case lf_is_c: + nr += lf_printf(file, "\n"); + nr += lf_printf(file, "#endif /* _"); + nr += lf_print__ucase_filename(file); + nr += lf_printf(file, "_*/\n"); + break; + default: + ASSERT(0); + } + return nr; +} + + +int +lf_print__function_type (lf *file, + const char *type, + const char *prefix, + const char *trailing_space) +{ + int nr = 0; + nr += lf_printf (file, "%s\\\n(%s)", prefix, type); + if (trailing_space != NULL) + nr += lf_printf (file, "%s", trailing_space); + return nr; +} + +int +lf_print__function_type_function (lf *file, + print_function *print_type, + const char *prefix, + const char *trailing_space) +{ + int nr = 0; + nr += lf_printf (file, "%s\\\n(", prefix); + nr += print_type (file); + nr += lf_printf (file, ")"); + if (trailing_space != NULL) + nr += lf_printf (file, "%s", trailing_space); + return nr; +} + diff --git a/sim/igen/lf.h b/sim/igen/lf.h new file mode 100644 index 00000000000..e968f5f6cb6 --- /dev/null +++ b/sim/igen/lf.h @@ -0,0 +1,143 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-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. + + */ + + +/* LF: Line Numbered Output Stream */ + +typedef struct _lf lf; + +typedef enum { + lf_is_h, + lf_is_c, + lf_is_text, +} lf_file_type; + + +typedef enum { + lf_include_references, + lf_omit_references, +} lf_file_references; + + +/* Open the file NAME for writing ("-" for stdout). Use REAL_NAME + when refering to the opened file. Line number information (in the + output) can be suppressed with FILE_REFERENCES == + LF_OMIT_REFERENCES. TYPE is to determine the formatting of some of + the print messages below. */ + +extern lf *lf_open +(char *name, + char *real_name, + lf_file_references file_references, + lf_file_type type, + const char *program); + +extern void lf_close +(lf *file); + + +/* Basic output functions */ + +extern int lf_write +(lf *file, + const char *string, + int len); + +extern int lf_putchr +(lf *file, + const char ch); + +extern int lf_putstr +(lf *file, + const char *string); + +extern int lf_putint +(lf *file, + int decimal); + +extern int lf_putbin +(lf *file, + int decimal, + int width); + +extern int lf_printf +(lf *file, + const char *fmt, + ...) __attribute__((format(printf, 2, 3))); + + +/* Indentation control. + + lf_indent_suppress suppresses indentation on the next line (current + line if that has not yet been started) */ + +extern void lf_indent_suppress +(lf *file); + +extern void lf_indent +(lf *file, + int delta); + + +/* Print generic text: */ + + +extern int lf_print__gnu_copyleft +(lf *file); + +extern int lf_print__file_start +(lf *file); + +extern int lf_print__this_file_is_empty +(lf *file, + const char *reason); + +extern int lf_print__file_finish +(lf *file); + +extern int lf_print__internal_ref +(lf *file); + +extern int lf_print__external_ref +(lf *file, + int line_nr, + const char *file_name); + +extern int lf_print__line_ref +(lf *file, + line_ref *line); + +extern int lf_print__ucase_filename +(lf *file); + +extern int lf_print__function_type +(lf *file, + const char *type, + const char *prefix, + const char *trailing_space); + +typedef int print_function(lf *file); + +extern int lf_print__function_type_function +(lf *file, + print_function *print_type, + const char *prefix, + const char *trailing_space); + diff --git a/sim/igen/misc.c b/sim/igen/misc.c new file mode 100644 index 00000000000..8490132f32e --- /dev/null +++ b/sim/igen/misc.c @@ -0,0 +1,284 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-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. + + */ + + +#include <stdio.h> +#include <stdarg.h> +#include <ctype.h> + +#include "config.h" +#include "misc.h" + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +/* NB: Because warning and error can be interchanged, neither append a + trailing '\n' */ + +void +error (const line_ref *line, + char *msg, + ...) +{ + va_list ap; + if (line != NULL) + fprintf (stderr, "%s:%d: ", line->file_name, line->line_nr); + va_start (ap, msg); + vfprintf (stderr, msg, ap); + va_end (ap); + exit (1); +} + +void +warning (const line_ref *line, + char *msg, + ...) +{ + va_list ap; + if (line != NULL) + fprintf (stderr, "%s:%d: warning: ", line->file_name, line->line_nr); + va_start (ap, msg); + vfprintf (stderr, msg, ap); + va_end (ap); +} + +void +notify (const line_ref *line, + char *msg, + ...) +{ + va_list ap; + if (line != NULL) + fprintf (stdout, "%s %d: info: ", line->file_name, line->line_nr); + va_start(ap, msg); + vfprintf (stdout, msg, ap); + va_end(ap); +} + +void * +zalloc(long size) +{ + void *memory = malloc(size); + if (memory == NULL) + ERROR ("zalloc failed"); + memset(memory, 0, size); + return memory; +} + + +unsigned long long +a2i (const char *a) +{ + int neg = 0; + int base = 10; + unsigned long long num = 0; + int looping; + + while (isspace (*a)) + a++; + + if (strcmp (a, "true") == 0 + || strcmp (a, "TRUE") == 0) + return 1; + + if (strcmp (a, "false") == 0 + || strcmp (a, "false") == 0) + return 0; + + if (*a == '-') + { + neg = 1; + a++; + } + + if (*a == '0') + { + if (a[1] == 'x' || a[1] == 'X') + { + a += 2; + base = 16; + } + else if (a[1] == 'b' || a[1] == 'b') + { + a += 2; + base = 2; + } + else + base = 8; + } + + looping = 1; + while (looping) + { + int ch = *a++; + + switch (base) + { + default: + looping = 0; + break; + + case 2: + if (ch >= '0' && ch <= '1') + { + num = (num * 2) + (ch - '0'); + } + else + { + looping = 0; + } + break; + + case 10: + if (ch >= '0' && ch <= '9') + { + num = (num * 10) + (ch - '0'); + } + else + { + looping = 0; + } + break; + + case 8: + if (ch >= '0' && ch <= '7') + { + num = (num * 8) + (ch - '0'); + } + else + { + looping = 0; + } + break; + + case 16: + if (ch >= '0' && ch <= '9') + { + num = (num * 16) + (ch - '0'); + } + else if (ch >= 'a' && ch <= 'f') + { + num = (num * 16) + (ch - 'a' + 10); + } + else if (ch >= 'A' && ch <= 'F') + { + num = (num * 16) + (ch - 'A' + 10); + } + else + { + looping = 0; + } + break; + } + } + + if (neg) + num = - num; + + return num; +} + +unsigned +target_a2i(int ms_bit_nr, + const char *a) +{ + if (ms_bit_nr) + return (ms_bit_nr - a2i(a)); + else + return a2i(a); +} + +unsigned +i2target(int ms_bit_nr, + unsigned bit) +{ + if (ms_bit_nr) + return ms_bit_nr - bit; + else + return bit; +} + + +int +name2i (const char *names, + const name_map *map) +{ + const name_map *curr; + const char *name = names; + while (*name != '\0') + { + /* find our name */ + char *end = strchr(name, ','); + char *next; + unsigned len; + if (end == NULL) + { + end = strchr(name, '\0'); + next = end; + } + else + { + next = end + 1; + } + len = end - name; + /* look it up */ + curr = map; + while (curr->name != NULL) + { + if (strncmp (curr->name, name, len) == 0 + && strlen (curr->name) == len) + return curr->i; + curr++; + } + name = next; + } + /* nothing found, possibly return a default */ + curr = map; + while (curr->name != NULL) + curr++; + if (curr->i >= 0) + return curr->i; + else + error (NULL, "%s contains no valid names", names); + return 0; +} + +const char * +i2name (const int i, + const name_map *map) +{ + while (map->name != NULL) + { + if (map->i == i) + return map->name; + map++; + } + error (NULL, "map lookup failed for %d\n", i); + return NULL; +} diff --git a/sim/igen/misc.h b/sim/igen/misc.h new file mode 100644 index 00000000000..10a807fecc8 --- /dev/null +++ b/sim/igen/misc.h @@ -0,0 +1,149 @@ +/* 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. + + */ + + +/* Frustrating header junk */ + +#include "config.h" + + +enum { + default_insn_bit_size = 32, + max_insn_bit_size = 64, +}; + + +/* Define a 64bit data type */ + +#if defined __GNUC__ || defined _WIN32 +#ifdef __GNUC__ + +typedef long long signed64; +typedef unsigned long long unsigned64; + +#else /* _WIN32 */ + +typedef __int64 signed64; +typedef unsigned __int64 unsigned64; + +#endif /* _WIN32 */ +#else /* Not GNUC or WIN32 */ +/* Not supported */ +#endif + + +#include <stdio.h> +#include <ctype.h> + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#if !defined (__attribute__) && (!defined(__GNUC__) || __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)) +#define __attribute__(arg) +#endif + + + +#include "filter_host.h" + +typedef struct _line_ref line_ref; +struct _line_ref { + const char *file_name; + int line_nr; +}; + +/* Error appends a new line, warning and notify do not */ +typedef void error_func +(const line_ref *line, + char *msg, + ...); + +extern error_func error; +extern error_func warning; +extern error_func notify; + + +#define ERROR(EXPRESSION) \ +do { \ + line_ref line; \ + line.file_name = filter_filename (__FILE__); \ + line.line_nr = __LINE__; \ + error (&line, EXPRESSION); \ +} while (0) + +#define ASSERT(EXPRESSION) \ +do { \ + if (!(EXPRESSION)) { \ + line_ref line; \ + line.file_name = filter_filename (__FILE__); \ + line.line_nr = __LINE__; \ + error(&line, "assertion failed - %s\n", #EXPRESSION); \ + } \ +} while (0) + +#define ZALLOC(TYPE) ((TYPE*) zalloc (sizeof(TYPE))) +#define NZALLOC(TYPE,N) ((TYPE*) zalloc (sizeof(TYPE) * (N))) +#if 0 +#define STRDUP(STRING) (strcpy (zalloc (strlen (STRING) + 1), (STRING))) +#define STRNDUP(STRING,LEN) (strncpy (zalloc ((LEN) + 1), (STRING), (LEN))) +#endif + +extern void *zalloc +(long size); + +extern unsigned target_a2i +(int ms_bit_nr, + const char *a); + +extern unsigned i2target +(int ms_bit_nr, + unsigned bit); + +extern unsigned long long a2i +(const char *a); + + +/* Try looking for name in the map table (returning the corresponding + integer value). + + If the the sentinal (NAME == NULL) its value if >= zero is returned + as the default. */ + +typedef struct _name_map { + const char *name; + int i; +} name_map; + +extern int name2i +(const char *name, + const name_map *map); + +extern const char *i2name +(const int i, + const name_map *map); diff --git a/sim/igen/table.c b/sim/igen/table.c new file mode 100644 index 00000000000..f6a9e9bb3fc --- /dev/null +++ b/sim/igen/table.c @@ -0,0 +1,632 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995,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. + + */ + + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <fcntl.h> +#include <ctype.h> + +#include "config.h" +#include "misc.h" +#include "lf.h" +#include "table.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +typedef struct _open_table open_table; +struct _open_table { + size_t size; + char *buffer; + char *pos; + line_ref pseudo_line; + line_ref real_line; + open_table *parent; + table *root; +}; +struct _table { + open_table *current; +}; + + +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) +{ + FILE *ff; + 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 (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; + /* open the file */ + + ff = fopen (dup_name, "rb"); + if (ff) + 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 */ + fseek (ff, 0, SEEK_END); + file->size = ftell (ff); + fseek (ff, 0, SEEK_SET); + + /* allocate this much memory */ + file->buffer = (char*) zalloc (file->size + 1); + if (file->buffer == NULL) + { + perror (file_name); + exit (1); + } + file->pos = file->buffer; + + /* read it all in */ + if (fread (file->buffer, 1, file->size, ff) < file->size) { + perror (file_name); + exit (1); + } + file->buffer[file->size] = '\0'; + + /* set the initial line numbering */ + file->real_line.line_nr = 1; /* specifies current line */ + file->pseudo_line.line_nr = 1; /* specifies current line */ + + /* done */ + fclose (ff); +} + +table * +table_open (const char *file_name) +{ + table *root; + + /* create a file descriptor */ + root = ZALLOC (table); + if (root == NULL) + { + perror (file_name); + exit (1); + } + + 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++; + } +} + + +char * +back_spaces (char *start, char *chp) +{ + while (1) + { + if (chp <= start + || !isspace (chp[-1])) + return chp; + chp--; + } +} + +char * +skip_digits (char *chp) +{ + while (1) + { + if (*chp == '\0' + || *chp == '\n' + || !isdigit (*chp)) + return chp; + chp++; + } +} + +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') + { + if (file->parent != NULL) + { + file = file->parent; + root->current = file; + } + else + return NULL; + } + + /* code_block? */ + if (*file->pos == '{') + { + 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; + } + + /* 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; + } + + /* 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; + } + + /* 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; + } + + /* comment - leading // or # - skip */ + if ((file->pos[0] == '/' && file->pos[1] == '/') + || (file->pos[0] == '#')) + { + next_line (file); + continue; + } + + /* 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; + } + + } + + ASSERT (entry == NULL || entry->field[entry->nr_fields] == NULL); + return entry; +} + +extern void +table_print_code (lf *file, + table_entry *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'); + } +} + + + +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); +} + + +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); +} + + +#ifdef MAIN +int +main(int argc, char **argv) +{ + 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 diff --git a/sim/igen/table.h b/sim/igen/table.h new file mode 100644 index 00000000000..e0bc81bf38e --- /dev/null +++ b/sim/igen/table.h @@ -0,0 +1,155 @@ +/* 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. + + */ + + +/* Read a table, line by line, from a file. + + A table line has several forms: + + Field line: + + <text> { ":" <text> } + type == table_colon_entry + + Fields points to a NULL terminated list of pointers. + + Tab indented block: + + <tab> <text> <nl> { <tab> <text> <nl> } + type == table_code_entry + + The leading tab at the start of each line is discarded. + fields[i] is the i'th line with the <nl> discarded. + + + Code block: + + "{" <ignore-text> <nl> { <text> <nl> } "}" <ignore-text> <nl> + type == table_code_entry + + The leading/trailing {/} lines are discarded. + Lines containing two leading spaces have those spaces striped. + fields[i] is the i'th line with the <nl> discarded. + + In addition, the table parser reconises and handles internally the + following (when not in a code block): + + "#" <line-nr> '"' <file> '"' + + As per CPP/CC, treat following lines as if they were taken from + <file> starting at <line-nr> + + No support for CPP's "#if/#else/#endif" style conditions are + planned. */ + +typedef struct _table table; + +typedef enum { + table_colon_entry, + table_code_entry, +} table_entry_type; + + +typedef struct _table_entry table_entry; +struct _table_entry { + table *file; + line_ref *line; + table_entry_type type; + int nr_fields; + char **field; +}; + +/* List of directories to search when opening a pushed file. Current + directory is always searched first */ +typedef struct _table_include table_include; +struct _table_include { + char *dir; + table_include *next; +}; + + +/* Open/read a table file. Since the file is read once during open + (and then closed immediatly) there is no close method. */ + +extern table *table_open +(const char *file_name); + +extern table_entry *table_read +(table *file); + + +/* Push the the state of the current file and open FILE_NAME. When + the end of FILE_NAME is reached, return to the pushed file */ + +extern void table_push +(table *file, + line_ref *line, + table_include *search, + const char *file_name); + + +/* Expand the specified field_nr using the internal expansion table. + A field is only expanded when explicitly specified. */ + +extern void table_expand_field +(table_entry *entry, + int field_nr); + + +/* Given a code entry, write the code to FILE. Since any + leading/trailing braces were striped as part of the read, they are + not written. */ + +extern void table_print_code +(lf *file, + table_entry *entry); + + +/* Debugging */ + +extern void dump_line_ref +(lf *file, + char *prefix, + const line_ref *line, + char *suffix); + +extern void dump_table_entry +(lf *file, + char *prefix, + const table_entry *entry, + char *suffix); + + + +/* Utilities for skipping around text */ + +extern char *skip_digits +(char *chp); + +extern char *skip_spaces +(char *chp); + +extern char *skip_to_separator +(char *chp, + char *separators); + +extern char *back_spaces +(char *start, + char *chp); |