mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-15 04:31:49 +08:00
1d506c26d9
This commit is the result of the following actions: - Running gdb/copyright.py to update all of the copyright headers to include 2024, - Manually updating a few files the copyright.py script told me to update, these files had copyright headers embedded within the file, - Regenerating gdbsupport/Makefile.in to refresh it's copyright date, - Using grep to find other files that still mentioned 2023. If these files were updated last year from 2022 to 2023 then I've updated them this year to 2024. I'm sure I've probably missed some dates. Feel free to fix them up as you spot them.
823 lines
23 KiB
C
823 lines
23 KiB
C
/* The IGEN simulator generator for GDB, the GNU Debugger.
|
|
|
|
Copyright 2002-2024 Free Software Foundation, Inc.
|
|
|
|
Contributed by Andrew Cagney.
|
|
|
|
This file is part of GDB.
|
|
|
|
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 3 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, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include <stdlib.h>
|
|
|
|
#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,
|
|
const 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,
|
|
const insn_entry *insn,
|
|
const opcode_bits *expanded_bits,
|
|
const 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,
|
|
const char *single_insn_field,
|
|
line_ref *line,
|
|
insn_field_entry *cur_field,
|
|
const opcode_bits *expanded_bits,
|
|
icache_decl_type what_to_declare,
|
|
icache_body_type what_to_do)
|
|
{
|
|
const char *expression;
|
|
const opcode_bits *bits;
|
|
const 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;
|
|
default:
|
|
abort (); /* Bad switch. */
|
|
}
|
|
|
|
/* 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,
|
|
const insn_entry *instruction,
|
|
const 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)
|
|
{
|
|
/* Always expand named fields (even if constant), so
|
|
references are valid. */
|
|
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))
|
|
{
|
|
const 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 (const 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, const 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;
|
|
const 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))
|
|
{
|
|
const 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,
|
|
const insn_entry *instruction,
|
|
const opcode_bits *expanded_bits,
|
|
const 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,
|
|
const insn_entry *insn,
|
|
const opcode_bits *expanded_bits,
|
|
const 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,
|
|
const 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,
|
|
const 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");
|
|
}
|
|
}
|