* Make-common.in (SCHEME,SCHEMEFLAGS): Delete.
[binutils-gdb.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