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