Commit | Line | Data |
---|---|---|
b9c8cd10 DE |
1 | # This shell script emits a C file. -*- C -*- |
2 | # Generate the main loop of the simulator. | |
dde54cb8 DE |
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 | # | |
b9c8cd10 DE |
10 | # FIXME: "multi" support is wip. |
11 | ||
dde54cb8 DE |
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 | |
b9c8cd10 DE |
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. | |
b500809f | 51 | Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. |
b9c8cd10 DE |
52 | Contributed by Cygnus Support. |
53 | ||
dde54cb8 | 54 | This file is part of the GNU simulators. |
b9c8cd10 DE |
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 | ||
dde54cb8 DE |
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@ | |
b9c8cd10 DE |
86 | |
87 | #include "sim-main.h" | |
88 | #include "bfd.h" | |
dde54cb8 DE |
89 | #include "cgen-mem.h" |
90 | #include "cgen-ops.h" | |
b9c8cd10 DE |
91 | #include "cpu-opc.h" |
92 | #include "cpu-sim.h" | |
dde54cb8 | 93 | #include "sim-assert.h" |
b9c8cd10 | 94 | |
6de2add2 | 95 | /* Tell sim_main_loop to use the scache if it's active. |
b9c8cd10 DE |
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: | |
6de2add2 | 99 | - use or don't use the scache |
b9c8cd10 DE |
100 | - run normally (full featured) or run fast |
101 | Supporting all four possibilities in one executable is a bit much but | |
dde54cb8 | 102 | supporting full/fast seems reasonable. |
6de2add2 | 103 | If the scache is configured in it is always used. |
b9c8cd10 DE |
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 | ||
dde54cb8 DE |
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 | ||
b9c8cd10 DE |
138 | EOF |
139 | ||
140 | ${SHELL} $file support | |
141 | ||
142 | cat <<EOF | |
143 | ||
144 | static volatile int keep_running; | |
ebd58f4d DE |
145 | /* FIXME: Should each cpu have its own copy? */ |
146 | static volatile enum sim_stop pending_reason; | |
147 | static volatile int pending_sigrc; | |
148 | ||
dde54cb8 DE |
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);} | |
b9c8cd10 | 157 | |
ebd58f4d DE |
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 | ||
b9c8cd10 | 162 | int |
ebd58f4d DE |
163 | @cpu@_engine_stop (SIM_DESC sd, SIM_CPU *cpu, PCADDR pc, |
164 | enum sim_stop reason, int sigrc) | |
b9c8cd10 DE |
165 | { |
166 | keep_running = 0; | |
ebd58f4d DE |
167 | pending_reason = reason; |
168 | pending_sigrc = sigrc; | |
b9c8cd10 DE |
169 | return 1; |
170 | } | |
171 | ||
172 | void | |
dde54cb8 | 173 | @cpu@_engine_run (SIM_DESC sd, int step, int siggnal) |
b9c8cd10 | 174 | { |
b9c8cd10 DE |
175 | #if WITH_SCACHE |
176 | if (USING_SCACHE_P (sd)) | |
177 | scache_flush (sd); | |
178 | #endif | |
179 | engine_resume (sd, step, siggnal); | |
180 | } | |
181 | ||
dde54cb8 | 182 | static void |
b9c8cd10 DE |
183 | engine_resume (SIM_DESC sd, int step, int siggnal) |
184 | { | |
b9c8cd10 | 185 | sim_cpu *current_cpu = STATE_CPU (sd, 0); |
dde54cb8 DE |
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; | |
b9c8cd10 | 191 | |
dde54cb8 | 192 | keep_running = ! step; |
b9c8cd10 | 193 | start_time = sim_elapsed_time_get (); |
dde54cb8 DE |
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. */ | |
b9c8cd10 DE |
197 | insn_count = 0; |
198 | ||
dde54cb8 | 199 | engine->jmpbuf = &buf; |
ebd58f4d DE |
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 | ||
dde54cb8 | 206 | if (setjmp (buf)) |
b9c8cd10 | 207 | { |
b500809f DE |
208 | /* Account for the last insn executed. */ |
209 | ++insn_count; | |
bcb829fd | 210 | TRACE_INSN_FINI ((sim_cpu *) cpu, 1); |
b9c8cd10 | 211 | } |
ebd58f4d DE |
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. */ | |
dde54cb8 DE |
218 | |
219 | EOF | |
220 | ||
221 | if [ x$fast = xyes ] ; then | |
222 | cat <<EOF | |
ebd58f4d DE |
223 | if (step |
224 | || !RUN_FAST_P (current_cpu)) | |
225 | engine_resume_full (sd); | |
226 | else | |
227 | engine_resume_fast (sd); | |
dde54cb8 DE |
228 | EOF |
229 | else | |
230 | cat <<EOF | |
ebd58f4d | 231 | engine_resume_full (sd); |
dde54cb8 DE |
232 | EOF |
233 | fi | |
234 | ||
235 | cat <<EOF | |
236 | ||
ebd58f4d DE |
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; | |
dde54cb8 DE |
250 | } |
251 | ||
252 | EOF | |
253 | ||
b500809f DE |
254 | ########################################################################## |
255 | ||
dde54cb8 DE |
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); | |
dde54cb8 | 266 | |
b9c8cd10 DE |
267 | EOF |
268 | ||
269 | # Any initialization code before looping starts. | |
b500809f | 270 | # Note that this code may declare some locals. |
b9c8cd10 DE |
271 | ${SHELL} $file init |
272 | ||
b500809f DE |
273 | if [ x$parallel = xyes ] ; then |
274 | cat << EOF | |
275 | ||
276 | #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__) | |
277 | { | |
6de2add2 | 278 | if (! CPU_IDESC_READ_INIT_P (current_cpu)) |
b500809f DE |
279 | { |
280 | /* ??? Later maybe paste read.c in when building mainloop.c. */ | |
281 | #define DEFINE_LABELS | |
282 | #include "readx.c" | |
6de2add2 | 283 | CPU_IDESC_READ_INIT_P (current_cpu) = 1; |
b500809f DE |
284 | } |
285 | } | |
286 | #endif | |
287 | ||
288 | EOF | |
289 | fi | |
290 | ||
b9c8cd10 DE |
291 | cat <<EOF |
292 | ||
dde54cb8 DE |
293 | do |
294 | { | |
295 | /* FIXME: Later check every insn for events and such. */ | |
b9c8cd10 | 296 | |
dde54cb8 DE |
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); | |
b500809f DE |
327 | /* Make core access statistics come out right. |
328 | The size is a guess, but it's currently not used either. */ | |
bcb829fd | 329 | PROFILE_COUNT_CORE (current_cpu, pc, 2, exec_map); |
dde54cb8 DE |
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 | ||
b500809f DE |
350 | ########################################################################## |
351 | ||
dde54cb8 DE |
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]; | |
dde54cb8 DE |
363 | |
364 | EOF | |
365 | ||
366 | # Any initialization code before looping starts. | |
b500809f | 367 | # Note that this code may declare some locals. |
dde54cb8 DE |
368 | ${SHELL} $file init |
369 | ||
b500809f DE |
370 | if [ x$parallel = xyes ] ; then |
371 | cat << EOF | |
372 | ||
373 | #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__) | |
374 | { | |
6de2add2 | 375 | if (! CPU_IDESC_READ_INIT_P (current_cpu)) |
b500809f DE |
376 | { |
377 | /* ??? Later maybe paste read.c in when building mainloop.c. */ | |
378 | #define DEFINE_LABELS | |
379 | #include "readx.c" | |
6de2add2 | 380 | CPU_IDESC_READ_INIT_P (current_cpu) = 1; |
b500809f DE |
381 | } |
382 | } | |
383 | #endif | |
384 | ||
385 | EOF | |
386 | fi | |
387 | ||
dde54cb8 DE |
388 | cat <<EOF |
389 | ||
390 | do | |
b9c8cd10 | 391 | { |
dde54cb8 | 392 | /* FIXME: Later check every insn for events and such. */ |
b9c8cd10 | 393 | |
dde54cb8 | 394 | SIM_PRE_EXEC_HOOK (current_cpu); |
b9c8cd10 | 395 | |
dde54cb8 DE |
396 | { |
397 | /* begin full-{extract,exec}-noscache */ | |
b9c8cd10 DE |
398 | EOF |
399 | ||
dde54cb8 DE |
400 | ${SHELL} $file full-extract-noscache |
401 | echo "" | |
402 | ${SHELL} $file full-exec-noscache | |
b9c8cd10 DE |
403 | |
404 | cat <<EOF | |
dde54cb8 DE |
405 | /* end full-{extract,exec}-noscache */ |
406 | } | |
b9c8cd10 | 407 | |
dde54cb8 | 408 | SIM_POST_EXEC_HOOK (current_cpu); |
b9c8cd10 | 409 | |
dde54cb8 | 410 | ++insn_count; |
b9c8cd10 | 411 | } |
dde54cb8 DE |
412 | while (keep_running); |
413 | #undef FAST_P | |
414 | } | |
415 | ||
416 | EOF | |
417 | fi # ! WITH_SCACHE | |
418 | ||
b500809f DE |
419 | ########################################################################## |
420 | ||
dde54cb8 DE |
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); | |
dde54cb8 DE |
431 | |
432 | EOF | |
433 | ||
434 | # Any initialization code before looping starts. | |
b500809f | 435 | # Note that this code may declare some locals. |
dde54cb8 DE |
436 | ${SHELL} $file init |
437 | ||
b500809f DE |
438 | if [ x$parallel = xyes ] ; then |
439 | cat << EOF | |
440 | ||
441 | #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__) | |
442 | { | |
6de2add2 | 443 | if (! CPU_IDESC_READ_INIT_P (current_cpu)) |
b500809f DE |
444 | { |
445 | /* ??? Later maybe paste read.c in when building mainloop.c. */ | |
446 | #define DEFINE_LABELS | |
447 | #include "readx.c" | |
6de2add2 | 448 | CPU_IDESC_READ_INIT_P (current_cpu) = 1; |
b500809f DE |
449 | } |
450 | } | |
451 | #endif | |
452 | ||
453 | EOF | |
454 | fi | |
455 | ||
dde54cb8 DE |
456 | cat <<EOF |
457 | ||
458 | #if defined (WITH_SEM_SWITCH_FAST) && defined (__GNUC__) | |
459 | { | |
6de2add2 | 460 | if (! CPU_IDESC_SEM_INIT_P (current_cpu)) |
dde54cb8 DE |
461 | { |
462 | /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */ | |
463 | #define DEFINE_LABELS | |
464 | #include "sem-switch.c" | |
6de2add2 | 465 | CPU_IDESC_SEM_INIT_P (current_cpu) = 1; |
dde54cb8 DE |
466 | } |
467 | } | |
468 | #endif | |
469 | ||
470 | do | |
b9c8cd10 | 471 | { |
dde54cb8 DE |
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 | ||
b500809f DE |
514 | ########################################################################## |
515 | ||
dde54cb8 DE |
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]; | |
b9c8cd10 DE |
527 | |
528 | EOF | |
529 | ||
dde54cb8 | 530 | # Any initialization code before looping starts. |
b500809f | 531 | # Note that this code may declare some locals. |
dde54cb8 | 532 | ${SHELL} $file init |
b9c8cd10 | 533 | |
b500809f DE |
534 | if [ x$parallel = xyes ] ; then |
535 | cat << EOF | |
536 | ||
537 | #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__) | |
538 | { | |
6de2add2 | 539 | if (! CPU_IDESC_READ_INIT_P (current_cpu)) |
b500809f DE |
540 | { |
541 | /* ??? Later maybe paste read.c in when building mainloop.c. */ | |
542 | #define DEFINE_LABELS | |
543 | #include "readx.c" | |
6de2add2 | 544 | CPU_IDESC_READ_INIT_P (current_cpu) = 1; |
b500809f DE |
545 | } |
546 | } | |
547 | #endif | |
548 | ||
549 | EOF | |
550 | fi | |
551 | ||
b9c8cd10 DE |
552 | cat <<EOF |
553 | ||
dde54cb8 DE |
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; | |
b9c8cd10 | 567 | } |
dde54cb8 DE |
568 | while (keep_running); |
569 | #undef FAST_P | |
b9c8cd10 | 570 | } |
dde54cb8 | 571 | |
b9c8cd10 | 572 | EOF |
dde54cb8 DE |
573 | |
574 | fi # ! WITH_SCACHE | |
575 | fi # -fast |