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