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 cache 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 cache
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 cache 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 /* Want to measure simulator speed even in fast mode. */
146 static unsigned long insn_count;
147 static SIM_ELAPSED_TIME start_time;
149 /* Forward decls of cpu-specific functions. */
150 static void engine_resume (SIM_DESC, int, int);
151 static void engine_resume_full (SIM_DESC);
152 ${scache+static void engine_resume_fast (SIM_DESC);}
155 @cpu@_engine_stop (SIM_DESC sd)
162 @cpu@_engine_run (SIM_DESC sd, int step, int siggnal)
165 if (USING_SCACHE_P (sd))
168 engine_resume (sd, step, siggnal);
172 engine_resume (SIM_DESC sd, int step, int siggnal)
174 sim_cpu *current_cpu = STATE_CPU (sd, 0);
175 /* These are volatile to survive setjmp. */
176 volatile sim_cpu *cpu = current_cpu;
177 volatile sim_engine *engine = STATE_ENGINE (sd);
181 keep_running = ! step;
182 start_time = sim_elapsed_time_get ();
183 /* FIXME: Having this global can slow things down a teensy bit.
184 After things are working see about moving engine_resume_{full,fast}
185 back into this function. */
188 engine->jmpbuf = &buf;
191 /* Account for the last insn executed. */
194 engine->jmpbuf = NULL;
195 TRACE_INSN_FINI ((sim_cpu *) cpu);
196 PROFILE_EXEC_TIME (CPU_PROFILE_DATA (cpu))
197 += sim_elapsed_time_since (start_time);
198 PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu))
204 /* ??? Restart support to be added in time. */
206 /* The computed goto switch can be used, and while the number of blocks
207 may swamp the relatively few that this function contains, when running
208 with the scache we put the actual semantic code in their own
213 if [ x$fast = xyes ] ; then
216 || !RUN_FAST_P (current_cpu))
217 engine_resume_full (sd);
219 engine_resume_fast (sd);
223 engine_resume_full (sd);
229 /* If the loop exits, either we single-stepped or engine_stop was called.
230 In either case we need to call engine_halt: to properly exit this
231 function we must go through the setjmp executed above. */
233 sim_engine_halt (sd, current_cpu, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP);
234 sim_engine_halt (sd, current_cpu, NULL, NULL_CIA, sim_stopped, SIM_SIGINT);
239 ##########################################################################
241 if [ x$scache = xyes ] ; then
245 engine_resume_full (SIM_DESC sd)
248 /* current_{state,cpu} exist for the generated code to use. */
249 SIM_DESC current_state = sd;
250 sim_cpu *current_cpu = STATE_CPU (sd, 0);
251 ${parallel+ int icount = 0;}
255 # Any initialization code before looping starts.
256 # Note that this code may declare some locals.
259 if [ x$parallel = xyes ] ; then
262 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
264 static read_init_p = 0;
267 /* ??? Later maybe paste read.c in when building mainloop.c. */
268 #define DEFINE_LABELS
282 /* FIXME: Later check every insn for events and such. */
284 SIM_PRE_EXEC_HOOK (current_cpu);
291 /* First step: look up current insn in hash table. */
292 hash = SCACHE_HASH_PC (sd, pc);
293 sc = CPU_SCACHE_CACHE (current_cpu) + hash;
295 /* If the entry isn't the one we want (cache miss),
296 fetch and decode the instruction. */
297 if (sc->argbuf.addr != pc)
301 PROFILE_COUNT_SCACHE_MISS (current_cpu);
303 /* begin full-extract-scache */
306 ${SHELL} $file full-extract-scache
309 /* end full-extract-scache */
313 PROFILE_COUNT_SCACHE_HIT (current_cpu);
314 /* Make core access statistics come out right.
315 The size is a guess, but it's currently not used either. */
316 PROFILE_COUNT_CORE (current_cpu, pc, 2, sim_core_execute_map);
319 /* begin full-exec-scache */
322 ${SHELL} $file full-exec-scache
325 /* end full-exec-scache */
328 SIM_POST_EXEC_HOOK (current_cpu);
332 while (keep_running);
337 ##########################################################################
343 engine_resume_full (SIM_DESC sd)
346 SIM_DESC current_state = sd;
347 sim_cpu *current_cpu = STATE_CPU (sd, 0);
348 SCACHE cache[MAX_LIW_INSNS];
349 SCACHE *sc = &cache[0];
350 ${parallel+ int icount = 0;}
354 # Any initialization code before looping starts.
355 # Note that this code may declare some locals.
358 if [ x$parallel = xyes ] ; then
361 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
363 static read_init_p = 0;
366 /* ??? Later maybe paste read.c in when building mainloop.c. */
367 #define DEFINE_LABELS
381 /* FIXME: Later check every insn for events and such. */
383 SIM_PRE_EXEC_HOOK (current_cpu);
386 /* begin full-{extract,exec}-noscache */
389 ${SHELL} $file full-extract-noscache
391 ${SHELL} $file full-exec-noscache
394 /* end full-{extract,exec}-noscache */
397 SIM_POST_EXEC_HOOK (current_cpu);
401 while (keep_running);
408 ##########################################################################
410 if [ x$fast = xyes ] ; then
411 if [ x$scache = xyes ] ; then
415 engine_resume_fast (SIM_DESC sd)
418 SIM_DESC current_state = sd;
419 sim_cpu *current_cpu = STATE_CPU (sd, 0);
420 ${parallel+ int icount = 0;}
424 # Any initialization code before looping starts.
425 # Note that this code may declare some locals.
428 if [ x$parallel = xyes ] ; then
431 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
433 static read_init_p = 0;
436 /* ??? Later maybe paste read.c in when building mainloop.c. */
437 #define DEFINE_LABELS
449 #if defined (WITH_SEM_SWITCH_FAST) && defined (__GNUC__)
451 static decode_init_p = 0;
454 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
455 #define DEFINE_LABELS
456 #include "sem-switch.c"
469 /* First step: look up current insn in hash table. */
470 hash = SCACHE_HASH_PC (sd, pc);
471 sc = CPU_SCACHE_CACHE (current_cpu) + hash;
473 /* If the entry isn't the one we want (cache miss),
474 fetch and decode the instruction. */
475 if (sc->argbuf.addr != pc)
479 /* begin fast-extract-scache */
482 ${SHELL} $file fast-extract-scache
485 /* end fast-extract-scache */
488 /* begin fast-exec-scache */
491 ${SHELL} $file fast-exec-scache
494 /* end fast-exec-scache */
500 while (keep_running);
506 ##########################################################################
512 engine_resume_fast (SIM_DESC sd)
515 SIM_DESC current_state = sd;
516 sim_cpu *current_cpu = STATE_CPU (sd, 0);
517 SCACHE cache[MAX_LIW_INSNS];
518 SCACHE *sc = &cache[0];
519 ${parallel+ int icount = 0;}
523 # Any initialization code before looping starts.
524 # Note that this code may declare some locals.
527 if [ x$parallel = xyes ] ; then
530 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
532 static read_init_p = 0;
535 /* ??? Later maybe paste read.c in when building mainloop.c. */
536 #define DEFINE_LABELS
550 /* begin fast-{extract,exec}-noscache */
553 ${SHELL} $file fast-extract-noscache
555 ${SHELL} $file fast-exec-noscache
558 /* end fast-{extract,exec}-noscache */
562 while (keep_running);