Initial creation of sourceware repository

This commit is contained in:
Stan Shebs
1999-04-16 01:35:26 +00:00
parent cd946cff9e
commit c906108c21
2470 changed files with 976797 additions and 0 deletions

998
sim/igen/ChangeLog Normal file
View File

@@ -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]

177
sim/igen/Makefile.in Normal file
View File

@@ -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:
#

15
sim/igen/acconfig.h Normal file
View File

@@ -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

31
sim/igen/config.in Normal file
View File

@@ -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

1806
sim/igen/configure vendored Executable file

File diff suppressed because it is too large Load Diff

52
sim/igen/configure.in Normal file
View File

@@ -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])

355
sim/igen/filter.c Normal file
View File

@@ -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

86
sim/igen/filter.h Normal file
View File

@@ -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);

37
sim/igen/filter_host.c Normal file
View File

@@ -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;
}

27
sim/igen/filter_host.h Normal file
View File

@@ -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

807
sim/igen/gen-engine.c Normal file
View File

@@ -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;
}
}
}

37
sim/igen/gen-engine.h Normal file
View File

@@ -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);

859
sim/igen/gen-icache.c Normal file
View File

@@ -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");
}
}

81
sim/igen/gen-icache.h Normal file
View File

@@ -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 */

1391
sim/igen/gen-idecode.c Normal file

File diff suppressed because it is too large Load Diff

50
sim/igen/gen-idecode.h Normal file
View File

@@ -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);

317
sim/igen/gen-itable.c Normal file
View File

@@ -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");
}

30
sim/igen/gen-itable.h Normal file
View File

@@ -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);

416
sim/igen/gen-model.c Normal file
View File

@@ -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");
}

29
sim/igen/gen-model.h Normal file
View File

@@ -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);

390
sim/igen/gen-semantics.c Normal file
View File

@@ -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);
}

104
sim/igen/gen-semantics.h Normal file
View File

@@ -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);

219
sim/igen/gen-support.c Normal file
View File

@@ -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);
}

29
sim/igen/gen-support.h Normal file
View File

@@ -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);

1765
sim/igen/gen.c Normal file

File diff suppressed because it is too large Load Diff

227
sim/igen/gen.h Normal file
View File

@@ -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);

1621
sim/igen/igen.c Normal file

File diff suppressed because it is too large Load Diff

234
sim/igen/igen.h Normal file
View File

@@ -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)

114
sim/igen/ld-cache.c Normal file
View File

@@ -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

66
sim/igen/ld-cache.h Normal file
View File

@@ -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);

404
sim/igen/ld-decode.c Normal file
View File

@@ -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

235
sim/igen/ld-decode.h Normal file
View File

@@ -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);

1829
sim/igen/ld-insn.c Normal file

File diff suppressed because it is too large Load Diff

703
sim/igen/ld-insn.h Normal file
View File

@@ -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);

418
sim/igen/lf.c Normal file
View File

@@ -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;
}

143
sim/igen/lf.h Normal file
View File

@@ -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);

284
sim/igen/misc.c Normal file
View File

@@ -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;
}

149
sim/igen/misc.h Normal file
View File

@@ -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);

632
sim/igen/table.c Normal file
View File

@@ -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

155
sim/igen/table.h Normal file
View File

@@ -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);