xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/cgen-run.c (revision 88241920d21b339bf319c0e979ffda80c49a2936)
1 /* Main simulator loop for CGEN-based simulators.
2    Copyright (C) 1998-2024 Free Software Foundation, Inc.
3    Contributed by Cygnus Solutions.
4 
5 This file is part of GDB, the GNU debugger.
6 
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 /* ??? These are old notes, kept around for now.
21    Collecting profile data and tracing slow us down so we don't do them in
22    "fast mode".
23    There are 6 possibilities on 2 axes:
24    - no-scaching, insn-scaching, basic-block-scaching
25    - run with full features or run fast
26    Supporting all six possibilities in one executable is a bit much but
27    supporting full/fast seems reasonable.
28    If the scache is configured in it is always used.
29    If pbb-scaching is configured in it is always used.
30    ??? Sometimes supporting more than one set of semantic functions will make
31    the simulator too large - this should be configurable.  Blah blah blah.
32    ??? Supporting full/fast can be more modular, blah blah blah.
33    When the framework is more modular, this can be.
34 */
35 
36 /* This must come before any other includes.  */
37 #include "defs.h"
38 
39 #include "sim-main.h"
40 #include "sim-assert.h"
41 #include "sim-signal.h"
42 
43 #ifndef SIM_ENGINE_PREFIX_HOOK
44 #define SIM_ENGINE_PREFIX_HOOK(sd)
45 #endif
46 #ifndef SIM_ENGINE_POSTFIX_HOOK
47 #define SIM_ENGINE_POSTFIX_HOOK(sd)
48 #endif
49 
50 static sim_event_handler has_stepped;
51 static void prime_cpu (SIM_CPU *, int);
52 static void engine_run_1 (SIM_DESC, int, int);
53 static void engine_run_n (SIM_DESC, int, int, int, int);
54 
55 /* If no profiling or tracing has been enabled, run in fast mode.  */
56 static int
57 cgen_get_fast_p (SIM_DESC sd)
58 {
59   int c;
60 
61   for (c = 0; c < MAX_NR_PROCESSORS; ++c)
62     {
63       SIM_CPU *cpu = STATE_CPU (sd, c);
64 
65       if (PROFILE_ANY_P (cpu) || TRACE_ANY_P (cpu))
66 	return 0;
67     }
68 
69   return 1;
70 }
71 
72 /* sim_resume for cgen */
73 
74 void
75 sim_resume (SIM_DESC sd, int step, int siggnal)
76 {
77   sim_engine *engine = STATE_ENGINE (sd);
78   jmp_buf buf;
79   int jmpval;
80   static int fast_p = -1;
81 
82   ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
83 
84   if (fast_p == -1)
85     fast_p = cgen_get_fast_p (sd);
86 
87   /* we only want to be single stepping the simulator once */
88   if (engine->stepper != NULL)
89     {
90       sim_events_deschedule (sd, engine->stepper);
91       engine->stepper = NULL;
92     }
93   if (step)
94     engine->stepper = sim_events_schedule (sd, 1, has_stepped, sd);
95 
96   sim_module_resume (sd);
97 
98 #if WITH_SCACHE
99   if (USING_SCACHE_P (sd))
100     scache_flush (sd);
101 #endif
102 
103   /* run/resume the simulator */
104 
105   sim_engine_set_run_state (sd, sim_running, 0);
106 
107   engine->jmpbuf = &buf;
108   jmpval = setjmp (buf);
109   if (jmpval == sim_engine_start_jmpval
110       || jmpval == sim_engine_restart_jmpval)
111     {
112       int last_cpu_nr = sim_engine_last_cpu_nr (sd);
113       int next_cpu_nr = sim_engine_next_cpu_nr (sd);
114       int nr_cpus = sim_engine_nr_cpus (sd);
115       /* ??? Setting max_insns to 0 allows pbb/jit code to run wild and is
116 	 useful if all one wants to do is run a benchmark.  Need some better
117 	 way to identify this case.  */
118       int max_insns = (step
119 		       ? 1
120 		       : (nr_cpus == 1
121 			  /*&& wip:no-events*/
122 			  /* Don't do this if running under gdb, need to
123 			     poll ui for events.  */
124 			  && STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
125 		       ? 0
126 		       : 8); /*FIXME: magic number*/
127 
128       sim_events_preprocess (sd, last_cpu_nr >= nr_cpus, next_cpu_nr >= nr_cpus);
129       if (next_cpu_nr >= nr_cpus)
130 	next_cpu_nr = 0;
131       if (nr_cpus == 1)
132 	engine_run_1 (sd, max_insns, fast_p);
133       else
134 	engine_run_n (sd, next_cpu_nr, nr_cpus, max_insns, fast_p);
135     }
136 #if 1 /*wip*/
137   else
138     {
139       /* Account for the last insn executed.  */
140       SIM_CPU *cpu = STATE_CPU (sd, sim_engine_last_cpu_nr (sd));
141       ++ CPU_INSN_COUNT (cpu);
142       CGEN_TRACE_INSN_FINI (cpu, NULL, 1);
143     }
144 #endif
145 
146   engine->jmpbuf = NULL;
147 
148   {
149     int i;
150     int nr_cpus = sim_engine_nr_cpus (sd);
151 
152 #if 0 /*wip,ignore*/
153     /* If the loop exits, either we single-stepped or @cpu@_engine_stop
154        was called.  */
155     if (step)
156       sim_engine_set_run_state (sd, sim_stopped, SIM_SIGTRAP);
157     else
158       sim_engine_set_run_state (sd, pending_reason, pending_sigrc);
159 #endif
160 
161     for (i = 0; i < nr_cpus; ++i)
162       {
163 	SIM_CPU *cpu = STATE_CPU (sd, i);
164 
165 	PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu)) += CPU_INSN_COUNT (cpu);
166       }
167   }
168 
169   sim_module_suspend (sd);
170 }
171 
172 /* Halt the simulator after just one instruction.  */
173 
174 static void
175 has_stepped (SIM_DESC sd, void *data)
176 {
177   ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
178   sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP);
179 }
180 
181 /* Prepare a cpu for running.
182    MAX_INSNS is the number of insns to execute per time slice.
183    If 0 it means the cpu can run as long as it wants (e.g. until the
184    program completes).
185    ??? Perhaps this should be an argument to the engine_fn.  */
186 
187 static void
188 prime_cpu (SIM_CPU *cpu, int max_insns)
189 {
190   CPU_MAX_SLICE_INSNS (cpu) = max_insns;
191   CPU_INSN_COUNT (cpu) = 0;
192 
193   /* Initialize the insn descriptor table.
194      This has to be done after all initialization so we just defer it to
195      here.  */
196 
197   if (MACH_PREPARE_RUN (CPU_MACH (cpu)))
198     (* MACH_PREPARE_RUN (CPU_MACH (cpu))) (cpu);
199 }
200 
201 /* Main loop, for 1 cpu.  */
202 
203 static void
204 engine_run_1 (SIM_DESC sd, int max_insns, int fast_p)
205 {
206   sim_cpu *cpu = STATE_CPU (sd, 0);
207   ENGINE_FN *fn = fast_p ? CPU_FAST_ENGINE_FN (cpu) : CPU_FULL_ENGINE_FN (cpu);
208 
209   prime_cpu (cpu, max_insns);
210 
211   while (1)
212     {
213       SIM_ENGINE_PREFIX_HOOK (sd);
214 
215       (*fn) (cpu);
216 
217       SIM_ENGINE_POSTFIX_HOOK (sd);
218 
219       /* process any events */
220       if (sim_events_tick (sd))
221 	sim_events_process (sd);
222     }
223 }
224 
225 /* Main loop, for multiple cpus.  */
226 
227 static void
228 engine_run_n (SIM_DESC sd, int next_cpu_nr, int nr_cpus, int max_insns, int fast_p)
229 {
230   int i;
231   /* Ensure that engine_fns is fully initialized, this silences a compiler
232      warning when engine_fns is used below.  */
233   ENGINE_FN *engine_fns[MAX_NR_PROCESSORS] = {};
234 
235   SIM_ASSERT (nr_cpus <= MAX_NR_PROCESSORS);
236   SIM_ASSERT (next_cpu_nr >= 0 && next_cpu_nr < nr_cpus);
237 
238   for (i = 0; i < nr_cpus; ++i)
239     {
240       SIM_CPU *cpu = STATE_CPU (sd, i);
241 
242       engine_fns[i] = fast_p ? CPU_FAST_ENGINE_FN (cpu) : CPU_FULL_ENGINE_FN (cpu);
243       prime_cpu (cpu, max_insns);
244     }
245 
246   while (1)
247     {
248       SIM_ENGINE_PREFIX_HOOK (sd);
249 
250       /* FIXME: proper cycling of all of them, blah blah blah.  */
251       while (next_cpu_nr < nr_cpus)
252 	{
253 	  SIM_CPU *cpu = STATE_CPU (sd, next_cpu_nr);
254 
255 	  (* engine_fns[next_cpu_nr]) (cpu);
256 	  ++next_cpu_nr;
257 	}
258 
259       SIM_ENGINE_POSTFIX_HOOK (sd);
260 
261       /* process any events */
262       if (sim_events_tick (sd))
263 	sim_events_process (sd);
264     }
265 }
266