* genmloop.sh (@cpu@_engine_run): Delete `current_state'.
[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 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 engine->jmpbuf = NULL;
192 TRACE_INSN_FINI ((sim_cpu *) cpu);
193 PROFILE_EXEC_TIME (CPU_PROFILE_DATA (cpu))
194 += sim_elapsed_time_since (start_time);
195 PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu))
196 += insn_count;
197 return;
198 }
199
200 /* ??? Restart support to be added in time. */
201
202 /* The computed goto switch can be used, and while the number of blocks
203 may swamp the relatively few that this function contains, when running
204 with the scache we put the actual semantic code in their own
205 functions. */
206
207 EOF
208
209 if [ x$fast = xyes ] ; then
210 cat <<EOF
211 if (step
212 || !RUN_FAST_P (current_cpu))
213 engine_resume_full (sd);
214 else
215 engine_resume_fast (sd);
216 EOF
217 else
218 cat <<EOF
219 engine_resume_full (sd);
220 EOF
221 fi
222
223 cat <<EOF
224
225 /* If the loop exits, either we single-stepped or engine_stop was called.
226 In either case we need to call engine_halt: to properly exit this
227 function we must go through the setjmp executed above. */
228 if (step)
229 sim_engine_halt (sd, current_cpu, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP);
230 sim_engine_halt (sd, current_cpu, NULL, NULL_CIA, sim_stopped, SIM_SIGINT);
231 }
232
233 EOF
234
235 if [ x$scache = xyes ] ; then
236 cat <<EOF
237
238 static void
239 engine_resume_full (SIM_DESC sd)
240 {
241 #define FAST_P 0
242 /* current_{state,cpu} exist for the generated code to use. */
243 SIM_DESC current_state = sd;
244 sim_cpu *current_cpu = STATE_CPU (sd, 0);
245 ${parallel+ int icount = 0;}
246
247 EOF
248
249 # Any initialization code before looping starts.
250 ${SHELL} $file init
251
252 cat <<EOF
253
254 do
255 {
256 /* FIXME: Later check every insn for events and such. */
257
258 SIM_PRE_EXEC_HOOK (current_cpu);
259
260 {
261 unsigned int hash;
262 SCACHE *sc;
263 PCADDR pc = PC;
264
265 /* First step: look up current insn in hash table. */
266 hash = SCACHE_HASH_PC (sd, pc);
267 sc = CPU_SCACHE_CACHE (current_cpu) + hash;
268
269 /* If the entry isn't the one we want (cache miss),
270 fetch and decode the instruction. */
271 if (sc->argbuf.addr != pc)
272 {
273 insn_t insn;
274
275 PROFILE_COUNT_SCACHE_MISS (current_cpu);
276
277 /* begin full-extract-scache */
278 EOF
279
280 ${SHELL} $file full-extract-scache
281
282 cat <<EOF
283 /* end full-extract-scache */
284 }
285 else
286 {
287 PROFILE_COUNT_SCACHE_HIT (current_cpu);
288 }
289
290 /* begin full-exec-scache */
291 EOF
292
293 ${SHELL} $file full-exec-scache
294
295 cat <<EOF
296 /* end full-exec-scache */
297 }
298
299 SIM_POST_EXEC_HOOK (current_cpu);
300
301 ++insn_count;
302 }
303 while (keep_running);
304 #undef FAST_P
305 }
306 EOF
307
308 else # ! WITH_SCACHE
309 cat <<EOF
310
311 static void
312 engine_resume_full (SIM_DESC sd)
313 {
314 #define FAST_P 0
315 SIM_DESC current_state = sd;
316 sim_cpu *current_cpu = STATE_CPU (sd, 0);
317 SCACHE cache[MAX_LIW_INSNS];
318 SCACHE *sc = &cache[0];
319 ${parallel+ int icount = 0;}
320
321 EOF
322
323 # Any initialization code before looping starts.
324 ${SHELL} $file init
325
326 cat <<EOF
327
328 do
329 {
330 /* FIXME: Later check every insn for events and such. */
331
332 SIM_PRE_EXEC_HOOK (current_cpu);
333
334 {
335 /* begin full-{extract,exec}-noscache */
336 EOF
337
338 ${SHELL} $file full-extract-noscache
339 echo ""
340 ${SHELL} $file full-exec-noscache
341
342 cat <<EOF
343 /* end full-{extract,exec}-noscache */
344 }
345
346 SIM_POST_EXEC_HOOK (current_cpu);
347
348 ++insn_count;
349 }
350 while (keep_running);
351 #undef FAST_P
352 }
353
354 EOF
355 fi # ! WITH_SCACHE
356
357 if [ x$fast = xyes ] ; then
358 if [ x$scache = xyes ] ; then
359 cat <<EOF
360
361 static void
362 engine_resume_fast (SIM_DESC sd)
363 {
364 #define FAST_P 1
365 SIM_DESC current_state = sd;
366 sim_cpu *current_cpu = STATE_CPU (sd, 0);
367 ${parallel+ int icount = 0;}
368
369 EOF
370
371 # Any initialization code before looping starts.
372 ${SHELL} $file init
373
374 cat <<EOF
375
376 #if defined (WITH_SEM_SWITCH_FAST) && defined (__GNUC__)
377 {
378 static decode_init_p = 0;
379 if (! decode_init_p)
380 {
381 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
382 #define DEFINE_LABELS
383 #include "sem-switch.c"
384 decode_init_p = 1;
385 }
386 }
387 #endif
388
389 do
390 {
391 {
392 unsigned int hash;
393 SCACHE *sc;
394 PCADDR pc = PC;
395
396 /* First step: look up current insn in hash table. */
397 hash = SCACHE_HASH_PC (sd, pc);
398 sc = CPU_SCACHE_CACHE (current_cpu) + hash;
399
400 /* If the entry isn't the one we want (cache miss),
401 fetch and decode the instruction. */
402 if (sc->argbuf.addr != pc)
403 {
404 insn_t insn;
405
406 /* begin fast-extract-scache */
407 EOF
408
409 ${SHELL} $file fast-extract-scache
410
411 cat <<EOF
412 /* end fast-extract-scache */
413 }
414
415 /* begin fast-exec-scache */
416 EOF
417
418 ${SHELL} $file fast-exec-scache
419
420 cat <<EOF
421 /* end fast-exec-scache */
422
423 }
424
425 ++insn_count;
426 }
427 while (keep_running);
428 #undef FAST_P
429 }
430
431 EOF
432
433 else # ! WITH_SCACHE
434 cat <<EOF
435
436 static void
437 engine_resume_fast (SIM_DESC sd)
438 {
439 #define FAST_P 1
440 SIM_DESC current_state = sd;
441 sim_cpu *current_cpu = STATE_CPU (sd, 0);
442 SCACHE cache[MAX_LIW_INSNS];
443 SCACHE *sc = &cache[0];
444 ${parallel+ int icount = 0;}
445
446 EOF
447
448 # Any initialization code before looping starts.
449 ${SHELL} $file init
450
451 cat <<EOF
452
453 do
454 {
455 /* begin fast-{extract,exec}-noscache */
456 EOF
457
458 ${SHELL} $file fast-extract-noscache
459 echo ""
460 ${SHELL} $file fast-exec-noscache
461
462 cat <<EOF
463 /* end fast-{extract,exec}-noscache */
464
465 ++insn_count;
466 }
467 while (keep_running);
468 #undef FAST_P
469 }
470
471 EOF
472
473 fi # ! WITH_SCACHE
474 fi # -fast