1/* Main simulator loop for CGEN-based simulators.
2   Copyright (C) 1998, 2007 Free Software Foundation, Inc.
3   Contributed by Cygnus Solutions.
4
5This file is part of GDB, the GNU debugger.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
46static sim_event_handler has_stepped;
47static void prime_cpu (SIM_CPU *, int);
48static void engine_run_1 (SIM_DESC, int, int);
49static void engine_run_n (SIM_DESC, int, int, int, int);
50
51/* sim_resume for cgen */
52
53void
54sim_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
150static void
151has_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
163static void
164prime_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
179static void
180engine_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
203static void
204engine_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