1 /* Main simulator loop for CGEN-based simulators.
2    Copyright (C) 1998-2013 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 #include "sim-main.h"
37 #include "sim-assert.h"
38 
39 #ifndef SIM_ENGINE_PREFIX_HOOK
40 #define SIM_ENGINE_PREFIX_HOOK(sd)
41 #endif
42 #ifndef SIM_ENGINE_POSTFIX_HOOK
43 #define SIM_ENGINE_POSTFIX_HOOK(sd)
44 #endif
45 
46 static sim_event_handler has_stepped;
47 static void prime_cpu (SIM_CPU *, int);
48 static void engine_run_1 (SIM_DESC, int, int);
49 static void engine_run_n (SIM_DESC, int, int, int, int);
50 
51 /* sim_resume for cgen */
52 
53 void
sim_resume(SIM_DESC sd,int step,int siggnal)54 sim_resume (SIM_DESC sd, int step, int siggnal)
55 {
56   sim_engine *engine = STATE_ENGINE (sd);
57   jmp_buf buf;
58   int jmpval;
59 
60   ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
61 
62   /* we only want to be single stepping the simulator once */
63   if (engine->stepper != NULL)
64     {
65       sim_events_deschedule (sd, engine->stepper);
66       engine->stepper = NULL;
67     }
68   if (step)
69     engine->stepper = sim_events_schedule (sd, 1, has_stepped, sd);
70 
71   sim_module_resume (sd);
72 
73 #if WITH_SCACHE
74   if (USING_SCACHE_P (sd))
75     scache_flush (sd);
76 #endif
77 
78   /* run/resume the simulator */
79 
80   sim_engine_set_run_state (sd, sim_running, 0);
81 
82   engine->jmpbuf = &buf;
83   jmpval = setjmp (buf);
84   if (jmpval == sim_engine_start_jmpval
85       || jmpval == sim_engine_restart_jmpval)
86     {
87       int last_cpu_nr = sim_engine_last_cpu_nr (sd);
88       int next_cpu_nr = sim_engine_next_cpu_nr (sd);
89       int nr_cpus = sim_engine_nr_cpus (sd);
90       /* ??? Setting max_insns to 0 allows pbb/jit code to run wild and is
91 	 useful if all one wants to do is run a benchmark.  Need some better
92 	 way to identify this case.  */
93       int max_insns = (step
94 		       ? 1
95 		       : (nr_cpus == 1
96 			  /*&& wip:no-events*/
97 			  /* Don't do this if running under gdb, need to
98 			     poll ui for events.  */
99 			  && STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
100 		       ? 0
101 		       : 8); /*FIXME: magic number*/
102       int fast_p = STATE_RUN_FAST_P (sd);
103 
104       sim_events_preprocess (sd, last_cpu_nr >= nr_cpus, next_cpu_nr >= nr_cpus);
105       if (next_cpu_nr >= nr_cpus)
106 	next_cpu_nr = 0;
107       if (nr_cpus == 1)
108 	engine_run_1 (sd, max_insns, fast_p);
109       else
110 	engine_run_n (sd, next_cpu_nr, nr_cpus, max_insns, fast_p);
111     }
112 #if 1 /*wip*/
113   else
114     {
115       /* Account for the last insn executed.  */
116       SIM_CPU *cpu = STATE_CPU (sd, sim_engine_last_cpu_nr (sd));
117       ++ CPU_INSN_COUNT (cpu);
118       TRACE_INSN_FINI (cpu, NULL, 1);
119     }
120 #endif
121 
122   engine->jmpbuf = NULL;
123 
124   {
125     int i;
126     int nr_cpus = sim_engine_nr_cpus (sd);
127 
128 #if 0 /*wip,ignore*/
129     /* If the loop exits, either we single-stepped or @cpu@_engine_stop
130        was called.  */
131     if (step)
132       sim_engine_set_run_state (sd, sim_stopped, SIM_SIGTRAP);
133     else
134       sim_engine_set_run_state (sd, pending_reason, pending_sigrc);
135 #endif
136 
137     for (i = 0; i < nr_cpus; ++i)
138       {
139 	SIM_CPU *cpu = STATE_CPU (sd, i);
140 
141 	PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu)) += CPU_INSN_COUNT (cpu);
142       }
143   }
144 
145   sim_module_suspend (sd);
146 }
147 
148 /* Halt the simulator after just one instruction.  */
149 
150 static void
has_stepped(SIM_DESC sd,void * data)151 has_stepped (SIM_DESC sd, void *data)
152 {
153   ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
154   sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP);
155 }
156 
157 /* Prepare a cpu for running.
158    MAX_INSNS is the number of insns to execute per time slice.
159    If 0 it means the cpu can run as long as it wants (e.g. until the
160    program completes).
161    ??? Perhaps this should be an argument to the engine_fn.  */
162 
163 static void
prime_cpu(SIM_CPU * cpu,int max_insns)164 prime_cpu (SIM_CPU *cpu, int max_insns)
165 {
166   CPU_MAX_SLICE_INSNS (cpu) = max_insns;
167   CPU_INSN_COUNT (cpu) = 0;
168 
169   /* Initialize the insn descriptor table.
170      This has to be done after all initialization so we just defer it to
171      here.  */
172 
173   if (MACH_PREPARE_RUN (CPU_MACH (cpu)))
174     (* MACH_PREPARE_RUN (CPU_MACH (cpu))) (cpu);
175 }
176 
177 /* Main loop, for 1 cpu.  */
178 
179 static void
engine_run_1(SIM_DESC sd,int max_insns,int fast_p)180 engine_run_1 (SIM_DESC sd, int max_insns, int fast_p)
181 {
182   sim_cpu *cpu = STATE_CPU (sd, 0);
183   ENGINE_FN *fn = fast_p ? CPU_FAST_ENGINE_FN (cpu) : CPU_FULL_ENGINE_FN (cpu);
184 
185   prime_cpu (cpu, max_insns);
186 
187   while (1)
188     {
189       SIM_ENGINE_PREFIX_HOOK (sd);
190 
191       (*fn) (cpu);
192 
193       SIM_ENGINE_POSTFIX_HOOK (sd);
194 
195       /* process any events */
196       if (sim_events_tick (sd))
197 	sim_events_process (sd);
198     }
199 }
200 
201 /* Main loop, for multiple cpus.  */
202 
203 static void
engine_run_n(SIM_DESC sd,int next_cpu_nr,int nr_cpus,int max_insns,int fast_p)204 engine_run_n (SIM_DESC sd, int next_cpu_nr, int nr_cpus, int max_insns, int fast_p)
205 {
206   int i;
207   ENGINE_FN *engine_fns[MAX_NR_PROCESSORS];
208 
209   for (i = 0; i < nr_cpus; ++i)
210     {
211       SIM_CPU *cpu = STATE_CPU (sd, i);
212 
213       engine_fns[i] = fast_p ? CPU_FAST_ENGINE_FN (cpu) : CPU_FULL_ENGINE_FN (cpu);
214       prime_cpu (cpu, max_insns);
215     }
216 
217   while (1)
218     {
219       SIM_ENGINE_PREFIX_HOOK (sd);
220 
221       /* FIXME: proper cycling of all of them, blah blah blah.  */
222       while (next_cpu_nr != nr_cpus)
223 	{
224 	  SIM_CPU *cpu = STATE_CPU (sd, next_cpu_nr);
225 
226 	  (* engine_fns[next_cpu_nr]) (cpu);
227 	  ++next_cpu_nr;
228 	}
229 
230       SIM_ENGINE_POSTFIX_HOOK (sd);
231 
232       /* process any events */
233       if (sim_events_tick (sd))
234 	sim_events_process (sd);
235     }
236 }
237