mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-26 01:07:52 +00:00
Initial creation of sourceware repository
This commit is contained in:
998
sim/igen/ChangeLog
Normal file
998
sim/igen/ChangeLog
Normal 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
177
sim/igen/Makefile.in
Normal 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
15
sim/igen/acconfig.h
Normal 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
31
sim/igen/config.in
Normal 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
1806
sim/igen/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
52
sim/igen/configure.in
Normal file
52
sim/igen/configure.in
Normal 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
355
sim/igen/filter.c
Normal 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
86
sim/igen/filter.h
Normal 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
37
sim/igen/filter_host.c
Normal 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
27
sim/igen/filter_host.h
Normal 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
807
sim/igen/gen-engine.c
Normal 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
37
sim/igen/gen-engine.h
Normal 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
859
sim/igen/gen-icache.c
Normal 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
81
sim/igen/gen-icache.h
Normal 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
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
50
sim/igen/gen-idecode.h
Normal 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
317
sim/igen/gen-itable.c
Normal 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
30
sim/igen/gen-itable.h
Normal 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
416
sim/igen/gen-model.c
Normal 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
29
sim/igen/gen-model.h
Normal 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
390
sim/igen/gen-semantics.c
Normal 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
104
sim/igen/gen-semantics.h
Normal 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
219
sim/igen/gen-support.c
Normal 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
29
sim/igen/gen-support.h
Normal 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
1765
sim/igen/gen.c
Normal file
File diff suppressed because it is too large
Load Diff
227
sim/igen/gen.h
Normal file
227
sim/igen/gen.h
Normal 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
1621
sim/igen/igen.c
Normal file
File diff suppressed because it is too large
Load Diff
234
sim/igen/igen.h
Normal file
234
sim/igen/igen.h
Normal 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
114
sim/igen/ld-cache.c
Normal 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
66
sim/igen/ld-cache.h
Normal 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
404
sim/igen/ld-decode.c
Normal 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
235
sim/igen/ld-decode.h
Normal 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
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
703
sim/igen/ld-insn.h
Normal 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
418
sim/igen/lf.c
Normal 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
143
sim/igen/lf.h
Normal 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
284
sim/igen/misc.c
Normal 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
149
sim/igen/misc.h
Normal 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
632
sim/igen/table.c
Normal 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
155
sim/igen/table.h
Normal 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);
|
||||
Reference in New Issue
Block a user