]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/common/genmloop.sh
* genmloop.sh (engine_resume): Update insn_count before exiting.
[thirdparty/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 /* 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