1 # Generate the main loop of the simulator.
2 # Copyright (C) 1996-2021 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 3 of the License, or
10 # (at your option) any later version.
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
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 # This file creates two files: eng.hin and mloop.cin.
21 # eng.hin defines a few macros that specify what kind of engine was selected
22 # based on the arguments to this script.
23 # mloop.cin contains the engine.
25 # ??? Rename mloop.c to eng.c?
26 # ??? Rename mainloop.in to engine.in?
27 # ??? Add options to specify output file names?
28 # ??? Rename this file to genengine.sh?
30 # Syntax: genmloop.sh [options]
35 # - specify single cpu or multiple cpus (number specifyable at runtime),
36 # maximum number is a configuration parameter
39 # -fast: include support for fast execution in addition to full featured mode
41 # Full featured mode is for tracing, profiling, etc. and is always
42 # provided. Fast mode contains no frills, except speed.
43 # A target need only provide a "full" version of one of
44 # simple,scache,pbb. If the target wants it can also provide a fast
45 # version of same. It can't provide more than this.
46 # ??? Later add ability to have another set of full/fast semantics
47 # for use in with-devices/with-smp situations (pbb can be inappropriate
50 # -full-switch: same as -fast but for full featured version of -switch
51 # Only needed if -fast present.
53 # -simple: simple execution engine (the default)
55 # This engine fetches and executes one instruction at a time.
56 # Field extraction is done in the semantic routines.
58 # ??? There are two possible flavours of -simple. One that extracts
59 # fields in the semantic routine (which is what is implemented here),
60 # and one that stores the extracted fields in ARGBUF before calling the
61 # semantic routine. The latter is essentially the -scache case with a
62 # cache size of one (and the scache lookup code removed). There are no
63 # current uses of this and it's not clear when doing this would be a win.
64 # More complicated ISA's that want to use -simple may find this a win.
65 # Should this ever be desirable, implement a new engine style here and
66 # call it -extract (or some such). It's believed that the CGEN-generated
67 # code for the -scache case would be usable here, so no new code
68 # generation option would be needed for CGEN.
70 # -scache: use the scache to speed things up (not always a win)
72 # This engine caches the extracted instruction before executing it.
73 # When executing instructions they are first looked up in the scache.
75 # -pbb: same as -scache but extract a (pseudo-) basic block at a time
77 # This engine is basically identical to the scache version except that
78 # extraction is done a pseudo-basic-block at a time and the address of
79 # the scache entry of a branch target is recorded as well.
80 # Additional speedups are then possible by defering Ctrl-C checking
81 # to the end of basic blocks and by threading the insns together.
82 # We call them pseudo-basic-block's instead of just basic-blocks because
83 # they're not necessarily basic-blocks, though normally are.
85 # -parallel-read: support parallel execution with read-before-exec support.
86 # -parallel-write: support parallel execution with write-after-exec support.
87 # -parallel-generic-write: support parallel execution with generic queued
90 # One of these options is specified in addition to -simple, -scache,
91 # -pbb. Note that while the code can determine if the cpu supports
92 # parallel execution with HAVE_PARALLEL_INSNS [and thus this option is
93 # technically unnecessary], having this option cuts down on the clutter
96 # -parallel-only: semantic code only supports parallel version of insn
98 # Semantic code only supports parallel versions of each insn.
99 # Things can be sped up by generating both serial and parallel versions
100 # and is better suited to mixed parallel architectures like the m32r.
102 # -prefix: string to prepend to function names in mloop.c/eng.h.
104 # If no prefix is specified, the cpu type is used.
106 # -switch file: specify file containing semantics implemented as a switch()
110 # Specify the cpu family name.
112 # -infile <input-file>
114 # Specify the mainloop.in input file.
116 # -outfile-suffix <output-file-suffix>
118 # Specify the suffix to append to output files.
122 # Specify the shell to use to execute <input-file>
124 # Only one of -scache/-pbb may be selected.
125 # -simple is the default.
130 # - build mainloop.in from .cpu file
149 -multi) type=multi
;;
152 -full-switch) full_switch
=yes ;;
154 -scache) scache
=yes ;;
157 -outfile-suffix) shift ; outsuffix
=$1 ;;
158 -parallel-read) parallel
=read ;;
159 -parallel-write) parallel
=write ;;
160 -parallel-generic-write) parallel
=genwrite
;;
161 -parallel-only) parallel_only
=yes ;;
162 -prefix) shift ; prefix
=$1 ;;
163 -switch) shift ; switch
=$1 ;;
164 -cpu) shift ; cpu
=$1 ;;
165 -infile) shift ; infile
=$1 ;;
166 -shell) shift ; SHELL
=$1 ;;
167 *) echo "unknown option: $1" >&2 ; exit 1 ;;
172 # Argument validation.
174 if [ x
$scache = xyes
-a x
$pbb = xyes
] ; then
175 echo "only one of -scache and -pbb may be selected" >&2
179 if [ "x$cpu" = xunknown
] ; then
180 echo "cpu family not specified" >&2
184 if [ "x$infile" = x
] ; then
185 echo "mainloop.in not specified" >&2
189 if [ "x$prefix" = xunknown
] ; then
193 lowercase
='abcdefghijklmnopqrstuvwxyz'
194 uppercase
='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
195 CPU
=`echo ${cpu} | tr "${lowercase}" "${uppercase}"`
196 PREFIX
=`echo ${prefix} | tr "${lowercase}" "${uppercase}"`
198 ##########################################################################
200 rm -f eng
${outsuffix}.hin
201 exec 1>eng
${outsuffix}.hin
203 echo "/* engine configuration for ${cpu} */"
206 echo "/* WITH_FAST: non-zero if a fast version of the engine is available"
207 echo " in addition to the full-featured version. */"
208 if [ x
$fast = xyes
] ; then
209 echo "#define WITH_FAST 1"
211 echo "#define WITH_FAST 0"
215 echo "/* WITH_SCACHE_PBB_${PREFIX}: non-zero if the pbb engine was selected. */"
216 if [ x
$pbb = xyes
] ; then
217 echo "#define WITH_SCACHE_PBB_${PREFIX} 1"
219 echo "#define WITH_SCACHE_PBB_${PREFIX} 0"
223 echo "/* HAVE_PARALLEL_INSNS: non-zero if cpu can parallelly execute > 1 insn. */"
224 # blah blah blah, other ways to do this, blah blah blah
227 echo "#define HAVE_PARALLEL_INSNS 0"
228 echo "#define WITH_PARALLEL_READ 0"
229 echo "#define WITH_PARALLEL_WRITE 0"
230 echo "#define WITH_PARALLEL_GENWRITE 0"
233 echo "#define HAVE_PARALLEL_INSNS 1"
234 echo "/* Parallel execution is supported by read-before-exec. */"
235 echo "#define WITH_PARALLEL_READ 1"
236 echo "#define WITH_PARALLEL_WRITE 0"
237 echo "#define WITH_PARALLEL_GENWRITE 0"
240 echo "#define HAVE_PARALLEL_INSNS 1"
241 echo "/* Parallel execution is supported by write-after-exec. */"
242 echo "#define WITH_PARALLEL_READ 0"
243 echo "#define WITH_PARALLEL_WRITE 1"
244 echo "#define WITH_PARALLEL_GENWRITE 0"
247 echo "#define HAVE_PARALLEL_INSNS 1"
248 echo "/* Parallel execution is supported by generic write-after-exec. */"
249 echo "#define WITH_PARALLEL_READ 0"
250 echo "#define WITH_PARALLEL_WRITE 0"
251 echo "#define WITH_PARALLEL_GENWRITE 1"
255 if [ "x$switch" != x
] ; then
257 echo "/* WITH_SEM_SWITCH_FULL: non-zero if full-featured engine is"
258 echo " implemented as a switch(). */"
259 if [ x
$fast != xyes
-o x
$full_switch = xyes
] ; then
260 echo "#define WITH_SEM_SWITCH_FULL 1"
262 echo "#define WITH_SEM_SWITCH_FULL 0"
265 echo "/* WITH_SEM_SWITCH_FAST: non-zero if fast engine is"
266 echo " implemented as a switch(). */"
267 if [ x
$fast = xyes
] ; then
268 echo "#define WITH_SEM_SWITCH_FAST 1"
270 echo "#define WITH_SEM_SWITCH_FAST 0"
274 # Decls of functions we define.
277 echo "/* Functions defined in the generated mainloop.c file"
278 echo " (which doesn't necessarily have that file name). */"
280 echo "extern ENGINE_FN ${prefix}_engine_run_full;"
281 echo "extern ENGINE_FN ${prefix}_engine_run_fast;"
283 if [ x
$pbb = xyes
] ; then
285 echo "extern SEM_PC ${prefix}_pbb_begin (SIM_CPU *, int);"
286 echo "extern SEM_PC ${prefix}_pbb_chain (SIM_CPU *, SEM_ARG);"
287 echo "extern SEM_PC ${prefix}_pbb_cti_chain (SIM_CPU *, SEM_ARG, SEM_BRANCH_TYPE, PCADDR);"
288 echo "extern void ${prefix}_pbb_before (SIM_CPU *, SCACHE *);"
289 echo "extern void ${prefix}_pbb_after (SIM_CPU *, SCACHE *);"
292 ##########################################################################
294 rm -f tmp-mloop-$$.cin mloop
${outsuffix}.cin
295 exec 1>tmp-mloop-$$.cin
297 # We use @cpu@ instead of ${cpu} because we still need to run sed to handle
298 # transformation of @cpu@ for mainloop.in, so there's no need to use ${cpu}
302 /* This file is generated by the genmloop script. DO NOT EDIT! */
304 /* This must come before any other includes. */
307 /* Enable switch() support in cgen headers. */
308 #define SEM_IN_SWITCH
310 #define WANT_CPU @cpu@
311 #define WANT_CPU_@CPU@
313 #include "sim-main.h"
315 #include "cgen-mem.h"
316 #include "cgen-ops.h"
317 #include "sim-assert.h"
319 /* Fill in the administrative ARGBUF fields required by all insns,
323 @prefix@_fill_argbuf (const SIM_CPU *cpu, ARGBUF *abuf, const IDESC *idesc,
324 PCADDR pc, int fast_p)
327 SEM_SET_CODE (abuf, idesc, fast_p);
328 ARGBUF_ADDR (abuf) = pc;
330 ARGBUF_IDESC (abuf) = idesc;
333 /* Fill in tracing/profiling fields of an ARGBUF. */
336 @prefix@_fill_argbuf_tp (const SIM_CPU *cpu, ARGBUF *abuf,
337 int trace_p, int profile_p)
339 ARGBUF_TRACE_P (abuf) = trace_p;
340 ARGBUF_PROFILE_P (abuf) = profile_p;
345 /* Emit the "x-before" handler.
346 x-before is emitted before each insn (serial or parallel).
347 This is as opposed to x-after which is only emitted at the end of a group
348 of parallel insns. */
351 @prefix@_emit_before (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc, int first_p)
353 ARGBUF *abuf = &sc[0].argbuf;
354 const IDESC *id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEFORE];
356 abuf->fields.before.first_p = first_p;
357 @prefix@_fill_argbuf (current_cpu, abuf, id, pc, 0);
358 /* no need to set trace_p,profile_p */
361 /* Emit the "x-after" handler.
362 x-after is emitted after a serial insn or at the end of a group of
366 @prefix@_emit_after (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc)
368 ARGBUF *abuf = &sc[0].argbuf;
369 const IDESC *id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_AFTER];
371 @prefix@_fill_argbuf (current_cpu, abuf, id, pc, 0);
372 /* no need to set trace_p,profile_p */
375 #endif /* WITH_SCACHE_PBB */
379 ${SHELL} $infile support
381 ##########################################################################
383 # Simple engine: fetch an instruction, execute the instruction.
385 # Instruction fields are not extracted into ARGBUF, they are extracted in
386 # the semantic routines themselves. However, there is still a need to pass
387 # and return misc. information to the semantic routines so we still use ARGBUF.
388 # [One could certainly implement things differently and remove ARGBUF.
389 # It's not clear this is necessarily always a win.]
390 # ??? The use of the SCACHE struct is for consistency with the with-scache
391 # case though it might be a source of confusion.
393 if [ x
$scache != xyes
-a x
$pbb != xyes
] ; then
400 @prefix@_engine_run_full (SIM_CPU *current_cpu)
403 SIM_DESC current_state = CPU_STATE (current_cpu);
404 /* ??? Use of SCACHE is a bit of a hack as we don't actually use the scache.
405 We do however use ARGBUF so for consistency with the other engine flavours
406 the SCACHE type is used. */
407 SCACHE cache[MAX_LIW_INSNS];
408 SCACHE *sc = &cache[0];
415 PAREXEC pbufs[MAX_PARALLEL_INSNS];
422 # Any initialization code before looping starts.
423 # Note that this code may declare some locals.
424 ${SHELL} $infile init
426 if [ x
$parallel = xread
] ; then
429 #if defined (__GNUC__)
431 if (! CPU_IDESC_READ_INIT_P (current_cpu))
433 /* ??? Later maybe paste read.c in when building mainloop.c. */
434 #define DEFINE_LABELS
436 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
446 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
448 #if WITH_SEM_SWITCH_FULL
449 #if defined (__GNUC__)
450 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
451 #define DEFINE_LABELS
455 @prefix@_sem_init_idesc_table (current_cpu);
457 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
462 /* begin full-exec-simple */
465 ${SHELL} $infile full-exec-simple
468 /* end full-exec-simple */
470 ++ CPU_INSN_COUNT (current_cpu);
472 while (0 /*CPU_RUNNING_P (current_cpu)*/);
479 ####################################
481 # Simple engine: fast version.
482 # ??? A somewhat dubious effort, but for completeness' sake.
484 if [ x
$fast = xyes
] ; then
490 FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh."
500 ##########################################################################
502 # Non-parallel scache engine: lookup insn in scache, fetch if missing,
505 if [ x
$scache = xyes
-a x
$parallel = xno
] ; then
509 static INLINE SCACHE *
510 @prefix@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
511 unsigned int hash_mask, int FAST_P)
513 /* First step: look up current insn in hash table. */
514 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
516 /* If the entry isn't the one we want (cache miss),
517 fetch and decode the instruction. */
518 if (sc->argbuf.addr != vpc)
521 PROFILE_COUNT_SCACHE_MISS (current_cpu);
523 /* begin extract-scache */
526 ${SHELL} $infile extract-scache
529 /* end extract-scache */
533 PROFILE_COUNT_SCACHE_HIT (current_cpu);
534 /* Make core access statistics come out right.
535 The size is a guess, but it's currently not used either. */
536 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
545 @prefix@_engine_run_full (SIM_CPU *current_cpu)
547 SIM_DESC current_state = CPU_STATE (current_cpu);
548 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
549 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
554 # Any initialization code before looping starts.
555 # Note that this code may declare some locals.
556 ${SHELL} $infile init
560 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
562 #if ! WITH_SEM_SWITCH_FULL
563 @prefix@_sem_init_idesc_table (current_cpu);
565 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
574 sc = @prefix@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
576 /* begin full-exec-scache */
579 ${SHELL} $infile full-exec-scache
582 /* end full-exec-scache */
586 ++ CPU_INSN_COUNT (current_cpu);
588 while (0 /*CPU_RUNNING_P (current_cpu)*/);
595 ####################################
597 # Non-parallel scache engine: fast version.
599 if [ x
$fast = xyes
] ; then
606 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
608 SIM_DESC current_state = CPU_STATE (current_cpu);
609 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
610 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
615 # Any initialization code before looping starts.
616 # Note that this code may declare some locals.
617 ${SHELL} $infile init
621 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
623 #if WITH_SEM_SWITCH_FAST
624 #if defined (__GNUC__)
625 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
626 #define DEFINE_LABELS
630 @prefix@_semf_init_idesc_table (current_cpu);
632 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
641 sc = @prefix@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
643 /* begin fast-exec-scache */
646 ${SHELL} $infile fast-exec-scache
649 /* end fast-exec-scache */
653 ++ CPU_INSN_COUNT (current_cpu);
655 while (0 /*CPU_RUNNING_P (current_cpu)*/);
664 fi # -scache && ! parallel
666 ##########################################################################
668 # Parallel scache engine: lookup insn in scache, fetch if missing,
670 # For the parallel case we give the target more flexibility.
672 if [ x
$scache = xyes
-a x
$parallel != xno
] ; then
676 static INLINE SCACHE *
677 @prefix@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
678 unsigned int hash_mask, int FAST_P)
680 /* First step: look up current insn in hash table. */
681 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
683 /* If the entry isn't the one we want (cache miss),
684 fetch and decode the instruction. */
685 if (sc->argbuf.addr != vpc)
688 PROFILE_COUNT_SCACHE_MISS (current_cpu);
690 #define SET_LAST_INSN_P(last_p) do { sc->last_insn_p = (last_p); } while (0)
691 /* begin extract-scache */
694 ${SHELL} $infile extract-scache
697 /* end extract-scache */
698 #undef SET_LAST_INSN_P
702 PROFILE_COUNT_SCACHE_HIT (current_cpu);
703 /* Make core access statistics come out right.
704 The size is a guess, but it's currently not used either. */
705 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
714 @prefix@_engine_run_full (SIM_CPU *current_cpu)
716 SIM_DESC current_state = CPU_STATE (current_cpu);
717 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
718 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
723 # Any initialization code before looping starts.
724 # Note that this code may declare some locals.
725 ${SHELL} $infile init
727 if [ x
$parallel = xread
] ; then
729 #if defined (__GNUC__)
731 if (! CPU_IDESC_READ_INIT_P (current_cpu))
733 /* ??? Later maybe paste read.c in when building mainloop.c. */
734 #define DEFINE_LABELS
736 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
746 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
748 #if ! WITH_SEM_SWITCH_FULL
749 @prefix@_sem_init_idesc_table (current_cpu);
751 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
758 /* begin full-exec-scache */
761 ${SHELL} $infile full-exec-scache
764 /* end full-exec-scache */
766 while (0 /*CPU_RUNNING_P (current_cpu)*/);
773 ####################################
775 # Parallel scache engine: fast version.
777 if [ x
$fast = xyes
] ; then
784 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
786 SIM_DESC current_state = CPU_STATE (current_cpu);
787 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
788 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
790 PAREXEC pbufs[MAX_PARALLEL_INSNS];
795 # Any initialization code before looping starts.
796 # Note that this code may declare some locals.
797 ${SHELL} $infile init
799 if [ x
$parallel = xread
] ; then
802 #if defined (__GNUC__)
804 if (! CPU_IDESC_READ_INIT_P (current_cpu))
806 /* ??? Later maybe paste read.c in when building mainloop.c. */
807 #define DEFINE_LABELS
809 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
819 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
821 #if WITH_SEM_SWITCH_FAST
822 #if defined (__GNUC__)
823 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
824 #define DEFINE_LABELS
828 @prefix@_semf_init_idesc_table (current_cpu);
830 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
837 /* begin fast-exec-scache */
840 ${SHELL} $infile fast-exec-scache
843 /* end fast-exec-scache */
845 while (0 /*CPU_RUNNING_P (current_cpu)*/);
854 fi # -scache && parallel
856 ##########################################################################
858 # Compilation engine: lookup insn in scache, extract a pbb
859 # (pseudo-basic-block) if missing, then execute the pbb.
860 # A "pbb" is a sequence of insns up to the next cti insn or until
861 # some prespecified maximum.
862 # CTI: control transfer instruction.
864 if [ x
$pbb = xyes
] ; then
868 /* Record address of cti terminating a pbb. */
869 #define SET_CTI_VPC(sc) do { _cti_sc = (sc); } while (0)
870 /* Record number of [real] insns in pbb. */
871 #define SET_INSN_COUNT(n) do { _insn_count = (n); } while (0)
873 /* Fetch and extract a pseudo-basic-block.
874 FAST_P is non-zero if no tracing/profiling/etc. is wanted. */
877 @prefix@_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
882 int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu);
886 new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
889 /* Leading '_' to avoid collision with mainloop.in. */
891 SCACHE *orig_sc = sc;
892 SCACHE *_cti_sc = NULL;
893 int slice_insns = CPU_MAX_SLICE_INSNS (current_cpu);
895 /* First figure out how many instructions to compile.
896 MAX_INSNS is the size of the allocated buffer, which includes space
897 for before/after handlers if they're being used.
898 SLICE_INSNS is the maxinum number of real insns that can be
899 executed. Zero means "as many as we want". */
900 /* ??? max_insns is serving two incompatible roles.
901 1) Number of slots available in scache buffer.
902 2) Number of real insns to execute.
903 They're incompatible because there are virtual insns emitted too
904 (chain,cti-chain,before,after handlers). */
906 if (slice_insns == 1)
908 /* No need to worry about extra slots required for virtual insns
909 and parallel exec support because MAX_CHAIN_LENGTH is
910 guaranteed to be big enough to execute at least 1 insn! */
915 /* Allow enough slop so that while compiling insns, if max_insns > 0
916 then there's guaranteed to be enough space to emit one real insn.
917 MAX_CHAIN_LENGTH is typically much longer than
918 the normal number of insns between cti's anyway. */
919 max_insns -= (1 /* one for the trailing chain insn */
922 : (1 + MAX_PARALLEL_INSNS) /* before+after */)
923 + (MAX_PARALLEL_INSNS > 1
924 ? (MAX_PARALLEL_INSNS * 2)
927 /* Account for before/after handlers. */
932 && slice_insns < max_insns)
933 max_insns = slice_insns;
938 /* SC,PC must be updated to point passed the last entry used.
939 SET_CTI_VPC must be called if pbb is terminated by a cti.
940 SET_INSN_COUNT must be called to record number of real insns in
941 pbb [could be computed by us of course, extra cpu but perhaps
942 negligible enough]. */
944 /* begin extract-pbb */
947 ${SHELL} $infile extract-pbb
950 /* end extract-pbb */
952 /* The last one is a pseudo-insn to link to the next chain.
953 It is also used to record the insn count for this chain. */
957 /* Was pbb terminated by a cti? */
960 id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_CTI_CHAIN];
964 id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_CHAIN];
966 SEM_SET_CODE (&sc->argbuf, id, FAST_P);
967 sc->argbuf.idesc = id;
968 sc->argbuf.addr = pc;
969 sc->argbuf.fields.chain.insn_count = _insn_count;
970 sc->argbuf.fields.chain.next = 0;
971 sc->argbuf.fields.chain.branch_target = 0;
975 /* Update the pointer to the next free entry, may not have used as
976 many entries as was asked for. */
977 CPU_SCACHE_NEXT_FREE (current_cpu) = sc;
978 /* Record length of chain if profiling.
979 This includes virtual insns since they count against
982 PROFILE_COUNT_SCACHE_CHAIN_LENGTH (current_cpu, sc - orig_sc);
988 /* Chain to the next block from a non-cti terminated previous block. */
991 @prefix@_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
993 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
995 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
997 SET_H_PC (abuf->addr);
999 /* If not running forever, exit back to main loop. */
1000 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
1001 /* Also exit back to main loop if there's an event.
1002 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
1003 at the "right" time, but then that was what was asked for.
1004 There is no silver bullet for simulator engines.
1005 ??? Clearly this needs a cleaner interface.
1006 At present it's just so Ctrl-C works. */
1007 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
1008 CPU_RUNNING_P (current_cpu) = 0;
1010 /* If chained to next block, go straight to it. */
1011 if (abuf->fields.chain.next)
1012 return abuf->fields.chain.next;
1013 /* See if next block has already been compiled. */
1014 abuf->fields.chain.next = scache_lookup (current_cpu, abuf->addr);
1015 if (abuf->fields.chain.next)
1016 return abuf->fields.chain.next;
1017 /* Nope, so next insn is a virtual insn to invoke the compiler
1019 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1022 /* Chain to the next block from a cti terminated previous block.
1023 BR_TYPE indicates whether the branch was taken and whether we can cache
1024 the vpc of the branch target.
1025 NEW_PC is the target's branch address, and is only valid if
1026 BR_TYPE != SEM_BRANCH_UNTAKEN. */
1029 @prefix@_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
1030 SEM_BRANCH_TYPE br_type, PCADDR new_pc)
1032 SEM_PC *new_vpc_ptr;
1034 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
1036 /* If not running forever, exit back to main loop. */
1037 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
1038 /* Also exit back to main loop if there's an event.
1039 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
1040 at the "right" time, but then that was what was asked for.
1041 There is no silver bullet for simulator engines.
1042 ??? Clearly this needs a cleaner interface.
1043 At present it's just so Ctrl-C works. */
1044 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
1045 CPU_RUNNING_P (current_cpu) = 0;
1047 /* Restart compiler if we branched to an uncacheable address
1049 if (br_type == SEM_BRANCH_UNCACHEABLE)
1052 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1055 /* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our
1057 if (br_type == SEM_BRANCH_UNTAKEN)
1059 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1060 new_pc = abuf->addr;
1062 new_vpc_ptr = &abuf->fields.chain.next;
1066 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1068 new_vpc_ptr = &abuf->fields.chain.branch_target;
1071 /* If chained to next block, go straight to it. */
1073 return *new_vpc_ptr;
1074 /* See if next block has already been compiled. */
1075 *new_vpc_ptr = scache_lookup (current_cpu, new_pc);
1077 return *new_vpc_ptr;
1078 /* Nope, so next insn is a virtual insn to invoke the compiler
1080 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1083 /* x-before handler.
1084 This is called before each insn. */
1087 @prefix@_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
1089 SEM_ARG sem_arg = sc;
1090 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1091 int first_p = abuf->fields.before.first_p;
1092 const ARGBUF *cur_abuf = SEM_ARGBUF (sc + 1);
1093 const IDESC *cur_idesc = cur_abuf->idesc;
1094 PCADDR pc = cur_abuf->addr;
1096 if (ARGBUF_PROFILE_P (cur_abuf))
1097 PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
1099 /* If this isn't the first insn, finish up the previous one. */
1103 if (PROFILE_MODEL_P (current_cpu))
1105 const SEM_ARG prev_sem_arg = sc - 1;
1106 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1107 const IDESC *prev_idesc = prev_abuf->idesc;
1110 /* ??? May want to measure all insns if doing insn tracing. */
1111 if (ARGBUF_PROFILE_P (prev_abuf))
1113 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1114 @prefix@_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
1118 CGEN_TRACE_INSN_FINI (current_cpu, cur_abuf, 0 /*last_p*/);
1121 /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */
1122 if (PROFILE_MODEL_P (current_cpu)
1123 && ARGBUF_PROFILE_P (cur_abuf))
1124 @prefix@_model_insn_before (current_cpu, first_p);
1126 CGEN_TRACE_INSN_INIT (current_cpu, cur_abuf, first_p);
1127 CGEN_TRACE_INSN (current_cpu, cur_idesc->idata, cur_abuf, pc);
1131 This is called after a serial insn or at the end of a group of parallel
1135 @prefix@_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
1137 SEM_ARG sem_arg = sc;
1138 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1139 const SEM_ARG prev_sem_arg = sc - 1;
1140 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1142 /* ??? May want to measure all insns if doing insn tracing. */
1143 if (PROFILE_MODEL_P (current_cpu)
1144 && ARGBUF_PROFILE_P (prev_abuf))
1146 const IDESC *prev_idesc = prev_abuf->idesc;
1149 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1150 @prefix@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
1152 CGEN_TRACE_INSN_FINI (current_cpu, prev_abuf, 1 /*last_p*/);
1158 @prefix@_engine_run_full (SIM_CPU *current_cpu)
1160 SIM_DESC current_state = CPU_STATE (current_cpu);
1161 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1162 /* virtual program counter */
1164 #if WITH_SEM_SWITCH_FULL
1165 /* For communication between cti's and cti-chain. */
1166 SEM_BRANCH_TYPE pbb_br_type;
1175 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1176 PAREXEC *par_exec = &pbufs[0];
1182 # Any initialization code before looping starts.
1183 # Note that this code may declare some locals.
1184 ${SHELL} $infile init
1188 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1190 /* ??? 'twould be nice to move this up a level and only call it once.
1191 On the other hand, in the "let's go fast" case the test is only done
1192 once per pbb (since we only return to the main loop at the end of
1193 a pbb). And in the "let's run until we're done" case we don't return
1194 until the program exits. */
1196 #if WITH_SEM_SWITCH_FULL
1197 #if defined (__GNUC__)
1198 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1199 #define DEFINE_LABELS
1203 @prefix@_sem_init_idesc_table (current_cpu);
1206 /* Initialize the "begin (compile) a pbb" virtual insn. */
1207 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1208 SEM_SET_FULL_CODE (SEM_ARGBUF (vpc),
1209 & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN]);
1210 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN];
1212 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1215 CPU_RUNNING_P (current_cpu) = 1;
1216 /* ??? In the case where we're returning to the main loop after every
1217 pbb we don't want to call pbb_begin each time (which hashes on the pc
1218 and does a table lookup). A way to speed this up is to save vpc
1220 vpc = @prefix@_pbb_begin (current_cpu, FAST_P);
1224 /* begin full-exec-pbb */
1227 ${SHELL} $infile full-exec-pbb
1230 /* end full-exec-pbb */
1232 while (CPU_RUNNING_P (current_cpu));
1239 ####################################
1241 # Compile engine: fast version.
1243 if [ x
$fast = xyes
] ; then
1250 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
1252 SIM_DESC current_state = CPU_STATE (current_cpu);
1253 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1254 /* virtual program counter */
1256 #if WITH_SEM_SWITCH_FAST
1257 /* For communication between cti's and cti-chain. */
1258 SEM_BRANCH_TYPE pbb_br_type;
1267 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1268 PAREXEC *par_exec = &pbufs[0];
1274 # Any initialization code before looping starts.
1275 # Note that this code may declare some locals.
1276 ${SHELL} $infile init
1280 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1282 /* ??? 'twould be nice to move this up a level and only call it once.
1283 On the other hand, in the "let's go fast" case the test is only done
1284 once per pbb (since we only return to the main loop at the end of
1285 a pbb). And in the "let's run until we're done" case we don't return
1286 until the program exits. */
1288 #if WITH_SEM_SWITCH_FAST
1289 #if defined (__GNUC__)
1290 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1291 #define DEFINE_LABELS
1295 @prefix@_semf_init_idesc_table (current_cpu);
1298 /* Initialize the "begin (compile) a pbb" virtual insn. */
1299 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1300 SEM_SET_FAST_CODE (SEM_ARGBUF (vpc),
1301 & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN]);
1302 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN];
1304 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1307 CPU_RUNNING_P (current_cpu) = 1;
1308 /* ??? In the case where we're returning to the main loop after every
1309 pbb we don't want to call pbb_begin each time (which hashes on the pc
1310 and does a table lookup). A way to speed this up is to save vpc
1312 vpc = @prefix@_pbb_begin (current_cpu, FAST_P);
1316 /* begin fast-exec-pbb */
1319 ${SHELL} $infile fast-exec-pbb
1322 /* end fast-exec-pbb */
1324 while (CPU_RUNNING_P (current_cpu));
1334 # Expand @..@ macros appearing in tmp-mloop-{pid}.cin.
1336 -e "s/@cpu@/$cpu/g" -e "s/@CPU@/$CPU/g" \
1337 -e "s/@prefix@/$prefix/g" -e "s/@PREFIX@/$PREFIX/g" < tmp-mloop-$$.cin
> mloop
${outsuffix}.cin
1339 rm -f tmp-mloop-$$.cin
This page took 0.077762 seconds and 5 git commands to generate.