* genmloop.sh (engine_resume): Update insn_count before exiting.
[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 cache 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 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.
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 /* Want to measure simulator speed even in fast mode.  */
146 static unsigned long insn_count;
147 static SIM_ELAPSED_TIME start_time;
148
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);}
153
154 int
155 @cpu@_engine_stop (SIM_DESC sd)
156 {
157   keep_running = 0;
158   return 1;
159 }
160
161 void
162 @cpu@_engine_run (SIM_DESC sd, int step, int siggnal)
163 {
164 #if WITH_SCACHE
165   if (USING_SCACHE_P (sd))
166     scache_flush (sd);
167 #endif
168   engine_resume (sd, step, siggnal);
169 }
170
171 static void
172 engine_resume (SIM_DESC sd, int step, int siggnal)
173 {
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);
178   jmp_buf buf;
179   int jmpval;
180
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.  */
186   insn_count = 0;
187
188   engine->jmpbuf = &buf;
189   if (setjmp (buf))
190     {
191       /* Account for the last insn executed.  */
192       ++insn_count;
193
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))
199         += insn_count;
200
201       return;
202     }
203
204   /* ??? Restart support to be added in time.  */
205
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
209      functions.  */
210
211 EOF
212
213 if [ x$fast = xyes ] ; then
214         cat <<EOF
215   if (step
216       || !RUN_FAST_P (current_cpu))
217     engine_resume_full (sd);
218   else
219     engine_resume_fast (sd);
220 EOF
221 else
222         cat <<EOF
223   engine_resume_full (sd);
224 EOF
225 fi
226
227 cat <<EOF
228
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.  */
232   if (step)
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);
235 }
236
237 EOF
238
239 ##########################################################################
240
241 if [ x$scache = xyes ] ; then
242         cat <<EOF
243
244 static void
245 engine_resume_full (SIM_DESC sd)
246 {
247 #define FAST_P 0
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;}
252
253 EOF
254
255 # Any initialization code before looping starts.
256 # Note that this code may declare some locals.
257 ${SHELL} $file init
258
259 if [ x$parallel = xyes ] ; then
260 cat << EOF
261
262 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
263   {
264     static read_init_p = 0;
265     if (! read_init_p)
266       {
267 /* ??? Later maybe paste read.c in when building mainloop.c.  */
268 #define DEFINE_LABELS
269 #include "readx.c"
270         read_init_p = 1;
271       }
272   }
273 #endif
274
275 EOF
276 fi
277
278 cat <<EOF
279
280   do
281     {
282       /* FIXME: Later check every insn for events and such.  */
283
284       SIM_PRE_EXEC_HOOK (current_cpu);
285
286       {
287         unsigned int hash;
288         SCACHE *sc;
289         PCADDR pc = PC;
290
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;
294
295         /* If the entry isn't the one we want (cache miss),
296            fetch and decode the instruction.  */
297         if (sc->argbuf.addr != pc)
298           {
299             insn_t insn;
300
301             PROFILE_COUNT_SCACHE_MISS (current_cpu);
302
303 /* begin full-extract-scache */
304 EOF
305
306 ${SHELL} $file full-extract-scache
307
308 cat <<EOF
309 /* end full-extract-scache */
310           }
311         else
312           {
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);
317           }
318
319 /* begin full-exec-scache */
320 EOF
321
322 ${SHELL} $file full-exec-scache
323
324 cat <<EOF
325 /* end full-exec-scache */
326       }
327
328       SIM_POST_EXEC_HOOK (current_cpu);
329
330       ++insn_count;
331     }
332   while (keep_running);
333 #undef FAST_P
334 }
335 EOF
336
337 ##########################################################################
338
339 else # ! WITH_SCACHE
340         cat <<EOF
341
342 static void
343 engine_resume_full (SIM_DESC sd)
344 {
345 #define FAST_P 0
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;}
351
352 EOF
353
354 # Any initialization code before looping starts.
355 # Note that this code may declare some locals.
356 ${SHELL} $file init
357
358 if [ x$parallel = xyes ] ; then
359 cat << EOF
360
361 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
362   {
363     static read_init_p = 0;
364     if (! read_init_p)
365       {
366 /* ??? Later maybe paste read.c in when building mainloop.c.  */
367 #define DEFINE_LABELS
368 #include "readx.c"
369         read_init_p = 1;
370       }
371   }
372 #endif
373
374 EOF
375 fi
376
377 cat <<EOF
378
379   do
380     {
381       /* FIXME: Later check every insn for events and such.  */
382
383       SIM_PRE_EXEC_HOOK (current_cpu);
384
385       {
386 /* begin full-{extract,exec}-noscache */
387 EOF
388
389 ${SHELL} $file full-extract-noscache
390 echo ""
391 ${SHELL} $file full-exec-noscache
392
393 cat <<EOF
394 /* end full-{extract,exec}-noscache */
395       }
396
397       SIM_POST_EXEC_HOOK (current_cpu);
398
399       ++insn_count;
400     }
401   while (keep_running);
402 #undef FAST_P
403 }
404
405 EOF
406 fi # ! WITH_SCACHE
407
408 ##########################################################################
409
410 if [ x$fast = xyes ] ; then
411     if [ x$scache = xyes ] ; then
412         cat <<EOF
413
414 static void
415 engine_resume_fast (SIM_DESC sd)
416 {
417 #define FAST_P 1
418   SIM_DESC current_state = sd;
419   sim_cpu *current_cpu = STATE_CPU (sd, 0);
420 ${parallel+  int icount = 0;}
421
422 EOF
423
424 # Any initialization code before looping starts.
425 # Note that this code may declare some locals.
426 ${SHELL} $file init
427
428 if [ x$parallel = xyes ] ; then
429 cat << EOF
430
431 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
432   {
433     static read_init_p = 0;
434     if (! read_init_p)
435       {
436 /* ??? Later maybe paste read.c in when building mainloop.c.  */
437 #define DEFINE_LABELS
438 #include "readx.c"
439         read_init_p = 1;
440       }
441   }
442 #endif
443
444 EOF
445 fi
446
447 cat <<EOF
448
449 #if defined (WITH_SEM_SWITCH_FAST) && defined (__GNUC__)
450   {
451     static decode_init_p = 0;
452     if (! decode_init_p)
453       {
454 /* ??? Later maybe paste sem-switch.c in when building mainloop.c.  */
455 #define DEFINE_LABELS
456 #include "sem-switch.c"
457         decode_init_p = 1;
458       }
459   }
460 #endif
461
462   do
463     {
464       {
465         unsigned int hash;
466         SCACHE *sc;
467         PCADDR pc = PC;
468
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;
472
473         /* If the entry isn't the one we want (cache miss),
474            fetch and decode the instruction.  */
475         if (sc->argbuf.addr != pc)
476           {
477             insn_t insn;
478
479 /* begin fast-extract-scache */
480 EOF
481
482 ${SHELL} $file fast-extract-scache
483
484 cat <<EOF
485 /* end fast-extract-scache */
486           }
487
488 /* begin fast-exec-scache */
489 EOF
490
491 ${SHELL} $file fast-exec-scache
492
493 cat <<EOF
494 /* end fast-exec-scache */
495
496       }
497
498       ++insn_count;
499     }
500   while (keep_running);
501 #undef FAST_P
502 }
503
504 EOF
505
506 ##########################################################################
507
508 else # ! WITH_SCACHE
509         cat <<EOF
510
511 static void
512 engine_resume_fast (SIM_DESC sd)
513 {
514 #define FAST_P 1
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;}
520
521 EOF
522
523 # Any initialization code before looping starts.
524 # Note that this code may declare some locals.
525 ${SHELL} $file init
526
527 if [ x$parallel = xyes ] ; then
528 cat << EOF
529
530 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
531   {
532     static read_init_p = 0;
533     if (! read_init_p)
534       {
535 /* ??? Later maybe paste read.c in when building mainloop.c.  */
536 #define DEFINE_LABELS
537 #include "readx.c"
538         read_init_p = 1;
539       }
540   }
541 #endif
542
543 EOF
544 fi
545
546 cat <<EOF
547
548   do
549     {
550 /* begin fast-{extract,exec}-noscache */
551 EOF
552
553 ${SHELL} $file fast-extract-noscache
554 echo ""
555 ${SHELL} $file fast-exec-noscache
556
557 cat <<EOF
558 /* end fast-{extract,exec}-noscache */
559
560       ++insn_count;
561     }
562   while (keep_running);
563 #undef FAST_P
564 }
565
566 EOF
567
568     fi # ! WITH_SCACHE
569 fi # -fast