xref: /netbsd-src/external/gpl3/gdb/dist/sim/igen/gen-engine.c (revision 71f621822dbfd5073a314948bec169b7bb05f7be)
1 /* The IGEN simulator generator for GDB, the GNU Debugger.
2 
3    Copyright 2002-2024 Free Software Foundation, Inc.
4 
5    Contributed by Andrew Cagney.
6 
7    This file is part of GDB.
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21 
22 #include "misc.h"
23 #include "lf.h"
24 #include "table.h"
25 #include "filter.h"
26 
27 #include "igen.h"
28 
29 #include "ld-insn.h"
30 #include "ld-decode.h"
31 
32 #include "gen.h"
33 
34 #include "gen-idecode.h"
35 #include "gen-engine.h"
36 #include "gen-icache.h"
37 #include "gen-semantics.h"
38 
39 
40 static void
41 print_engine_issue_prefix_hook (lf *file)
42 {
43   lf_printf (file, "\n");
44   lf_indent_suppress (file);
45   lf_printf (file, "#if defined (ENGINE_ISSUE_PREFIX_HOOK)\n");
46   lf_printf (file, "ENGINE_ISSUE_PREFIX_HOOK();\n");
47   lf_indent_suppress (file);
48   lf_printf (file, "#endif\n");
49   lf_printf (file, "\n");
50 }
51 
52 static void
53 print_engine_issue_postfix_hook (lf *file)
54 {
55   lf_printf (file, "\n");
56   lf_indent_suppress (file);
57   lf_printf (file, "#if defined (ENGINE_ISSUE_POSTFIX_HOOK)\n");
58   lf_printf (file, "ENGINE_ISSUE_POSTFIX_HOOK();\n");
59   lf_indent_suppress (file);
60   lf_printf (file, "#endif\n");
61   lf_printf (file, "\n");
62 }
63 
64 
65 static void
66 print_run_body (lf *file, const gen_entry *table)
67 {
68   /* Output the function to execute real code:
69 
70      Unfortunatly, there are multiple cases to consider vis:
71 
72      <icache> X <smp>
73 
74      Consequently this function is written in multiple different ways */
75 
76   lf_printf (file, "{\n");
77   lf_indent (file, +2);
78   if (!options.gen.smp)
79     {
80       lf_printf (file, "%sinstruction_address cia;\n",
81 		 options.module.global.prefix.l);
82     }
83   lf_printf (file, "int current_cpu = next_cpu_nr;\n");
84 
85   if (options.gen.icache)
86     {
87       lf_printf (file, "/* flush the icache of a possible break insn */\n");
88       lf_printf (file, "{\n");
89       lf_printf (file, "  int cpu_nr;\n");
90       lf_printf (file, "  for (cpu_nr = 0; cpu_nr < nr_cpus; cpu_nr++)\n");
91       lf_printf (file, "    cpu_flush_icache (STATE_CPU (sd, cpu_nr));\n");
92       lf_printf (file, "}\n");
93     }
94 
95   if (!options.gen.smp)
96     {
97 
98       lf_putstr (file, "\
99 /* CASE 1: NO SMP (with or with out instruction cache).\n\
100 \n\
101 In this case, we can take advantage of the fact that the current\n\
102 instruction address (CIA) does not need to be read from / written to\n\
103 the CPU object after the execution of an instruction.\n\
104 \n\
105 Instead, CIA is only saved when the main loop exits.  This occures\n\
106 when either sim_engine_halt or sim_engine_restart is called.  Both of\n\
107 these functions save the current instruction address before halting /\n\
108 restarting the simulator.\n\
109 \n\
110 As a variation, there may also be support for an instruction cracking\n\
111 cache. */\n\
112 \n\
113 ");
114 
115       lf_putstr (file, "\n");
116       lf_putstr (file, "/* prime the main loop */\n");
117       lf_putstr (file, "SIM_ASSERT (current_cpu == 0);\n");
118       lf_putstr (file, "SIM_ASSERT (nr_cpus == 1);\n");
119       lf_putstr (file, "cia = CPU_PC_GET (CPU);\n");
120 
121       lf_putstr (file, "\n");
122       lf_putstr (file, "while (1)\n");
123       lf_putstr (file, "  {\n");
124       lf_indent (file, +4);
125 
126       lf_printf (file, "%sinstruction_address nia;\n",
127 		 options.module.global.prefix.l);
128 
129       lf_printf (file, "\n");
130       if (!options.gen.icache)
131 	{
132 	  lf_printf (file,
133 		     "%sinstruction_word instruction_0 = IMEM%d (cia);\n",
134 		     options.module.global.prefix.l, options.insn_bit_size);
135 	  print_engine_issue_prefix_hook (file);
136 	  print_idecode_body (file, table, "nia = ");
137 	  print_engine_issue_postfix_hook (file);
138 	}
139       else
140 	{
141 	  lf_putstr (file, "idecode_cache *cache_entry =\n");
142 	  lf_putstr (file, "  cpu_icache_entry (cpu, cia);\n");
143 	  lf_putstr (file, "if (cache_entry->address == cia)\n");
144 	  lf_putstr (file, "  {\n");
145 	  lf_indent (file, -4);
146 	  lf_putstr (file, "/* cache hit */\n");
147 	  lf_putstr (file,
148 		     "idecode_semantic *const semantic = cache_entry->semantic;\n");
149 	  lf_putstr (file, "cia = semantic (cpu, cache_entry, cia);\n");
150 	  /* tail */
151 	  lf_indent (file, -4);
152 	  lf_putstr (file, "  }\n");
153 	  lf_putstr (file, "else\n");
154 	  lf_putstr (file, "  {\n");
155 	  lf_indent (file, +4);
156 	  lf_putstr (file, "/* cache miss */\n");
157 	  if (!options.gen.semantic_icache)
158 	    {
159 	      lf_putstr (file, "idecode_semantic *semantic;\n");
160 	    }
161 	  lf_printf (file, "instruction_word instruction = IMEM%d (cia);\n",
162 		     options.insn_bit_size);
163 	  lf_putstr (file, "if (WITH_MON != 0)\n");
164 	  lf_putstr (file,
165 		     "  mon_event (mon_event_icache_miss, cpu, cia);\n");
166 	  if (options.gen.semantic_icache)
167 	    {
168 	      lf_putstr (file, "{\n");
169 	      lf_indent (file, +2);
170 	      print_engine_issue_prefix_hook (file);
171 	      print_idecode_body (file, table, "nia =");
172 	      print_engine_issue_postfix_hook (file);
173 	      lf_indent (file, -2);
174 	      lf_putstr (file, "}\n");
175 	    }
176 	  else
177 	    {
178 	      print_engine_issue_prefix_hook (file);
179 	      print_idecode_body (file, table, "semantic =");
180 	      lf_putstr (file, "nia = semantic (cpu, cache_entry, cia);\n");
181 	      print_engine_issue_postfix_hook (file);
182 	    }
183 	  lf_indent (file, -4);
184 	  lf_putstr (file, "  }\n");
185 	}
186 
187       /* update the cpu if necessary */
188       switch (options.gen.nia)
189 	{
190 	case nia_is_cia_plus_one:
191 	  lf_printf (file, "\n");
192 	  lf_printf (file, "/* Update the instruction address */\n");
193 	  lf_printf (file, "cia = nia;\n");
194 	  break;
195 	case nia_is_void:
196 	case nia_is_invalid:
197 	  ERROR ("engine gen when NIA complex");
198 	}
199 
200       /* events */
201       lf_putstr (file, "\n");
202       lf_putstr (file, "/* process any events */\n");
203       lf_putstr (file, "if (sim_events_tick (sd))\n");
204       lf_putstr (file, "  {\n");
205       lf_putstr (file, "    CPU_PC_SET (CPU, cia);\n");
206       lf_putstr (file, "    sim_events_process (sd);\n");
207       lf_putstr (file, "    cia = CPU_PC_GET (CPU);\n");
208       lf_putstr (file, "  }\n");
209 
210       lf_indent (file, -4);
211       lf_printf (file, "  }\n");
212     }
213 
214   if (options.gen.smp)
215     {
216 
217       lf_putstr (file, "\
218 /* CASE 2: SMP (With or without ICACHE)\n\
219 \n\
220 The complexity here comes from needing to correctly halt the simulator\n\
221 when it is aborted.  For instance, if cpu0 requests a restart then\n\
222 cpu1 will normally be the next cpu that is run.  Cpu0 being restarted\n\
223 after all the other CPU's and the event queue have been processed */\n\
224 \n\
225 ");
226 
227       lf_putstr (file, "\n");
228       lf_printf (file,
229 		 "/* have ensured that the event queue is NOT next */\n");
230       lf_printf (file, "SIM_ASSERT (current_cpu >= 0);\n");
231       lf_printf (file, "SIM_ASSERT (current_cpu <= nr_cpus - 1);\n");
232       lf_printf (file, "SIM_ASSERT (nr_cpus <= MAX_NR_PROCESSORS);\n");
233 
234       lf_putstr (file, "\n");
235       lf_putstr (file, "while (1)\n");
236       lf_putstr (file, "  {\n");
237       lf_indent (file, +4);
238       lf_putstr (file, "sim_cpu *cpu = STATE_CPU (sd, current_cpu);\n");
239       lf_putstr (file, "instruction_address cia = CPU_PC_GET (cpu);\n");
240       lf_putstr (file, "\n");
241 
242       if (!options.gen.icache)
243 	{
244 	  lf_printf (file, "instruction_word instruction_0 = IMEM%d (cia);\n",
245 		     options.insn_bit_size);
246 	  print_engine_issue_prefix_hook (file);
247 	  print_idecode_body (file, table, "cia =");
248 	  lf_putstr (file, "CPU_PC_SET (cpu, cia);\n");
249 	  print_engine_issue_postfix_hook (file);
250 	}
251 
252       if (options.gen.icache)
253 	{
254 	  lf_putstr (file, "engine_cache *cache_entry =\n");
255 	  lf_putstr (file, "  cpu_icache_entry(processor, cia);\n");
256 	  lf_putstr (file, "\n");
257 	  lf_putstr (file, "if (cache_entry->address == cia) {\n");
258 	  {
259 	    lf_indent (file, +2);
260 	    lf_putstr (file, "\n");
261 	    lf_putstr (file, "/* cache hit */\n");
262 	    lf_putstr (file,
263 		       "engine_semantic *semantic = cache_entry->semantic;\n");
264 	    lf_putstr (file,
265 		       "cia = semantic(processor, cache_entry, cia);\n");
266 	    /* tail */
267 	    lf_putstr (file, "cpu_set_program_counter(processor, cia);\n");
268 	    lf_putstr (file, "\n");
269 	    lf_indent (file, -2);
270 	  }
271 	  lf_putstr (file, "}\n");
272 	  lf_putstr (file, "else {\n");
273 	  {
274 	    lf_indent (file, +2);
275 	    lf_putstr (file, "\n");
276 	    lf_putstr (file, "/* cache miss */\n");
277 	    if (!options.gen.semantic_icache)
278 	      {
279 		lf_putstr (file, "engine_semantic *semantic;\n");
280 	      }
281 	    lf_printf (file, "instruction_word instruction = IMEM%d (cia);\n",
282 		       options.insn_bit_size);
283 	    lf_putstr (file, "if (WITH_MON != 0)\n");
284 	    lf_putstr (file,
285 		       "  mon_event(mon_event_icache_miss, processors[current_cpu], cia);\n");
286 	    if (options.gen.semantic_icache)
287 	      {
288 		lf_putstr (file, "{\n");
289 		lf_indent (file, +2);
290 		print_engine_issue_prefix_hook (file);
291 		print_idecode_body (file, table, "cia =");
292 		print_engine_issue_postfix_hook (file);
293 		lf_indent (file, -2);
294 		lf_putstr (file, "}\n");
295 	      }
296 	    else
297 	      {
298 		print_engine_issue_prefix_hook (file);
299 		print_idecode_body (file, table, "semantic = ");
300 		lf_putstr (file,
301 			   "cia = semantic(processor, cache_entry, cia);\n");
302 		print_engine_issue_postfix_hook (file);
303 	      }
304 	    /* tail */
305 	    lf_putstr (file, "cpu_set_program_counter(processor, cia);\n");
306 	    lf_putstr (file, "\n");
307 	    lf_indent (file, -2);
308 	  }
309 	  lf_putstr (file, "}\n");
310 	}
311 
312       lf_putstr (file, "\n");
313       lf_putstr (file, "current_cpu += 1;\n");
314       lf_putstr (file, "if (current_cpu == nr_cpus)\n");
315       lf_putstr (file, "  {\n");
316       lf_putstr (file, "    if (sim_events_tick (sd))\n");
317       lf_putstr (file, "      {\n");
318       lf_putstr (file, "        sim_events_process (sd);\n");
319       lf_putstr (file, "      }\n");
320       lf_putstr (file, "    current_cpu = 0;\n");
321       lf_putstr (file, "  }\n");
322 
323       /* tail */
324       lf_indent (file, -4);
325       lf_putstr (file, "  }\n");
326     }
327 
328 
329   lf_indent (file, -2);
330   lf_putstr (file, "}\n");
331 }
332 
333 
334 /****************************************************************/
335 
336 void
337 print_engine_run_function_header (lf *file,
338 				  const char *processor,
339 				  function_decl_type decl_type)
340 {
341   int indent;
342   lf_printf (file, "\n");
343   switch (decl_type)
344     {
345     case is_function_declaration:
346       lf_print__function_type (file, "void", "INLINE_ENGINE", "\n");
347       break;
348     case is_function_definition:
349       lf_print__function_type (file, "void", "INLINE_ENGINE", " ");
350       break;
351     case is_function_variable:
352       lf_printf (file, "void (*");
353       break;
354     }
355   indent = print_function_name (file, "run", NULL,	/* format name */
356 				processor, NULL,	/* expanded bits */
357 				function_name_prefix_engine);
358   switch (decl_type)
359     {
360     case is_function_definition:
361       lf_putstr (file, "\n(");
362       indent = 1;
363       break;
364     case is_function_declaration:
365       indent += lf_printf (file, " (");
366       break;
367     case is_function_variable:
368       lf_putstr (file, ")\n(");
369       indent = 1;
370       break;
371     }
372   lf_indent (file, +indent);
373   lf_printf (file, "SIM_DESC sd,\n");
374   lf_printf (file, "int next_cpu_nr,\n");
375   lf_printf (file, "int nr_cpus,\n");
376   lf_printf (file, "int siggnal)");
377   lf_indent (file, -indent);
378   switch (decl_type)
379     {
380     case is_function_definition:
381       lf_putstr (file, "\n");
382       break;
383     case is_function_variable:
384     case is_function_declaration:
385       lf_putstr (file, ";\n");
386       break;
387     }
388 }
389 
390 
391 void
392 gen_engine_h (lf *file,
393 	      const gen_table *gen,
394 	      const insn_table *isa,
395 	      cache_entry *cache_rules)
396 {
397   gen_list *entry;
398   for (entry = gen->tables; entry != NULL; entry = entry->next)
399     {
400       print_engine_run_function_header (file,
401 					(options.gen.multi_sim
402 					 ? entry->model->name
403 					 : NULL), is_function_declaration);
404     }
405 }
406 
407 
408 void
409 gen_engine_c (lf *file,
410 	      const gen_table *gen,
411 	      const insn_table *isa,
412 	      cache_entry *cache_rules)
413 {
414   const gen_list *entry;
415   /* the intro */
416   print_includes (file);
417   print_include_inline (file, options.module.semantics);
418   print_include (file, options.module.engine);
419   lf_printf (file, "\n");
420   lf_printf (file, "#include \"sim-assert.h\"\n");
421   lf_printf (file, "\n");
422   print_idecode_globals (file);
423   lf_printf (file, "\n");
424 
425   for (entry = gen->tables; entry != NULL; entry = entry->next)
426     {
427       switch (options.gen.code)
428 	{
429 	case generate_calls:
430 	  print_idecode_lookups (file, entry->table, cache_rules);
431 
432 	  /* output the main engine routine */
433 	  print_engine_run_function_header (file,
434 					    (options.gen.multi_sim
435 					     ? entry->model->name
436 					     : NULL), is_function_definition);
437 	  print_run_body (file, entry->table);
438 	  break;
439 
440 	case generate_jumps:
441 	  ERROR ("Jumps currently unimplemented");
442 	  break;
443 	}
444     }
445 }
446