diff options
author | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:35:26 +0000 |
---|---|---|
committer | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:35:26 +0000 |
commit | c906108c21474dfb4ed285bcc0ac6fe02cd400cc (patch) | |
tree | a0015aa5cedc19ccbab307251353a41722a3ae13 /sim/ppc/gen-icache.c | |
parent | cd946cff9ede3f30935803403f06f6ed30cad136 (diff) | |
download | gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.zip gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.tar.gz gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.tar.bz2 |
Initial creation of sourceware repositorygdb-4_18-branchpoint
Diffstat (limited to 'sim/ppc/gen-icache.c')
-rw-r--r-- | sim/ppc/gen-icache.c | 675 |
1 files changed, 675 insertions, 0 deletions
diff --git a/sim/ppc/gen-icache.c b/sim/ppc/gen-icache.c new file mode 100644 index 0000000..0d58ab1 --- /dev/null +++ b/sim/ppc/gen-icache.c @@ -0,0 +1,675 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "misc.h" +#include "lf.h" +#include "table.h" + +#include "filter.h" + +#include "ld-decode.h" +#include "ld-cache.h" +#include "ld-insn.h" + +#include "igen.h" + +#include "gen-semantics.h" +#include "gen-idecode.h" +#include "gen-icache.h" + + + +static void +print_icache_function_header(lf *file, + const char *basename, + insn_bits *expanded_bits, + int is_function_definition) +{ + lf_printf(file, "\n"); + lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "EXTERN_ICACHE", " "); + print_function_name(file, + basename, + expanded_bits, + function_name_prefix_icache); + lf_printf(file, "\n(%s)", ICACHE_FUNCTION_FORMAL); + if (!is_function_definition) + lf_printf(file, ";"); + lf_printf(file, "\n"); +} + + +void +print_icache_declaration(insn_table *entry, + lf *file, + void *data, + insn *instruction, + int depth) +{ + if (generate_expanded_instructions) { + ASSERT(entry->nr_insn == 1); + print_icache_function_header(file, + entry->insns->file_entry->fields[insn_name], + entry->expanded_bits, + 0/* is not function definition */); + } + else { + print_icache_function_header(file, + instruction->file_entry->fields[insn_name], + NULL, + 0/* is not function definition */); + } +} + + + +static void +print_icache_extraction(lf *file, + insn *instruction, + const char *entry_name, + const char *entry_type, + const char *entry_expression, + const char *original_name, + const char *file_name, + int line_nr, + insn_field *cur_field, + insn_bits *bits, + icache_decl_type what_to_declare, + icache_body_type what_to_do, + const char *reason) +{ + const char *expression; + ASSERT(entry_name != NULL); + + /* Define a storage area for the cache element */ + if (what_to_declare == undef_variables) { + /* We've finished with the value - destory it */ + lf_indent_suppress(file); + lf_printf(file, "#undef %s\n", entry_name); + return; + } + else if (what_to_declare == define_variables) { + lf_indent_suppress(file); + lf_printf(file, "#define %s ", entry_name); + } + else { + if (file_name != NULL) + lf_print__external_reference(file, line_nr, file_name); + lf_printf(file, "%s const %s UNUSED = ", + entry_type == NULL ? "unsigned" : entry_type, + entry_name); + } + + /* define a value for that storage area as determined by what is in + the cache */ + if (bits != NULL + && strcmp(entry_name, cur_field->val_string) == 0 + && ((bits->opcode->is_boolean && bits->value == 0) + || (!bits->opcode->is_boolean))) { + /* The simple field has been made constant (as a result of + expanding instructions or similar). Remember that for a + boolean field, value is either 0 (implying the required + boolean_constant) or nonzero (implying some other value and + handled later below) - Define the variable accordingly */ + expression = "constant field"; + ASSERT(bits->field == cur_field); + ASSERT(entry_type == NULL); + if (bits->opcode->is_boolean) + 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 + && original_name != NULL + && strncmp(entry_name, + original_name, strlen(original_name)) == 0 + && strncmp(entry_name + strlen(original_name), + "_is_", strlen("_is_")) == 0 + && ((bits->opcode->is_boolean + && (atol(entry_name + strlen(original_name) + strlen("_is_")) + == bits->opcode->boolean_constant)) + || (!bits->opcode->is_boolean))) { + expression = "constant compare"; + /* An entry, derived from ORIGINAL_NAME, is testing to see of the + ORIGINAL_NAME has a specific constant value. That value + matching a boolean or constant field */ + if (bits->opcode->is_boolean) + lf_printf(file, "%d /* %s == %d */", + bits->value == 0, + original_name, + bits->opcode->boolean_constant); + else if (bits->opcode->last < bits->field->last) + lf_printf(file, "%d /* %s == %d */", + (atol(entry_name + strlen(original_name) + strlen("_is_")) + == (bits->value << (bits->field->last - bits->opcode->last))), + original_name, + (bits->value << (bits->field->last - bits->opcode->last))); + else + lf_printf(file, "%d /* %s == %d */", + (atol(entry_name + strlen(original_name) + strlen("_is_")) + == bits->value), + original_name, + 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", + instruction->file_entry->fields[insn_form], + 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 && strcmp(entry_name, cur_field->val_string) == 0) + lf_printf(file, "EXTRACTED32(instruction, %d, %d)", + i2target(hi_bit_nr, cur_field->first), + i2target(hi_bit_nr, cur_field->last)); + else if (entry_expression != NULL) + lf_printf(file, "%s", entry_expression); + else + lf_printf(file, "eval_%s", entry_name); + } + } + + if (!((what_to_declare == define_variables) + || (what_to_declare == undef_variables))) + lf_printf(file, ";"); + if (reason != NULL) + lf_printf(file, " /* %s - %s */", reason, expression); + lf_printf(file, "\n"); +} + + +void +print_icache_body(lf *file, + insn *instruction, + insn_bits *expanded_bits, + cache_table *cache_rules, + icache_decl_type what_to_declare, + icache_body_type what_to_do) +{ + insn_field *cur_field; + + /* extract instruction fields */ + lf_printf(file, "/* extraction: %s ", + instruction->file_entry->fields[insn_format]); + 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"); + + for (cur_field = instruction->fields->first; + cur_field->first < insn_bit_size; + cur_field = cur_field->next) { + if (cur_field->is_string) { + insn_bits *bits; + int found_rule = 0; + /* find any corresponding value */ + for (bits = expanded_bits; + bits != NULL; + bits = bits->last) { + if (bits->field == cur_field) + break; + } + /* try the cache rule table for what to do */ + { + cache_table *cache_rule; + for (cache_rule = cache_rules; + cache_rule != NULL; + cache_rule = cache_rule->next) { + if (strcmp(cur_field->val_string, cache_rule->field_name) == 0) { + found_rule = 1; + if (cache_rule->type == scratch_value + && ((what_to_do & put_values_in_icache) + || what_to_do == do_not_use_icache)) + print_icache_extraction(file, + instruction, + cache_rule->derived_name, + cache_rule->type_def, + cache_rule->expression, + cache_rule->field_name, + cache_rule->file_entry->file_name, + cache_rule->file_entry->line_nr, + cur_field, + bits, + what_to_declare, + do_not_use_icache, + "icache scratch"); + else if (cache_rule->type == compute_value + && ((what_to_do & get_values_from_icache) + || what_to_do == do_not_use_icache)) + print_icache_extraction(file, + instruction, + cache_rule->derived_name, + cache_rule->type_def, + cache_rule->expression, + cache_rule->field_name, + cache_rule->file_entry->file_name, + cache_rule->file_entry->line_nr, + cur_field, + bits, + what_to_declare, + do_not_use_icache, + "semantic compute"); + else if (cache_rule->type == cache_value + && ((what_to_declare != undef_variables) + || !(what_to_do & put_values_in_icache))) + print_icache_extraction(file, + instruction, + cache_rule->derived_name, + cache_rule->type_def, + cache_rule->expression, + cache_rule->field_name, + cache_rule->file_entry->file_name, + cache_rule->file_entry->line_nr, + cur_field, + bits, + ((what_to_do & put_values_in_icache) + ? declare_variables + : what_to_declare), + what_to_do, + "in icache"); + } + } + } + /* No rule at all, assume that this is needed in the semantic + function (when values are extracted from the icache) and + hence must be put into the cache */ + if (found_rule == 0 + && ((what_to_declare != undef_variables) + || !(what_to_do & put_values_in_icache))) + print_icache_extraction(file, + instruction, + cur_field->val_string, + NULL, NULL, NULL, /* type, exp, orig */ + instruction->file_entry->file_name, + instruction->file_entry->line_nr, + cur_field, + bits, + ((what_to_do & put_values_in_icache) + ? declare_variables + : what_to_declare), + what_to_do, + "default in icache"); + /* any thing else ... */ + } + } + + lf_print__internal_reference(file); + + if ((code & generate_with_insn_in_icache)) { + lf_printf(file, "\n"); + print_icache_extraction(file, + instruction, + "insn", + "instruction_word", + "instruction", + NULL, /* origin */ + NULL, 0, /* file_name & line_nr */ + NULL, NULL, + what_to_declare, + what_to_do, + NULL); + } +} + + + +typedef struct _icache_tree icache_tree; +struct _icache_tree { + char *name; + icache_tree *next; + icache_tree *children; +}; + +static icache_tree * +icache_tree_insert(icache_tree *tree, + char *name) +{ + icache_tree *new_tree; + /* find it */ + icache_tree **ptr_to_cur_tree = &tree->children; + icache_tree *cur_tree = *ptr_to_cur_tree; + while (cur_tree != NULL + && strcmp(cur_tree->name, name) < 0) { + ptr_to_cur_tree = &cur_tree->next; + cur_tree = *ptr_to_cur_tree; + } + ASSERT(cur_tree == NULL + || strcmp(cur_tree->name, name) >= 0); + /* already in the tree */ + if (cur_tree != NULL + && strcmp(cur_tree->name, name) == 0) + return cur_tree; + /* missing, insert it */ + ASSERT(cur_tree == NULL + || strcmp(cur_tree->name, name) > 0); + new_tree = ZALLOC(icache_tree); + new_tree->name = name; + new_tree->next = cur_tree; + *ptr_to_cur_tree = new_tree; + return new_tree; +} + + +static icache_tree * +insn_table_cache_fields(insn_table *table) +{ + icache_tree *tree = ZALLOC(icache_tree); + insn *instruction; + for (instruction = table->insns; + instruction != NULL; + instruction = instruction->next) { + insn_field *field; + icache_tree *form = + icache_tree_insert(tree, + instruction->file_entry->fields[insn_form]); + for (field = instruction->fields->first; + field != NULL; + field = field->next) { + if (field->is_string) + icache_tree_insert(form, field->val_string); + } + } + return tree; +} + + + +extern void +print_icache_struct(insn_table *instructions, + cache_table *cache_rules, + lf *file) +{ + icache_tree *tree = insn_table_cache_fields(instructions); + + lf_printf(file, "\n"); + lf_printf(file, "#define WITH_IDECODE_CACHE_SIZE %d\n", + (code & generate_with_icache) ? icache_size : 0); + lf_printf(file, "\n"); + + /* create an instruction cache if being used */ + if ((code & generate_with_icache)) { + icache_tree *form; + lf_printf(file, "typedef struct _idecode_cache {\n"); + lf_printf(file, " unsigned_word address;\n"); + lf_printf(file, " void *semantic;\n"); + lf_printf(file, " union {\n"); + for (form = tree->children; + form != NULL; + form = form->next) { + icache_tree *field; + lf_printf(file, " struct {\n"); + if (code & generate_with_insn_in_icache) + lf_printf(file, " instruction_word insn;\n"); + for (field = form->children; + field != NULL; + field = field->next) { + cache_table *cache_rule; + int found_rule = 0; + for (cache_rule = cache_rules; + cache_rule != NULL; + cache_rule = cache_rule->next) { + if (strcmp(field->name, cache_rule->field_name) == 0) { + found_rule = 1; + if (cache_rule->derived_name != NULL) + lf_printf(file, " %s %s; /* %s */\n", + (cache_rule->type_def == NULL + ? "unsigned" + : cache_rule->type_def), + cache_rule->derived_name, + cache_rule->field_name); + } + } + if (!found_rule) + lf_printf(file, " unsigned %s;\n", field->name); + } + lf_printf(file, " } %s;\n", form->name); + } + lf_printf(file, " } crack;\n"); + lf_printf(file, "} idecode_cache;\n"); + } + 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 idecode_cache;\n"); + } + lf_printf(file, "\n"); +} + + + +static void +print_icache_function(lf *file, + insn *instruction, + insn_bits *expanded_bits, + opcode_field *opcodes, + cache_table *cache_rules) +{ + int indent; + + /* generate code to enter decoded instruction into the icache */ + lf_printf(file, "\n"); + lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "EXTERN_ICACHE", "\n"); + indent = print_function_name(file, + instruction->file_entry->fields[insn_name], + expanded_bits, + function_name_prefix_icache); + lf_indent(file, +indent); + lf_printf(file, "(%s)\n", ICACHE_FUNCTION_FORMAL); + lf_indent(file, -indent); + + /* function header */ + lf_printf(file, "{\n"); + lf_indent(file, +2); + + print_my_defines(file, expanded_bits, instruction->file_entry); + print_itrace(file, instruction->file_entry, 1/*putting-value-in-cache*/); + + print_idecode_validate(file, instruction, opcodes); + + lf_printf(file, "\n"); + lf_printf(file, "{\n"); + lf_indent(file, +2); + if ((code & generate_with_semantic_icache)) + lf_printf(file, "unsigned_word nia;\n"); + print_icache_body(file, + instruction, + expanded_bits, + cache_rules, + ((code & generate_with_direct_access) + ? define_variables + : declare_variables), + ((code & generate_with_semantic_icache) + ? both_values_and_icache + : put_values_in_icache)); + + lf_printf(file, "\n"); + lf_printf(file, "cache_entry->address = cia;\n"); + lf_printf(file, "cache_entry->semantic = "); + print_function_name(file, + instruction->file_entry->fields[insn_name], + expanded_bits, + function_name_prefix_semantics); + lf_printf(file, ";\n"); + lf_printf(file, "\n"); + + if ((code & generate_with_semantic_icache)) { + lf_printf(file, "/* semantic routine */\n"); + print_semantic_body(file, + instruction, + expanded_bits, + opcodes); + lf_printf(file, "return nia;\n"); + } + + if (!(code & generate_with_semantic_icache)) { + lf_printf(file, "/* return the function proper */\n"); + lf_printf(file, "return "); + print_function_name(file, + instruction->file_entry->fields[insn_name], + expanded_bits, + function_name_prefix_semantics); + lf_printf(file, ";\n"); + } + + if ((code & generate_with_direct_access)) + print_icache_body(file, + instruction, + expanded_bits, + cache_rules, + undef_variables, + ((code & generate_with_semantic_icache) + ? both_values_and_icache + : put_values_in_icache)); + + lf_indent(file, -2); + lf_printf(file, "}\n"); + lf_indent(file, -2); + lf_printf(file, "}\n"); +} + + +void +print_icache_definition(insn_table *entry, + lf *file, + void *data, + insn *instruction, + int depth) +{ + cache_table *cache_rules = (cache_table*)data; + if (generate_expanded_instructions) { + ASSERT(entry->nr_insn == 1 + && entry->opcode == NULL + && entry->parent != NULL + && entry->parent->opcode != NULL); + ASSERT(entry->nr_insn == 1 + && entry->opcode == NULL + && entry->parent != NULL + && entry->parent->opcode != NULL + && entry->parent->opcode_rule != NULL); + print_icache_function(file, + entry->insns, + entry->expanded_bits, + entry->opcode, + cache_rules); + } + else { + print_icache_function(file, + instruction, + NULL, + NULL, + cache_rules); + } +} + + + +void +print_icache_internal_function_declaration(insn_table *table, + lf *file, + void *data, + table_entry *function) +{ + ASSERT((code & generate_with_icache) != 0); + if (it_is("internal", function->fields[insn_flags])) { + lf_printf(file, "\n"); + lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "INLINE_ICACHE", + "\n"); + print_function_name(file, + function->fields[insn_name], + NULL, + function_name_prefix_icache); + lf_printf(file, "\n(%s);\n", ICACHE_FUNCTION_FORMAL); + } +} + + +void +print_icache_internal_function_definition(insn_table *table, + lf *file, + void *data, + table_entry *function) +{ + ASSERT((code & generate_with_icache) != 0); + if (it_is("internal", function->fields[insn_flags])) { + lf_printf(file, "\n"); + lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "INLINE_ICACHE", + "\n"); + print_function_name(file, + function->fields[insn_name], + NULL, + function_name_prefix_icache); + lf_printf(file, "\n(%s)\n", ICACHE_FUNCTION_FORMAL); + lf_printf(file, "{\n"); + lf_indent(file, +2); + lf_printf(file, "/* semantic routine */\n"); + table_entry_print_cpp_line_nr(file, function); + if ((code & generate_with_semantic_icache)) { + lf_print__c_code(file, function->annex); + 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->fields[insn_name], + NULL, + function_name_prefix_semantics); + lf_printf(file, ";\n"); + } + + lf_print__internal_reference(file); + lf_indent(file, -2); + lf_printf(file, "}\n"); + } +} |