1 # This shell script emits a C file. -*- C -*-
2 # Generate the main loop of the simulator.
3 # Syntax: genmloop.sh /bin/sh [options] cpu mainloop.in
4 # Options: [-mono|-multi] -scache -fast -parallel
6 # -scache: use the scache
7 # -fast: include support for fast execution in addition to full featured mode
8 # -parallel: cpu can execute multiple instructions parallely
10 # FIXME: "multi" support is wip.
13 # - move this C code to mainloop.in
15 # - build exec.in from .cpu file
16 # - have each cpu provide handwritten cycle.in
17 # - integrate with common/sim-engine.[ch]
18 # - for sparc, have two main loops, outer one handles delay slot when npc != 0
19 # - inner loop does not handle delay slots, pc = pc + 4
34 -scache) scache=yes ;;
38 -parallel) parallel=yes ;;
48 /* This file is is generated by the genmloop script. DO NOT EDIT! */
50 /* Main loop for CGEN-based simulators.
51 Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
52 Contributed by Cygnus Support.
54 This file is part of the GNU simulators.
56 This program is free software; you can redistribute it and/or modify
57 it under the terms of the GNU General Public License as published by
58 the Free Software Foundation; either version 2, or (at your option)
61 This program is distributed in the hope that it will be useful,
62 but WITHOUT ANY WARRANTY; without even the implied warranty of
63 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
64 GNU General Public License for more details.
66 You should have received a copy of the GNU General Public License along
67 with this program; if not, write to the Free Software Foundation, Inc.,
68 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
70 /* We want the scache version of SEM_ARG.
71 This is used by the switch() version of the semantic code. */
74 if [ x$scache = xyes ] ; then
75 echo "#define SCACHE_P"
77 echo '/*#define SCACHE_P*/'
78 echo '#undef WITH_SCACHE'
79 echo '#define WITH_SCACHE 0'
85 #define WANT_CPU_@CPU@
93 #include "sim-assert.h"
95 /* Tell sim_main_loop to use the scache if it's active.
96 Collecting profile data and tracing slow us down so we don't do them in
98 There are 2 possibilities on 2 axes:
99 - use or don't use the scache
100 - run normally (full featured) or run fast
101 Supporting all four possibilities in one executable is a bit much but
102 supporting full/fast seems reasonable.
103 If the scache is configured in it is always used.
104 ??? Need to see whether it speeds up profiling significantly or not.
105 Speeding up tracing doesn't seem worth it.
106 ??? Sometimes supporting more than one set of semantic functions will make
107 the simulator too large - this should be configurable.
111 #define RUN_FAST_P(cpu) (STATE_RUN_FAST_P (CPU_STATE (cpu)))
113 #define RUN_FAST_P(cpu) 0
116 #ifndef SIM_PRE_EXEC_HOOK
117 #define SIM_PRE_EXEC_HOOK(state)
120 #ifndef SIM_POST_EXEC_HOOK
121 #define SIM_POST_EXEC_HOOK(state)
124 #if 0 /* FIXME:experiment */
125 /* "sc" is local to the calling function.
126 It is done this way to keep the internals of the implementation out of
127 the description file. */
128 #define EXTRACT(cpu, pc, insn, sc, num, fast_p) \
129 @cpu@_extract (cpu, pc, insn, sc + num, fast_p)
131 #define EXECUTE(cpu, sc, num, fast_p) \
132 @cpu@_execute (cpu, sc + num, fast_p)
135 #define GET_ATTR(cpu, num, attr) \
136 CGEN_INSN_ATTR (sc[num].argbuf.opcode, CGEN_INSN_##attr)
140 ${SHELL} $file support
144 static volatile int keep_running;
145 /* FIXME: Should each cpu have its own copy? */
146 static volatile enum sim_stop pending_reason;
147 static volatile int pending_sigrc;
149 /* Want to measure simulator speed even in fast mode. */
150 static unsigned long insn_count;
151 static SIM_ELAPSED_TIME start_time;
153 /* Forward decls of cpu-specific functions. */
154 static void engine_resume (SIM_DESC, int, int);
155 static void engine_resume_full (SIM_DESC);
156 ${scache+static void engine_resume_fast (SIM_DESC);}
158 /* Stop the simulation for REASON/SIGRC.
159 CPU is the cpu being stopped [at address PC].
160 If CPU is NULL, all cpu's are stopping for the same reason. */
163 @cpu@_engine_stop (SIM_DESC sd, SIM_CPU *cpu, PCADDR pc,
164 enum sim_stop reason, int sigrc)
167 pending_reason = reason;
168 pending_sigrc = sigrc;
173 @cpu@_engine_run (SIM_DESC sd, int step, int siggnal)
176 if (USING_SCACHE_P (sd))
179 engine_resume (sd, step, siggnal);
183 engine_resume (SIM_DESC sd, int step, int siggnal)
185 sim_cpu *current_cpu = STATE_CPU (sd, 0);
186 /* These are volatile to survive setjmp. */
187 volatile sim_cpu *cpu = current_cpu;
188 volatile sim_engine *engine = STATE_ENGINE (sd);
192 keep_running = ! step;
193 start_time = sim_elapsed_time_get ();
194 /* FIXME: Having this global can slow things down a teensy bit.
195 After things are working see about moving engine_resume_{full,fast}
196 back into this function. */
199 engine->jmpbuf = &buf;
200 sim_engine_set_run_state (sd, sim_running, 0);
201 pending_reason = sim_running;
204 /* ??? Restart support to be added in time. */
208 /* Account for the last insn executed. */
210 TRACE_INSN_FINI ((sim_cpu *) cpu, 1);
214 /* The computed goto switch can be used, and while the number of blocks
215 may swamp the relatively few that this function contains, when running
216 with the scache we put the actual semantic code in their own
221 if [ x$fast = xyes ] ; then
224 || !RUN_FAST_P (current_cpu))
225 engine_resume_full (sd);
227 engine_resume_fast (sd);
231 engine_resume_full (sd);
237 /* If the loop exits, either we single-stepped or @cpu@_engine_stop
240 sim_engine_set_run_state (sd, sim_stopped, SIM_SIGTRAP);
242 sim_engine_set_run_state (sd, pending_reason, pending_sigrc);
245 engine->jmpbuf = NULL;
246 PROFILE_EXEC_TIME (CPU_PROFILE_DATA (cpu))
247 += sim_elapsed_time_since (start_time);
248 PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu))
254 ##########################################################################
256 if [ x$scache = xyes ] ; then
260 engine_resume_full (SIM_DESC sd)
263 /* current_{state,cpu} exist for the generated code to use. */
264 SIM_DESC current_state = sd;
265 sim_cpu *current_cpu = STATE_CPU (sd, 0);
269 # Any initialization code before looping starts.
270 # Note that this code may declare some locals.
273 if [ x$parallel = xyes ] ; then
276 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
278 if (! CPU_IDESC_READ_INIT_P (current_cpu))
280 /* ??? Later maybe paste read.c in when building mainloop.c. */
281 #define DEFINE_LABELS
283 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
295 /* FIXME: Later check every insn for events and such. */
297 SIM_PRE_EXEC_HOOK (current_cpu);
304 /* First step: look up current insn in hash table. */
305 hash = SCACHE_HASH_PC (sd, pc);
306 sc = CPU_SCACHE_CACHE (current_cpu) + hash;
308 /* If the entry isn't the one we want (cache miss),
309 fetch and decode the instruction. */
310 if (sc->argbuf.addr != pc)
314 PROFILE_COUNT_SCACHE_MISS (current_cpu);
316 /* begin full-extract-scache */
319 ${SHELL} $file full-extract-scache
322 /* end full-extract-scache */
326 PROFILE_COUNT_SCACHE_HIT (current_cpu);
327 /* Make core access statistics come out right.
328 The size is a guess, but it's currently not used either. */
329 PROFILE_COUNT_CORE (current_cpu, pc, 2, exec_map);
332 /* begin full-exec-scache */
335 ${SHELL} $file full-exec-scache
338 /* end full-exec-scache */
341 SIM_POST_EXEC_HOOK (current_cpu);
345 while (keep_running);
350 ##########################################################################
356 engine_resume_full (SIM_DESC sd)
359 SIM_DESC current_state = sd;
360 sim_cpu *current_cpu = STATE_CPU (sd, 0);
361 SCACHE cache[MAX_LIW_INSNS];
362 SCACHE *sc = &cache[0];
366 # Any initialization code before looping starts.
367 # Note that this code may declare some locals.
370 if [ x$parallel = xyes ] ; then
373 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
375 if (! CPU_IDESC_READ_INIT_P (current_cpu))
377 /* ??? Later maybe paste read.c in when building mainloop.c. */
378 #define DEFINE_LABELS
380 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
392 /* FIXME: Later check every insn for events and such. */
394 SIM_PRE_EXEC_HOOK (current_cpu);
397 /* begin full-{extract,exec}-noscache */
400 ${SHELL} $file full-extract-noscache
402 ${SHELL} $file full-exec-noscache
405 /* end full-{extract,exec}-noscache */
408 SIM_POST_EXEC_HOOK (current_cpu);
412 while (keep_running);
419 ##########################################################################
421 if [ x$fast = xyes ] ; then
422 if [ x$scache = xyes ] ; then
426 engine_resume_fast (SIM_DESC sd)
429 SIM_DESC current_state = sd;
430 sim_cpu *current_cpu = STATE_CPU (sd, 0);
434 # Any initialization code before looping starts.
435 # Note that this code may declare some locals.
438 if [ x$parallel = xyes ] ; then
441 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
443 if (! CPU_IDESC_READ_INIT_P (current_cpu))
445 /* ??? Later maybe paste read.c in when building mainloop.c. */
446 #define DEFINE_LABELS
448 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
458 #if defined (WITH_SEM_SWITCH_FAST) && defined (__GNUC__)
460 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
462 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
463 #define DEFINE_LABELS
464 #include "sem-switch.c"
465 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
477 /* First step: look up current insn in hash table. */
478 hash = SCACHE_HASH_PC (sd, pc);
479 sc = CPU_SCACHE_CACHE (current_cpu) + hash;
481 /* If the entry isn't the one we want (cache miss),
482 fetch and decode the instruction. */
483 if (sc->argbuf.addr != pc)
487 /* begin fast-extract-scache */
490 ${SHELL} $file fast-extract-scache
493 /* end fast-extract-scache */
496 /* begin fast-exec-scache */
499 ${SHELL} $file fast-exec-scache
502 /* end fast-exec-scache */
508 while (keep_running);
514 ##########################################################################
520 engine_resume_fast (SIM_DESC sd)
523 SIM_DESC current_state = sd;
524 sim_cpu *current_cpu = STATE_CPU (sd, 0);
525 SCACHE cache[MAX_LIW_INSNS];
526 SCACHE *sc = &cache[0];
530 # Any initialization code before looping starts.
531 # Note that this code may declare some locals.
534 if [ x$parallel = xyes ] ; then
537 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
539 if (! CPU_IDESC_READ_INIT_P (current_cpu))
541 /* ??? Later maybe paste read.c in when building mainloop.c. */
542 #define DEFINE_LABELS
544 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
556 /* begin fast-{extract,exec}-noscache */
559 ${SHELL} $file fast-extract-noscache
561 ${SHELL} $file fast-exec-noscache
564 /* end fast-{extract,exec}-noscache */
568 while (keep_running);