1 # Generate the main loop of the simulator.
2 # Copyright (C) 1996, 1997, 1998, 1999 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 # -switch file: specify file containing semantics implemented as a switch()
107 # Specify the cpu family name.
109 # -infile <input-file>
111 # Specify the mainloop.in input file.
113 # Only one of -scache/-pbb may be selected.
114 # -simple is the default.
119 # - build mainloop.in from .cpu file
136 -multi) type=multi
;;
139 -full-switch) full_switch
=yes ;;
141 -scache) scache
=yes ;;
144 -parallel-read) parallel
=read ;;
145 -parallel-write) parallel
=write ;;
146 -parallel-generic-write) parallel
=genwrite
;;
147 -parallel-only) parallel_only
=yes ;;
148 -switch) shift ; switch
=$1 ;;
149 -cpu) shift ; cpu
=$1 ;;
150 -infile) shift ; infile
=$1 ;;
151 *) echo "unknown option: $1" >&2 ; exit 1 ;;
156 # Argument validation.
158 if [ x
$scache = xyes
-a x
$pbb = xyes
] ; then
159 echo "only one of -scache and -pbb may be selected" >&2
163 if [ "x$cpu" = xunknown
] ; then
164 echo "cpu family not specified" >&2
168 if [ "x$infile" = x
] ; then
169 echo "mainloop.in not specified" >&2
173 lowercase
='abcdefghijklmnopqrstuvwxyz'
174 uppercase
='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
175 CPU
=`echo ${cpu} | tr "${lowercase}" "${uppercase}"`
177 ##########################################################################
182 echo "/* engine configuration for ${cpu} */"
185 echo "/* WITH_FAST: non-zero if a fast version of the engine is available"
186 echo " in addition to the full-featured version. */"
187 if [ x
$fast = xyes
] ; then
188 echo "#define WITH_FAST 1"
190 echo "#define WITH_FAST 0"
194 echo "/* WITH_SCACHE_PBB_${CPU}: non-zero if the pbb engine was selected. */"
195 if [ x
$pbb = xyes
] ; then
196 echo "#define WITH_SCACHE_PBB_${CPU} 1"
198 echo "#define WITH_SCACHE_PBB_${CPU} 0"
202 echo "/* HAVE_PARALLEL_INSNS: non-zero if cpu can parallelly execute > 1 insn. */"
203 # blah blah blah, other ways to do this, blah blah blah
206 echo "#define HAVE_PARALLEL_INSNS 0"
207 echo "#define WITH_PARALLEL_READ 0"
208 echo "#define WITH_PARALLEL_WRITE 0"
209 echo "#define WITH_PARALLEL_GENWRITE 0"
212 echo "#define HAVE_PARALLEL_INSNS 1"
213 echo "/* Parallel execution is supported by read-before-exec. */"
214 echo "#define WITH_PARALLEL_READ 1"
215 echo "#define WITH_PARALLEL_WRITE 0"
216 echo "#define WITH_PARALLEL_GENWRITE 0"
219 echo "#define HAVE_PARALLEL_INSNS 1"
220 echo "/* Parallel execution is supported by write-after-exec. */"
221 echo "#define WITH_PARALLEL_READ 0"
222 echo "#define WITH_PARALLEL_WRITE 1"
223 echo "#define WITH_PARALLEL_GENWRITE 0"
226 echo "#define HAVE_PARALLEL_INSNS 1"
227 echo "/* Parallel execution is supported by generic write-after-exec. */"
228 echo "#define WITH_PARALLEL_READ 0"
229 echo "#define WITH_PARALLEL_WRITE 0"
230 echo "#define WITH_PARALLEL_GENWRITE 1"
234 if [ "x$switch" != x
] ; then
236 echo "/* WITH_SEM_SWITCH_FULL: non-zero if full-featured engine is"
237 echo " implemented as a switch(). */"
238 if [ x
$fast != xyes
-o x
$full_switch = xyes
] ; then
239 echo "#define WITH_SEM_SWITCH_FULL 1"
241 echo "#define WITH_SEM_SWITCH_FULL 0"
244 echo "/* WITH_SEM_SWITCH_FAST: non-zero if fast engine is"
245 echo " implemented as a switch(). */"
246 if [ x
$fast = xyes
] ; then
247 echo "#define WITH_SEM_SWITCH_FAST 1"
249 echo "#define WITH_SEM_SWITCH_FAST 0"
253 # Decls of functions we define.
256 echo "/* Functions defined in the generated mainloop.c file"
257 echo " (which doesn't necessarily have that file name). */"
259 echo "extern ENGINE_FN ${cpu}_engine_run_full;"
260 echo "extern ENGINE_FN ${cpu}_engine_run_fast;"
262 if [ x
$pbb = xyes
] ; then
264 echo "extern SEM_PC ${cpu}_pbb_begin (SIM_CPU *, int);"
265 echo "extern SEM_PC ${cpu}_pbb_chain (SIM_CPU *, SEM_ARG);"
266 echo "extern SEM_PC ${cpu}_pbb_cti_chain (SIM_CPU *, SEM_ARG, SEM_BRANCH_TYPE, PCADDR);"
267 echo "extern void ${cpu}_pbb_before (SIM_CPU *, SCACHE *);"
268 echo "extern void ${cpu}_pbb_after (SIM_CPU *, SCACHE *);"
271 ##########################################################################
273 rm -f tmp-mloop.cin mloop.cin
276 # We use @cpu@ instead of ${cpu} because we still need to run sed to handle
277 # transformation of @cpu@ for mainloop.in, so there's no need to use ${cpu}
281 /* This file is generated by the genmloop script. DO NOT EDIT! */
283 /* Enable switch() support in cgen headers. */
284 #define SEM_IN_SWITCH
286 #define WANT_CPU @cpu@
287 #define WANT_CPU_@CPU@
289 #include "sim-main.h"
291 #include "cgen-mem.h"
292 #include "cgen-ops.h"
293 #include "sim-assert.h"
295 /* Fill in the administrative ARGBUF fields required by all insns,
299 @cpu@_fill_argbuf (const SIM_CPU *cpu, ARGBUF *abuf, const IDESC *idesc,
300 PCADDR pc, int fast_p)
303 SEM_SET_CODE (abuf, idesc, fast_p);
304 ARGBUF_ADDR (abuf) = pc;
306 ARGBUF_IDESC (abuf) = idesc;
309 /* Fill in tracing/profiling fields of an ARGBUF. */
312 @cpu@_fill_argbuf_tp (const SIM_CPU *cpu, ARGBUF *abuf,
313 int trace_p, int profile_p)
315 ARGBUF_TRACE_P (abuf) = trace_p;
316 ARGBUF_PROFILE_P (abuf) = profile_p;
321 /* Emit the "x-before" handler.
322 x-before is emitted before each insn (serial or parallel).
323 This is as opposed to x-after which is only emitted at the end of a group
324 of parallel insns. */
327 @cpu@_emit_before (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc, int first_p)
329 ARGBUF *abuf = &sc[0].argbuf;
330 const IDESC *id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEFORE];
332 abuf->fields.before.first_p = first_p;
333 @cpu@_fill_argbuf (current_cpu, abuf, id, pc, 0);
334 /* no need to set trace_p,profile_p */
337 /* Emit the "x-after" handler.
338 x-after is emitted after a serial insn or at the end of a group of
342 @cpu@_emit_after (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc)
344 ARGBUF *abuf = &sc[0].argbuf;
345 const IDESC *id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_AFTER];
347 @cpu@_fill_argbuf (current_cpu, abuf, id, pc, 0);
348 /* no need to set trace_p,profile_p */
351 #endif /* WITH_SCACHE_PBB */
355 ${SHELL} $infile support
357 ##########################################################################
359 # Simple engine: fetch an instruction, execute the instruction.
361 # Instruction fields are not extracted into ARGBUF, they are extracted in
362 # the semantic routines themselves. However, there is still a need to pass
363 # and return misc. information to the semantic routines so we still use ARGBUF.
364 # [One could certainly implement things differently and remove ARGBUF.
365 # It's not clear this is necessarily always a win.]
366 # ??? The use of the SCACHE struct is for consistency with the with-scache
367 # case though it might be a source of confusion.
369 if [ x
$scache != xyes
-a x
$pbb != xyes
] ; then
376 @cpu@_engine_run_full (SIM_CPU *current_cpu)
379 SIM_DESC current_state = CPU_STATE (current_cpu);
380 /* ??? Use of SCACHE is a bit of a hack as we don't actually use the scache.
381 We do however use ARGBUF so for consistency with the other engine flavours
382 the SCACHE type is used. */
383 SCACHE cache[MAX_LIW_INSNS];
384 SCACHE *sc = &cache[0];
391 PAREXEC pbufs[MAX_PARALLEL_INSNS];
398 # Any initialization code before looping starts.
399 # Note that this code may declare some locals.
400 ${SHELL} $infile init
402 if [ x
$parallel = xread
] ; then
405 #if defined (__GNUC__)
407 if (! CPU_IDESC_READ_INIT_P (current_cpu))
409 /* ??? Later maybe paste read.c in when building mainloop.c. */
410 #define DEFINE_LABELS
412 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
422 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
424 #if WITH_SEM_SWITCH_FULL
425 #if defined (__GNUC__)
426 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
427 #define DEFINE_LABELS
431 @cpu@_sem_init_idesc_table (current_cpu);
433 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
438 /* begin full-exec-simple */
441 ${SHELL} $infile full-exec-simple
444 /* end full-exec-simple */
446 ++ CPU_INSN_COUNT (current_cpu);
448 while (0 /*CPU_RUNNING_P (current_cpu)*/);
455 ####################################
457 # Simple engine: fast version.
458 # ??? A somewhat dubious effort, but for completeness' sake.
460 if [ x
$fast = xyes
] ; then
466 FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh."
476 ##########################################################################
478 # Non-parallel scache engine: lookup insn in scache, fetch if missing,
481 if [ x
$scache = xyes
-a x
$parallel = xno
] ; then
485 static INLINE SCACHE *
486 @cpu@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
487 unsigned int hash_mask, int FAST_P)
489 /* First step: look up current insn in hash table. */
490 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
492 /* If the entry isn't the one we want (cache miss),
493 fetch and decode the instruction. */
494 if (sc->argbuf.addr != vpc)
497 PROFILE_COUNT_SCACHE_MISS (current_cpu);
499 /* begin extract-scache */
502 ${SHELL} $infile extract-scache
505 /* end extract-scache */
509 PROFILE_COUNT_SCACHE_HIT (current_cpu);
510 /* Make core access statistics come out right.
511 The size is a guess, but it's currently not used either. */
512 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
521 @cpu@_engine_run_full (SIM_CPU *current_cpu)
523 SIM_DESC current_state = CPU_STATE (current_cpu);
524 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
525 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
530 # Any initialization code before looping starts.
531 # Note that this code may declare some locals.
532 ${SHELL} $infile init
536 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
538 #if ! WITH_SEM_SWITCH_FULL
539 @cpu@_sem_init_idesc_table (current_cpu);
541 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
550 sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
552 /* begin full-exec-scache */
555 ${SHELL} $infile full-exec-scache
558 /* end full-exec-scache */
562 ++ CPU_INSN_COUNT (current_cpu);
564 while (0 /*CPU_RUNNING_P (current_cpu)*/);
571 ####################################
573 # Non-parallel scache engine: fast version.
575 if [ x
$fast = xyes
] ; then
582 @cpu@_engine_run_fast (SIM_CPU *current_cpu)
584 SIM_DESC current_state = CPU_STATE (current_cpu);
585 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
586 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
591 # Any initialization code before looping starts.
592 # Note that this code may declare some locals.
593 ${SHELL} $infile init
597 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
599 #if WITH_SEM_SWITCH_FAST
600 #if defined (__GNUC__)
601 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
602 #define DEFINE_LABELS
606 @cpu@_semf_init_idesc_table (current_cpu);
608 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
617 sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
619 /* begin fast-exec-scache */
622 ${SHELL} $infile fast-exec-scache
625 /* end fast-exec-scache */
629 ++ CPU_INSN_COUNT (current_cpu);
631 while (0 /*CPU_RUNNING_P (current_cpu)*/);
640 fi # -scache && ! parallel
642 ##########################################################################
644 # Parallel scache engine: lookup insn in scache, fetch if missing,
646 # For the parallel case we give the target more flexibility.
648 if [ x
$scache = xyes
-a x
$parallel != xno
] ; then
652 static INLINE SCACHE *
653 @cpu@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
654 unsigned int hash_mask, int FAST_P)
656 /* First step: look up current insn in hash table. */
657 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
659 /* If the entry isn't the one we want (cache miss),
660 fetch and decode the instruction. */
661 if (sc->argbuf.addr != vpc)
664 PROFILE_COUNT_SCACHE_MISS (current_cpu);
666 #define SET_LAST_INSN_P(last_p) do { sc->last_insn_p = (last_p); } while (0)
667 /* begin extract-scache */
670 ${SHELL} $infile extract-scache
673 /* end extract-scache */
674 #undef SET_LAST_INSN_P
678 PROFILE_COUNT_SCACHE_HIT (current_cpu);
679 /* Make core access statistics come out right.
680 The size is a guess, but it's currently not used either. */
681 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
690 @cpu@_engine_run_full (SIM_CPU *current_cpu)
692 SIM_DESC current_state = CPU_STATE (current_cpu);
693 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
694 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
699 # Any initialization code before looping starts.
700 # Note that this code may declare some locals.
701 ${SHELL} $infile init
703 if [ x
$parallel = xread
] ; then
705 #if defined (__GNUC__)
707 if (! CPU_IDESC_READ_INIT_P (current_cpu))
709 /* ??? Later maybe paste read.c in when building mainloop.c. */
710 #define DEFINE_LABELS
712 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
722 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
724 #if ! WITH_SEM_SWITCH_FULL
725 @cpu@_sem_init_idesc_table (current_cpu);
727 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
734 /* begin full-exec-scache */
737 ${SHELL} $infile full-exec-scache
740 /* end full-exec-scache */
742 while (0 /*CPU_RUNNING_P (current_cpu)*/);
749 ####################################
751 # Parallel scache engine: fast version.
753 if [ x
$fast = xyes
] ; then
760 @cpu@_engine_run_fast (SIM_CPU *current_cpu)
762 SIM_DESC current_state = CPU_STATE (current_cpu);
763 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
764 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
766 PAREXEC pbufs[MAX_PARALLEL_INSNS];
771 # Any initialization code before looping starts.
772 # Note that this code may declare some locals.
773 ${SHELL} $infile init
775 if [ x
$parallel = xread
] ; then
778 #if defined (__GNUC__)
780 if (! CPU_IDESC_READ_INIT_P (current_cpu))
782 /* ??? Later maybe paste read.c in when building mainloop.c. */
783 #define DEFINE_LABELS
785 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
795 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
797 #if WITH_SEM_SWITCH_FAST
798 #if defined (__GNUC__)
799 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
800 #define DEFINE_LABELS
804 @cpu@_semf_init_idesc_table (current_cpu);
806 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
813 /* begin fast-exec-scache */
816 ${SHELL} $infile fast-exec-scache
819 /* end fast-exec-scache */
821 while (0 /*CPU_RUNNING_P (current_cpu)*/);
830 fi # -scache && parallel
832 ##########################################################################
834 # Compilation engine: lookup insn in scache, extract a pbb
835 # (pseudo-basic-block) if missing, then execute the pbb.
836 # A "pbb" is a sequence of insns up to the next cti insn or until
837 # some prespecified maximum.
838 # CTI: control transfer instruction.
840 if [ x
$pbb = xyes
] ; then
844 /* Record address of cti terminating a pbb. */
845 #define SET_CTI_VPC(sc) do { _cti_sc = (sc); } while (0)
846 /* Record number of [real] insns in pbb. */
847 #define SET_INSN_COUNT(n) do { _insn_count = (n); } while (0)
849 /* Fetch and extract a pseudo-basic-block.
850 FAST_P is non-zero if no tracing/profiling/etc. is wanted. */
853 @cpu@_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
858 int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu);
862 new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
865 /* Leading '_' to avoid collision with mainloop.in. */
867 SCACHE *orig_sc = sc;
868 SCACHE *_cti_sc = NULL;
869 int slice_insns = CPU_MAX_SLICE_INSNS (current_cpu);
871 /* First figure out how many instructions to compile.
872 MAX_INSNS is the size of the allocated buffer, which includes space
873 for before/after handlers if they're being used.
874 SLICE_INSNS is the maxinum number of real insns that can be
875 executed. Zero means "as many as we want". */
876 /* ??? max_insns is serving two incompatible roles.
877 1) Number of slots available in scache buffer.
878 2) Number of real insns to execute.
879 They're incompatible because there are virtual insns emitted too
880 (chain,cti-chain,before,after handlers). */
882 if (slice_insns == 1)
884 /* No need to worry about extra slots required for virtual insns
885 and parallel exec support because MAX_CHAIN_LENGTH is
886 guaranteed to be big enough to execute at least 1 insn! */
891 /* Allow enough slop so that while compiling insns, if max_insns > 0
892 then there's guaranteed to be enough space to emit one real insn.
893 MAX_CHAIN_LENGTH is typically much longer than
894 the normal number of insns between cti's anyway. */
895 max_insns -= (1 /* one for the trailing chain insn */
898 : (1 + MAX_PARALLEL_INSNS) /* before+after */)
899 + (MAX_PARALLEL_INSNS > 1
900 ? (MAX_PARALLEL_INSNS * 2)
903 /* Account for before/after handlers. */
908 && slice_insns < max_insns)
909 max_insns = slice_insns;
914 /* SC,PC must be updated to point passed the last entry used.
915 SET_CTI_VPC must be called if pbb is terminated by a cti.
916 SET_INSN_COUNT must be called to record number of real insns in
917 pbb [could be computed by us of course, extra cpu but perhaps
918 negligible enough]. */
920 /* begin extract-pbb */
923 ${SHELL} $infile extract-pbb
926 /* end extract-pbb */
928 /* The last one is a pseudo-insn to link to the next chain.
929 It is also used to record the insn count for this chain. */
933 /* Was pbb terminated by a cti? */
936 id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_CTI_CHAIN];
940 id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_CHAIN];
942 SEM_SET_CODE (&sc->argbuf, id, FAST_P);
943 sc->argbuf.idesc = id;
944 sc->argbuf.addr = pc;
945 sc->argbuf.fields.chain.insn_count = _insn_count;
946 sc->argbuf.fields.chain.next = 0;
947 sc->argbuf.fields.chain.branch_target = 0;
951 /* Update the pointer to the next free entry, may not have used as
952 many entries as was asked for. */
953 CPU_SCACHE_NEXT_FREE (current_cpu) = sc;
954 /* Record length of chain if profiling.
955 This includes virtual insns since they count against
958 PROFILE_COUNT_SCACHE_CHAIN_LENGTH (current_cpu, sc - orig_sc);
964 /* Chain to the next block from a non-cti terminated previous block. */
967 @cpu@_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
969 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
971 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
973 SET_H_PC (abuf->addr);
975 /* If not running forever, exit back to main loop. */
976 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
977 /* Also exit back to main loop if there's an event.
978 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
979 at the "right" time, but then that was what was asked for.
980 There is no silver bullet for simulator engines.
981 ??? Clearly this needs a cleaner interface.
982 At present it's just so Ctrl-C works. */
983 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
984 CPU_RUNNING_P (current_cpu) = 0;
986 /* If chained to next block, go straight to it. */
987 if (abuf->fields.chain.next)
988 return abuf->fields.chain.next;
989 /* See if next block has already been compiled. */
990 abuf->fields.chain.next = scache_lookup (current_cpu, abuf->addr);
991 if (abuf->fields.chain.next)
992 return abuf->fields.chain.next;
993 /* Nope, so next insn is a virtual insn to invoke the compiler
995 return CPU_SCACHE_PBB_BEGIN (current_cpu);
998 /* Chain to the next block from a cti terminated previous block.
999 BR_TYPE indicates whether the branch was taken and whether we can cache
1000 the vpc of the branch target.
1001 NEW_PC is the target's branch address, and is only valid if
1002 BR_TYPE != SEM_BRANCH_UNTAKEN. */
1005 @cpu@_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
1006 SEM_BRANCH_TYPE br_type, PCADDR new_pc)
1008 SEM_PC *new_vpc_ptr;
1010 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
1012 /* If not running forever, exit back to main loop. */
1013 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
1014 /* Also exit back to main loop if there's an event.
1015 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
1016 at the "right" time, but then that was what was asked for.
1017 There is no silver bullet for simulator engines.
1018 ??? Clearly this needs a cleaner interface.
1019 At present it's just so Ctrl-C works. */
1020 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
1021 CPU_RUNNING_P (current_cpu) = 0;
1023 /* Restart compiler if we branched to an uncacheable address
1025 if (br_type == SEM_BRANCH_UNCACHEABLE)
1028 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1031 /* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our
1033 if (br_type == SEM_BRANCH_UNTAKEN)
1035 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1036 new_pc = abuf->addr;
1038 new_vpc_ptr = &abuf->fields.chain.next;
1042 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1044 new_vpc_ptr = &abuf->fields.chain.branch_target;
1047 /* If chained to next block, go straight to it. */
1049 return *new_vpc_ptr;
1050 /* See if next block has already been compiled. */
1051 *new_vpc_ptr = scache_lookup (current_cpu, new_pc);
1053 return *new_vpc_ptr;
1054 /* Nope, so next insn is a virtual insn to invoke the compiler
1056 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1059 /* x-before handler.
1060 This is called before each insn. */
1063 @cpu@_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
1065 SEM_ARG sem_arg = sc;
1066 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1067 int first_p = abuf->fields.before.first_p;
1068 const ARGBUF *cur_abuf = SEM_ARGBUF (sc + 1);
1069 const IDESC *cur_idesc = cur_abuf->idesc;
1070 PCADDR pc = cur_abuf->addr;
1072 if (ARGBUF_PROFILE_P (cur_abuf))
1073 PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
1075 /* If this isn't the first insn, finish up the previous one. */
1079 if (PROFILE_MODEL_P (current_cpu))
1081 const SEM_ARG prev_sem_arg = sc - 1;
1082 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1083 const IDESC *prev_idesc = prev_abuf->idesc;
1086 /* ??? May want to measure all insns if doing insn tracing. */
1087 if (ARGBUF_PROFILE_P (prev_abuf))
1089 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1090 @cpu@_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
1094 TRACE_INSN_FINI (current_cpu, cur_abuf, 0 /*last_p*/);
1097 /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */
1098 if (PROFILE_MODEL_P (current_cpu)
1099 && ARGBUF_PROFILE_P (cur_abuf))
1100 @cpu@_model_insn_before (current_cpu, first_p);
1102 TRACE_INSN_INIT (current_cpu, cur_abuf, first_p);
1103 TRACE_INSN (current_cpu, cur_idesc->idata, cur_abuf, pc);
1107 This is called after a serial insn or at the end of a group of parallel
1111 @cpu@_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
1113 SEM_ARG sem_arg = sc;
1114 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1115 const SEM_ARG prev_sem_arg = sc - 1;
1116 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1118 /* ??? May want to measure all insns if doing insn tracing. */
1119 if (PROFILE_MODEL_P (current_cpu)
1120 && ARGBUF_PROFILE_P (prev_abuf))
1122 const IDESC *prev_idesc = prev_abuf->idesc;
1125 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1126 @cpu@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
1128 TRACE_INSN_FINI (current_cpu, prev_abuf, 1 /*last_p*/);
1134 @cpu@_engine_run_full (SIM_CPU *current_cpu)
1136 SIM_DESC current_state = CPU_STATE (current_cpu);
1137 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1138 /* virtual program counter */
1140 #if WITH_SEM_SWITCH_FULL
1141 /* For communication between cti's and cti-chain. */
1142 SEM_BRANCH_TYPE pbb_br_type;
1151 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1152 PAREXEC *par_exec = &pbufs[0];
1158 # Any initialization code before looping starts.
1159 # Note that this code may declare some locals.
1160 ${SHELL} $infile init
1164 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1166 /* ??? 'twould be nice to move this up a level and only call it once.
1167 On the other hand, in the "let's go fast" case the test is only done
1168 once per pbb (since we only return to the main loop at the end of
1169 a pbb). And in the "let's run until we're done" case we don't return
1170 until the program exits. */
1172 #if WITH_SEM_SWITCH_FULL
1173 #if defined (__GNUC__)
1174 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1175 #define DEFINE_LABELS
1179 @cpu@_sem_init_idesc_table (current_cpu);
1182 /* Initialize the "begin (compile) a pbb" virtual insn. */
1183 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1184 SEM_SET_FULL_CODE (SEM_ARGBUF (vpc),
1185 & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN]);
1186 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN];
1188 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1191 CPU_RUNNING_P (current_cpu) = 1;
1192 /* ??? In the case where we're returning to the main loop after every
1193 pbb we don't want to call pbb_begin each time (which hashes on the pc
1194 and does a table lookup). A way to speed this up is to save vpc
1196 vpc = @cpu@_pbb_begin (current_cpu, FAST_P);
1200 /* begin full-exec-pbb */
1203 ${SHELL} $infile full-exec-pbb
1206 /* end full-exec-pbb */
1208 while (CPU_RUNNING_P (current_cpu));
1215 ####################################
1217 # Compile engine: fast version.
1219 if [ x
$fast = xyes
] ; then
1226 @cpu@_engine_run_fast (SIM_CPU *current_cpu)
1228 SIM_DESC current_state = CPU_STATE (current_cpu);
1229 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1230 /* virtual program counter */
1232 #if WITH_SEM_SWITCH_FAST
1233 /* For communication between cti's and cti-chain. */
1234 SEM_BRANCH_TYPE pbb_br_type;
1243 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1244 PAREXEC *par_exec = &pbufs[0];
1250 # Any initialization code before looping starts.
1251 # Note that this code may declare some locals.
1252 ${SHELL} $infile init
1256 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1258 /* ??? 'twould be nice to move this up a level and only call it once.
1259 On the other hand, in the "let's go fast" case the test is only done
1260 once per pbb (since we only return to the main loop at the end of
1261 a pbb). And in the "let's run until we're done" case we don't return
1262 until the program exits. */
1264 #if WITH_SEM_SWITCH_FAST
1265 #if defined (__GNUC__)
1266 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1267 #define DEFINE_LABELS
1271 @cpu@_semf_init_idesc_table (current_cpu);
1274 /* Initialize the "begin (compile) a pbb" virtual insn. */
1275 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1276 SEM_SET_FAST_CODE (SEM_ARGBUF (vpc),
1277 & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN]);
1278 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN];
1280 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1283 CPU_RUNNING_P (current_cpu) = 1;
1284 /* ??? In the case where we're returning to the main loop after every
1285 pbb we don't want to call pbb_begin each time (which hashes on the pc
1286 and does a table lookup). A way to speed this up is to save vpc
1288 vpc = @cpu@_pbb_begin (current_cpu, FAST_P);
1292 /* begin fast-exec-pbb */
1295 ${SHELL} $infile fast-exec-pbb
1298 /* end fast-exec-pbb */
1300 while (CPU_RUNNING_P (current_cpu));
1310 # Process @cpu@,@CPU@ appearing in mainloop.in.
1311 sed -e "s/@cpu@/$cpu/g" -e "s/@CPU@/$CPU/g" < tmp-mloop.cin
> mloop.cin