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