OSDN Git Service

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