* Make-common.in (SCHEME,SCHEMEFLAGS): Delete.
[external/binutils.git] / sim / common / genmloop.sh
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
5 #
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
9 #
10 # FIXME: "multi" support is wip.
11
12 # TODO
13 # - move this C code to mainloop.in
14 # - keep genmloop.sh
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
20
21 type=mono
22 #scache=
23 #fast=
24 #parallel=
25
26 shell=$1 ; shift
27
28 while true
29 do
30         case $1 in
31         -mono) type=mono ;;
32         -multi) type=multi ;;
33         -no-scache) ;;
34         -scache) scache=yes ;;
35         -no-fast) ;;
36         -fast) fast=yes ;;
37         -no-parallel) ;;
38         -parallel) parallel=yes ;;
39         *) break ;;
40         esac
41         shift
42 done
43
44 cpu=$1
45 file=$2
46
47 cat <<EOF
48 /* This file is is generated by the genmloop script.  DO NOT EDIT! */
49
50 /* Main loop for CGEN-based simulators.
51    Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
52    Contributed by Cygnus Support.
53
54 This file is part of the GNU simulators.
55
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)
59 any later version.
60
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.
65
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.  */
69
70 /* We want the scache version of SEM_ARG.
71    This is used by the switch() version of the semantic code.  */
72 EOF
73
74 if [ x$scache = xyes ] ; then
75         echo "#define SCACHE_P"
76 else
77         echo '/*#define SCACHE_P*/'
78         echo '#undef WITH_SCACHE'
79         echo '#define WITH_SCACHE 0'
80 fi
81
82 cat <<EOF
83
84 #define WANT_CPU
85 #define WANT_CPU_@CPU@
86
87 #include "sim-main.h"
88 #include "bfd.h"
89 #include "cgen-mem.h"
90 #include "cgen-ops.h"
91 #include "cpu-opc.h"
92 #include "cpu-sim.h"
93 #include "sim-assert.h"
94
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
97    "fast mode".
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.
108 */
109
110 #if WITH_SCACHE
111 #define RUN_FAST_P(cpu) (STATE_RUN_FAST_P (CPU_STATE (cpu)))
112 #else
113 #define RUN_FAST_P(cpu) 0
114 #endif
115
116 #ifndef SIM_PRE_EXEC_HOOK
117 #define SIM_PRE_EXEC_HOOK(state)
118 #endif
119
120 #ifndef SIM_POST_EXEC_HOOK
121 #define SIM_POST_EXEC_HOOK(state)
122 #endif
123
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)
130
131 #define EXECUTE(cpu, sc, num, fast_p) \
132 @cpu@_execute (cpu, sc + num, fast_p)
133 #endif
134
135 #define GET_ATTR(cpu, num, attr) \
136 CGEN_INSN_ATTR (sc[num].argbuf.opcode, CGEN_INSN_##attr)
137
138 EOF
139
140 ${SHELL} $file support
141
142 cat <<EOF
143
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;
148
149 /* Want to measure simulator speed even in fast mode.  */
150 static unsigned long insn_count;
151 static SIM_ELAPSED_TIME start_time;
152
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);}
157
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.  */
161
162 int
163 @cpu@_engine_stop (SIM_DESC sd, SIM_CPU *cpu, PCADDR pc,
164                    enum sim_stop reason, int sigrc)
165 {
166   keep_running = 0;
167   pending_reason = reason;
168   pending_sigrc = sigrc;
169   return 1;
170 }
171
172 void
173 @cpu@_engine_run (SIM_DESC sd, int step, int siggnal)
174 {
175 #if WITH_SCACHE
176   if (USING_SCACHE_P (sd))
177     scache_flush (sd);
178 #endif
179   engine_resume (sd, step, siggnal);
180 }
181
182 static void
183 engine_resume (SIM_DESC sd, int step, int siggnal)
184 {
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);
189   jmp_buf buf;
190   int jmpval;
191
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.  */
197   insn_count = 0;
198
199   engine->jmpbuf = &buf;
200   sim_engine_set_run_state (sd, sim_running, 0);
201   pending_reason = sim_running;
202   pending_sigrc = 0;
203
204   /* ??? Restart support to be added in time.  */
205
206   if (setjmp (buf))
207     {
208       /* Account for the last insn executed.  */
209       ++insn_count;
210       TRACE_INSN_FINI ((sim_cpu *) cpu, 1);
211     }
212   else
213     {
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
217          functions.  */
218
219 EOF
220
221 if [ x$fast = xyes ] ; then
222         cat <<EOF
223       if (step
224           || !RUN_FAST_P (current_cpu))
225         engine_resume_full (sd);
226       else
227         engine_resume_fast (sd);
228 EOF
229 else
230         cat <<EOF
231       engine_resume_full (sd);
232 EOF
233 fi
234
235 cat <<EOF
236
237       /* If the loop exits, either we single-stepped or @cpu@_engine_stop
238          was called.  */
239       if (step)
240         sim_engine_set_run_state (sd, sim_stopped, SIM_SIGTRAP);
241       else
242         sim_engine_set_run_state (sd, pending_reason, pending_sigrc);
243     }
244
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))
249     += insn_count;
250 }
251
252 EOF
253
254 ##########################################################################
255
256 if [ x$scache = xyes ] ; then
257         cat <<EOF
258
259 static void
260 engine_resume_full (SIM_DESC sd)
261 {
262 #define FAST_P 0
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);
266
267 EOF
268
269 # Any initialization code before looping starts.
270 # Note that this code may declare some locals.
271 ${SHELL} $file init
272
273 if [ x$parallel = xyes ] ; then
274 cat << EOF
275
276 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
277   {
278     if (! CPU_IDESC_READ_INIT_P (current_cpu))
279       {
280 /* ??? Later maybe paste read.c in when building mainloop.c.  */
281 #define DEFINE_LABELS
282 #include "readx.c"
283         CPU_IDESC_READ_INIT_P (current_cpu) = 1;
284       }
285   }
286 #endif
287
288 EOF
289 fi
290
291 cat <<EOF
292
293   do
294     {
295       /* FIXME: Later check every insn for events and such.  */
296
297       SIM_PRE_EXEC_HOOK (current_cpu);
298
299       {
300         unsigned int hash;
301         SCACHE *sc;
302         PCADDR pc = PC;
303
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;
307
308         /* If the entry isn't the one we want (cache miss),
309            fetch and decode the instruction.  */
310         if (sc->argbuf.addr != pc)
311           {
312             insn_t insn;
313
314             PROFILE_COUNT_SCACHE_MISS (current_cpu);
315
316 /* begin full-extract-scache */
317 EOF
318
319 ${SHELL} $file full-extract-scache
320
321 cat <<EOF
322 /* end full-extract-scache */
323           }
324         else
325           {
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);
330           }
331
332 /* begin full-exec-scache */
333 EOF
334
335 ${SHELL} $file full-exec-scache
336
337 cat <<EOF
338 /* end full-exec-scache */
339       }
340
341       SIM_POST_EXEC_HOOK (current_cpu);
342
343       ++insn_count;
344     }
345   while (keep_running);
346 #undef FAST_P
347 }
348 EOF
349
350 ##########################################################################
351
352 else # ! WITH_SCACHE
353         cat <<EOF
354
355 static void
356 engine_resume_full (SIM_DESC sd)
357 {
358 #define FAST_P 0
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];
363
364 EOF
365
366 # Any initialization code before looping starts.
367 # Note that this code may declare some locals.
368 ${SHELL} $file init
369
370 if [ x$parallel = xyes ] ; then
371 cat << EOF
372
373 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
374   {
375     if (! CPU_IDESC_READ_INIT_P (current_cpu))
376       {
377 /* ??? Later maybe paste read.c in when building mainloop.c.  */
378 #define DEFINE_LABELS
379 #include "readx.c"
380         CPU_IDESC_READ_INIT_P (current_cpu) = 1;
381       }
382   }
383 #endif
384
385 EOF
386 fi
387
388 cat <<EOF
389
390   do
391     {
392       /* FIXME: Later check every insn for events and such.  */
393
394       SIM_PRE_EXEC_HOOK (current_cpu);
395
396       {
397 /* begin full-{extract,exec}-noscache */
398 EOF
399
400 ${SHELL} $file full-extract-noscache
401 echo ""
402 ${SHELL} $file full-exec-noscache
403
404 cat <<EOF
405 /* end full-{extract,exec}-noscache */
406       }
407
408       SIM_POST_EXEC_HOOK (current_cpu);
409
410       ++insn_count;
411     }
412   while (keep_running);
413 #undef FAST_P
414 }
415
416 EOF
417 fi # ! WITH_SCACHE
418
419 ##########################################################################
420
421 if [ x$fast = xyes ] ; then
422     if [ x$scache = xyes ] ; then
423         cat <<EOF
424
425 static void
426 engine_resume_fast (SIM_DESC sd)
427 {
428 #define FAST_P 1
429   SIM_DESC current_state = sd;
430   sim_cpu *current_cpu = STATE_CPU (sd, 0);
431
432 EOF
433
434 # Any initialization code before looping starts.
435 # Note that this code may declare some locals.
436 ${SHELL} $file init
437
438 if [ x$parallel = xyes ] ; then
439 cat << EOF
440
441 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
442   {
443     if (! CPU_IDESC_READ_INIT_P (current_cpu))
444       {
445 /* ??? Later maybe paste read.c in when building mainloop.c.  */
446 #define DEFINE_LABELS
447 #include "readx.c"
448         CPU_IDESC_READ_INIT_P (current_cpu) = 1;
449       }
450   }
451 #endif
452
453 EOF
454 fi
455
456 cat <<EOF
457
458 #if defined (WITH_SEM_SWITCH_FAST) && defined (__GNUC__)
459   {
460     if (! CPU_IDESC_SEM_INIT_P (current_cpu))
461       {
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;
466       }
467   }
468 #endif
469
470   do
471     {
472       {
473         unsigned int hash;
474         SCACHE *sc;
475         PCADDR pc = PC;
476
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;
480
481         /* If the entry isn't the one we want (cache miss),
482            fetch and decode the instruction.  */
483         if (sc->argbuf.addr != pc)
484           {
485             insn_t insn;
486
487 /* begin fast-extract-scache */
488 EOF
489
490 ${SHELL} $file fast-extract-scache
491
492 cat <<EOF
493 /* end fast-extract-scache */
494           }
495
496 /* begin fast-exec-scache */
497 EOF
498
499 ${SHELL} $file fast-exec-scache
500
501 cat <<EOF
502 /* end fast-exec-scache */
503
504       }
505
506       ++insn_count;
507     }
508   while (keep_running);
509 #undef FAST_P
510 }
511
512 EOF
513
514 ##########################################################################
515
516 else # ! WITH_SCACHE
517         cat <<EOF
518
519 static void
520 engine_resume_fast (SIM_DESC sd)
521 {
522 #define FAST_P 1
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];
527
528 EOF
529
530 # Any initialization code before looping starts.
531 # Note that this code may declare some locals.
532 ${SHELL} $file init
533
534 if [ x$parallel = xyes ] ; then
535 cat << EOF
536
537 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
538   {
539     if (! CPU_IDESC_READ_INIT_P (current_cpu))
540       {
541 /* ??? Later maybe paste read.c in when building mainloop.c.  */
542 #define DEFINE_LABELS
543 #include "readx.c"
544         CPU_IDESC_READ_INIT_P (current_cpu) = 1;
545       }
546   }
547 #endif
548
549 EOF
550 fi
551
552 cat <<EOF
553
554   do
555     {
556 /* begin fast-{extract,exec}-noscache */
557 EOF
558
559 ${SHELL} $file fast-extract-noscache
560 echo ""
561 ${SHELL} $file fast-exec-noscache
562
563 cat <<EOF
564 /* end fast-{extract,exec}-noscache */
565
566       ++insn_count;
567     }
568   while (keep_running);
569 #undef FAST_P
570 }
571
572 EOF
573
574     fi # ! WITH_SCACHE
575 fi # -fast