14e98e3e1Schristos /* The IGEN simulator generator for GDB, the GNU Debugger. 24e98e3e1Schristos 3*71f62182Schristos Copyright 2002-2024 Free Software Foundation, Inc. 44e98e3e1Schristos 54e98e3e1Schristos Contributed by Andrew Cagney. 64e98e3e1Schristos 74e98e3e1Schristos This file is part of GDB. 84e98e3e1Schristos 94e98e3e1Schristos This program is free software; you can redistribute it and/or modify 104e98e3e1Schristos it under the terms of the GNU General Public License as published by 114e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 124e98e3e1Schristos (at your option) any later version. 134e98e3e1Schristos 144e98e3e1Schristos This program is distributed in the hope that it will be useful, 154e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 164e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 174e98e3e1Schristos GNU General Public License for more details. 184e98e3e1Schristos 194e98e3e1Schristos You should have received a copy of the GNU General Public License 204e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 214e98e3e1Schristos 224b169a6bSchristos #include <stdlib.h> 234e98e3e1Schristos 244e98e3e1Schristos #include "misc.h" 254e98e3e1Schristos #include "lf.h" 264e98e3e1Schristos #include "table.h" 274e98e3e1Schristos #include "filter.h" 284e98e3e1Schristos #include "igen.h" 294e98e3e1Schristos 304e98e3e1Schristos #include "ld-insn.h" 314e98e3e1Schristos #include "ld-decode.h" 324e98e3e1Schristos 334e98e3e1Schristos #include "gen.h" 344e98e3e1Schristos 354e98e3e1Schristos #include "gen-semantics.h" 364e98e3e1Schristos #include "gen-idecode.h" 374e98e3e1Schristos #include "gen-icache.h" 384e98e3e1Schristos 394e98e3e1Schristos 404e98e3e1Schristos 414e98e3e1Schristos static void 424e98e3e1Schristos print_icache_function_header (lf *file, 434e98e3e1Schristos const char *basename, 444e98e3e1Schristos const char *format_name, 454b169a6bSchristos const opcode_bits *expanded_bits, 464e98e3e1Schristos int is_function_definition, 474e98e3e1Schristos int nr_prefetched_words) 484e98e3e1Schristos { 494e98e3e1Schristos lf_printf (file, "\n"); 504e98e3e1Schristos lf_print__function_type_function (file, print_icache_function_type, 514e98e3e1Schristos "EXTERN_ICACHE", " "); 524e98e3e1Schristos print_function_name (file, 534e98e3e1Schristos basename, format_name, NULL, 544e98e3e1Schristos expanded_bits, function_name_prefix_icache); 554e98e3e1Schristos lf_printf (file, "\n("); 564e98e3e1Schristos print_icache_function_formal (file, nr_prefetched_words); 574e98e3e1Schristos lf_printf (file, ")"); 584e98e3e1Schristos if (!is_function_definition) 594e98e3e1Schristos lf_printf (file, ";"); 604e98e3e1Schristos lf_printf (file, "\n"); 614e98e3e1Schristos } 624e98e3e1Schristos 634e98e3e1Schristos 644e98e3e1Schristos void 654e98e3e1Schristos print_icache_declaration (lf *file, 664b169a6bSchristos const insn_entry *insn, 674b169a6bSchristos const opcode_bits *expanded_bits, 684b169a6bSchristos const insn_opcodes *opcodes, 694b169a6bSchristos int nr_prefetched_words) 704e98e3e1Schristos { 714e98e3e1Schristos print_icache_function_header (file, 724e98e3e1Schristos insn->name, 734e98e3e1Schristos insn->format_name, 744e98e3e1Schristos expanded_bits, 754e98e3e1Schristos 0 /* is not function definition */ , 764e98e3e1Schristos nr_prefetched_words); 774e98e3e1Schristos } 784e98e3e1Schristos 794e98e3e1Schristos 804e98e3e1Schristos 814e98e3e1Schristos static void 824e98e3e1Schristos print_icache_extraction (lf *file, 834e98e3e1Schristos const char *format_name, 844e98e3e1Schristos cache_entry_type cache_type, 854e98e3e1Schristos const char *entry_name, 864e98e3e1Schristos const char *entry_type, 874e98e3e1Schristos const char *entry_expression, 884b169a6bSchristos const char *single_insn_field, 894e98e3e1Schristos line_ref *line, 904e98e3e1Schristos insn_field_entry *cur_field, 914b169a6bSchristos const opcode_bits *expanded_bits, 924e98e3e1Schristos icache_decl_type what_to_declare, 934e98e3e1Schristos icache_body_type what_to_do) 944e98e3e1Schristos { 954e98e3e1Schristos const char *expression; 964b169a6bSchristos const opcode_bits *bits; 974b169a6bSchristos const char *reason; 984e98e3e1Schristos ASSERT (format_name != NULL); 994e98e3e1Schristos ASSERT (entry_name != NULL); 1004e98e3e1Schristos 1014e98e3e1Schristos /* figure out exactly what should be going on here */ 1024e98e3e1Schristos switch (cache_type) 1034e98e3e1Schristos { 1044e98e3e1Schristos case scratch_value: 1054e98e3e1Schristos if ((what_to_do & put_values_in_icache) 1064e98e3e1Schristos || what_to_do == do_not_use_icache) 1074e98e3e1Schristos { 1084e98e3e1Schristos reason = "scratch"; 1094e98e3e1Schristos what_to_do = do_not_use_icache; 1104e98e3e1Schristos } 1114e98e3e1Schristos else 1124e98e3e1Schristos return; 1134e98e3e1Schristos break; 1144e98e3e1Schristos case compute_value: 1154e98e3e1Schristos if ((what_to_do & get_values_from_icache) 1164e98e3e1Schristos || what_to_do == do_not_use_icache) 1174e98e3e1Schristos { 1184e98e3e1Schristos reason = "compute"; 1194e98e3e1Schristos what_to_do = do_not_use_icache; 1204e98e3e1Schristos } 1214e98e3e1Schristos else 1224e98e3e1Schristos return; 1234e98e3e1Schristos break; 1244e98e3e1Schristos case cache_value: 1254e98e3e1Schristos if ((what_to_declare != undef_variables) 1264e98e3e1Schristos || !(what_to_do & put_values_in_icache)) 1274e98e3e1Schristos { 1284e98e3e1Schristos reason = "cache"; 1294e98e3e1Schristos what_to_declare = ((what_to_do & put_values_in_icache) 1304e98e3e1Schristos ? declare_variables : what_to_declare); 1314e98e3e1Schristos } 1324e98e3e1Schristos else 1334e98e3e1Schristos return; 1344e98e3e1Schristos break; 1354e98e3e1Schristos default: 1364e98e3e1Schristos abort (); /* Bad switch. */ 1374e98e3e1Schristos } 1384e98e3e1Schristos 1394e98e3e1Schristos /* For the type, default to a simple unsigned */ 1404e98e3e1Schristos if (entry_type == NULL || strlen (entry_type) == 0) 1414e98e3e1Schristos entry_type = "unsigned"; 1424e98e3e1Schristos 1434e98e3e1Schristos /* look through the set of expanded sub fields to see if this field 1444e98e3e1Schristos has been given a constant value */ 1454e98e3e1Schristos for (bits = expanded_bits; bits != NULL; bits = bits->next) 1464e98e3e1Schristos { 1474e98e3e1Schristos if (bits->field == cur_field) 1484e98e3e1Schristos break; 1494e98e3e1Schristos } 1504e98e3e1Schristos 1514e98e3e1Schristos /* Define a storage area for the cache element */ 1524e98e3e1Schristos switch (what_to_declare) 1534e98e3e1Schristos { 1544e98e3e1Schristos case undef_variables: 1554e98e3e1Schristos /* We've finished with the #define value - destory it */ 1564e98e3e1Schristos lf_indent_suppress (file); 1574e98e3e1Schristos lf_printf (file, "#undef %s\n", entry_name); 1584e98e3e1Schristos return; 1594e98e3e1Schristos case define_variables: 1604e98e3e1Schristos /* Using direct access for this entry, clear any prior 1614e98e3e1Schristos definition, then define it */ 1624e98e3e1Schristos lf_indent_suppress (file); 1634e98e3e1Schristos lf_printf (file, "#undef %s\n", entry_name); 1644e98e3e1Schristos /* Don't type cast pointer types! */ 1654e98e3e1Schristos lf_indent_suppress (file); 1664e98e3e1Schristos if (strchr (entry_type, '*') != NULL) 1674e98e3e1Schristos lf_printf (file, "#define %s (", entry_name); 1684e98e3e1Schristos else 1694e98e3e1Schristos lf_printf (file, "#define %s ((%s) ", entry_name, entry_type); 1704e98e3e1Schristos break; 1714e98e3e1Schristos case declare_variables: 1724e98e3e1Schristos /* using variables to define the value */ 1734e98e3e1Schristos if (line != NULL) 1744e98e3e1Schristos lf_print__line_ref (file, line); 1754e98e3e1Schristos lf_printf (file, "%s const %s UNUSED = ", entry_type, entry_name); 1764e98e3e1Schristos break; 1774e98e3e1Schristos } 1784e98e3e1Schristos 1794e98e3e1Schristos 1804e98e3e1Schristos /* define a value for that storage area as determined by what is in 1814e98e3e1Schristos the cache */ 1824e98e3e1Schristos if (bits != NULL 1834e98e3e1Schristos && single_insn_field != NULL 1844e98e3e1Schristos && strcmp (entry_name, single_insn_field) == 0 1854e98e3e1Schristos && strcmp (entry_name, cur_field->val_string) == 0 1864e98e3e1Schristos && ((bits->opcode->is_boolean && bits->value == 0) 1874e98e3e1Schristos || (!bits->opcode->is_boolean))) 1884e98e3e1Schristos { 1894e98e3e1Schristos /* The cache rule is specifying what to do with a simple 1904e98e3e1Schristos instruction field. 1914e98e3e1Schristos 1924e98e3e1Schristos Because of instruction expansion, the field is either a 1934e98e3e1Schristos constant value or equal to the specified constant (boolean 1944e98e3e1Schristos comparison). (The latter indicated by bits->value == 0). 1954e98e3e1Schristos 1964e98e3e1Schristos The case of a field not being equal to the specified boolean 1974e98e3e1Schristos value is handled later. */ 1984e98e3e1Schristos expression = "constant field"; 1994e98e3e1Schristos ASSERT (bits->field == cur_field); 2004e98e3e1Schristos if (bits->opcode->is_boolean) 2014e98e3e1Schristos { 2024e98e3e1Schristos ASSERT (bits->value == 0); 2034e98e3e1Schristos lf_printf (file, "%d", bits->opcode->boolean_constant); 2044e98e3e1Schristos } 2054e98e3e1Schristos else if (bits->opcode->last < bits->field->last) 2064e98e3e1Schristos { 2074e98e3e1Schristos lf_printf (file, "%d", 2084e98e3e1Schristos bits->value << (bits->field->last - bits->opcode->last)); 2094e98e3e1Schristos } 2104e98e3e1Schristos else 2114e98e3e1Schristos { 2124e98e3e1Schristos lf_printf (file, "%d", bits->value); 2134e98e3e1Schristos } 2144e98e3e1Schristos } 2154e98e3e1Schristos else if (bits != NULL 2164e98e3e1Schristos && single_insn_field != NULL 2174e98e3e1Schristos && strncmp (entry_name, 2184e98e3e1Schristos single_insn_field, 2194e98e3e1Schristos strlen (single_insn_field)) == 0 2204e98e3e1Schristos && strncmp (entry_name + strlen (single_insn_field), 2214e98e3e1Schristos "_is_", 2224e98e3e1Schristos strlen ("_is_")) == 0 2234e98e3e1Schristos && ((bits->opcode->is_boolean 2244e98e3e1Schristos && ((unsigned) 2254e98e3e1Schristos atol (entry_name + strlen (single_insn_field) + 2264e98e3e1Schristos strlen ("_is_")) == bits->opcode->boolean_constant)) 2274e98e3e1Schristos || (!bits->opcode->is_boolean))) 2284e98e3e1Schristos { 2294e98e3e1Schristos /* The cache rule defines an entry for the comparison between a 2304e98e3e1Schristos single instruction field and a constant. The value of the 2314e98e3e1Schristos comparison in someway matches that of the opcode field that 2324e98e3e1Schristos was made constant through expansion. */ 2334e98e3e1Schristos expression = "constant compare"; 2344e98e3e1Schristos if (bits->opcode->is_boolean) 2354e98e3e1Schristos { 2364e98e3e1Schristos lf_printf (file, "%d /* %s == %d */", 2374e98e3e1Schristos bits->value == 0, 2384e98e3e1Schristos single_insn_field, bits->opcode->boolean_constant); 2394e98e3e1Schristos } 2404e98e3e1Schristos else if (bits->opcode->last < bits->field->last) 2414e98e3e1Schristos { 2424e98e3e1Schristos lf_printf (file, "%d /* %s == %d */", 2434e98e3e1Schristos (atol 2444e98e3e1Schristos (entry_name + strlen (single_insn_field) + 2454e98e3e1Schristos strlen ("_is_")) == 2464e98e3e1Schristos (bits-> 2474e98e3e1Schristos value << (bits->field->last - bits->opcode->last))), 2484e98e3e1Schristos single_insn_field, 2494e98e3e1Schristos (bits-> 2504e98e3e1Schristos value << (bits->field->last - bits->opcode->last))); 2514e98e3e1Schristos } 2524e98e3e1Schristos else 2534e98e3e1Schristos { 2544e98e3e1Schristos lf_printf (file, "%d /* %s == %d */", 2554e98e3e1Schristos (atol 2564e98e3e1Schristos (entry_name + strlen (single_insn_field) + 2574e98e3e1Schristos strlen ("_is_")) == bits->value), single_insn_field, 2584e98e3e1Schristos bits->value); 2594e98e3e1Schristos } 2604e98e3e1Schristos } 2614e98e3e1Schristos else 2624e98e3e1Schristos { 2634e98e3e1Schristos /* put the field in the local variable, possibly also enter it 2644e98e3e1Schristos into the cache */ 2654e98e3e1Schristos expression = "extraction"; 2664e98e3e1Schristos /* handle the cache */ 2674e98e3e1Schristos if ((what_to_do & get_values_from_icache) 2684e98e3e1Schristos || (what_to_do & put_values_in_icache)) 2694e98e3e1Schristos { 2704e98e3e1Schristos lf_printf (file, "cache_entry->crack.%s.%s", 2714e98e3e1Schristos format_name, entry_name); 2724e98e3e1Schristos if (what_to_do & put_values_in_icache) /* also put it in the cache? */ 2734e98e3e1Schristos { 2744e98e3e1Schristos lf_printf (file, " = "); 2754e98e3e1Schristos } 2764e98e3e1Schristos } 2774e98e3e1Schristos if ((what_to_do & put_values_in_icache) 2784e98e3e1Schristos || what_to_do == do_not_use_icache) 2794e98e3e1Schristos { 2804e98e3e1Schristos if (cur_field != NULL) 2814e98e3e1Schristos { 2824e98e3e1Schristos if (entry_expression != NULL && strlen (entry_expression) > 0) 2834e98e3e1Schristos error (line, 2844e98e3e1Schristos "Instruction field entry with nonempty expression\n"); 2854e98e3e1Schristos if (cur_field->first == 0 2864e98e3e1Schristos && cur_field->last == options.insn_bit_size - 1) 2874e98e3e1Schristos lf_printf (file, "(instruction_%d)", cur_field->word_nr); 2884e98e3e1Schristos else if (cur_field->last == options.insn_bit_size - 1) 2894e98e3e1Schristos lf_printf (file, "MASKED%d (instruction_%d, %d, %d)", 2904e98e3e1Schristos options.insn_bit_size, 2914e98e3e1Schristos cur_field->word_nr, 2924e98e3e1Schristos i2target (options.hi_bit_nr, cur_field->first), 2934e98e3e1Schristos i2target (options.hi_bit_nr, cur_field->last)); 2944e98e3e1Schristos else 2954e98e3e1Schristos lf_printf (file, "EXTRACTED%d (instruction_%d, %d, %d)", 2964e98e3e1Schristos options.insn_bit_size, 2974e98e3e1Schristos cur_field->word_nr, 2984e98e3e1Schristos i2target (options.hi_bit_nr, cur_field->first), 2994e98e3e1Schristos i2target (options.hi_bit_nr, cur_field->last)); 3004e98e3e1Schristos } 3014e98e3e1Schristos else 3024e98e3e1Schristos { 3034e98e3e1Schristos lf_printf (file, "%s", entry_expression); 3044e98e3e1Schristos } 3054e98e3e1Schristos } 3064e98e3e1Schristos } 3074e98e3e1Schristos 3084e98e3e1Schristos switch (what_to_declare) 3094e98e3e1Schristos { 3104e98e3e1Schristos case define_variables: 3114e98e3e1Schristos lf_printf (file, ")"); 3124e98e3e1Schristos break; 3134e98e3e1Schristos case undef_variables: 3144e98e3e1Schristos break; 3154e98e3e1Schristos case declare_variables: 3164e98e3e1Schristos lf_printf (file, ";"); 3174e98e3e1Schristos break; 3184e98e3e1Schristos } 3194e98e3e1Schristos 3204e98e3e1Schristos ASSERT (reason != NULL && expression != NULL); 3214e98e3e1Schristos lf_printf (file, " /* %s - %s */\n", reason, expression); 3224e98e3e1Schristos } 3234e98e3e1Schristos 3244e98e3e1Schristos 3254e98e3e1Schristos void 3264e98e3e1Schristos print_icache_body (lf *file, 3274b169a6bSchristos const insn_entry *instruction, 3284b169a6bSchristos const opcode_bits *expanded_bits, 3294e98e3e1Schristos cache_entry *cache_rules, 3304e98e3e1Schristos icache_decl_type what_to_declare, 3314e98e3e1Schristos icache_body_type what_to_do, int nr_prefetched_words) 3324e98e3e1Schristos { 3334e98e3e1Schristos /* extract instruction fields */ 3344e98e3e1Schristos lf_printf (file, "/* Extraction: %s\n", instruction->name); 3354e98e3e1Schristos lf_printf (file, " "); 3364e98e3e1Schristos switch (what_to_declare) 3374e98e3e1Schristos { 3384e98e3e1Schristos case define_variables: 3394e98e3e1Schristos lf_printf (file, "#define"); 3404e98e3e1Schristos break; 3414e98e3e1Schristos case declare_variables: 3424e98e3e1Schristos lf_printf (file, "declare"); 3434e98e3e1Schristos break; 3444e98e3e1Schristos case undef_variables: 3454e98e3e1Schristos lf_printf (file, "#undef"); 3464e98e3e1Schristos break; 3474e98e3e1Schristos } 3484e98e3e1Schristos lf_printf (file, " "); 3494e98e3e1Schristos switch (what_to_do) 3504e98e3e1Schristos { 3514e98e3e1Schristos case get_values_from_icache: 3524e98e3e1Schristos lf_printf (file, "get-values-from-icache"); 3534e98e3e1Schristos break; 3544e98e3e1Schristos case put_values_in_icache: 3554e98e3e1Schristos lf_printf (file, "put-values-in-icache"); 3564e98e3e1Schristos break; 3574e98e3e1Schristos case both_values_and_icache: 3584e98e3e1Schristos lf_printf (file, "get-values-from-icache|put-values-in-icache"); 3594e98e3e1Schristos break; 3604e98e3e1Schristos case do_not_use_icache: 3614e98e3e1Schristos lf_printf (file, "do-not-use-icache"); 3624e98e3e1Schristos break; 3634e98e3e1Schristos } 3644e98e3e1Schristos lf_printf (file, "\n "); 3654e98e3e1Schristos print_insn_words (file, instruction); 3664e98e3e1Schristos lf_printf (file, " */\n"); 3674e98e3e1Schristos 3684e98e3e1Schristos /* pass zero - fetch from memory any missing instructions. 3694e98e3e1Schristos 3704e98e3e1Schristos Some of the instructions will have already been fetched (in the 3714e98e3e1Schristos instruction array), others will still need fetching. */ 3724e98e3e1Schristos switch (what_to_do) 3734e98e3e1Schristos { 3744e98e3e1Schristos case get_values_from_icache: 3754e98e3e1Schristos break; 3764e98e3e1Schristos case put_values_in_icache: 3774e98e3e1Schristos case both_values_and_icache: 3784e98e3e1Schristos case do_not_use_icache: 3794e98e3e1Schristos { 3804e98e3e1Schristos int word_nr; 3814e98e3e1Schristos switch (what_to_declare) 3824e98e3e1Schristos { 3834e98e3e1Schristos case undef_variables: 3844e98e3e1Schristos break; 3854e98e3e1Schristos case define_variables: 3864e98e3e1Schristos case declare_variables: 3874e98e3e1Schristos for (word_nr = nr_prefetched_words; 3884e98e3e1Schristos word_nr < instruction->nr_words; word_nr++) 3894e98e3e1Schristos { 3904e98e3e1Schristos /* FIXME - should be using print_icache_extraction? */ 3914e98e3e1Schristos lf_printf (file, 3924e98e3e1Schristos "%sinstruction_word instruction_%d UNUSED = ", 3934e98e3e1Schristos options.module.global.prefix.l, word_nr); 3944e98e3e1Schristos lf_printf (file, "IMEM%d_IMMED (cia, %d)", 3954e98e3e1Schristos options.insn_bit_size, word_nr); 3964e98e3e1Schristos lf_printf (file, ";\n"); 3974e98e3e1Schristos } 3984e98e3e1Schristos } 3994e98e3e1Schristos } 4004e98e3e1Schristos } 4014e98e3e1Schristos 4024e98e3e1Schristos /* if putting the instruction words in the cache, define references 4034e98e3e1Schristos for them */ 4044e98e3e1Schristos if (options.gen.insn_in_icache) 4054e98e3e1Schristos { 4064e98e3e1Schristos /* FIXME: is the instruction_word type correct? */ 4074e98e3e1Schristos print_icache_extraction (file, instruction->format_name, cache_value, "insn", /* name */ 4084e98e3e1Schristos "instruction_word", /* type */ 4094e98e3e1Schristos "instruction", /* expression */ 4104e98e3e1Schristos NULL, /* origin */ 4114e98e3e1Schristos NULL, /* line */ 4124e98e3e1Schristos NULL, NULL, what_to_declare, what_to_do); 4134e98e3e1Schristos } 4144e98e3e1Schristos lf_printf (file, "\n"); 4154e98e3e1Schristos 4164e98e3e1Schristos /* pass one - process instruction fields. 4174e98e3e1Schristos 4184e98e3e1Schristos If there is no cache rule, the default is to enter the field into 4194e98e3e1Schristos the cache */ 4204e98e3e1Schristos { 4214e98e3e1Schristos insn_word_entry *word; 4224e98e3e1Schristos for (word = instruction->words; word != NULL; word = word->next) 4234e98e3e1Schristos { 4244e98e3e1Schristos insn_field_entry *cur_field; 4254e98e3e1Schristos for (cur_field = word->first; 4264e98e3e1Schristos cur_field->first < options.insn_bit_size; 4274e98e3e1Schristos cur_field = cur_field->next) 4284e98e3e1Schristos { 429a2e2270fSchristos /* Always expand named fields (even if constant), so 430a2e2270fSchristos references are valid. */ 4314e98e3e1Schristos if (cur_field->type == insn_field_string) 4324e98e3e1Schristos { 4334e98e3e1Schristos cache_entry *cache_rule; 4344e98e3e1Schristos cache_entry_type value_type = cache_value; 4354e98e3e1Schristos line_ref *value_line = instruction->line; 4364e98e3e1Schristos /* check the cache table to see if it contains a rule 4374e98e3e1Schristos overriding the default cache action for an 4384e98e3e1Schristos instruction field */ 4394e98e3e1Schristos for (cache_rule = cache_rules; 4404e98e3e1Schristos cache_rule != NULL; cache_rule = cache_rule->next) 4414e98e3e1Schristos { 4424e98e3e1Schristos if (filter_is_subset (instruction->field_names, 4434e98e3e1Schristos cache_rule->original_fields) 4444e98e3e1Schristos && strcmp (cache_rule->name, 4454e98e3e1Schristos cur_field->val_string) == 0) 4464e98e3e1Schristos { 4474e98e3e1Schristos value_type = cache_rule->entry_type; 4484e98e3e1Schristos value_line = cache_rule->line; 4494e98e3e1Schristos if (value_type == compute_value) 4504e98e3e1Schristos { 4514e98e3e1Schristos options.warning (cache_rule->line, 4524e98e3e1Schristos "instruction field of type `compute' changed to `cache'\n"); 4534e98e3e1Schristos cache_rule->entry_type = cache_value; 4544e98e3e1Schristos } 4554e98e3e1Schristos break; 4564e98e3e1Schristos } 4574e98e3e1Schristos } 4584e98e3e1Schristos /* Define an entry for the field within the 4594e98e3e1Schristos instruction */ 4604e98e3e1Schristos print_icache_extraction (file, instruction->format_name, value_type, cur_field->val_string, /* name */ 4614e98e3e1Schristos NULL, /* type */ 4624e98e3e1Schristos NULL, /* expression */ 4634e98e3e1Schristos cur_field->val_string, /* insn field */ 4644e98e3e1Schristos value_line, 4654e98e3e1Schristos cur_field, 4664e98e3e1Schristos expanded_bits, 4674e98e3e1Schristos what_to_declare, what_to_do); 4684e98e3e1Schristos } 4694e98e3e1Schristos } 4704e98e3e1Schristos } 4714e98e3e1Schristos } 4724e98e3e1Schristos 4734e98e3e1Schristos /* pass two - any cache fields not processed above */ 4744e98e3e1Schristos { 4754e98e3e1Schristos cache_entry *cache_rule; 4764e98e3e1Schristos for (cache_rule = cache_rules; 4774e98e3e1Schristos cache_rule != NULL; cache_rule = cache_rule->next) 4784e98e3e1Schristos { 4794e98e3e1Schristos if (filter_is_subset (instruction->field_names, 4804e98e3e1Schristos cache_rule->original_fields) 4814e98e3e1Schristos && !filter_is_member (instruction->field_names, cache_rule->name)) 4824e98e3e1Schristos { 4834b169a6bSchristos const char *single_field = 4844e98e3e1Schristos filter_next (cache_rule->original_fields, ""); 4854e98e3e1Schristos if (filter_next (cache_rule->original_fields, single_field) != 4864e98e3e1Schristos NULL) 4874e98e3e1Schristos single_field = NULL; 4884e98e3e1Schristos 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 */ 4894e98e3e1Schristos expanded_bits, 4904e98e3e1Schristos what_to_declare, what_to_do); 4914e98e3e1Schristos } 4924e98e3e1Schristos } 4934e98e3e1Schristos } 4944e98e3e1Schristos 4954e98e3e1Schristos lf_print__internal_ref (file); 4964e98e3e1Schristos } 4974e98e3e1Schristos 4984e98e3e1Schristos 4994e98e3e1Schristos 5004e98e3e1Schristos typedef struct _form_fields form_fields; 5014e98e3e1Schristos struct _form_fields 5024e98e3e1Schristos { 5034e98e3e1Schristos char *name; 5044e98e3e1Schristos filter *fields; 5054e98e3e1Schristos form_fields *next; 5064e98e3e1Schristos }; 5074e98e3e1Schristos 5084e98e3e1Schristos static form_fields * 5094b169a6bSchristos insn_table_cache_fields (const insn_table *isa) 5104e98e3e1Schristos { 5114e98e3e1Schristos form_fields *forms = NULL; 5124e98e3e1Schristos insn_entry *insn; 5134e98e3e1Schristos for (insn = isa->insns; insn != NULL; insn = insn->next) 5144e98e3e1Schristos { 5154e98e3e1Schristos form_fields **form = &forms; 5164e98e3e1Schristos while (1) 5174e98e3e1Schristos { 5184e98e3e1Schristos if (*form == NULL) 5194e98e3e1Schristos { 5204e98e3e1Schristos /* new format name, add it */ 5214e98e3e1Schristos form_fields *new_form = ZALLOC (form_fields); 5224e98e3e1Schristos new_form->name = insn->format_name; 5234e98e3e1Schristos filter_add (&new_form->fields, insn->field_names); 5244e98e3e1Schristos *form = new_form; 5254e98e3e1Schristos break; 5264e98e3e1Schristos } 5274e98e3e1Schristos else if (strcmp ((*form)->name, insn->format_name) == 0) 5284e98e3e1Schristos { 5294e98e3e1Schristos /* already present, add field names to the existing list */ 5304e98e3e1Schristos filter_add (&(*form)->fields, insn->field_names); 5314e98e3e1Schristos break; 5324e98e3e1Schristos } 5334e98e3e1Schristos form = &(*form)->next; 5344e98e3e1Schristos } 5354e98e3e1Schristos } 5364e98e3e1Schristos return forms; 5374e98e3e1Schristos } 5384e98e3e1Schristos 5394e98e3e1Schristos 5404e98e3e1Schristos 5414e98e3e1Schristos extern void 5424b169a6bSchristos print_icache_struct (lf *file, const insn_table *isa, cache_entry *cache_rules) 5434e98e3e1Schristos { 5444e98e3e1Schristos /* Create a list of all the different instruction formats with their 5454e98e3e1Schristos corresponding field names. */ 5464e98e3e1Schristos form_fields *formats = insn_table_cache_fields (isa); 5474e98e3e1Schristos 5484e98e3e1Schristos lf_printf (file, "\n"); 5494e98e3e1Schristos lf_printf (file, "#define WITH_%sIDECODE_CACHE_SIZE %d\n", 5504e98e3e1Schristos options.module.global.prefix.u, 5514e98e3e1Schristos (options.gen.icache ? options.gen.icache_size : 0)); 5524e98e3e1Schristos lf_printf (file, "\n"); 5534e98e3e1Schristos 5544e98e3e1Schristos /* create an instruction cache if being used */ 5554e98e3e1Schristos if (options.gen.icache) 5564e98e3e1Schristos { 5574e98e3e1Schristos lf_printf (file, "typedef struct _%sidecode_cache {\n", 5584e98e3e1Schristos options.module.global.prefix.l); 5594e98e3e1Schristos lf_indent (file, +2); 5604e98e3e1Schristos { 5614e98e3e1Schristos form_fields *format; 5624e98e3e1Schristos lf_printf (file, "unsigned_word address;\n"); 5634e98e3e1Schristos lf_printf (file, "void *semantic;\n"); 5644e98e3e1Schristos lf_printf (file, "union {\n"); 5654e98e3e1Schristos lf_indent (file, +2); 5664e98e3e1Schristos for (format = formats; format != NULL; format = format->next) 5674e98e3e1Schristos { 5684e98e3e1Schristos lf_printf (file, "struct {\n"); 5694e98e3e1Schristos lf_indent (file, +2); 5704e98e3e1Schristos { 5714e98e3e1Schristos cache_entry *cache_rule; 5724b169a6bSchristos const char *field; 5734e98e3e1Schristos /* space for any instruction words */ 5744e98e3e1Schristos if (options.gen.insn_in_icache) 5754e98e3e1Schristos lf_printf (file, "instruction_word insn[%d];\n", 5764e98e3e1Schristos isa->max_nr_words); 5774e98e3e1Schristos /* define an entry for any applicable cache rules */ 5784e98e3e1Schristos for (cache_rule = cache_rules; 5794e98e3e1Schristos cache_rule != NULL; cache_rule = cache_rule->next) 5804e98e3e1Schristos { 5814e98e3e1Schristos /* nb - sort of correct - should really check against 5824e98e3e1Schristos individual instructions */ 5834e98e3e1Schristos if (filter_is_subset 5844e98e3e1Schristos (format->fields, cache_rule->original_fields)) 5854e98e3e1Schristos { 5864b169a6bSchristos const char *memb; 5874e98e3e1Schristos lf_printf (file, "%s %s;", 5884e98e3e1Schristos (cache_rule->type == NULL 5894e98e3e1Schristos ? "unsigned" 5904e98e3e1Schristos : cache_rule->type), cache_rule->name); 5914e98e3e1Schristos lf_printf (file, " /*"); 5924e98e3e1Schristos for (memb = 5934e98e3e1Schristos filter_next (cache_rule->original_fields, ""); 5944e98e3e1Schristos memb != NULL; 5954e98e3e1Schristos memb = 5964e98e3e1Schristos filter_next (cache_rule->original_fields, memb)) 5974e98e3e1Schristos { 5984e98e3e1Schristos lf_printf (file, " %s", memb); 5994e98e3e1Schristos } 6004e98e3e1Schristos lf_printf (file, " */\n"); 6014e98e3e1Schristos } 6024e98e3e1Schristos } 6034e98e3e1Schristos /* define an entry for any fields not covered by a cache rule */ 6044e98e3e1Schristos for (field = filter_next (format->fields, ""); 6054e98e3e1Schristos field != NULL; field = filter_next (format->fields, field)) 6064e98e3e1Schristos { 6074e98e3e1Schristos cache_entry *cache_rule; 6084e98e3e1Schristos int found_rule = 0; 6094e98e3e1Schristos for (cache_rule = cache_rules; 6104e98e3e1Schristos cache_rule != NULL; cache_rule = cache_rule->next) 6114e98e3e1Schristos { 6124e98e3e1Schristos if (strcmp (cache_rule->name, field) == 0) 6134e98e3e1Schristos { 6144e98e3e1Schristos found_rule = 1; 6154e98e3e1Schristos break; 6164e98e3e1Schristos } 6174e98e3e1Schristos } 6184e98e3e1Schristos if (!found_rule) 6194e98e3e1Schristos lf_printf (file, "unsigned %s; /* default */\n", field); 6204e98e3e1Schristos } 6214e98e3e1Schristos } 6224e98e3e1Schristos lf_indent (file, -2); 6234e98e3e1Schristos lf_printf (file, "} %s;\n", format->name); 6244e98e3e1Schristos } 6254e98e3e1Schristos lf_indent (file, -2); 6264e98e3e1Schristos lf_printf (file, "} crack;\n"); 6274e98e3e1Schristos } 6284e98e3e1Schristos lf_indent (file, -2); 6294e98e3e1Schristos lf_printf (file, "} %sidecode_cache;\n", 6304e98e3e1Schristos options.module.global.prefix.l); 6314e98e3e1Schristos } 6324e98e3e1Schristos else 6334e98e3e1Schristos { 6344e98e3e1Schristos /* alernativly, since no cache, emit a dummy definition for 6354e98e3e1Schristos idecode_cache so that code refering to the type can still compile */ 6364e98e3e1Schristos lf_printf (file, "typedef void %sidecode_cache;\n", 6374e98e3e1Schristos options.module.global.prefix.l); 6384e98e3e1Schristos } 6394e98e3e1Schristos lf_printf (file, "\n"); 6404e98e3e1Schristos } 6414e98e3e1Schristos 6424e98e3e1Schristos 6434e98e3e1Schristos 6444e98e3e1Schristos static void 6454e98e3e1Schristos print_icache_function (lf *file, 6464b169a6bSchristos const insn_entry *instruction, 6474b169a6bSchristos const opcode_bits *expanded_bits, 6484b169a6bSchristos const insn_opcodes *opcodes, 6494e98e3e1Schristos cache_entry *cache_rules, int nr_prefetched_words) 6504e98e3e1Schristos { 6514e98e3e1Schristos int indent; 6524e98e3e1Schristos 6534e98e3e1Schristos /* generate code to enter decoded instruction into the icache */ 6544e98e3e1Schristos lf_printf (file, "\n"); 6554e98e3e1Schristos lf_print__function_type_function (file, print_icache_function_type, 6564e98e3e1Schristos "EXTERN_ICACHE", "\n"); 6574e98e3e1Schristos indent = print_function_name (file, 6584e98e3e1Schristos instruction->name, 6594e98e3e1Schristos instruction->format_name, 6604e98e3e1Schristos NULL, 6614e98e3e1Schristos expanded_bits, function_name_prefix_icache); 6624e98e3e1Schristos indent += lf_printf (file, " "); 6634e98e3e1Schristos lf_indent (file, +indent); 6644e98e3e1Schristos lf_printf (file, "("); 6654e98e3e1Schristos print_icache_function_formal (file, nr_prefetched_words); 6664e98e3e1Schristos lf_printf (file, ")\n"); 6674e98e3e1Schristos lf_indent (file, -indent); 6684e98e3e1Schristos 6694e98e3e1Schristos /* function header */ 6704e98e3e1Schristos lf_printf (file, "{\n"); 6714e98e3e1Schristos lf_indent (file, +2); 6724e98e3e1Schristos 6734e98e3e1Schristos print_my_defines (file, 6744e98e3e1Schristos instruction->name, 6754e98e3e1Schristos instruction->format_name, expanded_bits); 6764e98e3e1Schristos print_itrace (file, instruction, 1 /*putting-value-in-cache */ ); 6774e98e3e1Schristos 6784e98e3e1Schristos print_idecode_validate (file, instruction, opcodes); 6794e98e3e1Schristos 6804e98e3e1Schristos lf_printf (file, "\n"); 6814e98e3e1Schristos lf_printf (file, "{\n"); 6824e98e3e1Schristos lf_indent (file, +2); 6834e98e3e1Schristos if (options.gen.semantic_icache) 6844e98e3e1Schristos lf_printf (file, "unsigned_word nia;\n"); 6854e98e3e1Schristos print_icache_body (file, 6864e98e3e1Schristos instruction, 6874e98e3e1Schristos expanded_bits, 6884e98e3e1Schristos cache_rules, 6894e98e3e1Schristos (options.gen.direct_access 6904e98e3e1Schristos ? define_variables 6914e98e3e1Schristos : declare_variables), 6924e98e3e1Schristos (options.gen.semantic_icache 6934e98e3e1Schristos ? both_values_and_icache 6944e98e3e1Schristos : put_values_in_icache), nr_prefetched_words); 6954e98e3e1Schristos 6964e98e3e1Schristos lf_printf (file, "\n"); 6974e98e3e1Schristos lf_printf (file, "cache_entry->address = cia;\n"); 6984e98e3e1Schristos lf_printf (file, "cache_entry->semantic = "); 6994e98e3e1Schristos print_function_name (file, 7004e98e3e1Schristos instruction->name, 7014e98e3e1Schristos instruction->format_name, 7024e98e3e1Schristos NULL, expanded_bits, function_name_prefix_semantics); 7034e98e3e1Schristos lf_printf (file, ";\n"); 7044e98e3e1Schristos lf_printf (file, "\n"); 7054e98e3e1Schristos 7064e98e3e1Schristos if (options.gen.semantic_icache) 7074e98e3e1Schristos { 7084e98e3e1Schristos lf_printf (file, "/* semantic routine */\n"); 7094e98e3e1Schristos print_semantic_body (file, instruction, expanded_bits, opcodes); 7104e98e3e1Schristos lf_printf (file, "return nia;\n"); 7114e98e3e1Schristos } 7124e98e3e1Schristos 7134e98e3e1Schristos if (!options.gen.semantic_icache) 7144e98e3e1Schristos { 7154e98e3e1Schristos lf_printf (file, "/* return the function proper */\n"); 7164e98e3e1Schristos lf_printf (file, "return "); 7174e98e3e1Schristos print_function_name (file, 7184e98e3e1Schristos instruction->name, 7194e98e3e1Schristos instruction->format_name, 7204e98e3e1Schristos NULL, 7214e98e3e1Schristos expanded_bits, function_name_prefix_semantics); 7224e98e3e1Schristos lf_printf (file, ";\n"); 7234e98e3e1Schristos } 7244e98e3e1Schristos 7254e98e3e1Schristos if (options.gen.direct_access) 7264e98e3e1Schristos { 7274e98e3e1Schristos print_icache_body (file, 7284e98e3e1Schristos instruction, 7294e98e3e1Schristos expanded_bits, 7304e98e3e1Schristos cache_rules, 7314e98e3e1Schristos undef_variables, 7324e98e3e1Schristos (options.gen.semantic_icache 7334e98e3e1Schristos ? both_values_and_icache 7344e98e3e1Schristos : put_values_in_icache), nr_prefetched_words); 7354e98e3e1Schristos } 7364e98e3e1Schristos 7374e98e3e1Schristos lf_indent (file, -2); 7384e98e3e1Schristos lf_printf (file, "}\n"); 7394e98e3e1Schristos lf_indent (file, -2); 7404e98e3e1Schristos lf_printf (file, "}\n"); 7414e98e3e1Schristos } 7424e98e3e1Schristos 7434e98e3e1Schristos 7444e98e3e1Schristos void 7454e98e3e1Schristos print_icache_definition (lf *file, 7464b169a6bSchristos const insn_entry *insn, 7474b169a6bSchristos const opcode_bits *expanded_bits, 7484b169a6bSchristos const insn_opcodes *opcodes, 7494e98e3e1Schristos cache_entry *cache_rules, int nr_prefetched_words) 7504e98e3e1Schristos { 7514e98e3e1Schristos print_icache_function (file, 7524e98e3e1Schristos insn, 7534e98e3e1Schristos expanded_bits, 7544e98e3e1Schristos opcodes, cache_rules, nr_prefetched_words); 7554e98e3e1Schristos } 7564e98e3e1Schristos 7574e98e3e1Schristos 7584e98e3e1Schristos 7594e98e3e1Schristos void 7604e98e3e1Schristos print_icache_internal_function_declaration (lf *file, 7614b169a6bSchristos const function_entry *function, 7624e98e3e1Schristos void *data) 7634e98e3e1Schristos { 7644e98e3e1Schristos ASSERT (options.gen.icache); 7654e98e3e1Schristos if (function->is_internal) 7664e98e3e1Schristos { 7674e98e3e1Schristos lf_printf (file, "\n"); 7684e98e3e1Schristos lf_print__function_type_function (file, print_icache_function_type, 7694e98e3e1Schristos "INLINE_ICACHE", "\n"); 7704e98e3e1Schristos print_function_name (file, 7714e98e3e1Schristos function->name, 7724e98e3e1Schristos NULL, NULL, NULL, function_name_prefix_icache); 7734e98e3e1Schristos lf_printf (file, "\n("); 7744e98e3e1Schristos print_icache_function_formal (file, 0); 7754e98e3e1Schristos lf_printf (file, ");\n"); 7764e98e3e1Schristos } 7774e98e3e1Schristos } 7784e98e3e1Schristos 7794e98e3e1Schristos 7804e98e3e1Schristos void 7814e98e3e1Schristos print_icache_internal_function_definition (lf *file, 7824b169a6bSchristos const function_entry *function, 7834e98e3e1Schristos void *data) 7844e98e3e1Schristos { 7854e98e3e1Schristos ASSERT (options.gen.icache); 7864e98e3e1Schristos if (function->is_internal) 7874e98e3e1Schristos { 7884e98e3e1Schristos lf_printf (file, "\n"); 7894e98e3e1Schristos lf_print__function_type_function (file, print_icache_function_type, 7904e98e3e1Schristos "INLINE_ICACHE", "\n"); 7914e98e3e1Schristos print_function_name (file, 7924e98e3e1Schristos function->name, 7934e98e3e1Schristos NULL, NULL, NULL, function_name_prefix_icache); 7944e98e3e1Schristos lf_printf (file, "\n("); 7954e98e3e1Schristos print_icache_function_formal (file, 0); 7964e98e3e1Schristos lf_printf (file, ")\n"); 7974e98e3e1Schristos lf_printf (file, "{\n"); 7984e98e3e1Schristos lf_indent (file, +2); 7994e98e3e1Schristos lf_printf (file, "/* semantic routine */\n"); 8004e98e3e1Schristos if (options.gen.semantic_icache) 8014e98e3e1Schristos { 8024e98e3e1Schristos lf_print__line_ref (file, function->code->line); 8034e98e3e1Schristos table_print_code (file, function->code); 8044e98e3e1Schristos lf_printf (file, 8054e98e3e1Schristos "error (\"Internal function must longjump\\n\");\n"); 8064e98e3e1Schristos lf_printf (file, "return 0;\n"); 8074e98e3e1Schristos } 8084e98e3e1Schristos else 8094e98e3e1Schristos { 8104e98e3e1Schristos lf_printf (file, "return "); 8114e98e3e1Schristos print_function_name (file, 8124e98e3e1Schristos function->name, 8134e98e3e1Schristos NULL, 8144e98e3e1Schristos NULL, NULL, function_name_prefix_semantics); 8154e98e3e1Schristos lf_printf (file, ";\n"); 8164e98e3e1Schristos } 8174e98e3e1Schristos 8184e98e3e1Schristos lf_print__internal_ref (file); 8194e98e3e1Schristos lf_indent (file, -2); 8204e98e3e1Schristos lf_printf (file, "}\n"); 8214e98e3e1Schristos } 8224e98e3e1Schristos } 823