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
print_engine_issue_prefix_hook(lf * file)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
print_engine_issue_postfix_hook(lf * file)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
print_run_body(lf * file,const gen_entry * table)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
print_engine_run_function_header(lf * file,const char * processor,function_decl_type decl_type)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
gen_engine_h(lf * file,const gen_table * gen,const insn_table * isa,cache_entry * cache_rules)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
gen_engine_c(lf * file,const gen_table * gen,const insn_table * isa,cache_entry * cache_rules)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