This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / sim / common / genmloop.sh
1 # Generate the main loop of the simulator.
2 # Copyright (C) 1996, 1997, 1998 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 2, or (at your option)
10 # 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 along
18 # with this program; if not, write to the Free Software Foundation, Inc.,
19 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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 # ??? 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 #       ??? The implementation is currently slower than necessary for
57 #       simplicity.  Instead of storing extract insn fields in ARGBUF,
58 #       they should just be extracted from the insn when needed.
59 #
60 # -scache: use the scache to speed things up (not always a win)
61 #
62 #       This engine caches the extracted instruction before executing it.
63 #       When executing instructions they are first looked up in the scache.
64 #
65 # -pbb: same as -scache but extract a (pseudo-) basic block at a time
66 #
67 #       This engine is basically identical to the scache version except that
68 #       extraction is done a pseudo-basic-block at a time and the address of
69 #       the scache entry of a branch target is recorded as well.
70 #       Additional speedups are then possible by defering Ctrl-C checking
71 #       to the end of basic blocks and by threading the insns together.
72 #       We call them pseudo-basic-block's instead of just basic-blocks because
73 #       they're not necessarily basic-blocks, though normally are.
74 #
75 # -parallel: cpu can execute multiple instructions parallely
76 #
77 #       This option is specified in addition to -simple, -scache, -pbb.
78 #       Note that while the code can determine if the cpu supports parallel
79 #       execution with HAVE_PARALLEL_INSNS [and thus this option is
80 #       technically unnecessary], having this option cuts down on the clutter
81 #       in the result.
82 #
83 # -switch file: specify file containing semantics implemented as a switch()
84 #
85 # -cpu <cpu-family>
86 #
87 #       Specify the cpu family name.
88 #
89 # -infile <input-file>
90 #
91 #       Specify the mainloop.in input file.
92 #
93 # Only one of -scache/-pbb may be selected.
94 # -simple is the default.
95 #
96 ####
97 #
98 # TODO
99 # - build mainloop.in from .cpu file
100
101 type=mono
102 #scache=
103 #fast=
104 #full_switch=
105 #pbb=
106 #parallel=
107 switch=
108 cpu="unknown"
109 infile=""
110
111 while test $# -gt 0
112 do
113         case $1 in
114         -mono) type=mono ;;
115         -multi) type=multi ;;
116         -no-fast) ;;
117         -fast) fast=yes ;;
118         -full-switch) full_switch=yes ;;
119         -simple) ;;
120         -scache) scache=yes ;;
121         -pbb) pbb=yes ;;
122         -no-parallel) ;;
123         -parallel) parallel=yes ;;
124         -switch) shift ; switch=$1 ;;
125         -cpu) shift ; cpu=$1 ;;
126         -infile) shift ; infile=$1 ;;
127         *) echo "unknown option: $1" >&2 ; exit 1 ;;
128         esac
129         shift
130 done
131
132 # Argument validation.
133
134 if [ x$scache = xyes -a x$pbb = xyes ] ; then
135     echo "only one of -scache and -pbb may be selected" >&2
136     exit 1
137 fi
138
139 if [ "x$cpu" = xunknown ] ; then
140     echo "cpu family not specified" >&2
141     exit 1
142 fi
143
144 if [ "x$infile" = x ] ; then
145     echo "mainloop.in not specified" >&2
146     exit 1
147 fi
148
149 lowercase='abcdefghijklmnopqrstuvwxyz'
150 uppercase='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
151 CPU=`echo ${cpu} | tr "${lowercase}" "${uppercase}"`
152
153 ##########################################################################
154
155 rm -f eng.hin
156 exec 1>eng.hin
157
158 echo "/* engine configuration for ${cpu} */"
159 echo ""
160
161 echo "/* WITH_FAST: non-zero if a fast version of the engine is available"
162 echo "   in addition to the full-featured version.  */"
163 if [ x$fast = xyes ] ; then
164         echo "#define WITH_FAST 1"
165 else
166         echo "#define WITH_FAST 0"
167 fi
168
169 echo ""
170 echo "/* WITH_SCACHE_PBB_${CPU}: non-zero if the pbb engine was selected.  */"
171 if [ x$pbb = xyes ] ; then
172         echo "#define WITH_SCACHE_PBB_${CPU} 1"
173 else
174         echo "#define WITH_SCACHE_PBB_${CPU} 0"
175 fi
176
177 echo ""
178 echo "/* HAVE_PARALLEL_INSNS: non-zero if cpu can parallelly execute > 1 insn.  */"
179 if [ x$parallel = xyes ] ; then
180         echo "#define HAVE_PARALLEL_INSNS 1"
181 else
182         echo "#define HAVE_PARALLEL_INSNS 0"
183 fi
184
185 if [ "x$switch" != x ] ; then
186         echo ""
187         echo "/* WITH_SEM_SWITCH_FULL: non-zero if full-featured engine is"
188         echo "   implemented as a switch().  */"
189         if [ x$fast != xyes -o x$full_switch = xyes ] ; then
190                 echo "#define WITH_SEM_SWITCH_FULL 1"
191         else
192                 echo "#define WITH_SEM_SWITCH_FULL 0"
193         fi
194         echo ""
195         echo "/* WITH_SEM_SWITCH_FAST: non-zero if fast engine is"
196         echo "   implemented as a switch().  */"
197         if [ x$fast = xyes ] ; then
198                 echo "#define WITH_SEM_SWITCH_FAST 1"
199         else
200                 echo "#define WITH_SEM_SWITCH_FAST 0"
201         fi
202 fi
203
204 # Decls of functions we define.
205
206 echo ""
207 echo "/* Functions defined in the generated mainloop.c file"
208 echo "   (which doesn't necessarily have that file name).  */"
209 echo ""
210 echo "extern ENGINE_FN ${cpu}_engine_run_full;"
211 echo "extern ENGINE_FN ${cpu}_engine_run_fast;"
212
213 if [ x$pbb = xyes ] ; then
214         echo ""
215         echo "extern SEM_PC ${cpu}_pbb_begin (SIM_CPU *, int);"
216         echo "extern SEM_PC ${cpu}_pbb_chain (SIM_CPU *, SEM_ARG);"
217         echo "extern SEM_PC ${cpu}_pbb_cti_chain (SIM_CPU *, SEM_ARG, SEM_PC *, PCADDR);"
218         echo "extern void ${cpu}_pbb_before (SIM_CPU *, SCACHE *);"
219         echo "extern void ${cpu}_pbb_after (SIM_CPU *, SCACHE *);"
220 fi
221
222 ##########################################################################
223
224 rm -f tmp-mloop.cin mloop.cin
225 exec 1>tmp-mloop.cin
226
227 # We use @cpu@ instead of ${cpu} because we still want to run sed to handle
228 # transformation of @cpu@ for mainloop.in.
229
230 cat << EOF
231 /* This file is generated by the genmloop script.  DO NOT EDIT! */
232
233 /* Enable switch() support in cgen headers.  */
234 #define SEM_IN_SWITCH
235
236 #define WANT_CPU
237 #define WANT_CPU_${CPU}
238
239 #include "sim-main.h"
240 #include "bfd.h"
241 #include "cgen-mem.h"
242 #include "cgen-ops.h"
243 #include "cpu-opc.h"
244 #include "cpu-sim.h"
245 #include "sim-assert.h"
246
247 EOF
248
249 ${SHELL} $infile support
250
251 ##########################################################################
252
253 # Simple engine: fetch an instruction, execute the instruction.
254
255 if [ x$scache != xyes -a x$pbb != xyes ] ; then
256
257     cat << EOF
258
259 #define FAST_P 0
260
261 void
262 ${cpu}_engine_run_full (SIM_CPU *current_cpu)
263 {
264 #define FAST_P 0
265   SIM_DESC current_state = CPU_STATE (current_cpu);
266   SCACHE cache[MAX_LIW_INSNS];
267   SCACHE *sc = &cache[0];
268
269 EOF
270
271 if [ x$parallel = xyes ] ; then
272   cat << EOF
273   PAREXEC pbufs[MAX_PARALLEL_INSNS];
274   PAREXEC *par_exec;
275
276 EOF
277 fi
278
279 # Any initialization code before looping starts.
280 # Note that this code may declare some locals.
281 ${SHELL} $infile init
282
283 if [ x$parallel = xyes ] ; then
284   cat << EOF
285
286 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
287   {
288     if (! CPU_IDESC_READ_INIT_P (current_cpu))
289       {
290 /* ??? Later maybe paste read.c in when building mainloop.c.  */
291 #define DEFINE_LABELS
292 #include "readx.c"
293         CPU_IDESC_READ_INIT_P (current_cpu) = 1;
294       }
295   }
296 #endif
297
298 EOF
299 fi
300
301 cat << EOF
302
303   do
304     {
305 /* begin full-{extract,exec}-simple */
306 EOF
307
308 ${SHELL} $infile extract-simple
309 echo ""
310 ${SHELL} $infile full-exec-simple
311
312 cat << EOF
313 /* end full-{extract,exec}-simple */
314
315       ++ CPU_INSN_COUNT (current_cpu);
316     }
317   while (0 /*CPU_RUNNING_P (current_cpu)*/);
318 #undef FAST_P
319 }
320
321 #undef FAST_P
322
323 EOF
324
325 ####################################
326
327 # Simple engine: fast version.
328 # ??? A somewhat dubious effort, but for completeness' sake.
329
330 if [ x$fast = xyes ] ; then
331
332     cat << EOF
333
334 #define FAST_P 1
335
336 FIXME
337
338 #undef FAST_P
339
340 EOF
341
342 fi # -fast
343
344 fi # simple engine
345
346 ##########################################################################
347
348 # Scache engine: lookup insn in scache, fetch if missing, then execute it.
349
350 if [ x$scache = xyes ] ; then
351
352     cat << EOF
353
354 static INLINE SCACHE *
355 ${cpu}_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
356                      unsigned int hash_mask, int FAST_P)
357 {
358   /* First step: look up current insn in hash table.  */
359   SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
360
361   /* If the entry isn't the one we want (cache miss),
362      fetch and decode the instruction.  */
363   if (sc->argbuf.addr != vpc)
364     {
365       insn_t insn;
366
367       if (FAST_P)
368         PROFILE_COUNT_SCACHE_MISS (current_cpu);
369
370 /* begin extract-scache */
371 EOF
372
373 ${SHELL} $infile extract-scache
374
375 cat << EOF
376 /* end extract-scache */
377     }
378   else if (FAST_P)
379     {
380       PROFILE_COUNT_SCACHE_HIT (current_cpu);
381       /* Make core access statistics come out right.
382          The size is a guess, but it's currently not used either.  */
383       PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
384     }
385
386   return sc;
387 }
388
389 #define FAST_P 0
390
391 void
392 ${cpu}_engine_run_full (SIM_CPU *current_cpu)
393 {
394   SIM_DESC current_state = CPU_STATE (current_cpu);
395   SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
396   unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
397   SEM_PC vpc;
398
399 EOF
400
401 if [ x$parallel = xyes ] ; then
402   cat << EOF
403   PAREXEC pbufs[MAX_PARALLEL_INSNS];
404   PAREXEC *par_exec;
405
406 EOF
407 fi
408
409 # Any initialization code before looping starts.
410 # Note that this code may declare some locals.
411 ${SHELL} $infile init
412
413 if [ x$parallel = xyes ] ; then
414   cat << EOF
415
416 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
417   {
418     if (! CPU_IDESC_READ_INIT_P (current_cpu))
419       {
420 /* ??? Later maybe paste read.c in when building mainloop.c.  */
421 #define DEFINE_LABELS
422 #include "readx.c"
423         CPU_IDESC_READ_INIT_P (current_cpu) = 1;
424       }
425   }
426 #endif
427
428 EOF
429 fi
430
431 cat << EOF
432
433   vpc = GET_H_PC ();
434
435   do
436     {
437       SCACHE *sc;
438
439       sc = ${cpu}_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
440
441 /* begin full-exec-scache */
442 EOF
443
444 ${SHELL} $infile full-exec-scache
445
446 cat << EOF
447 /* end full-exec-scache */
448
449       SET_H_PC (vpc);
450
451       ++ CPU_INSN_COUNT (current_cpu);
452     }
453   while (0 /*CPU_RUNNING_P (current_cpu)*/);
454 }
455
456 #undef FAST_P
457
458 EOF
459
460 ####################################
461
462 # Scache engine: fast version.
463
464 if [ x$fast = xyes ] ; then
465
466     cat << EOF
467
468 #define FAST_P 1
469
470 void
471 ${cpu}_engine_run_fast (SIM_CPU *current_cpu)
472 {
473   SIM_DESC current_state = CPU_STATE (current_cpu);
474   SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
475   unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
476   SEM_PC vpc;
477
478 EOF
479
480 if [ x$parallel = xyes ] ; then
481   cat << EOF
482   PAREXEC pbufs[MAX_PARALLEL_INSNS];
483   PAREXEC *par_exec;
484
485 EOF
486 fi
487
488 # Any initialization code before looping starts.
489 # Note that this code may declare some locals.
490 ${SHELL} $infile init
491
492 if [ x$parallel = xyes ] ; then
493   cat << EOF
494
495 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
496   {
497     if (! CPU_IDESC_READ_INIT_P (current_cpu))
498       {
499 /* ??? Later maybe paste read.c in when building mainloop.c.  */
500 #define DEFINE_LABELS
501 #include "readx.c"
502         CPU_IDESC_READ_INIT_P (current_cpu) = 1;
503       }
504   }
505 #endif
506
507 EOF
508 fi # parallel = yes
509
510 cat << EOF
511
512 #if WITH_SEM_SWITCH_FAST && defined (__GNUC__)
513   {
514     if (! CPU_IDESC_SEM_INIT_P (current_cpu))
515       {
516 /* ??? Later maybe paste sem-switch.c in when building mainloop.c.  */
517 #define DEFINE_LABELS
518 #include "$switch"
519         CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
520       }
521   }
522 #endif
523
524   vpc = GET_H_PC ();
525
526   do
527     {
528       SCACHE *sc;
529
530       sc = ${cpu}_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
531
532 /* begin fast-exec-scache */
533 EOF
534
535 ${SHELL} $infile fast-exec-scache
536
537 cat << EOF
538 /* end fast-exec-scache */
539
540       SET_H_PC (vpc);
541
542       ++ CPU_INSN_COUNT (current_cpu);
543     }
544   while (0 /*CPU_RUNNING_P (current_cpu)*/);
545 }
546
547 #undef FAST_P
548
549 EOF
550
551 fi # -fast
552
553 fi # -scache
554
555 ##########################################################################
556
557 # Compilation engine: lookup insn in scache, extract a pbb
558 # (pseudo-basic-block) if missing, then execute the pbb.
559 # A "pbb" is a sequence of insns up to the next cti insn or until
560 # some prespecified maximum.
561 # CTI: control transfer instruction.
562
563 if [ x$pbb = xyes ] ; then
564
565     cat << EOF
566
567 /* Record address of cti terminating a pbb.  */
568 #define SET_CTI_VPC(sc) do { cti_sc = (sc); } while (0)
569 /* Record number of [real] insns in pbb.  */
570 #define SET_INSN_COUNT(n) do { insn_count = (n); } while (0)
571
572 /* Fetch and extract a pseudo-basic-block.
573    FAST_P is non-zero if no tracing/profiling/etc. is wanted.  */
574
575 INLINE SEM_PC
576 ${cpu}_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
577 {
578   SEM_PC new_vpc;
579   PCADDR pc;
580   SCACHE *sc;
581   int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu);
582
583   pc = GET_H_PC ();
584
585   new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
586   if (! new_vpc)
587     {
588       int insn_count = 0;
589       SCACHE *orig_sc = sc;
590       SCACHE *cti_sc = NULL;
591       int slice_insns = CPU_MAX_SLICE_INSNS (current_cpu);
592
593       /* First figure out how many instructions to compile.
594          MAX_INSNS is the size of the allocated buffer, which includes space
595          for before/after handlers if they're being used.
596          SLICE_INSNS is the maxinum number of real insns that can be
597          executed.  Zero means "as many as we want".  */
598       /* ??? max_insns is serving two incompatible roles.
599          1) Number of slots available in scache buffer.
600          2) Number of real insns to execute.
601          They're incompatible because there are virtual insns emitted too
602          (chain,cti-chain,before,after handlers).  */
603
604       if (slice_insns == 1)
605         {
606           /* No need to worry about extra slots required for virtual insns
607              and parallel exec support because MAX_CHAIN_LENGTH is
608              guaranteed to be big enough to execute at least 1 insn!  */
609           max_insns = 1;
610         }
611       else
612         {
613           /* Allow enough slop so that while compiling insns, if max_insns > 0
614              then there's guaranteed to be enough space to emit one real insn.
615              MAX_CHAIN_LENGTH is typically much longer than
616              the normal number of insns between cti's anyway.  */
617           max_insns -= (1 /* one for the trailing chain insn */
618                         + (FAST_P
619                            ? 0
620                            : (1 + MAX_PARALLEL_INSNS) /* before+after */)
621                         + (MAX_PARALLEL_INSNS > 1
622                            ? (MAX_PARALLEL_INSNS * 2)
623                            : 0));
624
625           /* Account for before/after handlers.  */
626           if (! FAST_P)
627             slice_insns *= 3;
628
629           if (slice_insns > 0
630               && slice_insns < max_insns)
631             max_insns = slice_insns;
632         }
633
634       new_vpc = sc;
635
636       /* SC,PC must be updated to point passed the last entry used.
637          SET_CTI_VPC must be called if pbb is terminated by a cti.
638          SET_INSN_COUNT must be called to record number of real insns in
639          pbb [could be computed by us of course, extra cpu but perhaps
640          negligible enough].  */
641
642 /* begin extract-pbb */
643 EOF
644
645 ${SHELL} $infile extract-pbb
646
647 cat << EOF
648 /* end extract-pbb */
649
650       /* The last one is a pseudo-insn to link to the next chain.
651          It is also used to record the insn count for this chain.  */
652       {
653         const IDESC *id;
654
655         /* Was pbb terminated by a cti?  */
656         if (cti_sc)
657           {
658             id = & CPU_IDESC (current_cpu) [${CPU}_INSN_X_CTI_CHAIN];
659           }
660         else
661           {
662             id = & CPU_IDESC (current_cpu) [${CPU}_INSN_X_CHAIN];
663           }
664         SEM_SET_CODE (&sc->argbuf, id, FAST_P);
665         sc->argbuf.idesc = id;
666         sc->argbuf.addr = pc;
667         sc->argbuf.fields.chain.insn_count = insn_count;
668         sc->argbuf.fields.chain.next = 0;
669         ++sc;
670       }
671
672       /* Update the pointer to the next free entry.  */
673       CPU_SCACHE_NEXT_FREE (current_cpu) = sc;
674       /* Record length of chain if profiling.
675          This includes virtual insns since they count against
676          max_insns too.  */
677       if (! FAST_P)
678         PROFILE_COUNT_SCACHE_CHAIN_LENGTH (current_cpu, sc - orig_sc);
679     }
680
681   return new_vpc;
682 }
683
684 /* Chain to the next block from a non-cti terminated previous block.  */
685
686 INLINE SEM_PC
687 ${cpu}_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
688 {
689   ARGBUF *abuf = SEM_ARGBUF (sem_arg);
690
691   PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
692
693   SET_H_PC (abuf->addr);
694
695   /* If not running forever, exit back to main loop.  */
696   if (CPU_MAX_SLICE_INSNS (current_cpu) != 0)
697     CPU_RUNNING_P (current_cpu) = 0;
698
699   /* If chained to next block, go straight to it.  */
700   if (abuf->fields.chain.next)
701     return abuf->fields.chain.next;
702   /* See if next block has already been compiled.  */
703   abuf->fields.chain.next = scache_lookup (current_cpu, abuf->addr);
704   if (abuf->fields.chain.next)
705     return abuf->fields.chain.next;
706   /* Nope, so next insn is a virtual insn to invoke the compiler
707      (begin a pbb).  */
708   return CPU_SCACHE_PBB_BEGIN (current_cpu);
709 }
710
711 /* Chain to the next block from a cti terminated previous block.
712    NEW_VPC_PTR is one of SEM_BRANCH_UNTAKEN, SEM_BRANCH_UNCACHEABLE, or
713    a pointer to a location containing the SEM_PC of the branch's address.
714    NEW_PC is the target's branch address, and is only valid if
715    NEW_VPC_PTR != SEM_BRANCH_UNTAKEN.  */
716
717 INLINE SEM_PC
718 ${cpu}_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
719                      SEM_PC *new_vpc_ptr, PCADDR new_pc)
720 {
721   ARGBUF *abuf;
722
723   PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
724
725   /* If not running forever, exit back to main loop.  */
726   if (CPU_MAX_SLICE_INSNS (current_cpu) != 0)
727     CPU_RUNNING_P (current_cpu) = 0;
728
729   /* Restart compiler if we branched to an uncacheable address
730      (e.g. "j reg").  */
731   if (new_vpc_ptr == SEM_BRANCH_UNCACHEABLE)
732     {
733       SET_H_PC (new_pc);
734       return CPU_SCACHE_PBB_BEGIN (current_cpu);
735     }
736
737   /* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our
738      next chain ptr.  */
739   if (new_vpc_ptr == SEM_BRANCH_UNTAKEN)
740     {
741       abuf = SEM_ARGBUF (sem_arg);
742       SET_H_PC (abuf->addr);
743       new_vpc_ptr = &abuf->fields.chain.next;
744     }
745   else
746     {
747       SET_H_PC (new_pc);
748     }
749
750   /* If chained to next block, go straight to it.  */
751   if (*new_vpc_ptr)
752     return *new_vpc_ptr;
753   /* See if next block has already been compiled.  */
754   *new_vpc_ptr = scache_lookup (current_cpu, GET_H_PC ());
755   if (*new_vpc_ptr)
756     return *new_vpc_ptr;
757   /* Nope, so next insn is a virtual insn to invoke the compiler
758      (begin a pbb).  */
759   return CPU_SCACHE_PBB_BEGIN (current_cpu);
760 }
761
762 /* x-before handler.
763    This is called before each insn.  */
764
765 void
766 ${cpu}_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
767 {
768   SEM_ARG sem_arg = sc;
769   const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
770   int first_p = abuf->fields.before.first_p;
771   const ARGBUF *cur_abuf = SEM_ARGBUF (sc + 1);
772   const IDESC *cur_idesc = cur_abuf->idesc;
773   PCADDR pc = cur_abuf->addr;
774
775   PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
776
777   /* If this isn't the first insn, finish up the previous one.  */
778
779   if (! first_p)
780     {
781       if (PROFILE_MODEL_P (current_cpu))
782         {
783           const SEM_ARG prev_sem_arg = sc - 1;
784           const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
785           const IDESC *prev_idesc = prev_abuf->idesc;
786           int cycles;
787
788           cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
789           ${cpu}_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
790         }
791
792       TRACE_INSN_FINI (current_cpu, 0 /*last_p*/);
793     }
794
795   /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}.  */
796   if (PROFILE_MODEL_P (current_cpu))
797     ${cpu}_model_insn_before (current_cpu, first_p);
798
799   TRACE_INSN_INIT (current_cpu, first_p);
800   TRACE_INSN (current_cpu, cur_idesc->opcode, cur_abuf, cur_abuf->addr);
801 }
802
803 /* x-after handler.
804    This is called after a serial insn or at the end of a group of parallel
805    insns.  */
806
807 void
808 ${cpu}_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
809 {
810   SEM_ARG sem_arg = sc;
811   const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
812
813   if (PROFILE_MODEL_P (current_cpu))
814     {
815       const SEM_ARG prev_sem_arg = sc - 1;
816       const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
817       const IDESC *prev_idesc = prev_abuf->idesc;
818       int cycles;
819
820       cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
821       ${cpu}_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
822     }
823   TRACE_INSN_FINI (current_cpu, 1 /*last_p*/);
824 }
825
826 #define FAST_P 0
827
828 void
829 ${cpu}_engine_run_full (SIM_CPU *current_cpu)
830 {
831   SIM_DESC current_state = CPU_STATE (current_cpu);
832   SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
833   /* virtual program counter */
834   SEM_PC vpc;
835 #if WITH_SEM_SWITCH_FULL
836   /* For communication between cti's and cti-chain.  */
837   PCADDR pbb_br_npc;
838   SEM_PC *pbb_br_npc_ptr;
839 #endif
840
841 EOF
842
843 if [ x$parallel = xyes ] ; then
844   cat << EOF
845   PAREXEC pbufs[MAX_PARALLEL_INSNS];
846   PAREXEC *par_exec = &pbufs[0];
847
848 EOF
849 fi
850
851 # Any initialization code before looping starts.
852 # Note that this code may declare some locals.
853 ${SHELL} $infile init
854
855 cat << EOF
856
857   if (! CPU_IDESC_SEM_INIT_P (current_cpu))
858     {
859       /* ??? 'twould be nice to move this up a level and only call it once.
860          On the other hand, in the "let's go fast" case the test is only done
861          once per pbb (since we only return to the main loop at the end of
862          a pbb).  And in the "let's run until we're done" case we don't return
863          until the program exits.  */
864
865 #if WITH_SEM_SWITCH_FULL && defined (__GNUC__)
866 /* ??? Later maybe paste sem-switch.c in when building mainloop.c.  */
867 #define DEFINE_LABELS
868 #include "$switch"
869 #endif
870
871       /* Initialize the "begin (compile) a pbb" virtual insn.  */
872       vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
873       SEM_SET_FULL_CODE (SEM_ARGBUF (vpc),
874                          & CPU_IDESC (current_cpu) [${CPU}_INSN_X_BEGIN]);
875       vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [${CPU}_INSN_X_BEGIN];
876
877       CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
878     }
879
880   CPU_RUNNING_P (current_cpu) = 1;
881   /* ??? In the case where we're returning to the main loop after every
882      pbb we don't want to call pbb_begin each time (which hashes on the pc
883      and does a table lookup).  A way to speed this up is to save vpc
884      between calls.  */
885   vpc = ${cpu}_pbb_begin (current_cpu, FAST_P);
886
887   do
888     {
889 /* begin full-exec-pbb */
890 EOF
891
892 ${SHELL} $infile full-exec-pbb
893
894 cat << EOF
895 /* end full-exec-pbb */
896     }
897   while (CPU_RUNNING_P (current_cpu));
898 }
899
900 #undef FAST_P
901
902 EOF
903
904 ####################################
905
906 # Compile engine: fast version.
907
908 if [ x$fast = xyes ] ; then
909
910     cat << EOF
911
912 #define FAST_P 1
913
914 void
915 ${cpu}_engine_run_fast (SIM_CPU *current_cpu)
916 {
917   SIM_DESC current_state = CPU_STATE (current_cpu);
918   SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
919   /* virtual program counter */
920   SEM_PC vpc;
921 #if WITH_SEM_SWITCH_FAST
922   /* For communication between cti's and cti-chain.  */
923   PCADDR pbb_br_npc;
924   SEM_PC *pbb_br_npc_ptr;
925 #endif
926
927 EOF
928
929 if [ x$parallel = xyes ] ; then
930   cat << EOF
931   PAREXEC pbufs[MAX_PARALLEL_INSNS];
932   PAREXEC *par_exec = &pbufs[0];
933
934 EOF
935 fi
936
937 # Any initialization code before looping starts.
938 # Note that this code may declare some locals.
939 ${SHELL} $infile init
940
941 cat << EOF
942
943   if (! CPU_IDESC_SEM_INIT_P (current_cpu))
944     {
945       /* ??? 'twould be nice to move this up a level and only call it once.
946          On the other hand, in the "let's go fast" case the test is only done
947          once per pbb (since we only return to the main loop at the end of
948          a pbb).  And in the "let's run until we're done" case we don't return
949          until the program exits.  */
950
951 #if WITH_SEM_SWITCH_FAST && defined (__GNUC__)
952 /* ??? Later maybe paste sem-switch.c in when building mainloop.c.  */
953 #define DEFINE_LABELS
954 #include "$switch"
955 #endif
956
957       /* Initialize the "begin (compile) a pbb" virtual insn.  */
958       vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
959       SEM_SET_FAST_CODE (SEM_ARGBUF (vpc),
960                          & CPU_IDESC (current_cpu) [${CPU}_INSN_X_BEGIN]);
961       vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [${CPU}_INSN_X_BEGIN];
962
963       CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
964     }
965
966   CPU_RUNNING_P (current_cpu) = 1;
967   /* ??? In the case where we're returning to the main loop after every
968      pbb we don't want to call pbb_begin each time (which hashes on the pc
969      and does a table lookup).  A way to speed this up is to save vpc
970      between calls.  */
971   vpc = ${cpu}_pbb_begin (current_cpu, FAST_P);
972
973   do
974     {
975 /* begin fast-exec-pbb */
976 EOF
977
978 ${SHELL} $infile fast-exec-pbb
979
980 cat << EOF
981 /* end fast-exec-pbb */
982     }
983   while (CPU_RUNNING_P (current_cpu));
984 }
985
986 #undef FAST_P
987
988 EOF
989 fi # -fast
990
991 fi # -pbb
992
993 sed -e "s/@cpu@/$cpu/g" -e "s/@CPU@/$CPU/g" < tmp-mloop.cin > mloop.cin
994 rc=$?
995 rm -f tmp-mloop.cin
996
997 exit $rc