1 # Generate the main loop of the simulator.
2 # Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
3 # Contributed by Cygnus Support.
5 # This file is part of the GNU simulators.
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2, or (at your option)
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License along
18 # with this program; if not, write to the Free Software Foundation, Inc.,
19 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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.
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?
31 # Syntax: genmloop.sh [options]
36 # - specify single cpu or multiple cpus (number specifyable at runtime),
37 # maximum number is a configuration parameter
40 # -fast: include support for fast execution in addition to full featured mode
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
51 # -full-switch: same as -fast but for full featured version of -switch
52 # Only needed if -fast present.
54 # -simple: simple execution engine (the default)
56 # This engine fetches and executes one instruction at a time.
57 # Field extraction is done in the semantic routines.
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.
71 # -scache: use the scache to speed things up (not always a win)
73 # This engine caches the extracted instruction before executing it.
74 # When executing instructions they are first looked up in the scache.
76 # -pbb: same as -scache but extract a (pseudo-) basic block at a time
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.
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
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
97 # -parallel-only: semantic code only supports parallel version of insn
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.
103 # -prefix: string to prepend to function names in mloop.c/eng.h.
105 # If no prefix is specified, the cpu type is used.
107 # -switch file: specify file containing semantics implemented as a switch()
111 # Specify the cpu family name.
113 # -infile <input-file>
115 # Specify the mainloop.in input file.
117 # -outfile-suffix <output-file-suffix>
119 # Specify the suffix to append to output files.
121 # Only one of -scache/-pbb may be selected.
122 # -simple is the default.
127 # - build mainloop.in from .cpu file
146 -multi) type=multi
;;
149 -full-switch) full_switch
=yes ;;
151 -scache) scache
=yes ;;
154 -outfile-suffix) shift ; outsuffix
=$1 ;;
155 -parallel-read) parallel
=read ;;
156 -parallel-write) parallel
=write ;;
157 -parallel-generic-write) parallel
=genwrite
;;
158 -parallel-only) parallel_only
=yes ;;
159 -prefix) shift ; prefix
=$1 ;;
160 -switch) shift ; switch
=$1 ;;
161 -cpu) shift ; cpu
=$1 ;;
162 -infile) shift ; infile
=$1 ;;
163 *) echo "unknown option: $1" >&2 ; exit 1 ;;
168 # Argument validation.
170 if [ x
$scache = xyes
-a x
$pbb = xyes
] ; then
171 echo "only one of -scache and -pbb may be selected" >&2
175 if [ "x$cpu" = xunknown
] ; then
176 echo "cpu family not specified" >&2
180 if [ "x$infile" = x
] ; then
181 echo "mainloop.in not specified" >&2
185 if [ "x$prefix" = xunknown
] ; then
189 lowercase
='abcdefghijklmnopqrstuvwxyz'
190 uppercase
='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
191 CPU
=`echo ${cpu} | tr "${lowercase}" "${uppercase}"`
192 PREFIX
=`echo ${prefix} | tr "${lowercase}" "${uppercase}"`
194 ##########################################################################
196 rm -f eng
${outsuffix}.hin
197 exec 1>eng
${outsuffix}.hin
199 echo "/* engine configuration for ${cpu} */"
202 echo "/* WITH_FAST: non-zero if a fast version of the engine is available"
203 echo " in addition to the full-featured version. */"
204 if [ x
$fast = xyes
] ; then
205 echo "#define WITH_FAST 1"
207 echo "#define WITH_FAST 0"
211 echo "/* WITH_SCACHE_PBB_${PREFIX}: non-zero if the pbb engine was selected. */"
212 if [ x
$pbb = xyes
] ; then
213 echo "#define WITH_SCACHE_PBB_${PREFIX} 1"
215 echo "#define WITH_SCACHE_PBB_${PREFIX} 0"
219 echo "/* HAVE_PARALLEL_INSNS: non-zero if cpu can parallelly execute > 1 insn. */"
220 # blah blah blah, other ways to do this, blah blah blah
223 echo "#define HAVE_PARALLEL_INSNS 0"
224 echo "#define WITH_PARALLEL_READ 0"
225 echo "#define WITH_PARALLEL_WRITE 0"
226 echo "#define WITH_PARALLEL_GENWRITE 0"
229 echo "#define HAVE_PARALLEL_INSNS 1"
230 echo "/* Parallel execution is supported by read-before-exec. */"
231 echo "#define WITH_PARALLEL_READ 1"
232 echo "#define WITH_PARALLEL_WRITE 0"
233 echo "#define WITH_PARALLEL_GENWRITE 0"
236 echo "#define HAVE_PARALLEL_INSNS 1"
237 echo "/* Parallel execution is supported by write-after-exec. */"
238 echo "#define WITH_PARALLEL_READ 0"
239 echo "#define WITH_PARALLEL_WRITE 1"
240 echo "#define WITH_PARALLEL_GENWRITE 0"
243 echo "#define HAVE_PARALLEL_INSNS 1"
244 echo "/* Parallel execution is supported by generic write-after-exec. */"
245 echo "#define WITH_PARALLEL_READ 0"
246 echo "#define WITH_PARALLEL_WRITE 0"
247 echo "#define WITH_PARALLEL_GENWRITE 1"
251 if [ "x$switch" != x
] ; then
253 echo "/* WITH_SEM_SWITCH_FULL: non-zero if full-featured engine is"
254 echo " implemented as a switch(). */"
255 if [ x
$fast != xyes
-o x
$full_switch = xyes
] ; then
256 echo "#define WITH_SEM_SWITCH_FULL 1"
258 echo "#define WITH_SEM_SWITCH_FULL 0"
261 echo "/* WITH_SEM_SWITCH_FAST: non-zero if fast engine is"
262 echo " implemented as a switch(). */"
263 if [ x
$fast = xyes
] ; then
264 echo "#define WITH_SEM_SWITCH_FAST 1"
266 echo "#define WITH_SEM_SWITCH_FAST 0"
270 # Decls of functions we define.
273 echo "/* Functions defined in the generated mainloop.c file"
274 echo " (which doesn't necessarily have that file name). */"
276 echo "extern ENGINE_FN ${prefix}_engine_run_full;"
277 echo "extern ENGINE_FN ${prefix}_engine_run_fast;"
279 if [ x
$pbb = xyes
] ; then
281 echo "extern SEM_PC ${prefix}_pbb_begin (SIM_CPU *, int);"
282 echo "extern SEM_PC ${prefix}_pbb_chain (SIM_CPU *, SEM_ARG);"
283 echo "extern SEM_PC ${prefix}_pbb_cti_chain (SIM_CPU *, SEM_ARG, SEM_BRANCH_TYPE, PCADDR);"
284 echo "extern void ${prefix}_pbb_before (SIM_CPU *, SCACHE *);"
285 echo "extern void ${prefix}_pbb_after (SIM_CPU *, SCACHE *);"
288 ##########################################################################
290 rm -f tmp-mloop-$$.cin mloop
${outsuffix}.cin
291 exec 1>tmp-mloop-$$.cin
293 # We use @cpu@ instead of ${cpu} because we still need to run sed to handle
294 # transformation of @cpu@ for mainloop.in, so there's no need to use ${cpu}
298 /* This file is generated by the genmloop script. DO NOT EDIT! */
300 /* Enable switch() support in cgen headers. */
301 #define SEM_IN_SWITCH
303 #define WANT_CPU @cpu@
304 #define WANT_CPU_@CPU@
306 #include "sim-main.h"
308 #include "cgen-mem.h"
309 #include "cgen-ops.h"
310 #include "sim-assert.h"
312 /* Fill in the administrative ARGBUF fields required by all insns,
316 @prefix@_fill_argbuf (const SIM_CPU *cpu, ARGBUF *abuf, const IDESC *idesc,
317 PCADDR pc, int fast_p)
320 SEM_SET_CODE (abuf, idesc, fast_p);
321 ARGBUF_ADDR (abuf) = pc;
323 ARGBUF_IDESC (abuf) = idesc;
326 /* Fill in tracing/profiling fields of an ARGBUF. */
329 @prefix@_fill_argbuf_tp (const SIM_CPU *cpu, ARGBUF *abuf,
330 int trace_p, int profile_p)
332 ARGBUF_TRACE_P (abuf) = trace_p;
333 ARGBUF_PROFILE_P (abuf) = profile_p;
338 /* Emit the "x-before" handler.
339 x-before is emitted before each insn (serial or parallel).
340 This is as opposed to x-after which is only emitted at the end of a group
341 of parallel insns. */
344 @prefix@_emit_before (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc, int first_p)
346 ARGBUF *abuf = &sc[0].argbuf;
347 const IDESC *id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEFORE];
349 abuf->fields.before.first_p = first_p;
350 @prefix@_fill_argbuf (current_cpu, abuf, id, pc, 0);
351 /* no need to set trace_p,profile_p */
354 /* Emit the "x-after" handler.
355 x-after is emitted after a serial insn or at the end of a group of
359 @prefix@_emit_after (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc)
361 ARGBUF *abuf = &sc[0].argbuf;
362 const IDESC *id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_AFTER];
364 @prefix@_fill_argbuf (current_cpu, abuf, id, pc, 0);
365 /* no need to set trace_p,profile_p */
368 #endif /* WITH_SCACHE_PBB */
372 ${SHELL} $infile support
374 ##########################################################################
376 # Simple engine: fetch an instruction, execute the instruction.
378 # Instruction fields are not extracted into ARGBUF, they are extracted in
379 # the semantic routines themselves. However, there is still a need to pass
380 # and return misc. information to the semantic routines so we still use ARGBUF.
381 # [One could certainly implement things differently and remove ARGBUF.
382 # It's not clear this is necessarily always a win.]
383 # ??? The use of the SCACHE struct is for consistency with the with-scache
384 # case though it might be a source of confusion.
386 if [ x
$scache != xyes
-a x
$pbb != xyes
] ; then
393 @prefix@_engine_run_full (SIM_CPU *current_cpu)
396 SIM_DESC current_state = CPU_STATE (current_cpu);
397 /* ??? Use of SCACHE is a bit of a hack as we don't actually use the scache.
398 We do however use ARGBUF so for consistency with the other engine flavours
399 the SCACHE type is used. */
400 SCACHE cache[MAX_LIW_INSNS];
401 SCACHE *sc = &cache[0];
408 PAREXEC pbufs[MAX_PARALLEL_INSNS];
415 # Any initialization code before looping starts.
416 # Note that this code may declare some locals.
417 ${SHELL} $infile init
419 if [ x
$parallel = xread
] ; then
422 #if defined (__GNUC__)
424 if (! CPU_IDESC_READ_INIT_P (current_cpu))
426 /* ??? Later maybe paste read.c in when building mainloop.c. */
427 #define DEFINE_LABELS
429 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
439 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
441 #if WITH_SEM_SWITCH_FULL
442 #if defined (__GNUC__)
443 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
444 #define DEFINE_LABELS
448 @prefix@_sem_init_idesc_table (current_cpu);
450 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
455 /* begin full-exec-simple */
458 ${SHELL} $infile full-exec-simple
461 /* end full-exec-simple */
463 ++ CPU_INSN_COUNT (current_cpu);
465 while (0 /*CPU_RUNNING_P (current_cpu)*/);
472 ####################################
474 # Simple engine: fast version.
475 # ??? A somewhat dubious effort, but for completeness' sake.
477 if [ x
$fast = xyes
] ; then
483 FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh."
493 ##########################################################################
495 # Non-parallel scache engine: lookup insn in scache, fetch if missing,
498 if [ x
$scache = xyes
-a x
$parallel = xno
] ; then
502 static INLINE SCACHE *
503 @prefix@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
504 unsigned int hash_mask, int FAST_P)
506 /* First step: look up current insn in hash table. */
507 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
509 /* If the entry isn't the one we want (cache miss),
510 fetch and decode the instruction. */
511 if (sc->argbuf.addr != vpc)
514 PROFILE_COUNT_SCACHE_MISS (current_cpu);
516 /* begin extract-scache */
519 ${SHELL} $infile extract-scache
522 /* end extract-scache */
526 PROFILE_COUNT_SCACHE_HIT (current_cpu);
527 /* Make core access statistics come out right.
528 The size is a guess, but it's currently not used either. */
529 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
538 @prefix@_engine_run_full (SIM_CPU *current_cpu)
540 SIM_DESC current_state = CPU_STATE (current_cpu);
541 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
542 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
547 # Any initialization code before looping starts.
548 # Note that this code may declare some locals.
549 ${SHELL} $infile init
553 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
555 #if ! WITH_SEM_SWITCH_FULL
556 @prefix@_sem_init_idesc_table (current_cpu);
558 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
567 sc = @prefix@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
569 /* begin full-exec-scache */
572 ${SHELL} $infile full-exec-scache
575 /* end full-exec-scache */
579 ++ CPU_INSN_COUNT (current_cpu);
581 while (0 /*CPU_RUNNING_P (current_cpu)*/);
588 ####################################
590 # Non-parallel scache engine: fast version.
592 if [ x
$fast = xyes
] ; then
599 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
601 SIM_DESC current_state = CPU_STATE (current_cpu);
602 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
603 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
608 # Any initialization code before looping starts.
609 # Note that this code may declare some locals.
610 ${SHELL} $infile init
614 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
616 #if WITH_SEM_SWITCH_FAST
617 #if defined (__GNUC__)
618 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
619 #define DEFINE_LABELS
623 @prefix@_semf_init_idesc_table (current_cpu);
625 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
634 sc = @prefix@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
636 /* begin fast-exec-scache */
639 ${SHELL} $infile fast-exec-scache
642 /* end fast-exec-scache */
646 ++ CPU_INSN_COUNT (current_cpu);
648 while (0 /*CPU_RUNNING_P (current_cpu)*/);
657 fi # -scache && ! parallel
659 ##########################################################################
661 # Parallel scache engine: lookup insn in scache, fetch if missing,
663 # For the parallel case we give the target more flexibility.
665 if [ x
$scache = xyes
-a x
$parallel != xno
] ; then
669 static INLINE SCACHE *
670 @prefix@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
671 unsigned int hash_mask, int FAST_P)
673 /* First step: look up current insn in hash table. */
674 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
676 /* If the entry isn't the one we want (cache miss),
677 fetch and decode the instruction. */
678 if (sc->argbuf.addr != vpc)
681 PROFILE_COUNT_SCACHE_MISS (current_cpu);
683 #define SET_LAST_INSN_P(last_p) do { sc->last_insn_p = (last_p); } while (0)
684 /* begin extract-scache */
687 ${SHELL} $infile extract-scache
690 /* end extract-scache */
691 #undef SET_LAST_INSN_P
695 PROFILE_COUNT_SCACHE_HIT (current_cpu);
696 /* Make core access statistics come out right.
697 The size is a guess, but it's currently not used either. */
698 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
707 @prefix@_engine_run_full (SIM_CPU *current_cpu)
709 SIM_DESC current_state = CPU_STATE (current_cpu);
710 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
711 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
716 # Any initialization code before looping starts.
717 # Note that this code may declare some locals.
718 ${SHELL} $infile init
720 if [ x
$parallel = xread
] ; then
722 #if defined (__GNUC__)
724 if (! CPU_IDESC_READ_INIT_P (current_cpu))
726 /* ??? Later maybe paste read.c in when building mainloop.c. */
727 #define DEFINE_LABELS
729 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
739 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
741 #if ! WITH_SEM_SWITCH_FULL
742 @prefix@_sem_init_idesc_table (current_cpu);
744 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
751 /* begin full-exec-scache */
754 ${SHELL} $infile full-exec-scache
757 /* end full-exec-scache */
759 while (0 /*CPU_RUNNING_P (current_cpu)*/);
766 ####################################
768 # Parallel scache engine: fast version.
770 if [ x
$fast = xyes
] ; then
777 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
779 SIM_DESC current_state = CPU_STATE (current_cpu);
780 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
781 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
783 PAREXEC pbufs[MAX_PARALLEL_INSNS];
788 # Any initialization code before looping starts.
789 # Note that this code may declare some locals.
790 ${SHELL} $infile init
792 if [ x
$parallel = xread
] ; then
795 #if defined (__GNUC__)
797 if (! CPU_IDESC_READ_INIT_P (current_cpu))
799 /* ??? Later maybe paste read.c in when building mainloop.c. */
800 #define DEFINE_LABELS
802 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
812 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
814 #if WITH_SEM_SWITCH_FAST
815 #if defined (__GNUC__)
816 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
817 #define DEFINE_LABELS
821 @prefix@_semf_init_idesc_table (current_cpu);
823 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
830 /* begin fast-exec-scache */
833 ${SHELL} $infile fast-exec-scache
836 /* end fast-exec-scache */
838 while (0 /*CPU_RUNNING_P (current_cpu)*/);
847 fi # -scache && parallel
849 ##########################################################################
851 # Compilation engine: lookup insn in scache, extract a pbb
852 # (pseudo-basic-block) if missing, then execute the pbb.
853 # A "pbb" is a sequence of insns up to the next cti insn or until
854 # some prespecified maximum.
855 # CTI: control transfer instruction.
857 if [ x
$pbb = xyes
] ; then
861 /* Record address of cti terminating a pbb. */
862 #define SET_CTI_VPC(sc) do { _cti_sc = (sc); } while (0)
863 /* Record number of [real] insns in pbb. */
864 #define SET_INSN_COUNT(n) do { _insn_count = (n); } while (0)
866 /* Fetch and extract a pseudo-basic-block.
867 FAST_P is non-zero if no tracing/profiling/etc. is wanted. */
870 @prefix@_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
875 int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu);
879 new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
882 /* Leading '_' to avoid collision with mainloop.in. */
884 SCACHE *orig_sc = sc;
885 SCACHE *_cti_sc = NULL;
886 int slice_insns = CPU_MAX_SLICE_INSNS (current_cpu);
888 /* First figure out how many instructions to compile.
889 MAX_INSNS is the size of the allocated buffer, which includes space
890 for before/after handlers if they're being used.
891 SLICE_INSNS is the maxinum number of real insns that can be
892 executed. Zero means "as many as we want". */
893 /* ??? max_insns is serving two incompatible roles.
894 1) Number of slots available in scache buffer.
895 2) Number of real insns to execute.
896 They're incompatible because there are virtual insns emitted too
897 (chain,cti-chain,before,after handlers). */
899 if (slice_insns == 1)
901 /* No need to worry about extra slots required for virtual insns
902 and parallel exec support because MAX_CHAIN_LENGTH is
903 guaranteed to be big enough to execute at least 1 insn! */
908 /* Allow enough slop so that while compiling insns, if max_insns > 0
909 then there's guaranteed to be enough space to emit one real insn.
910 MAX_CHAIN_LENGTH is typically much longer than
911 the normal number of insns between cti's anyway. */
912 max_insns -= (1 /* one for the trailing chain insn */
915 : (1 + MAX_PARALLEL_INSNS) /* before+after */)
916 + (MAX_PARALLEL_INSNS > 1
917 ? (MAX_PARALLEL_INSNS * 2)
920 /* Account for before/after handlers. */
925 && slice_insns < max_insns)
926 max_insns = slice_insns;
931 /* SC,PC must be updated to point passed the last entry used.
932 SET_CTI_VPC must be called if pbb is terminated by a cti.
933 SET_INSN_COUNT must be called to record number of real insns in
934 pbb [could be computed by us of course, extra cpu but perhaps
935 negligible enough]. */
937 /* begin extract-pbb */
940 ${SHELL} $infile extract-pbb
943 /* end extract-pbb */
945 /* The last one is a pseudo-insn to link to the next chain.
946 It is also used to record the insn count for this chain. */
950 /* Was pbb terminated by a cti? */
953 id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_CTI_CHAIN];
957 id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_CHAIN];
959 SEM_SET_CODE (&sc->argbuf, id, FAST_P);
960 sc->argbuf.idesc = id;
961 sc->argbuf.addr = pc;
962 sc->argbuf.fields.chain.insn_count = _insn_count;
963 sc->argbuf.fields.chain.next = 0;
964 sc->argbuf.fields.chain.branch_target = 0;
968 /* Update the pointer to the next free entry, may not have used as
969 many entries as was asked for. */
970 CPU_SCACHE_NEXT_FREE (current_cpu) = sc;
971 /* Record length of chain if profiling.
972 This includes virtual insns since they count against
975 PROFILE_COUNT_SCACHE_CHAIN_LENGTH (current_cpu, sc - orig_sc);
981 /* Chain to the next block from a non-cti terminated previous block. */
984 @prefix@_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
986 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
988 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
990 SET_H_PC (abuf->addr);
992 /* If not running forever, exit back to main loop. */
993 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
994 /* Also exit back to main loop if there's an event.
995 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
996 at the "right" time, but then that was what was asked for.
997 There is no silver bullet for simulator engines.
998 ??? Clearly this needs a cleaner interface.
999 At present it's just so Ctrl-C works. */
1000 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
1001 CPU_RUNNING_P (current_cpu) = 0;
1003 /* If chained to next block, go straight to it. */
1004 if (abuf->fields.chain.next)
1005 return abuf->fields.chain.next;
1006 /* See if next block has already been compiled. */
1007 abuf->fields.chain.next = scache_lookup (current_cpu, abuf->addr);
1008 if (abuf->fields.chain.next)
1009 return abuf->fields.chain.next;
1010 /* Nope, so next insn is a virtual insn to invoke the compiler
1012 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1015 /* Chain to the next block from a cti terminated previous block.
1016 BR_TYPE indicates whether the branch was taken and whether we can cache
1017 the vpc of the branch target.
1018 NEW_PC is the target's branch address, and is only valid if
1019 BR_TYPE != SEM_BRANCH_UNTAKEN. */
1022 @prefix@_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
1023 SEM_BRANCH_TYPE br_type, PCADDR new_pc)
1025 SEM_PC *new_vpc_ptr;
1027 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
1029 /* If not running forever, exit back to main loop. */
1030 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
1031 /* Also exit back to main loop if there's an event.
1032 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
1033 at the "right" time, but then that was what was asked for.
1034 There is no silver bullet for simulator engines.
1035 ??? Clearly this needs a cleaner interface.
1036 At present it's just so Ctrl-C works. */
1037 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
1038 CPU_RUNNING_P (current_cpu) = 0;
1040 /* Restart compiler if we branched to an uncacheable address
1042 if (br_type == SEM_BRANCH_UNCACHEABLE)
1045 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1048 /* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our
1050 if (br_type == SEM_BRANCH_UNTAKEN)
1052 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1053 new_pc = abuf->addr;
1055 new_vpc_ptr = &abuf->fields.chain.next;
1059 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1061 new_vpc_ptr = &abuf->fields.chain.branch_target;
1064 /* If chained to next block, go straight to it. */
1066 return *new_vpc_ptr;
1067 /* See if next block has already been compiled. */
1068 *new_vpc_ptr = scache_lookup (current_cpu, new_pc);
1070 return *new_vpc_ptr;
1071 /* Nope, so next insn is a virtual insn to invoke the compiler
1073 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1076 /* x-before handler.
1077 This is called before each insn. */
1080 @prefix@_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
1082 SEM_ARG sem_arg = sc;
1083 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1084 int first_p = abuf->fields.before.first_p;
1085 const ARGBUF *cur_abuf = SEM_ARGBUF (sc + 1);
1086 const IDESC *cur_idesc = cur_abuf->idesc;
1087 PCADDR pc = cur_abuf->addr;
1089 if (ARGBUF_PROFILE_P (cur_abuf))
1090 PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
1092 /* If this isn't the first insn, finish up the previous one. */
1096 if (PROFILE_MODEL_P (current_cpu))
1098 const SEM_ARG prev_sem_arg = sc - 1;
1099 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1100 const IDESC *prev_idesc = prev_abuf->idesc;
1103 /* ??? May want to measure all insns if doing insn tracing. */
1104 if (ARGBUF_PROFILE_P (prev_abuf))
1106 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1107 @prefix@_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
1111 TRACE_INSN_FINI (current_cpu, cur_abuf, 0 /*last_p*/);
1114 /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */
1115 if (PROFILE_MODEL_P (current_cpu)
1116 && ARGBUF_PROFILE_P (cur_abuf))
1117 @prefix@_model_insn_before (current_cpu, first_p);
1119 TRACE_INSN_INIT (current_cpu, cur_abuf, first_p);
1120 TRACE_INSN (current_cpu, cur_idesc->idata, cur_abuf, pc);
1124 This is called after a serial insn or at the end of a group of parallel
1128 @prefix@_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
1130 SEM_ARG sem_arg = sc;
1131 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1132 const SEM_ARG prev_sem_arg = sc - 1;
1133 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1135 /* ??? May want to measure all insns if doing insn tracing. */
1136 if (PROFILE_MODEL_P (current_cpu)
1137 && ARGBUF_PROFILE_P (prev_abuf))
1139 const IDESC *prev_idesc = prev_abuf->idesc;
1142 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1143 @prefix@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
1145 TRACE_INSN_FINI (current_cpu, prev_abuf, 1 /*last_p*/);
1151 @prefix@_engine_run_full (SIM_CPU *current_cpu)
1153 SIM_DESC current_state = CPU_STATE (current_cpu);
1154 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1155 /* virtual program counter */
1157 #if WITH_SEM_SWITCH_FULL
1158 /* For communication between cti's and cti-chain. */
1159 SEM_BRANCH_TYPE pbb_br_type;
1168 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1169 PAREXEC *par_exec = &pbufs[0];
1175 # Any initialization code before looping starts.
1176 # Note that this code may declare some locals.
1177 ${SHELL} $infile init
1181 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1183 /* ??? 'twould be nice to move this up a level and only call it once.
1184 On the other hand, in the "let's go fast" case the test is only done
1185 once per pbb (since we only return to the main loop at the end of
1186 a pbb). And in the "let's run until we're done" case we don't return
1187 until the program exits. */
1189 #if WITH_SEM_SWITCH_FULL
1190 #if defined (__GNUC__)
1191 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1192 #define DEFINE_LABELS
1196 @prefix@_sem_init_idesc_table (current_cpu);
1199 /* Initialize the "begin (compile) a pbb" virtual insn. */
1200 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1201 SEM_SET_FULL_CODE (SEM_ARGBUF (vpc),
1202 & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN]);
1203 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN];
1205 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1208 CPU_RUNNING_P (current_cpu) = 1;
1209 /* ??? In the case where we're returning to the main loop after every
1210 pbb we don't want to call pbb_begin each time (which hashes on the pc
1211 and does a table lookup). A way to speed this up is to save vpc
1213 vpc = @prefix@_pbb_begin (current_cpu, FAST_P);
1217 /* begin full-exec-pbb */
1220 ${SHELL} $infile full-exec-pbb
1223 /* end full-exec-pbb */
1225 while (CPU_RUNNING_P (current_cpu));
1232 ####################################
1234 # Compile engine: fast version.
1236 if [ x
$fast = xyes
] ; then
1243 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
1245 SIM_DESC current_state = CPU_STATE (current_cpu);
1246 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1247 /* virtual program counter */
1249 #if WITH_SEM_SWITCH_FAST
1250 /* For communication between cti's and cti-chain. */
1251 SEM_BRANCH_TYPE pbb_br_type;
1260 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1261 PAREXEC *par_exec = &pbufs[0];
1267 # Any initialization code before looping starts.
1268 # Note that this code may declare some locals.
1269 ${SHELL} $infile init
1273 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1275 /* ??? 'twould be nice to move this up a level and only call it once.
1276 On the other hand, in the "let's go fast" case the test is only done
1277 once per pbb (since we only return to the main loop at the end of
1278 a pbb). And in the "let's run until we're done" case we don't return
1279 until the program exits. */
1281 #if WITH_SEM_SWITCH_FAST
1282 #if defined (__GNUC__)
1283 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1284 #define DEFINE_LABELS
1288 @prefix@_semf_init_idesc_table (current_cpu);
1291 /* Initialize the "begin (compile) a pbb" virtual insn. */
1292 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1293 SEM_SET_FAST_CODE (SEM_ARGBUF (vpc),
1294 & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN]);
1295 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN];
1297 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1300 CPU_RUNNING_P (current_cpu) = 1;
1301 /* ??? In the case where we're returning to the main loop after every
1302 pbb we don't want to call pbb_begin each time (which hashes on the pc
1303 and does a table lookup). A way to speed this up is to save vpc
1305 vpc = @prefix@_pbb_begin (current_cpu, FAST_P);
1309 /* begin fast-exec-pbb */
1312 ${SHELL} $infile fast-exec-pbb
1315 /* end fast-exec-pbb */
1317 while (CPU_RUNNING_P (current_cpu));
1327 # Expand @..@ macros appearing in tmp-mloop-{pid}.cin.
1329 -e "s/@cpu@/$cpu/g" -e "s/@CPU@/$CPU/g" \
1330 -e "s/@prefix@/$prefix/g" -e "s/@PREFIX@/$PREFIX/g" < tmp-mloop-$$.cin
> mloop
${outsuffix}.cin
1332 rm -f tmp-mloop-$$.cin