1 # Generate the main loop of the simulator.
2 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007
3 # Free Software Foundation, Inc.
4 # Contributed by Cygnus Support.
6 # This file is part of the GNU simulators.
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2, or (at your option)
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License along
19 # with this program; if not, write to the Free Software Foundation, Inc.,
20 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 # This file creates two files: eng.hin and mloop.cin.
23 # eng.hin defines a few macros that specify what kind of engine was selected
24 # based on the arguments to this script.
25 # mloop.cin contains the engine.
27 # ??? Rename mloop.c to eng.c?
28 # ??? Rename mainloop.in to engine.in?
29 # ??? Add options to specify output file names?
30 # ??? Rename this file to genengine.sh?
32 # Syntax: genmloop.sh [options]
37 # - specify single cpu or multiple cpus (number specifyable at runtime),
38 # maximum number is a configuration parameter
41 # -fast: include support for fast execution in addition to full featured mode
43 # Full featured mode is for tracing, profiling, etc. and is always
44 # provided. Fast mode contains no frills, except speed.
45 # A target need only provide a "full" version of one of
46 # simple,scache,pbb. If the target wants it can also provide a fast
47 # version of same. It can't provide more than this.
48 # ??? Later add ability to have another set of full/fast semantics
49 # for use in with-devices/with-smp situations (pbb can be inappropriate
52 # -full-switch: same as -fast but for full featured version of -switch
53 # Only needed if -fast present.
55 # -simple: simple execution engine (the default)
57 # This engine fetches and executes one instruction at a time.
58 # Field extraction is done in the semantic routines.
60 # ??? There are two possible flavours of -simple. One that extracts
61 # fields in the semantic routine (which is what is implemented here),
62 # and one that stores the extracted fields in ARGBUF before calling the
63 # semantic routine. The latter is essentially the -scache case with a
64 # cache size of one (and the scache lookup code removed). There are no
65 # current uses of this and it's not clear when doing this would be a win.
66 # More complicated ISA's that want to use -simple may find this a win.
67 # Should this ever be desirable, implement a new engine style here and
68 # call it -extract (or some such). It's believed that the CGEN-generated
69 # code for the -scache case would be usable here, so no new code
70 # generation option would be needed for CGEN.
72 # -scache: use the scache to speed things up (not always a win)
74 # This engine caches the extracted instruction before executing it.
75 # When executing instructions they are first looked up in the scache.
77 # -pbb: same as -scache but extract a (pseudo-) basic block at a time
79 # This engine is basically identical to the scache version except that
80 # extraction is done a pseudo-basic-block at a time and the address of
81 # the scache entry of a branch target is recorded as well.
82 # Additional speedups are then possible by defering Ctrl-C checking
83 # to the end of basic blocks and by threading the insns together.
84 # We call them pseudo-basic-block's instead of just basic-blocks because
85 # they're not necessarily basic-blocks, though normally are.
87 # -parallel-read: support parallel execution with read-before-exec support.
88 # -parallel-write: support parallel execution with write-after-exec support.
89 # -parallel-generic-write: support parallel execution with generic queued
92 # One of these options is specified in addition to -simple, -scache,
93 # -pbb. Note that while the code can determine if the cpu supports
94 # parallel execution with HAVE_PARALLEL_INSNS [and thus this option is
95 # technically unnecessary], having this option cuts down on the clutter
98 # -parallel-only: semantic code only supports parallel version of insn
100 # Semantic code only supports parallel versions of each insn.
101 # Things can be sped up by generating both serial and parallel versions
102 # and is better suited to mixed parallel architectures like the m32r.
104 # -prefix: string to prepend to function names in mloop.c/eng.h.
106 # If no prefix is specified, the cpu type is used.
108 # -switch file: specify file containing semantics implemented as a switch()
112 # Specify the cpu family name.
114 # -infile <input-file>
116 # Specify the mainloop.in input file.
118 # -outfile-suffix <output-file-suffix>
120 # Specify the suffix to append to output files.
122 # Only one of -scache/-pbb may be selected.
123 # -simple is the default.
128 # - build mainloop.in from .cpu file
147 -multi) type=multi ;;
150 -full-switch) full_switch=yes ;;
152 -scache) scache=yes ;;
155 -outfile-suffix) shift ; outsuffix=$1 ;;
156 -parallel-read) parallel=read ;;
157 -parallel-write) parallel=write ;;
158 -parallel-generic-write) parallel=genwrite ;;
159 -parallel-only) parallel_only=yes ;;
160 -prefix) shift ; prefix=$1 ;;
161 -switch) shift ; switch=$1 ;;
162 -cpu) shift ; cpu=$1 ;;
163 -infile) shift ; infile=$1 ;;
164 *) echo "unknown option: $1" >&2 ; exit 1 ;;
169 # Argument validation.
171 if [ x$scache = xyes -a x$pbb = xyes ] ; then
172 echo "only one of -scache and -pbb may be selected" >&2
176 if [ "x$cpu" = xunknown ] ; then
177 echo "cpu family not specified" >&2
181 if [ "x$infile" = x ] ; then
182 echo "mainloop.in not specified" >&2
186 if [ "x$prefix" = xunknown ] ; then
190 lowercase='abcdefghijklmnopqrstuvwxyz'
191 uppercase='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
192 CPU=`echo ${cpu} | tr "${lowercase}" "${uppercase}"`
193 PREFIX=`echo ${prefix} | tr "${lowercase}" "${uppercase}"`
195 ##########################################################################
197 rm -f eng${outsuffix}.hin
198 exec 1>eng${outsuffix}.hin
200 echo "/* engine configuration for ${cpu} */"
203 echo "/* WITH_FAST: non-zero if a fast version of the engine is available"
204 echo " in addition to the full-featured version. */"
205 if [ x$fast = xyes ] ; then
206 echo "#define WITH_FAST 1"
208 echo "#define WITH_FAST 0"
212 echo "/* WITH_SCACHE_PBB_${PREFIX}: non-zero if the pbb engine was selected. */"
213 if [ x$pbb = xyes ] ; then
214 echo "#define WITH_SCACHE_PBB_${PREFIX} 1"
216 echo "#define WITH_SCACHE_PBB_${PREFIX} 0"
220 echo "/* HAVE_PARALLEL_INSNS: non-zero if cpu can parallelly execute > 1 insn. */"
221 # blah blah blah, other ways to do this, blah blah blah
224 echo "#define HAVE_PARALLEL_INSNS 0"
225 echo "#define WITH_PARALLEL_READ 0"
226 echo "#define WITH_PARALLEL_WRITE 0"
227 echo "#define WITH_PARALLEL_GENWRITE 0"
230 echo "#define HAVE_PARALLEL_INSNS 1"
231 echo "/* Parallel execution is supported by read-before-exec. */"
232 echo "#define WITH_PARALLEL_READ 1"
233 echo "#define WITH_PARALLEL_WRITE 0"
234 echo "#define WITH_PARALLEL_GENWRITE 0"
237 echo "#define HAVE_PARALLEL_INSNS 1"
238 echo "/* Parallel execution is supported by write-after-exec. */"
239 echo "#define WITH_PARALLEL_READ 0"
240 echo "#define WITH_PARALLEL_WRITE 1"
241 echo "#define WITH_PARALLEL_GENWRITE 0"
244 echo "#define HAVE_PARALLEL_INSNS 1"
245 echo "/* Parallel execution is supported by generic write-after-exec. */"
246 echo "#define WITH_PARALLEL_READ 0"
247 echo "#define WITH_PARALLEL_WRITE 0"
248 echo "#define WITH_PARALLEL_GENWRITE 1"
252 if [ "x$switch" != x ] ; then
254 echo "/* WITH_SEM_SWITCH_FULL: non-zero if full-featured engine is"
255 echo " implemented as a switch(). */"
256 if [ x$fast != xyes -o x$full_switch = xyes ] ; then
257 echo "#define WITH_SEM_SWITCH_FULL 1"
259 echo "#define WITH_SEM_SWITCH_FULL 0"
262 echo "/* WITH_SEM_SWITCH_FAST: non-zero if fast engine is"
263 echo " implemented as a switch(). */"
264 if [ x$fast = xyes ] ; then
265 echo "#define WITH_SEM_SWITCH_FAST 1"
267 echo "#define WITH_SEM_SWITCH_FAST 0"
271 # Decls of functions we define.
274 echo "/* Functions defined in the generated mainloop.c file"
275 echo " (which doesn't necessarily have that file name). */"
277 echo "extern ENGINE_FN ${prefix}_engine_run_full;"
278 echo "extern ENGINE_FN ${prefix}_engine_run_fast;"
280 if [ x$pbb = xyes ] ; then
282 echo "extern SEM_PC ${prefix}_pbb_begin (SIM_CPU *, int);"
283 echo "extern SEM_PC ${prefix}_pbb_chain (SIM_CPU *, SEM_ARG);"
284 echo "extern SEM_PC ${prefix}_pbb_cti_chain (SIM_CPU *, SEM_ARG, SEM_BRANCH_TYPE, PCADDR);"
285 echo "extern void ${prefix}_pbb_before (SIM_CPU *, SCACHE *);"
286 echo "extern void ${prefix}_pbb_after (SIM_CPU *, SCACHE *);"
289 ##########################################################################
291 rm -f tmp-mloop-$$.cin mloop${outsuffix}.cin
292 exec 1>tmp-mloop-$$.cin
294 # We use @cpu@ instead of ${cpu} because we still need to run sed to handle
295 # transformation of @cpu@ for mainloop.in, so there's no need to use ${cpu}
299 /* This file is generated by the genmloop script. DO NOT EDIT! */
301 /* Enable switch() support in cgen headers. */
302 #define SEM_IN_SWITCH
304 #define WANT_CPU @cpu@
305 #define WANT_CPU_@CPU@
307 #include "sim-main.h"
309 #include "cgen-mem.h"
310 #include "cgen-ops.h"
311 #include "sim-assert.h"
313 /* Fill in the administrative ARGBUF fields required by all insns,
317 @prefix@_fill_argbuf (const SIM_CPU *cpu, ARGBUF *abuf, const IDESC *idesc,
318 PCADDR pc, int fast_p)
321 SEM_SET_CODE (abuf, idesc, fast_p);
322 ARGBUF_ADDR (abuf) = pc;
324 ARGBUF_IDESC (abuf) = idesc;
327 /* Fill in tracing/profiling fields of an ARGBUF. */
330 @prefix@_fill_argbuf_tp (const SIM_CPU *cpu, ARGBUF *abuf,
331 int trace_p, int profile_p)
333 ARGBUF_TRACE_P (abuf) = trace_p;
334 ARGBUF_PROFILE_P (abuf) = profile_p;
339 /* Emit the "x-before" handler.
340 x-before is emitted before each insn (serial or parallel).
341 This is as opposed to x-after which is only emitted at the end of a group
342 of parallel insns. */
345 @prefix@_emit_before (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc, int first_p)
347 ARGBUF *abuf = &sc[0].argbuf;
348 const IDESC *id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEFORE];
350 abuf->fields.before.first_p = first_p;
351 @prefix@_fill_argbuf (current_cpu, abuf, id, pc, 0);
352 /* no need to set trace_p,profile_p */
355 /* Emit the "x-after" handler.
356 x-after is emitted after a serial insn or at the end of a group of
360 @prefix@_emit_after (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc)
362 ARGBUF *abuf = &sc[0].argbuf;
363 const IDESC *id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_AFTER];
365 @prefix@_fill_argbuf (current_cpu, abuf, id, pc, 0);
366 /* no need to set trace_p,profile_p */
369 #endif /* WITH_SCACHE_PBB */
373 ${SHELL} $infile support
375 ##########################################################################
377 # Simple engine: fetch an instruction, execute the instruction.
379 # Instruction fields are not extracted into ARGBUF, they are extracted in
380 # the semantic routines themselves. However, there is still a need to pass
381 # and return misc. information to the semantic routines so we still use ARGBUF.
382 # [One could certainly implement things differently and remove ARGBUF.
383 # It's not clear this is necessarily always a win.]
384 # ??? The use of the SCACHE struct is for consistency with the with-scache
385 # case though it might be a source of confusion.
387 if [ x$scache != xyes -a x$pbb != xyes ] ; then
394 @prefix@_engine_run_full (SIM_CPU *current_cpu)
397 SIM_DESC current_state = CPU_STATE (current_cpu);
398 /* ??? Use of SCACHE is a bit of a hack as we don't actually use the scache.
399 We do however use ARGBUF so for consistency with the other engine flavours
400 the SCACHE type is used. */
401 SCACHE cache[MAX_LIW_INSNS];
402 SCACHE *sc = &cache[0];
409 PAREXEC pbufs[MAX_PARALLEL_INSNS];
416 # Any initialization code before looping starts.
417 # Note that this code may declare some locals.
418 ${SHELL} $infile init
420 if [ x$parallel = xread ] ; then
423 #if defined (__GNUC__)
425 if (! CPU_IDESC_READ_INIT_P (current_cpu))
427 /* ??? Later maybe paste read.c in when building mainloop.c. */
428 #define DEFINE_LABELS
430 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
440 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
442 #if WITH_SEM_SWITCH_FULL
443 #if defined (__GNUC__)
444 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
445 #define DEFINE_LABELS
449 @prefix@_sem_init_idesc_table (current_cpu);
451 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
456 /* begin full-exec-simple */
459 ${SHELL} $infile full-exec-simple
462 /* end full-exec-simple */
464 ++ CPU_INSN_COUNT (current_cpu);
466 while (0 /*CPU_RUNNING_P (current_cpu)*/);
473 ####################################
475 # Simple engine: fast version.
476 # ??? A somewhat dubious effort, but for completeness' sake.
478 if [ x$fast = xyes ] ; then
484 FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh."
494 ##########################################################################
496 # Non-parallel scache engine: lookup insn in scache, fetch if missing,
499 if [ x$scache = xyes -a x$parallel = xno ] ; then
503 static INLINE SCACHE *
504 @prefix@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
505 unsigned int hash_mask, int FAST_P)
507 /* First step: look up current insn in hash table. */
508 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
510 /* If the entry isn't the one we want (cache miss),
511 fetch and decode the instruction. */
512 if (sc->argbuf.addr != vpc)
515 PROFILE_COUNT_SCACHE_MISS (current_cpu);
517 /* begin extract-scache */
520 ${SHELL} $infile extract-scache
523 /* end extract-scache */
527 PROFILE_COUNT_SCACHE_HIT (current_cpu);
528 /* Make core access statistics come out right.
529 The size is a guess, but it's currently not used either. */
530 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
539 @prefix@_engine_run_full (SIM_CPU *current_cpu)
541 SIM_DESC current_state = CPU_STATE (current_cpu);
542 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
543 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
548 # Any initialization code before looping starts.
549 # Note that this code may declare some locals.
550 ${SHELL} $infile init
554 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
556 #if ! WITH_SEM_SWITCH_FULL
557 @prefix@_sem_init_idesc_table (current_cpu);
559 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
568 sc = @prefix@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
570 /* begin full-exec-scache */
573 ${SHELL} $infile full-exec-scache
576 /* end full-exec-scache */
580 ++ CPU_INSN_COUNT (current_cpu);
582 while (0 /*CPU_RUNNING_P (current_cpu)*/);
589 ####################################
591 # Non-parallel scache engine: fast version.
593 if [ x$fast = xyes ] ; then
600 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
602 SIM_DESC current_state = CPU_STATE (current_cpu);
603 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
604 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
609 # Any initialization code before looping starts.
610 # Note that this code may declare some locals.
611 ${SHELL} $infile init
615 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
617 #if WITH_SEM_SWITCH_FAST
618 #if defined (__GNUC__)
619 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
620 #define DEFINE_LABELS
624 @prefix@_semf_init_idesc_table (current_cpu);
626 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
635 sc = @prefix@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
637 /* begin fast-exec-scache */
640 ${SHELL} $infile fast-exec-scache
643 /* end fast-exec-scache */
647 ++ CPU_INSN_COUNT (current_cpu);
649 while (0 /*CPU_RUNNING_P (current_cpu)*/);
658 fi # -scache && ! parallel
660 ##########################################################################
662 # Parallel scache engine: lookup insn in scache, fetch if missing,
664 # For the parallel case we give the target more flexibility.
666 if [ x$scache = xyes -a x$parallel != xno ] ; then
670 static INLINE SCACHE *
671 @prefix@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
672 unsigned int hash_mask, int FAST_P)
674 /* First step: look up current insn in hash table. */
675 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
677 /* If the entry isn't the one we want (cache miss),
678 fetch and decode the instruction. */
679 if (sc->argbuf.addr != vpc)
682 PROFILE_COUNT_SCACHE_MISS (current_cpu);
684 #define SET_LAST_INSN_P(last_p) do { sc->last_insn_p = (last_p); } while (0)
685 /* begin extract-scache */
688 ${SHELL} $infile extract-scache
691 /* end extract-scache */
692 #undef SET_LAST_INSN_P
696 PROFILE_COUNT_SCACHE_HIT (current_cpu);
697 /* Make core access statistics come out right.
698 The size is a guess, but it's currently not used either. */
699 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
708 @prefix@_engine_run_full (SIM_CPU *current_cpu)
710 SIM_DESC current_state = CPU_STATE (current_cpu);
711 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
712 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
717 # Any initialization code before looping starts.
718 # Note that this code may declare some locals.
719 ${SHELL} $infile init
721 if [ x$parallel = xread ] ; then
723 #if defined (__GNUC__)
725 if (! CPU_IDESC_READ_INIT_P (current_cpu))
727 /* ??? Later maybe paste read.c in when building mainloop.c. */
728 #define DEFINE_LABELS
730 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
740 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
742 #if ! WITH_SEM_SWITCH_FULL
743 @prefix@_sem_init_idesc_table (current_cpu);
745 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
752 /* begin full-exec-scache */
755 ${SHELL} $infile full-exec-scache
758 /* end full-exec-scache */
760 while (0 /*CPU_RUNNING_P (current_cpu)*/);
767 ####################################
769 # Parallel scache engine: fast version.
771 if [ x$fast = xyes ] ; then
778 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
780 SIM_DESC current_state = CPU_STATE (current_cpu);
781 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
782 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
784 PAREXEC pbufs[MAX_PARALLEL_INSNS];
789 # Any initialization code before looping starts.
790 # Note that this code may declare some locals.
791 ${SHELL} $infile init
793 if [ x$parallel = xread ] ; then
796 #if defined (__GNUC__)
798 if (! CPU_IDESC_READ_INIT_P (current_cpu))
800 /* ??? Later maybe paste read.c in when building mainloop.c. */
801 #define DEFINE_LABELS
803 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
813 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
815 #if WITH_SEM_SWITCH_FAST
816 #if defined (__GNUC__)
817 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
818 #define DEFINE_LABELS
822 @prefix@_semf_init_idesc_table (current_cpu);
824 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
831 /* begin fast-exec-scache */
834 ${SHELL} $infile fast-exec-scache
837 /* end fast-exec-scache */
839 while (0 /*CPU_RUNNING_P (current_cpu)*/);
848 fi # -scache && parallel
850 ##########################################################################
852 # Compilation engine: lookup insn in scache, extract a pbb
853 # (pseudo-basic-block) if missing, then execute the pbb.
854 # A "pbb" is a sequence of insns up to the next cti insn or until
855 # some prespecified maximum.
856 # CTI: control transfer instruction.
858 if [ x$pbb = xyes ] ; then
862 /* Record address of cti terminating a pbb. */
863 #define SET_CTI_VPC(sc) do { _cti_sc = (sc); } while (0)
864 /* Record number of [real] insns in pbb. */
865 #define SET_INSN_COUNT(n) do { _insn_count = (n); } while (0)
867 /* Fetch and extract a pseudo-basic-block.
868 FAST_P is non-zero if no tracing/profiling/etc. is wanted. */
871 @prefix@_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
876 int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu);
880 new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
883 /* Leading '_' to avoid collision with mainloop.in. */
885 SCACHE *orig_sc = sc;
886 SCACHE *_cti_sc = NULL;
887 int slice_insns = CPU_MAX_SLICE_INSNS (current_cpu);
889 /* First figure out how many instructions to compile.
890 MAX_INSNS is the size of the allocated buffer, which includes space
891 for before/after handlers if they're being used.
892 SLICE_INSNS is the maxinum number of real insns that can be
893 executed. Zero means "as many as we want". */
894 /* ??? max_insns is serving two incompatible roles.
895 1) Number of slots available in scache buffer.
896 2) Number of real insns to execute.
897 They're incompatible because there are virtual insns emitted too
898 (chain,cti-chain,before,after handlers). */
900 if (slice_insns == 1)
902 /* No need to worry about extra slots required for virtual insns
903 and parallel exec support because MAX_CHAIN_LENGTH is
904 guaranteed to be big enough to execute at least 1 insn! */
909 /* Allow enough slop so that while compiling insns, if max_insns > 0
910 then there's guaranteed to be enough space to emit one real insn.
911 MAX_CHAIN_LENGTH is typically much longer than
912 the normal number of insns between cti's anyway. */
913 max_insns -= (1 /* one for the trailing chain insn */
916 : (1 + MAX_PARALLEL_INSNS) /* before+after */)
917 + (MAX_PARALLEL_INSNS > 1
918 ? (MAX_PARALLEL_INSNS * 2)
921 /* Account for before/after handlers. */
926 && slice_insns < max_insns)
927 max_insns = slice_insns;
932 /* SC,PC must be updated to point passed the last entry used.
933 SET_CTI_VPC must be called if pbb is terminated by a cti.
934 SET_INSN_COUNT must be called to record number of real insns in
935 pbb [could be computed by us of course, extra cpu but perhaps
936 negligible enough]. */
938 /* begin extract-pbb */
941 ${SHELL} $infile extract-pbb
944 /* end extract-pbb */
946 /* The last one is a pseudo-insn to link to the next chain.
947 It is also used to record the insn count for this chain. */
951 /* Was pbb terminated by a cti? */
954 id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_CTI_CHAIN];
958 id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_CHAIN];
960 SEM_SET_CODE (&sc->argbuf, id, FAST_P);
961 sc->argbuf.idesc = id;
962 sc->argbuf.addr = pc;
963 sc->argbuf.fields.chain.insn_count = _insn_count;
964 sc->argbuf.fields.chain.next = 0;
965 sc->argbuf.fields.chain.branch_target = 0;
969 /* Update the pointer to the next free entry, may not have used as
970 many entries as was asked for. */
971 CPU_SCACHE_NEXT_FREE (current_cpu) = sc;
972 /* Record length of chain if profiling.
973 This includes virtual insns since they count against
976 PROFILE_COUNT_SCACHE_CHAIN_LENGTH (current_cpu, sc - orig_sc);
982 /* Chain to the next block from a non-cti terminated previous block. */
985 @prefix@_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
987 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
989 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
991 SET_H_PC (abuf->addr);
993 /* If not running forever, exit back to main loop. */
994 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
995 /* Also exit back to main loop if there's an event.
996 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
997 at the "right" time, but then that was what was asked for.
998 There is no silver bullet for simulator engines.
999 ??? Clearly this needs a cleaner interface.
1000 At present it's just so Ctrl-C works. */
1001 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
1002 CPU_RUNNING_P (current_cpu) = 0;
1004 /* If chained to next block, go straight to it. */
1005 if (abuf->fields.chain.next)
1006 return abuf->fields.chain.next;
1007 /* See if next block has already been compiled. */
1008 abuf->fields.chain.next = scache_lookup (current_cpu, abuf->addr);
1009 if (abuf->fields.chain.next)
1010 return abuf->fields.chain.next;
1011 /* Nope, so next insn is a virtual insn to invoke the compiler
1013 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1016 /* Chain to the next block from a cti terminated previous block.
1017 BR_TYPE indicates whether the branch was taken and whether we can cache
1018 the vpc of the branch target.
1019 NEW_PC is the target's branch address, and is only valid if
1020 BR_TYPE != SEM_BRANCH_UNTAKEN. */
1023 @prefix@_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
1024 SEM_BRANCH_TYPE br_type, PCADDR new_pc)
1026 SEM_PC *new_vpc_ptr;
1028 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
1030 /* If not running forever, exit back to main loop. */
1031 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
1032 /* Also exit back to main loop if there's an event.
1033 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
1034 at the "right" time, but then that was what was asked for.
1035 There is no silver bullet for simulator engines.
1036 ??? Clearly this needs a cleaner interface.
1037 At present it's just so Ctrl-C works. */
1038 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
1039 CPU_RUNNING_P (current_cpu) = 0;
1041 /* Restart compiler if we branched to an uncacheable address
1043 if (br_type == SEM_BRANCH_UNCACHEABLE)
1046 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1049 /* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our
1051 if (br_type == SEM_BRANCH_UNTAKEN)
1053 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1054 new_pc = abuf->addr;
1056 new_vpc_ptr = &abuf->fields.chain.next;
1060 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1062 new_vpc_ptr = &abuf->fields.chain.branch_target;
1065 /* If chained to next block, go straight to it. */
1067 return *new_vpc_ptr;
1068 /* See if next block has already been compiled. */
1069 *new_vpc_ptr = scache_lookup (current_cpu, new_pc);
1071 return *new_vpc_ptr;
1072 /* Nope, so next insn is a virtual insn to invoke the compiler
1074 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1077 /* x-before handler.
1078 This is called before each insn. */
1081 @prefix@_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
1083 SEM_ARG sem_arg = sc;
1084 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1085 int first_p = abuf->fields.before.first_p;
1086 const ARGBUF *cur_abuf = SEM_ARGBUF (sc + 1);
1087 const IDESC *cur_idesc = cur_abuf->idesc;
1088 PCADDR pc = cur_abuf->addr;
1090 if (ARGBUF_PROFILE_P (cur_abuf))
1091 PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
1093 /* If this isn't the first insn, finish up the previous one. */
1097 if (PROFILE_MODEL_P (current_cpu))
1099 const SEM_ARG prev_sem_arg = sc - 1;
1100 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1101 const IDESC *prev_idesc = prev_abuf->idesc;
1104 /* ??? May want to measure all insns if doing insn tracing. */
1105 if (ARGBUF_PROFILE_P (prev_abuf))
1107 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1108 @prefix@_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
1112 TRACE_INSN_FINI (current_cpu, cur_abuf, 0 /*last_p*/);
1115 /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */
1116 if (PROFILE_MODEL_P (current_cpu)
1117 && ARGBUF_PROFILE_P (cur_abuf))
1118 @prefix@_model_insn_before (current_cpu, first_p);
1120 TRACE_INSN_INIT (current_cpu, cur_abuf, first_p);
1121 TRACE_INSN (current_cpu, cur_idesc->idata, cur_abuf, pc);
1125 This is called after a serial insn or at the end of a group of parallel
1129 @prefix@_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
1131 SEM_ARG sem_arg = sc;
1132 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1133 const SEM_ARG prev_sem_arg = sc - 1;
1134 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1136 /* ??? May want to measure all insns if doing insn tracing. */
1137 if (PROFILE_MODEL_P (current_cpu)
1138 && ARGBUF_PROFILE_P (prev_abuf))
1140 const IDESC *prev_idesc = prev_abuf->idesc;
1143 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1144 @prefix@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
1146 TRACE_INSN_FINI (current_cpu, prev_abuf, 1 /*last_p*/);
1152 @prefix@_engine_run_full (SIM_CPU *current_cpu)
1154 SIM_DESC current_state = CPU_STATE (current_cpu);
1155 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1156 /* virtual program counter */
1158 #if WITH_SEM_SWITCH_FULL
1159 /* For communication between cti's and cti-chain. */
1160 SEM_BRANCH_TYPE pbb_br_type;
1169 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1170 PAREXEC *par_exec = &pbufs[0];
1176 # Any initialization code before looping starts.
1177 # Note that this code may declare some locals.
1178 ${SHELL} $infile init
1182 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1184 /* ??? 'twould be nice to move this up a level and only call it once.
1185 On the other hand, in the "let's go fast" case the test is only done
1186 once per pbb (since we only return to the main loop at the end of
1187 a pbb). And in the "let's run until we're done" case we don't return
1188 until the program exits. */
1190 #if WITH_SEM_SWITCH_FULL
1191 #if defined (__GNUC__)
1192 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1193 #define DEFINE_LABELS
1197 @prefix@_sem_init_idesc_table (current_cpu);
1200 /* Initialize the "begin (compile) a pbb" virtual insn. */
1201 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1202 SEM_SET_FULL_CODE (SEM_ARGBUF (vpc),
1203 & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN]);
1204 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN];
1206 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1209 CPU_RUNNING_P (current_cpu) = 1;
1210 /* ??? In the case where we're returning to the main loop after every
1211 pbb we don't want to call pbb_begin each time (which hashes on the pc
1212 and does a table lookup). A way to speed this up is to save vpc
1214 vpc = @prefix@_pbb_begin (current_cpu, FAST_P);
1218 /* begin full-exec-pbb */
1221 ${SHELL} $infile full-exec-pbb
1224 /* end full-exec-pbb */
1226 while (CPU_RUNNING_P (current_cpu));
1233 ####################################
1235 # Compile engine: fast version.
1237 if [ x$fast = xyes ] ; then
1244 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
1246 SIM_DESC current_state = CPU_STATE (current_cpu);
1247 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1248 /* virtual program counter */
1250 #if WITH_SEM_SWITCH_FAST
1251 /* For communication between cti's and cti-chain. */
1252 SEM_BRANCH_TYPE pbb_br_type;
1261 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1262 PAREXEC *par_exec = &pbufs[0];
1268 # Any initialization code before looping starts.
1269 # Note that this code may declare some locals.
1270 ${SHELL} $infile init
1274 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1276 /* ??? 'twould be nice to move this up a level and only call it once.
1277 On the other hand, in the "let's go fast" case the test is only done
1278 once per pbb (since we only return to the main loop at the end of
1279 a pbb). And in the "let's run until we're done" case we don't return
1280 until the program exits. */
1282 #if WITH_SEM_SWITCH_FAST
1283 #if defined (__GNUC__)
1284 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1285 #define DEFINE_LABELS
1289 @prefix@_semf_init_idesc_table (current_cpu);
1292 /* Initialize the "begin (compile) a pbb" virtual insn. */
1293 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1294 SEM_SET_FAST_CODE (SEM_ARGBUF (vpc),
1295 & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN]);
1296 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN];
1298 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1301 CPU_RUNNING_P (current_cpu) = 1;
1302 /* ??? In the case where we're returning to the main loop after every
1303 pbb we don't want to call pbb_begin each time (which hashes on the pc
1304 and does a table lookup). A way to speed this up is to save vpc
1306 vpc = @prefix@_pbb_begin (current_cpu, FAST_P);
1310 /* begin fast-exec-pbb */
1313 ${SHELL} $infile fast-exec-pbb
1316 /* end fast-exec-pbb */
1318 while (CPU_RUNNING_P (current_cpu));
1328 # Expand @..@ macros appearing in tmp-mloop-{pid}.cin.
1330 -e "s/@cpu@/$cpu/g" -e "s/@CPU@/$CPU/g" \
1331 -e "s/@prefix@/$prefix/g" -e "s/@PREFIX@/$PREFIX/g" < tmp-mloop-$$.cin > mloop${outsuffix}.cin
1333 rm -f tmp-mloop-$$.cin