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