* sim-engine.c (sim_engine_set_run_state): New function.
[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 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 /* 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 ${parallel+ int icount = 0;}
267
268 EOF
269
270 # Any initialization code before looping starts.
271 # Note that this code may declare some locals.
272 ${SHELL} $file init
273
274 if [ x$parallel = xyes ] ; then
275 cat << EOF
276
277 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
278 {
279 static read_init_p = 0;
280 if (! read_init_p)
281 {
282 /* ??? Later maybe paste read.c in when building mainloop.c. */
283 #define DEFINE_LABELS
284 #include "readx.c"
285 read_init_p = 1;
286 }
287 }
288 #endif
289
290 EOF
291 fi
292
293 cat <<EOF
294
295 do
296 {
297 /* FIXME: Later check every insn for events and such. */
298
299 SIM_PRE_EXEC_HOOK (current_cpu);
300
301 {
302 unsigned int hash;
303 SCACHE *sc;
304 PCADDR pc = PC;
305
306 /* First step: look up current insn in hash table. */
307 hash = SCACHE_HASH_PC (sd, pc);
308 sc = CPU_SCACHE_CACHE (current_cpu) + hash;
309
310 /* If the entry isn't the one we want (cache miss),
311 fetch and decode the instruction. */
312 if (sc->argbuf.addr != pc)
313 {
314 insn_t insn;
315
316 PROFILE_COUNT_SCACHE_MISS (current_cpu);
317
318 /* begin full-extract-scache */
319 EOF
320
321 ${SHELL} $file full-extract-scache
322
323 cat <<EOF
324 /* end full-extract-scache */
325 }
326 else
327 {
328 PROFILE_COUNT_SCACHE_HIT (current_cpu);
329 /* Make core access statistics come out right.
330 The size is a guess, but it's currently not used either. */
331 PROFILE_COUNT_CORE (current_cpu, pc, 2, exec_map);
332 }
333
334 /* begin full-exec-scache */
335 EOF
336
337 ${SHELL} $file full-exec-scache
338
339 cat <<EOF
340 /* end full-exec-scache */
341 }
342
343 SIM_POST_EXEC_HOOK (current_cpu);
344
345 ++insn_count;
346 }
347 while (keep_running);
348 #undef FAST_P
349 }
350 EOF
351
352 ##########################################################################
353
354 else # ! WITH_SCACHE
355 cat <<EOF
356
357 static void
358 engine_resume_full (SIM_DESC sd)
359 {
360 #define FAST_P 0
361 SIM_DESC current_state = sd;
362 sim_cpu *current_cpu = STATE_CPU (sd, 0);
363 SCACHE cache[MAX_LIW_INSNS];
364 SCACHE *sc = &cache[0];
365 ${parallel+ int icount = 0;}
366
367 EOF
368
369 # Any initialization code before looping starts.
370 # Note that this code may declare some locals.
371 ${SHELL} $file init
372
373 if [ x$parallel = xyes ] ; then
374 cat << EOF
375
376 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
377 {
378 static read_init_p = 0;
379 if (! read_init_p)
380 {
381 /* ??? Later maybe paste read.c in when building mainloop.c. */
382 #define DEFINE_LABELS
383 #include "readx.c"
384 read_init_p = 1;
385 }
386 }
387 #endif
388
389 EOF
390 fi
391
392 cat <<EOF
393
394 do
395 {
396 /* FIXME: Later check every insn for events and such. */
397
398 SIM_PRE_EXEC_HOOK (current_cpu);
399
400 {
401 /* begin full-{extract,exec}-noscache */
402 EOF
403
404 ${SHELL} $file full-extract-noscache
405 echo ""
406 ${SHELL} $file full-exec-noscache
407
408 cat <<EOF
409 /* end full-{extract,exec}-noscache */
410 }
411
412 SIM_POST_EXEC_HOOK (current_cpu);
413
414 ++insn_count;
415 }
416 while (keep_running);
417 #undef FAST_P
418 }
419
420 EOF
421 fi # ! WITH_SCACHE
422
423 ##########################################################################
424
425 if [ x$fast = xyes ] ; then
426 if [ x$scache = xyes ] ; then
427 cat <<EOF
428
429 static void
430 engine_resume_fast (SIM_DESC sd)
431 {
432 #define FAST_P 1
433 SIM_DESC current_state = sd;
434 sim_cpu *current_cpu = STATE_CPU (sd, 0);
435 ${parallel+ int icount = 0;}
436
437 EOF
438
439 # Any initialization code before looping starts.
440 # Note that this code may declare some locals.
441 ${SHELL} $file init
442
443 if [ x$parallel = xyes ] ; then
444 cat << EOF
445
446 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
447 {
448 static read_init_p = 0;
449 if (! read_init_p)
450 {
451 /* ??? Later maybe paste read.c in when building mainloop.c. */
452 #define DEFINE_LABELS
453 #include "readx.c"
454 read_init_p = 1;
455 }
456 }
457 #endif
458
459 EOF
460 fi
461
462 cat <<EOF
463
464 #if defined (WITH_SEM_SWITCH_FAST) && defined (__GNUC__)
465 {
466 static decode_init_p = 0;
467 if (! decode_init_p)
468 {
469 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
470 #define DEFINE_LABELS
471 #include "sem-switch.c"
472 decode_init_p = 1;
473 }
474 }
475 #endif
476
477 do
478 {
479 {
480 unsigned int hash;
481 SCACHE *sc;
482 PCADDR pc = PC;
483
484 /* First step: look up current insn in hash table. */
485 hash = SCACHE_HASH_PC (sd, pc);
486 sc = CPU_SCACHE_CACHE (current_cpu) + hash;
487
488 /* If the entry isn't the one we want (cache miss),
489 fetch and decode the instruction. */
490 if (sc->argbuf.addr != pc)
491 {
492 insn_t insn;
493
494 /* begin fast-extract-scache */
495 EOF
496
497 ${SHELL} $file fast-extract-scache
498
499 cat <<EOF
500 /* end fast-extract-scache */
501 }
502
503 /* begin fast-exec-scache */
504 EOF
505
506 ${SHELL} $file fast-exec-scache
507
508 cat <<EOF
509 /* end fast-exec-scache */
510
511 }
512
513 ++insn_count;
514 }
515 while (keep_running);
516 #undef FAST_P
517 }
518
519 EOF
520
521 ##########################################################################
522
523 else # ! WITH_SCACHE
524 cat <<EOF
525
526 static void
527 engine_resume_fast (SIM_DESC sd)
528 {
529 #define FAST_P 1
530 SIM_DESC current_state = sd;
531 sim_cpu *current_cpu = STATE_CPU (sd, 0);
532 SCACHE cache[MAX_LIW_INSNS];
533 SCACHE *sc = &cache[0];
534 ${parallel+ int icount = 0;}
535
536 EOF
537
538 # Any initialization code before looping starts.
539 # Note that this code may declare some locals.
540 ${SHELL} $file init
541
542 if [ x$parallel = xyes ] ; then
543 cat << EOF
544
545 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
546 {
547 static read_init_p = 0;
548 if (! read_init_p)
549 {
550 /* ??? Later maybe paste read.c in when building mainloop.c. */
551 #define DEFINE_LABELS
552 #include "readx.c"
553 read_init_p = 1;
554 }
555 }
556 #endif
557
558 EOF
559 fi
560
561 cat <<EOF
562
563 do
564 {
565 /* begin fast-{extract,exec}-noscache */
566 EOF
567
568 ${SHELL} $file fast-extract-noscache
569 echo ""
570 ${SHELL} $file fast-exec-noscache
571
572 cat <<EOF
573 /* end fast-{extract,exec}-noscache */
574
575 ++insn_count;
576 }
577 while (keep_running);
578 #undef FAST_P
579 }
580
581 EOF
582
583 fi # ! WITH_SCACHE
584 fi # -fast