OSDN Git Service

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