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