sim: reorder header includes
[binutils-gdb.git] / sim / common / genmloop.sh
1 # Generate the main loop of the simulator.
2 # Copyright (C) 1996-2021 Free Software Foundation, Inc.
3 # Contributed by Cygnus Support.
4 #
5 # This file is part of the GNU simulators.
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #
20 # This file creates two files: eng.hin and mloop.cin.
21 # eng.hin defines a few macros that specify what kind of engine was selected
22 # based on the arguments to this script.
23 # mloop.cin contains the engine.
24 #
25 # ??? Rename mloop.c to eng.c?
26 # ??? Rename mainloop.in to engine.in?
27 # ??? Add options to specify output file names?
28 # ??? Rename this file to genengine.sh?
29 #
30 # Syntax: genmloop.sh [options]
31 #
32 # Options:
33 #
34 # -mono | -multi
35 # - specify single cpu or multiple cpus (number specifyable at runtime),
36 # maximum number is a configuration parameter
37 # - -multi wip
38 #
39 # -fast: include support for fast execution in addition to full featured mode
40 #
41 # Full featured mode is for tracing, profiling, etc. and is always
42 # provided. Fast mode contains no frills, except speed.
43 # A target need only provide a "full" version of one of
44 # simple,scache,pbb. If the target wants it can also provide a fast
45 # version of same. It can't provide more than this.
46 # ??? Later add ability to have another set of full/fast semantics
47 # for use in with-devices/with-smp situations (pbb can be inappropriate
48 # here).
49 #
50 # -full-switch: same as -fast but for full featured version of -switch
51 # Only needed if -fast present.
52 #
53 # -simple: simple execution engine (the default)
54 #
55 # This engine fetches and executes one instruction at a time.
56 # Field extraction is done in the semantic routines.
57 #
58 # ??? There are two possible flavours of -simple. One that extracts
59 # fields in the semantic routine (which is what is implemented here),
60 # and one that stores the extracted fields in ARGBUF before calling the
61 # semantic routine. The latter is essentially the -scache case with a
62 # cache size of one (and the scache lookup code removed). There are no
63 # current uses of this and it's not clear when doing this would be a win.
64 # More complicated ISA's that want to use -simple may find this a win.
65 # Should this ever be desirable, implement a new engine style here and
66 # call it -extract (or some such). It's believed that the CGEN-generated
67 # code for the -scache case would be usable here, so no new code
68 # generation option would be needed for CGEN.
69 #
70 # -scache: use the scache to speed things up (not always a win)
71 #
72 # This engine caches the extracted instruction before executing it.
73 # When executing instructions they are first looked up in the scache.
74 #
75 # -pbb: same as -scache but extract a (pseudo-) basic block at a time
76 #
77 # This engine is basically identical to the scache version except that
78 # extraction is done a pseudo-basic-block at a time and the address of
79 # the scache entry of a branch target is recorded as well.
80 # Additional speedups are then possible by defering Ctrl-C checking
81 # to the end of basic blocks and by threading the insns together.
82 # We call them pseudo-basic-block's instead of just basic-blocks because
83 # they're not necessarily basic-blocks, though normally are.
84 #
85 # -parallel-read: support parallel execution with read-before-exec support.
86 # -parallel-write: support parallel execution with write-after-exec support.
87 # -parallel-generic-write: support parallel execution with generic queued
88 # writes.
89 #
90 # One of these options is specified in addition to -simple, -scache,
91 # -pbb. Note that while the code can determine if the cpu supports
92 # parallel execution with HAVE_PARALLEL_INSNS [and thus this option is
93 # technically unnecessary], having this option cuts down on the clutter
94 # in the result.
95 #
96 # -parallel-only: semantic code only supports parallel version of insn
97 #
98 # Semantic code only supports parallel versions of each insn.
99 # Things can be sped up by generating both serial and parallel versions
100 # and is better suited to mixed parallel architectures like the m32r.
101 #
102 # -prefix: string to prepend to function names in mloop.c/eng.h.
103 #
104 # If no prefix is specified, the cpu type is used.
105 #
106 # -switch file: specify file containing semantics implemented as a switch()
107 #
108 # -cpu <cpu-family>
109 #
110 # Specify the cpu family name.
111 #
112 # -infile <input-file>
113 #
114 # Specify the mainloop.in input file.
115 #
116 # -outfile-suffix <output-file-suffix>
117 #
118 # Specify the suffix to append to output files.
119 #
120 # -shell <shell>
121 #
122 # Specify the shell to use to execute <input-file>
123 #
124 # Only one of -scache/-pbb may be selected.
125 # -simple is the default.
126 #
127 ####
128 #
129 # TODO
130 # - build mainloop.in from .cpu file
131
132 type=mono
133 #scache=
134 #fast=
135 #full_switch=
136 #pbb=
137 parallel=no
138 parallel_only=no
139 switch=
140 cpu="unknown"
141 infile=""
142 prefix="unknown"
143 outprefix=""
144 outsuffix=""
145
146 while test $# -gt 0
147 do
148 case $1 in
149 -mono) type=mono ;;
150 -multi) type=multi ;;
151 -no-fast) ;;
152 -fast) fast=yes ;;
153 -full-switch) full_switch=yes ;;
154 -simple) ;;
155 -scache) scache=yes ;;
156 -pbb) pbb=yes ;;
157 -no-parallel) ;;
158 -outfile-prefix) shift ; outprefix=$1 ;;
159 -outfile-suffix) shift ; outsuffix=$1 ;;
160 -parallel-read) parallel=read ;;
161 -parallel-write) parallel=write ;;
162 -parallel-generic-write) parallel=genwrite ;;
163 -parallel-only) parallel_only=yes ;;
164 -prefix) shift ; prefix=$1 ;;
165 -switch) shift ; switch=$1 ;;
166 -cpu) shift ; cpu=$1 ;;
167 -infile) shift ; infile=$1 ;;
168 -shell) shift ; SHELL=$1 ;;
169 *) echo "unknown option: $1" >&2 ; exit 1 ;;
170 esac
171 shift
172 done
173
174 # Argument validation.
175
176 if [ x$scache = xyes -a x$pbb = xyes ] ; then
177 echo "only one of -scache and -pbb may be selected" >&2
178 exit 1
179 fi
180
181 if [ "x$cpu" = xunknown ] ; then
182 echo "cpu family not specified" >&2
183 exit 1
184 fi
185
186 if [ "x$infile" = x ] ; then
187 echo "mainloop.in not specified" >&2
188 exit 1
189 fi
190
191 if [ "x$prefix" = xunknown ] ; then
192 prefix=$cpu
193 fi
194
195 lowercase='abcdefghijklmnopqrstuvwxyz'
196 uppercase='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
197 CPU=`echo ${cpu} | tr "${lowercase}" "${uppercase}"`
198 PREFIX=`echo ${prefix} | tr "${lowercase}" "${uppercase}"`
199
200 ##########################################################################
201
202 rm -f ${outprefix}eng${outsuffix}.hin
203 exec 1>${outprefix}eng${outsuffix}.hin
204
205 echo "/* engine configuration for ${cpu} */"
206 echo ""
207
208 echo "/* WITH_FAST: non-zero if a fast version of the engine is available"
209 echo " in addition to the full-featured version. */"
210 if [ x$fast = xyes ] ; then
211 echo "#define WITH_FAST 1"
212 else
213 echo "#define WITH_FAST 0"
214 fi
215
216 echo ""
217 echo "/* WITH_SCACHE_PBB_${PREFIX}: non-zero if the pbb engine was selected. */"
218 if [ x$pbb = xyes ] ; then
219 echo "#define WITH_SCACHE_PBB_${PREFIX} 1"
220 else
221 echo "#define WITH_SCACHE_PBB_${PREFIX} 0"
222 fi
223
224 echo ""
225 echo "/* HAVE_PARALLEL_INSNS: non-zero if cpu can parallelly execute > 1 insn. */"
226 # blah blah blah, other ways to do this, blah blah blah
227 case x$parallel in
228 xno)
229 echo "#define HAVE_PARALLEL_INSNS 0"
230 echo "#define WITH_PARALLEL_READ 0"
231 echo "#define WITH_PARALLEL_WRITE 0"
232 echo "#define WITH_PARALLEL_GENWRITE 0"
233 ;;
234 xread)
235 echo "#define HAVE_PARALLEL_INSNS 1"
236 echo "/* Parallel execution is supported by read-before-exec. */"
237 echo "#define WITH_PARALLEL_READ 1"
238 echo "#define WITH_PARALLEL_WRITE 0"
239 echo "#define WITH_PARALLEL_GENWRITE 0"
240 ;;
241 xwrite)
242 echo "#define HAVE_PARALLEL_INSNS 1"
243 echo "/* Parallel execution is supported by write-after-exec. */"
244 echo "#define WITH_PARALLEL_READ 0"
245 echo "#define WITH_PARALLEL_WRITE 1"
246 echo "#define WITH_PARALLEL_GENWRITE 0"
247 ;;
248 xgenwrite)
249 echo "#define HAVE_PARALLEL_INSNS 1"
250 echo "/* Parallel execution is supported by generic write-after-exec. */"
251 echo "#define WITH_PARALLEL_READ 0"
252 echo "#define WITH_PARALLEL_WRITE 0"
253 echo "#define WITH_PARALLEL_GENWRITE 1"
254 ;;
255 esac
256
257 if [ "x$switch" != x ] ; then
258 echo ""
259 echo "/* WITH_SEM_SWITCH_FULL: non-zero if full-featured engine is"
260 echo " implemented as a switch(). */"
261 if [ x$fast != xyes -o x$full_switch = xyes ] ; then
262 echo "#define WITH_SEM_SWITCH_FULL 1"
263 else
264 echo "#define WITH_SEM_SWITCH_FULL 0"
265 fi
266 echo ""
267 echo "/* WITH_SEM_SWITCH_FAST: non-zero if fast engine is"
268 echo " implemented as a switch(). */"
269 if [ x$fast = xyes ] ; then
270 echo "#define WITH_SEM_SWITCH_FAST 1"
271 else
272 echo "#define WITH_SEM_SWITCH_FAST 0"
273 fi
274 fi
275
276 # Decls of functions we define.
277
278 echo ""
279 echo "/* Functions defined in the generated mainloop.c file"
280 echo " (which doesn't necessarily have that file name). */"
281 echo ""
282 echo "extern ENGINE_FN ${prefix}_engine_run_full;"
283 echo "extern ENGINE_FN ${prefix}_engine_run_fast;"
284
285 if [ x$pbb = xyes ] ; then
286 echo ""
287 echo "extern SEM_PC ${prefix}_pbb_begin (SIM_CPU *, int);"
288 echo "extern SEM_PC ${prefix}_pbb_chain (SIM_CPU *, SEM_ARG);"
289 echo "extern SEM_PC ${prefix}_pbb_cti_chain (SIM_CPU *, SEM_ARG, SEM_BRANCH_TYPE, PCADDR);"
290 echo "extern void ${prefix}_pbb_before (SIM_CPU *, SCACHE *);"
291 echo "extern void ${prefix}_pbb_after (SIM_CPU *, SCACHE *);"
292 fi
293
294 ##########################################################################
295
296 rm -f ${outprefix}tmp-mloop-$$.cin ${outprefix}mloop${outsuffix}.cin
297 exec 1>${outprefix}tmp-mloop-$$.cin
298
299 # We use @cpu@ instead of ${cpu} because we still need to run sed to handle
300 # transformation of @cpu@ for mainloop.in, so there's no need to use ${cpu}
301 # here.
302
303 cat << EOF
304 /* This file is generated by the genmloop script. DO NOT EDIT! */
305
306 /* This must come before any other includes. */
307 #include "defs.h"
308
309 /* Enable switch() support in cgen headers. */
310 #define SEM_IN_SWITCH
311
312 #define WANT_CPU @cpu@
313 #define WANT_CPU_@CPU@
314
315 #include "bfd.h"
316
317 #include "sim-main.h"
318 #include "cgen-mem.h"
319 #include "cgen-ops.h"
320 #include "sim-assert.h"
321
322 /* Fill in the administrative ARGBUF fields required by all insns,
323 virtual and real. */
324
325 static INLINE void
326 @prefix@_fill_argbuf (const SIM_CPU *cpu, ARGBUF *abuf, const IDESC *idesc,
327 PCADDR pc, int fast_p)
328 {
329 #if WITH_SCACHE
330 SEM_SET_CODE (abuf, idesc, fast_p);
331 ARGBUF_ADDR (abuf) = pc;
332 #endif
333 ARGBUF_IDESC (abuf) = idesc;
334 }
335
336 /* Fill in tracing/profiling fields of an ARGBUF. */
337
338 static INLINE void
339 @prefix@_fill_argbuf_tp (const SIM_CPU *cpu, ARGBUF *abuf,
340 int trace_p, int profile_p)
341 {
342 ARGBUF_TRACE_P (abuf) = trace_p;
343 ARGBUF_PROFILE_P (abuf) = profile_p;
344 }
345
346 #if WITH_SCACHE_PBB
347
348 /* Emit the "x-before" handler.
349 x-before is emitted before each insn (serial or parallel).
350 This is as opposed to x-after which is only emitted at the end of a group
351 of parallel insns. */
352
353 ATTRIBUTE_UNUSED static INLINE void
354 @prefix@_emit_before (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc, int first_p)
355 {
356 ARGBUF *abuf = &sc[0].argbuf;
357 const IDESC *id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEFORE];
358
359 abuf->fields.before.first_p = first_p;
360 @prefix@_fill_argbuf (current_cpu, abuf, id, pc, 0);
361 /* no need to set trace_p,profile_p */
362 }
363
364 /* Emit the "x-after" handler.
365 x-after is emitted after a serial insn or at the end of a group of
366 parallel insns. */
367
368 ATTRIBUTE_UNUSED static INLINE void
369 @prefix@_emit_after (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc)
370 {
371 ARGBUF *abuf = &sc[0].argbuf;
372 const IDESC *id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_AFTER];
373
374 @prefix@_fill_argbuf (current_cpu, abuf, id, pc, 0);
375 /* no need to set trace_p,profile_p */
376 }
377
378 #endif /* WITH_SCACHE_PBB */
379
380 EOF
381
382 ${SHELL} $infile support
383
384 ##########################################################################
385
386 # Simple engine: fetch an instruction, execute the instruction.
387 #
388 # Instruction fields are not extracted into ARGBUF, they are extracted in
389 # the semantic routines themselves. However, there is still a need to pass
390 # and return misc. information to the semantic routines so we still use ARGBUF.
391 # [One could certainly implement things differently and remove ARGBUF.
392 # It's not clear this is necessarily always a win.]
393 # ??? The use of the SCACHE struct is for consistency with the with-scache
394 # case though it might be a source of confusion.
395
396 if [ x$scache != xyes -a x$pbb != xyes ] ; then
397
398 cat << EOF
399
400 #define FAST_P 0
401
402 void
403 @prefix@_engine_run_full (SIM_CPU *current_cpu)
404 {
405 #define FAST_P 0
406 SIM_DESC current_state = CPU_STATE (current_cpu);
407 /* ??? Use of SCACHE is a bit of a hack as we don't actually use the scache.
408 We do however use ARGBUF so for consistency with the other engine flavours
409 the SCACHE type is used. */
410 SCACHE cache[MAX_LIW_INSNS];
411 SCACHE *sc = &cache[0];
412
413 EOF
414
415 case x$parallel in
416 xread | xwrite)
417 cat << EOF
418 PAREXEC pbufs[MAX_PARALLEL_INSNS];
419 PAREXEC *par_exec;
420
421 EOF
422 ;;
423 esac
424
425 # Any initialization code before looping starts.
426 # Note that this code may declare some locals.
427 ${SHELL} $infile init
428
429 if [ x$parallel = xread ] ; then
430 cat << EOF
431
432 #if defined (__GNUC__)
433 {
434 if (! CPU_IDESC_READ_INIT_P (current_cpu))
435 {
436 /* ??? Later maybe paste read.c in when building mainloop.c. */
437 #define DEFINE_LABELS
438 #include "readx.c"
439 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
440 }
441 }
442 #endif
443
444 EOF
445 fi
446
447 cat << EOF
448
449 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
450 {
451 #if WITH_SEM_SWITCH_FULL
452 #if defined (__GNUC__)
453 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
454 #define DEFINE_LABELS
455 #include "$switch"
456 #endif
457 #else
458 @prefix@_sem_init_idesc_table (current_cpu);
459 #endif
460 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
461 }
462
463 do
464 {
465 /* begin full-exec-simple */
466 EOF
467
468 ${SHELL} $infile full-exec-simple
469
470 cat << EOF
471 /* end full-exec-simple */
472
473 ++ CPU_INSN_COUNT (current_cpu);
474 }
475 while (0 /*CPU_RUNNING_P (current_cpu)*/);
476 }
477
478 #undef FAST_P
479
480 EOF
481
482 ####################################
483
484 # Simple engine: fast version.
485 # ??? A somewhat dubious effort, but for completeness' sake.
486
487 if [ x$fast = xyes ] ; then
488
489 cat << EOF
490
491 #define FAST_P 1
492
493 FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh."
494
495 #undef FAST_P
496
497 EOF
498
499 fi # -fast
500
501 fi # simple engine
502
503 ##########################################################################
504
505 # Non-parallel scache engine: lookup insn in scache, fetch if missing,
506 # then execute it.
507
508 if [ x$scache = xyes -a x$parallel = xno ] ; then
509
510 cat << EOF
511
512 static INLINE SCACHE *
513 @prefix@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
514 unsigned int hash_mask, int FAST_P)
515 {
516 /* First step: look up current insn in hash table. */
517 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
518
519 /* If the entry isn't the one we want (cache miss),
520 fetch and decode the instruction. */
521 if (sc->argbuf.addr != vpc)
522 {
523 if (! FAST_P)
524 PROFILE_COUNT_SCACHE_MISS (current_cpu);
525
526 /* begin extract-scache */
527 EOF
528
529 ${SHELL} $infile extract-scache
530
531 cat << EOF
532 /* end extract-scache */
533 }
534 else if (! FAST_P)
535 {
536 PROFILE_COUNT_SCACHE_HIT (current_cpu);
537 /* Make core access statistics come out right.
538 The size is a guess, but it's currently not used either. */
539 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
540 }
541
542 return sc;
543 }
544
545 #define FAST_P 0
546
547 void
548 @prefix@_engine_run_full (SIM_CPU *current_cpu)
549 {
550 SIM_DESC current_state = CPU_STATE (current_cpu);
551 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
552 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
553 SEM_PC vpc;
554
555 EOF
556
557 # Any initialization code before looping starts.
558 # Note that this code may declare some locals.
559 ${SHELL} $infile init
560
561 cat << EOF
562
563 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
564 {
565 #if ! WITH_SEM_SWITCH_FULL
566 @prefix@_sem_init_idesc_table (current_cpu);
567 #endif
568 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
569 }
570
571 vpc = GET_H_PC ();
572
573 do
574 {
575 SCACHE *sc;
576
577 sc = @prefix@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
578
579 /* begin full-exec-scache */
580 EOF
581
582 ${SHELL} $infile full-exec-scache
583
584 cat << EOF
585 /* end full-exec-scache */
586
587 SET_H_PC (vpc);
588
589 ++ CPU_INSN_COUNT (current_cpu);
590 }
591 while (0 /*CPU_RUNNING_P (current_cpu)*/);
592 }
593
594 #undef FAST_P
595
596 EOF
597
598 ####################################
599
600 # Non-parallel scache engine: fast version.
601
602 if [ x$fast = xyes ] ; then
603
604 cat << EOF
605
606 #define FAST_P 1
607
608 void
609 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
610 {
611 SIM_DESC current_state = CPU_STATE (current_cpu);
612 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
613 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
614 SEM_PC vpc;
615
616 EOF
617
618 # Any initialization code before looping starts.
619 # Note that this code may declare some locals.
620 ${SHELL} $infile init
621
622 cat << EOF
623
624 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
625 {
626 #if WITH_SEM_SWITCH_FAST
627 #if defined (__GNUC__)
628 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
629 #define DEFINE_LABELS
630 #include "$switch"
631 #endif
632 #else
633 @prefix@_semf_init_idesc_table (current_cpu);
634 #endif
635 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
636 }
637
638 vpc = GET_H_PC ();
639
640 do
641 {
642 SCACHE *sc;
643
644 sc = @prefix@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
645
646 /* begin fast-exec-scache */
647 EOF
648
649 ${SHELL} $infile fast-exec-scache
650
651 cat << EOF
652 /* end fast-exec-scache */
653
654 SET_H_PC (vpc);
655
656 ++ CPU_INSN_COUNT (current_cpu);
657 }
658 while (0 /*CPU_RUNNING_P (current_cpu)*/);
659 }
660
661 #undef FAST_P
662
663 EOF
664
665 fi # -fast
666
667 fi # -scache && ! parallel
668
669 ##########################################################################
670
671 # Parallel scache engine: lookup insn in scache, fetch if missing,
672 # then execute it.
673 # For the parallel case we give the target more flexibility.
674
675 if [ x$scache = xyes -a x$parallel != xno ] ; then
676
677 cat << EOF
678
679 static INLINE SCACHE *
680 @prefix@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
681 unsigned int hash_mask, int FAST_P)
682 {
683 /* First step: look up current insn in hash table. */
684 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
685
686 /* If the entry isn't the one we want (cache miss),
687 fetch and decode the instruction. */
688 if (sc->argbuf.addr != vpc)
689 {
690 if (! FAST_P)
691 PROFILE_COUNT_SCACHE_MISS (current_cpu);
692
693 #define SET_LAST_INSN_P(last_p) do { sc->last_insn_p = (last_p); } while (0)
694 /* begin extract-scache */
695 EOF
696
697 ${SHELL} $infile extract-scache
698
699 cat << EOF
700 /* end extract-scache */
701 #undef SET_LAST_INSN_P
702 }
703 else if (! FAST_P)
704 {
705 PROFILE_COUNT_SCACHE_HIT (current_cpu);
706 /* Make core access statistics come out right.
707 The size is a guess, but it's currently not used either. */
708 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
709 }
710
711 return sc;
712 }
713
714 #define FAST_P 0
715
716 void
717 @prefix@_engine_run_full (SIM_CPU *current_cpu)
718 {
719 SIM_DESC current_state = CPU_STATE (current_cpu);
720 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
721 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
722 SEM_PC vpc;
723
724 EOF
725
726 # Any initialization code before looping starts.
727 # Note that this code may declare some locals.
728 ${SHELL} $infile init
729
730 if [ x$parallel = xread ] ; then
731 cat << EOF
732 #if defined (__GNUC__)
733 {
734 if (! CPU_IDESC_READ_INIT_P (current_cpu))
735 {
736 /* ??? Later maybe paste read.c in when building mainloop.c. */
737 #define DEFINE_LABELS
738 #include "readx.c"
739 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
740 }
741 }
742 #endif
743
744 EOF
745 fi
746
747 cat << EOF
748
749 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
750 {
751 #if ! WITH_SEM_SWITCH_FULL
752 @prefix@_sem_init_idesc_table (current_cpu);
753 #endif
754 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
755 }
756
757 vpc = GET_H_PC ();
758
759 do
760 {
761 /* begin full-exec-scache */
762 EOF
763
764 ${SHELL} $infile full-exec-scache
765
766 cat << EOF
767 /* end full-exec-scache */
768 }
769 while (0 /*CPU_RUNNING_P (current_cpu)*/);
770 }
771
772 #undef FAST_P
773
774 EOF
775
776 ####################################
777
778 # Parallel scache engine: fast version.
779
780 if [ x$fast = xyes ] ; then
781
782 cat << EOF
783
784 #define FAST_P 1
785
786 void
787 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
788 {
789 SIM_DESC current_state = CPU_STATE (current_cpu);
790 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
791 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
792 SEM_PC vpc;
793 PAREXEC pbufs[MAX_PARALLEL_INSNS];
794 PAREXEC *par_exec;
795
796 EOF
797
798 # Any initialization code before looping starts.
799 # Note that this code may declare some locals.
800 ${SHELL} $infile init
801
802 if [ x$parallel = xread ] ; then
803 cat << EOF
804
805 #if defined (__GNUC__)
806 {
807 if (! CPU_IDESC_READ_INIT_P (current_cpu))
808 {
809 /* ??? Later maybe paste read.c in when building mainloop.c. */
810 #define DEFINE_LABELS
811 #include "readx.c"
812 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
813 }
814 }
815 #endif
816
817 EOF
818 fi
819
820 cat << EOF
821
822 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
823 {
824 #if WITH_SEM_SWITCH_FAST
825 #if defined (__GNUC__)
826 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
827 #define DEFINE_LABELS
828 #include "$switch"
829 #endif
830 #else
831 @prefix@_semf_init_idesc_table (current_cpu);
832 #endif
833 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
834 }
835
836 vpc = GET_H_PC ();
837
838 do
839 {
840 /* begin fast-exec-scache */
841 EOF
842
843 ${SHELL} $infile fast-exec-scache
844
845 cat << EOF
846 /* end fast-exec-scache */
847 }
848 while (0 /*CPU_RUNNING_P (current_cpu)*/);
849 }
850
851 #undef FAST_P
852
853 EOF
854
855 fi # -fast
856
857 fi # -scache && parallel
858
859 ##########################################################################
860
861 # Compilation engine: lookup insn in scache, extract a pbb
862 # (pseudo-basic-block) if missing, then execute the pbb.
863 # A "pbb" is a sequence of insns up to the next cti insn or until
864 # some prespecified maximum.
865 # CTI: control transfer instruction.
866
867 if [ x$pbb = xyes ] ; then
868
869 cat << EOF
870
871 /* Record address of cti terminating a pbb. */
872 #define SET_CTI_VPC(sc) do { _cti_sc = (sc); } while (0)
873 /* Record number of [real] insns in pbb. */
874 #define SET_INSN_COUNT(n) do { _insn_count = (n); } while (0)
875
876 /* Fetch and extract a pseudo-basic-block.
877 FAST_P is non-zero if no tracing/profiling/etc. is wanted. */
878
879 INLINE SEM_PC
880 @prefix@_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
881 {
882 SEM_PC new_vpc;
883 PCADDR pc;
884 SCACHE *sc;
885 int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu);
886
887 pc = GET_H_PC ();
888
889 new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
890 if (! new_vpc)
891 {
892 /* Leading '_' to avoid collision with mainloop.in. */
893 int _insn_count = 0;
894 SCACHE *orig_sc = sc;
895 SCACHE *_cti_sc = NULL;
896 int slice_insns = CPU_MAX_SLICE_INSNS (current_cpu);
897
898 /* First figure out how many instructions to compile.
899 MAX_INSNS is the size of the allocated buffer, which includes space
900 for before/after handlers if they're being used.
901 SLICE_INSNS is the maxinum number of real insns that can be
902 executed. Zero means "as many as we want". */
903 /* ??? max_insns is serving two incompatible roles.
904 1) Number of slots available in scache buffer.
905 2) Number of real insns to execute.
906 They're incompatible because there are virtual insns emitted too
907 (chain,cti-chain,before,after handlers). */
908
909 if (slice_insns == 1)
910 {
911 /* No need to worry about extra slots required for virtual insns
912 and parallel exec support because MAX_CHAIN_LENGTH is
913 guaranteed to be big enough to execute at least 1 insn! */
914 max_insns = 1;
915 }
916 else
917 {
918 /* Allow enough slop so that while compiling insns, if max_insns > 0
919 then there's guaranteed to be enough space to emit one real insn.
920 MAX_CHAIN_LENGTH is typically much longer than
921 the normal number of insns between cti's anyway. */
922 max_insns -= (1 /* one for the trailing chain insn */
923 + (FAST_P
924 ? 0
925 : (1 + MAX_PARALLEL_INSNS) /* before+after */)
926 + (MAX_PARALLEL_INSNS > 1
927 ? (MAX_PARALLEL_INSNS * 2)
928 : 0));
929
930 /* Account for before/after handlers. */
931 if (! FAST_P)
932 slice_insns *= 3;
933
934 if (slice_insns > 0
935 && slice_insns < max_insns)
936 max_insns = slice_insns;
937 }
938
939 new_vpc = sc;
940
941 /* SC,PC must be updated to point passed the last entry used.
942 SET_CTI_VPC must be called if pbb is terminated by a cti.
943 SET_INSN_COUNT must be called to record number of real insns in
944 pbb [could be computed by us of course, extra cpu but perhaps
945 negligible enough]. */
946
947 /* begin extract-pbb */
948 EOF
949
950 ${SHELL} $infile extract-pbb
951
952 cat << EOF
953 /* end extract-pbb */
954
955 /* The last one is a pseudo-insn to link to the next chain.
956 It is also used to record the insn count for this chain. */
957 {
958 const IDESC *id;
959
960 /* Was pbb terminated by a cti? */
961 if (_cti_sc)
962 {
963 id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_CTI_CHAIN];
964 }
965 else
966 {
967 id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_CHAIN];
968 }
969 SEM_SET_CODE (&sc->argbuf, id, FAST_P);
970 sc->argbuf.idesc = id;
971 sc->argbuf.addr = pc;
972 sc->argbuf.fields.chain.insn_count = _insn_count;
973 sc->argbuf.fields.chain.next = 0;
974 sc->argbuf.fields.chain.branch_target = 0;
975 ++sc;
976 }
977
978 /* Update the pointer to the next free entry, may not have used as
979 many entries as was asked for. */
980 CPU_SCACHE_NEXT_FREE (current_cpu) = sc;
981 /* Record length of chain if profiling.
982 This includes virtual insns since they count against
983 max_insns too. */
984 if (! FAST_P)
985 PROFILE_COUNT_SCACHE_CHAIN_LENGTH (current_cpu, sc - orig_sc);
986 }
987
988 return new_vpc;
989 }
990
991 /* Chain to the next block from a non-cti terminated previous block. */
992
993 INLINE SEM_PC
994 @prefix@_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
995 {
996 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
997
998 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
999
1000 SET_H_PC (abuf->addr);
1001
1002 /* If not running forever, exit back to main loop. */
1003 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
1004 /* Also exit back to main loop if there's an event.
1005 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
1006 at the "right" time, but then that was what was asked for.
1007 There is no silver bullet for simulator engines.
1008 ??? Clearly this needs a cleaner interface.
1009 At present it's just so Ctrl-C works. */
1010 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
1011 CPU_RUNNING_P (current_cpu) = 0;
1012
1013 /* If chained to next block, go straight to it. */
1014 if (abuf->fields.chain.next)
1015 return abuf->fields.chain.next;
1016 /* See if next block has already been compiled. */
1017 abuf->fields.chain.next = scache_lookup (current_cpu, abuf->addr);
1018 if (abuf->fields.chain.next)
1019 return abuf->fields.chain.next;
1020 /* Nope, so next insn is a virtual insn to invoke the compiler
1021 (begin a pbb). */
1022 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1023 }
1024
1025 /* Chain to the next block from a cti terminated previous block.
1026 BR_TYPE indicates whether the branch was taken and whether we can cache
1027 the vpc of the branch target.
1028 NEW_PC is the target's branch address, and is only valid if
1029 BR_TYPE != SEM_BRANCH_UNTAKEN. */
1030
1031 INLINE SEM_PC
1032 @prefix@_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
1033 SEM_BRANCH_TYPE br_type, PCADDR new_pc)
1034 {
1035 SEM_PC *new_vpc_ptr;
1036
1037 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
1038
1039 /* If not running forever, exit back to main loop. */
1040 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
1041 /* Also exit back to main loop if there's an event.
1042 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
1043 at the "right" time, but then that was what was asked for.
1044 There is no silver bullet for simulator engines.
1045 ??? Clearly this needs a cleaner interface.
1046 At present it's just so Ctrl-C works. */
1047 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
1048 CPU_RUNNING_P (current_cpu) = 0;
1049
1050 /* Restart compiler if we branched to an uncacheable address
1051 (e.g. "j reg"). */
1052 if (br_type == SEM_BRANCH_UNCACHEABLE)
1053 {
1054 SET_H_PC (new_pc);
1055 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1056 }
1057
1058 /* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our
1059 next chain ptr. */
1060 if (br_type == SEM_BRANCH_UNTAKEN)
1061 {
1062 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1063 new_pc = abuf->addr;
1064 SET_H_PC (new_pc);
1065 new_vpc_ptr = &abuf->fields.chain.next;
1066 }
1067 else
1068 {
1069 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1070 SET_H_PC (new_pc);
1071 new_vpc_ptr = &abuf->fields.chain.branch_target;
1072 }
1073
1074 /* If chained to next block, go straight to it. */
1075 if (*new_vpc_ptr)
1076 return *new_vpc_ptr;
1077 /* See if next block has already been compiled. */
1078 *new_vpc_ptr = scache_lookup (current_cpu, new_pc);
1079 if (*new_vpc_ptr)
1080 return *new_vpc_ptr;
1081 /* Nope, so next insn is a virtual insn to invoke the compiler
1082 (begin a pbb). */
1083 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1084 }
1085
1086 /* x-before handler.
1087 This is called before each insn. */
1088
1089 void
1090 @prefix@_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
1091 {
1092 SEM_ARG sem_arg = sc;
1093 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1094 int first_p = abuf->fields.before.first_p;
1095 const ARGBUF *cur_abuf = SEM_ARGBUF (sc + 1);
1096 const IDESC *cur_idesc = cur_abuf->idesc;
1097 PCADDR pc = cur_abuf->addr;
1098
1099 if (ARGBUF_PROFILE_P (cur_abuf))
1100 PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
1101
1102 /* If this isn't the first insn, finish up the previous one. */
1103
1104 if (! first_p)
1105 {
1106 if (PROFILE_MODEL_P (current_cpu))
1107 {
1108 const SEM_ARG prev_sem_arg = sc - 1;
1109 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1110 const IDESC *prev_idesc = prev_abuf->idesc;
1111 int cycles;
1112
1113 /* ??? May want to measure all insns if doing insn tracing. */
1114 if (ARGBUF_PROFILE_P (prev_abuf))
1115 {
1116 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1117 @prefix@_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
1118 }
1119 }
1120
1121 CGEN_TRACE_INSN_FINI (current_cpu, cur_abuf, 0 /*last_p*/);
1122 }
1123
1124 /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */
1125 if (PROFILE_MODEL_P (current_cpu)
1126 && ARGBUF_PROFILE_P (cur_abuf))
1127 @prefix@_model_insn_before (current_cpu, first_p);
1128
1129 CGEN_TRACE_INSN_INIT (current_cpu, cur_abuf, first_p);
1130 CGEN_TRACE_INSN (current_cpu, cur_idesc->idata, cur_abuf, pc);
1131 }
1132
1133 /* x-after handler.
1134 This is called after a serial insn or at the end of a group of parallel
1135 insns. */
1136
1137 void
1138 @prefix@_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
1139 {
1140 SEM_ARG sem_arg = sc;
1141 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1142 const SEM_ARG prev_sem_arg = sc - 1;
1143 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1144
1145 /* ??? May want to measure all insns if doing insn tracing. */
1146 if (PROFILE_MODEL_P (current_cpu)
1147 && ARGBUF_PROFILE_P (prev_abuf))
1148 {
1149 const IDESC *prev_idesc = prev_abuf->idesc;
1150 int cycles;
1151
1152 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1153 @prefix@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
1154 }
1155 CGEN_TRACE_INSN_FINI (current_cpu, prev_abuf, 1 /*last_p*/);
1156 }
1157
1158 #define FAST_P 0
1159
1160 void
1161 @prefix@_engine_run_full (SIM_CPU *current_cpu)
1162 {
1163 SIM_DESC current_state = CPU_STATE (current_cpu);
1164 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1165 /* virtual program counter */
1166 SEM_PC vpc;
1167 #if WITH_SEM_SWITCH_FULL
1168 /* For communication between cti's and cti-chain. */
1169 SEM_BRANCH_TYPE pbb_br_type;
1170 PCADDR pbb_br_npc;
1171 #endif
1172
1173 EOF
1174
1175 case x$parallel in
1176 xread | xwrite)
1177 cat << EOF
1178 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1179 PAREXEC *par_exec = &pbufs[0];
1180
1181 EOF
1182 ;;
1183 esac
1184
1185 # Any initialization code before looping starts.
1186 # Note that this code may declare some locals.
1187 ${SHELL} $infile init
1188
1189 cat << EOF
1190
1191 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1192 {
1193 /* ??? 'twould be nice to move this up a level and only call it once.
1194 On the other hand, in the "let's go fast" case the test is only done
1195 once per pbb (since we only return to the main loop at the end of
1196 a pbb). And in the "let's run until we're done" case we don't return
1197 until the program exits. */
1198
1199 #if WITH_SEM_SWITCH_FULL
1200 #if defined (__GNUC__)
1201 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1202 #define DEFINE_LABELS
1203 #include "$switch"
1204 #endif
1205 #else
1206 @prefix@_sem_init_idesc_table (current_cpu);
1207 #endif
1208
1209 /* Initialize the "begin (compile) a pbb" virtual insn. */
1210 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1211 SEM_SET_FULL_CODE (SEM_ARGBUF (vpc),
1212 & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN]);
1213 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN];
1214
1215 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1216 }
1217
1218 CPU_RUNNING_P (current_cpu) = 1;
1219 /* ??? In the case where we're returning to the main loop after every
1220 pbb we don't want to call pbb_begin each time (which hashes on the pc
1221 and does a table lookup). A way to speed this up is to save vpc
1222 between calls. */
1223 vpc = @prefix@_pbb_begin (current_cpu, FAST_P);
1224
1225 do
1226 {
1227 /* begin full-exec-pbb */
1228 EOF
1229
1230 ${SHELL} $infile full-exec-pbb
1231
1232 cat << EOF
1233 /* end full-exec-pbb */
1234 }
1235 while (CPU_RUNNING_P (current_cpu));
1236 }
1237
1238 #undef FAST_P
1239
1240 EOF
1241
1242 ####################################
1243
1244 # Compile engine: fast version.
1245
1246 if [ x$fast = xyes ] ; then
1247
1248 cat << EOF
1249
1250 #define FAST_P 1
1251
1252 void
1253 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
1254 {
1255 SIM_DESC current_state = CPU_STATE (current_cpu);
1256 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1257 /* virtual program counter */
1258 SEM_PC vpc;
1259 #if WITH_SEM_SWITCH_FAST
1260 /* For communication between cti's and cti-chain. */
1261 SEM_BRANCH_TYPE pbb_br_type;
1262 PCADDR pbb_br_npc;
1263 #endif
1264
1265 EOF
1266
1267 case x$parallel in
1268 xread | xwrite)
1269 cat << EOF
1270 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1271 PAREXEC *par_exec = &pbufs[0];
1272
1273 EOF
1274 ;;
1275 esac
1276
1277 # Any initialization code before looping starts.
1278 # Note that this code may declare some locals.
1279 ${SHELL} $infile init
1280
1281 cat << EOF
1282
1283 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1284 {
1285 /* ??? 'twould be nice to move this up a level and only call it once.
1286 On the other hand, in the "let's go fast" case the test is only done
1287 once per pbb (since we only return to the main loop at the end of
1288 a pbb). And in the "let's run until we're done" case we don't return
1289 until the program exits. */
1290
1291 #if WITH_SEM_SWITCH_FAST
1292 #if defined (__GNUC__)
1293 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1294 #define DEFINE_LABELS
1295 #include "$switch"
1296 #endif
1297 #else
1298 @prefix@_semf_init_idesc_table (current_cpu);
1299 #endif
1300
1301 /* Initialize the "begin (compile) a pbb" virtual insn. */
1302 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1303 SEM_SET_FAST_CODE (SEM_ARGBUF (vpc),
1304 & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN]);
1305 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN];
1306
1307 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1308 }
1309
1310 CPU_RUNNING_P (current_cpu) = 1;
1311 /* ??? In the case where we're returning to the main loop after every
1312 pbb we don't want to call pbb_begin each time (which hashes on the pc
1313 and does a table lookup). A way to speed this up is to save vpc
1314 between calls. */
1315 vpc = @prefix@_pbb_begin (current_cpu, FAST_P);
1316
1317 do
1318 {
1319 /* begin fast-exec-pbb */
1320 EOF
1321
1322 ${SHELL} $infile fast-exec-pbb
1323
1324 cat << EOF
1325 /* end fast-exec-pbb */
1326 }
1327 while (CPU_RUNNING_P (current_cpu));
1328 }
1329
1330 #undef FAST_P
1331
1332 EOF
1333 fi # -fast
1334
1335 fi # -pbb
1336
1337 # Expand @..@ macros appearing in tmp-mloop-{pid}.cin.
1338 sed \
1339 -e "s/@cpu@/$cpu/g" -e "s/@CPU@/$CPU/g" \
1340 -e "s/@prefix@/$prefix/g" -e "s/@PREFIX@/$PREFIX/g" \
1341 < ${outprefix}tmp-mloop-$$.cin > ${outprefix}mloop${outsuffix}.cin
1342 rc=$?
1343 rm -f ${outprefix}tmp-mloop-$$.cin
1344
1345 exit $rc