xref: /netbsd-src/external/gpl3/gdb/dist/sim/igen/gen-semantics.c (revision 71f621822dbfd5073a314948bec169b7bb05f7be)
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 
224e98e3e1Schristos 
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-icache.h"
374e98e3e1Schristos #include "gen-idecode.h"
384e98e3e1Schristos 
394e98e3e1Schristos 
404e98e3e1Schristos static void
414e98e3e1Schristos print_semantic_function_header (lf *file,
424e98e3e1Schristos 				const char *basename,
434e98e3e1Schristos 				const char *format_name,
444b169a6bSchristos 				const opcode_bits *expanded_bits,
454e98e3e1Schristos 				int is_function_definition,
464e98e3e1Schristos 				int nr_prefetched_words)
474e98e3e1Schristos {
484e98e3e1Schristos   int indent;
494e98e3e1Schristos   lf_printf (file, "\n");
504e98e3e1Schristos   lf_print__function_type_function (file, print_semantic_function_type,
514e98e3e1Schristos 				    "EXTERN_SEMANTICS",
524e98e3e1Schristos 				    (is_function_definition ? "\n" : " "));
534e98e3e1Schristos   indent = print_function_name (file,
544e98e3e1Schristos 				basename,
554e98e3e1Schristos 				format_name,
564e98e3e1Schristos 				NULL,
574e98e3e1Schristos 				expanded_bits,
584e98e3e1Schristos 				function_name_prefix_semantics);
594e98e3e1Schristos   if (is_function_definition)
604e98e3e1Schristos     {
614e98e3e1Schristos       indent += lf_printf (file, " ");
624e98e3e1Schristos       lf_indent (file, +indent);
634e98e3e1Schristos     }
644e98e3e1Schristos   else
654e98e3e1Schristos     {
664e98e3e1Schristos       lf_printf (file, "\n");
674e98e3e1Schristos     }
684e98e3e1Schristos   lf_printf (file, "(");
694e98e3e1Schristos   lf_indent (file, +1);
704e98e3e1Schristos   print_semantic_function_formal (file, nr_prefetched_words);
714e98e3e1Schristos   lf_indent (file, -1);
724e98e3e1Schristos   lf_printf (file, ")");
734e98e3e1Schristos   if (is_function_definition)
744e98e3e1Schristos     {
754e98e3e1Schristos       lf_indent (file, -indent);
764e98e3e1Schristos     }
774e98e3e1Schristos   else
784e98e3e1Schristos     {
794e98e3e1Schristos       lf_printf (file, ";");
804e98e3e1Schristos     }
814e98e3e1Schristos   lf_printf (file, "\n");
824e98e3e1Schristos }
834e98e3e1Schristos 
844e98e3e1Schristos void
854e98e3e1Schristos print_semantic_declaration (lf *file,
864b169a6bSchristos 			    const insn_entry *insn,
874b169a6bSchristos 			    const opcode_bits *expanded_bits,
884b169a6bSchristos 			    const insn_opcodes *opcodes,
894b169a6bSchristos 			    int nr_prefetched_words)
904e98e3e1Schristos {
914e98e3e1Schristos   print_semantic_function_header (file,
924e98e3e1Schristos 				  insn->name,
934e98e3e1Schristos 				  insn->format_name,
944e98e3e1Schristos 				  expanded_bits,
954e98e3e1Schristos 				  0 /* is not function definition */ ,
964e98e3e1Schristos 				  nr_prefetched_words);
974e98e3e1Schristos }
984e98e3e1Schristos 
994e98e3e1Schristos 
1004e98e3e1Schristos 
1014e98e3e1Schristos /* generate the semantics.c file */
1024e98e3e1Schristos 
1034e98e3e1Schristos 
1044e98e3e1Schristos void
1054e98e3e1Schristos print_idecode_invalid (lf *file, const char *result, invalid_type type)
1064e98e3e1Schristos {
1074e98e3e1Schristos   const char *name;
1084e98e3e1Schristos   switch (type)
1094e98e3e1Schristos     {
1104e98e3e1Schristos     default:
1114e98e3e1Schristos       name = "unknown";
1124e98e3e1Schristos       break;
1134e98e3e1Schristos     case invalid_illegal:
1144e98e3e1Schristos       name = "illegal";
1154e98e3e1Schristos       break;
1164e98e3e1Schristos     case invalid_fp_unavailable:
1174e98e3e1Schristos       name = "fp_unavailable";
1184e98e3e1Schristos       break;
1194e98e3e1Schristos     case invalid_wrong_slot:
1204e98e3e1Schristos       name = "wrong_slot";
1214e98e3e1Schristos       break;
1224e98e3e1Schristos     }
1234e98e3e1Schristos   if (options.gen.code == generate_jumps)
1244e98e3e1Schristos     {
1254e98e3e1Schristos       lf_printf (file, "goto %s_%s;\n",
1264e98e3e1Schristos 		 (options.gen.icache ? "icache" : "semantic"), name);
1274e98e3e1Schristos     }
1284e98e3e1Schristos   else if (options.gen.icache)
1294e98e3e1Schristos     {
1304e98e3e1Schristos       lf_printf (file, "%s %sicache_%s (", result,
1314e98e3e1Schristos 		 options.module.global.prefix.l, name);
1324e98e3e1Schristos       print_icache_function_actual (file, 0);
1334e98e3e1Schristos       lf_printf (file, ");\n");
1344e98e3e1Schristos     }
1354e98e3e1Schristos   else
1364e98e3e1Schristos     {
1374e98e3e1Schristos       lf_printf (file, "%s %ssemantic_%s (", result,
1384e98e3e1Schristos 		 options.module.global.prefix.l, name);
1394e98e3e1Schristos       print_semantic_function_actual (file, 0);
1404e98e3e1Schristos       lf_printf (file, ");\n");
1414e98e3e1Schristos     }
1424e98e3e1Schristos }
1434e98e3e1Schristos 
1444e98e3e1Schristos 
1454e98e3e1Schristos void
1464e98e3e1Schristos print_semantic_body (lf *file,
1474b169a6bSchristos 		     const insn_entry *instruction,
1484b169a6bSchristos 		     const opcode_bits *expanded_bits,
1494b169a6bSchristos 		     const insn_opcodes *opcodes)
1504e98e3e1Schristos {
1514e98e3e1Schristos   /* validate the instruction, if a cache this has already been done */
1524e98e3e1Schristos   if (!options.gen.icache)
1534e98e3e1Schristos     {
1544e98e3e1Schristos       print_idecode_validate (file, instruction, opcodes);
1554e98e3e1Schristos     }
1564e98e3e1Schristos 
1574e98e3e1Schristos   print_itrace (file, instruction, 0 /*put_value_in_cache */ );
1584e98e3e1Schristos 
1594e98e3e1Schristos   /* generate the instruction profile call - this is delayed until
1604e98e3e1Schristos      after the instruction has been verified.  The count macro
1614e98e3e1Schristos      generated is prefixed by ITABLE_PREFIX */
1624e98e3e1Schristos   {
1634e98e3e1Schristos     lf_printf (file, "\n");
1644e98e3e1Schristos     lf_indent_suppress (file);
1654e98e3e1Schristos     lf_printf (file, "#if defined (%sPROFILE_COUNT_INSN)\n",
1664e98e3e1Schristos 	       options.module.itable.prefix.u);
1674e98e3e1Schristos     lf_printf (file, "%sPROFILE_COUNT_INSN (CPU, CIA, MY_INDEX);\n",
1684e98e3e1Schristos 	       options.module.itable.prefix.u);
1694e98e3e1Schristos     lf_indent_suppress (file);
1704e98e3e1Schristos     lf_printf (file, "#endif\n");
1714e98e3e1Schristos   }
1724e98e3e1Schristos 
1734e98e3e1Schristos   /* generate the model call - this is delayed until after the
1744e98e3e1Schristos      instruction has been verified */
1754e98e3e1Schristos   {
1764e98e3e1Schristos     lf_printf (file, "\n");
1774e98e3e1Schristos     lf_indent_suppress (file);
1784e98e3e1Schristos     lf_printf (file, "#if defined (WITH_MON)\n");
1794e98e3e1Schristos     lf_printf (file, "/* monitoring: */\n");
1804e98e3e1Schristos     lf_printf (file, "if (WITH_MON & MONITOR_INSTRUCTION_ISSUE)\n");
1814e98e3e1Schristos     lf_printf (file, "  mon_issue (");
1824e98e3e1Schristos     print_function_name (file,
1834e98e3e1Schristos 			 instruction->name,
1844e98e3e1Schristos 			 instruction->format_name,
1854e98e3e1Schristos 			 NULL, NULL, function_name_prefix_itable);
1864e98e3e1Schristos     lf_printf (file, ", cpu, cia);\n");
1874e98e3e1Schristos     lf_indent_suppress (file);
1884e98e3e1Schristos     lf_printf (file, "#endif\n");
1894e98e3e1Schristos     lf_printf (file, "\n");
1904e98e3e1Schristos   }
1914e98e3e1Schristos 
1924e98e3e1Schristos   /* determine the new instruction address */
1934e98e3e1Schristos   {
1944e98e3e1Schristos     lf_printf (file, "/* keep the next instruction address handy */\n");
1954e98e3e1Schristos     if (options.gen.nia == nia_is_invalid)
1964e98e3e1Schristos       {
1974e98e3e1Schristos 	lf_printf (file, "nia = %sINVALID_INSTRUCTION_ADDRESS;\n",
1984e98e3e1Schristos 		   options.module.global.prefix.u);
1994e98e3e1Schristos       }
2004e98e3e1Schristos     else
2014e98e3e1Schristos       {
2024e98e3e1Schristos 	int nr_immeds = instruction->nr_words - 1;
2034e98e3e1Schristos 	if (options.gen.delayed_branch)
2044e98e3e1Schristos 	  {
2054e98e3e1Schristos 	    if (nr_immeds > 0)
2064e98e3e1Schristos 	      {
2074e98e3e1Schristos 		lf_printf (file, "cia.dp += %d * %d; %s\n",
2084e98e3e1Schristos 			   options.insn_bit_size / 8, nr_immeds,
2094e98e3e1Schristos 			   "/* skip dp immeds */");
2104e98e3e1Schristos 	      }
2114e98e3e1Schristos 	    lf_printf (file, "nia.ip = cia.dp; %s\n",
2124e98e3e1Schristos 		       "/* instruction pointer */");
2134e98e3e1Schristos 	    lf_printf (file, "nia.dp = cia.dp + %d; %s\n",
2144e98e3e1Schristos 		       options.insn_bit_size / 8,
2154e98e3e1Schristos 		       "/* delayed-slot pointer */");
2164e98e3e1Schristos 	  }
2174e98e3e1Schristos 	else
2184e98e3e1Schristos 	  {
2194e98e3e1Schristos 	    if (nr_immeds > 0)
2204e98e3e1Schristos 	      {
2214e98e3e1Schristos 		lf_printf (file, "nia = cia + %d * (%d + 1); %s\n",
2224e98e3e1Schristos 			   options.insn_bit_size / 8, nr_immeds,
2234e98e3e1Schristos 			   "/* skip immeds as well */");
2244e98e3e1Schristos 
2254e98e3e1Schristos 	      }
2264e98e3e1Schristos 	    else
2274e98e3e1Schristos 	      {
2284e98e3e1Schristos 		lf_printf (file, "nia = cia + %d;\n",
2294e98e3e1Schristos 			   options.insn_bit_size / 8);
2304e98e3e1Schristos 	      }
2314e98e3e1Schristos 	  }
2324e98e3e1Schristos       }
2334e98e3e1Schristos   }
2344e98e3e1Schristos 
2354e98e3e1Schristos   /* if conditional, generate code to verify that the instruction
2364e98e3e1Schristos      should be issued */
2374e98e3e1Schristos   if (filter_is_member (instruction->options, "c")
2384e98e3e1Schristos       || options.gen.conditional_issue)
2394e98e3e1Schristos     {
2404e98e3e1Schristos       lf_printf (file, "\n");
2414e98e3e1Schristos       lf_printf (file, "/* execute only if conditional passes */\n");
2424e98e3e1Schristos       lf_printf (file, "if (IS_CONDITION_OK)\n");
2434e98e3e1Schristos       lf_printf (file, "  {\n");
2444e98e3e1Schristos       lf_indent (file, +4);
2454e98e3e1Schristos       /* FIXME - need to log a conditional failure */
2464e98e3e1Schristos     }
2474e98e3e1Schristos 
2484e98e3e1Schristos   /* Architecture expects a REG to be zero.  Instead of having to
2494e98e3e1Schristos      check every read to see if it is refering to that REG just zap it
2504e98e3e1Schristos      at the start of every instruction */
2514e98e3e1Schristos   if (options.gen.zero_reg)
2524e98e3e1Schristos     {
2534e98e3e1Schristos       lf_printf (file, "\n");
2544e98e3e1Schristos       lf_printf (file, "/* Architecture expects REG to be zero */\n");
2554e98e3e1Schristos       lf_printf (file, "GPR_CLEAR(%d);\n", options.gen.zero_reg_nr);
2564e98e3e1Schristos     }
2574e98e3e1Schristos 
2584e98e3e1Schristos   /* generate the code (or at least something */
2594e98e3e1Schristos   lf_printf (file, "\n");
2604e98e3e1Schristos   lf_printf (file, "/* semantics: */\n");
2614e98e3e1Schristos   if (instruction->code != NULL)
2624e98e3e1Schristos     {
2634e98e3e1Schristos       /* true code */
2644e98e3e1Schristos       lf_printf (file, "{\n");
265*71f62182Schristos       /* NB: Do not indent the code.  If the .igen source files cause a compiler
266*71f62182Schristos 	 warning, the diagnostics can read the line from the original source,
267*71f62182Schristos 	 but use column offsets from the generated files, causing columns to be
268*71f62182Schristos 	 misaligned.  It makes the generated code slightly more difficult to
269*71f62182Schristos 	 read, but accurate compiler diagnostics relative to the original source
270*71f62182Schristos 	 are more important here.
271*71f62182Schristos       lf_indent (file, +2); */
2724e98e3e1Schristos       lf_print__line_ref (file, instruction->code->line);
2734e98e3e1Schristos       table_print_code (file, instruction->code);
274*71f62182Schristos       /* NB: Disabled -- see above.
275*71f62182Schristos       lf_indent (file, -2); */
2764e98e3e1Schristos       lf_printf (file, "}\n");
2774e98e3e1Schristos       lf_print__internal_ref (file);
2784e98e3e1Schristos     }
2794e98e3e1Schristos   else if (filter_is_member (instruction->options, "nop"))
2804e98e3e1Schristos     {
2814e98e3e1Schristos       lf_print__internal_ref (file);
2824e98e3e1Schristos     }
2834e98e3e1Schristos   else
2844e98e3e1Schristos     {
2854e98e3e1Schristos       const char *prefix = "sim_engine_abort (";
2864e98e3e1Schristos       int indent = strlen (prefix);
2874e98e3e1Schristos       /* abort so it is implemented now */
2884e98e3e1Schristos       lf_print__line_ref (file, instruction->line);
2894e98e3e1Schristos       lf_printf (file, "%sSD, CPU, cia, \\\n", prefix);
2904e98e3e1Schristos       lf_indent (file, +indent);
2914e98e3e1Schristos       lf_printf (file, "\"%s:%d:0x%%08lx:%%s unimplemented\\n\", \\\n",
2924e98e3e1Schristos 		 filter_filename (instruction->line->file_name),
2934e98e3e1Schristos 		 instruction->line->line_nr);
2944e98e3e1Schristos       lf_printf (file, "(long) CIA, \\\n");
2954e98e3e1Schristos       lf_printf (file, "%sitable[MY_INDEX].name);\n",
2964e98e3e1Schristos 		 options.module.itable.prefix.l);
2974e98e3e1Schristos       lf_indent (file, -indent);
2984e98e3e1Schristos       lf_print__internal_ref (file);
2994e98e3e1Schristos     }
3004e98e3e1Schristos 
3014e98e3e1Schristos   /* Close off the conditional execution */
3024e98e3e1Schristos   if (filter_is_member (instruction->options, "c")
3034e98e3e1Schristos       || options.gen.conditional_issue)
3044e98e3e1Schristos     {
3054e98e3e1Schristos       lf_indent (file, -4);
3064e98e3e1Schristos       lf_printf (file, "  }\n");
3074e98e3e1Schristos     }
3084e98e3e1Schristos }
3094e98e3e1Schristos 
3104e98e3e1Schristos static void
3114e98e3e1Schristos print_c_semantic (lf *file,
3124b169a6bSchristos 		  const insn_entry *instruction,
3134b169a6bSchristos 		  const opcode_bits *expanded_bits,
3144b169a6bSchristos 		  const insn_opcodes *opcodes,
3154b169a6bSchristos 		  cache_entry *cache_rules,
3164b169a6bSchristos 		  int nr_prefetched_words)
3174e98e3e1Schristos {
3184e98e3e1Schristos 
3194e98e3e1Schristos   lf_printf (file, "{\n");
3204e98e3e1Schristos   lf_indent (file, +2);
3214e98e3e1Schristos 
3224e98e3e1Schristos   print_my_defines (file,
3234e98e3e1Schristos 		    instruction->name,
3244e98e3e1Schristos 		    instruction->format_name, expanded_bits);
3254e98e3e1Schristos   lf_printf (file, "\n");
3264e98e3e1Schristos   print_icache_body (file,
3274e98e3e1Schristos 		     instruction,
3284e98e3e1Schristos 		     expanded_bits,
3294e98e3e1Schristos 		     cache_rules,
3304e98e3e1Schristos 		     (options.gen.direct_access
3314e98e3e1Schristos 		      ? define_variables
3324e98e3e1Schristos 		      : declare_variables),
3334e98e3e1Schristos 		     (options.gen.icache
3344e98e3e1Schristos 		      ? get_values_from_icache
3354e98e3e1Schristos 		      : do_not_use_icache), nr_prefetched_words);
3364e98e3e1Schristos 
3374e98e3e1Schristos   lf_printf (file, "%sinstruction_address nia;\n",
3384e98e3e1Schristos 	     options.module.global.prefix.l);
3394e98e3e1Schristos   print_semantic_body (file, instruction, expanded_bits, opcodes);
3404e98e3e1Schristos   lf_printf (file, "return nia;\n");
3414e98e3e1Schristos 
3424e98e3e1Schristos   /* generate something to clean up any #defines created for the cache */
3434e98e3e1Schristos   if (options.gen.direct_access)
3444e98e3e1Schristos     {
3454e98e3e1Schristos       print_icache_body (file,
3464e98e3e1Schristos 			 instruction,
3474e98e3e1Schristos 			 expanded_bits,
3484e98e3e1Schristos 			 cache_rules,
3494e98e3e1Schristos 			 undef_variables,
3504e98e3e1Schristos 			 (options.gen.icache
3514e98e3e1Schristos 			  ? get_values_from_icache
3524e98e3e1Schristos 			  : do_not_use_icache), nr_prefetched_words);
3534e98e3e1Schristos     }
3544e98e3e1Schristos 
3554e98e3e1Schristos   lf_indent (file, -2);
3564e98e3e1Schristos   lf_printf (file, "}\n");
3574e98e3e1Schristos }
3584e98e3e1Schristos 
3594e98e3e1Schristos static void
3604e98e3e1Schristos print_c_semantic_function (lf *file,
3614b169a6bSchristos 			   const insn_entry *instruction,
3624b169a6bSchristos 			   const opcode_bits *expanded_bits,
3634b169a6bSchristos 			   const insn_opcodes *opcodes,
3644b169a6bSchristos 			   cache_entry *cache_rules,
3654b169a6bSchristos 			   int nr_prefetched_words)
3664e98e3e1Schristos {
3674e98e3e1Schristos   /* build the semantic routine to execute the instruction */
3684e98e3e1Schristos   print_semantic_function_header (file,
3694e98e3e1Schristos 				  instruction->name,
3704e98e3e1Schristos 				  instruction->format_name,
3714e98e3e1Schristos 				  expanded_bits,
3724e98e3e1Schristos 				  1 /*is-function-definition */ ,
3734e98e3e1Schristos 				  nr_prefetched_words);
3744e98e3e1Schristos   print_c_semantic (file,
3754e98e3e1Schristos 		    instruction,
3764e98e3e1Schristos 		    expanded_bits, opcodes, cache_rules, nr_prefetched_words);
3774e98e3e1Schristos }
3784e98e3e1Schristos 
3794e98e3e1Schristos void
3804e98e3e1Schristos print_semantic_definition (lf *file,
3814b169a6bSchristos 			   const insn_entry *insn,
3824b169a6bSchristos 			   const opcode_bits *expanded_bits,
3834b169a6bSchristos 			   const insn_opcodes *opcodes,
3844b169a6bSchristos 			   cache_entry *cache_rules,
3854b169a6bSchristos 			   int nr_prefetched_words)
3864e98e3e1Schristos {
3874e98e3e1Schristos   print_c_semantic_function (file,
3884e98e3e1Schristos 			     insn,
3894e98e3e1Schristos 			     expanded_bits,
3904e98e3e1Schristos 			     opcodes, cache_rules, nr_prefetched_words);
3914e98e3e1Schristos }
392