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