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.
89 # One of these options is specified in addition to -simple, -scache,
90 # -pbb. Note that while the code can determine if the cpu supports
91 # parallel execution with HAVE_PARALLEL_INSNS [and thus this option is
92 # technically unnecessary], having this option cuts down on the clutter
95 # -switch file: specify file containing semantics implemented as a switch()
99 # Specify the cpu family name.
101 # -infile <input-file>
103 # Specify the mainloop.in input file.
105 # Only one of -scache/-pbb may be selected.
106 # -simple is the default.
111 # - build mainloop.in from .cpu file
127 -multi) type=multi
;;
130 -full-switch) full_switch
=yes ;;
132 -scache) scache
=yes ;;
135 -parallel-read) parallel
=read ;;
136 -parallel-write) parallel
=write ;;
137 -switch) shift ; switch
=$1 ;;
138 -cpu) shift ; cpu
=$1 ;;
139 -infile) shift ; infile
=$1 ;;
140 *) echo "unknown option: $1" >&2 ; exit 1 ;;
145 # Argument validation.
147 if [ x
$scache = xyes
-a x
$pbb = xyes
] ; then
148 echo "only one of -scache and -pbb may be selected" >&2
152 if [ "x$cpu" = xunknown
] ; then
153 echo "cpu family not specified" >&2
157 if [ "x$infile" = x
] ; then
158 echo "mainloop.in not specified" >&2
162 lowercase
='abcdefghijklmnopqrstuvwxyz'
163 uppercase
='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
164 CPU
=`echo ${cpu} | tr "${lowercase}" "${uppercase}"`
166 ##########################################################################
171 echo "/* engine configuration for ${cpu} */"
174 echo "/* WITH_FAST: non-zero if a fast version of the engine is available"
175 echo " in addition to the full-featured version. */"
176 if [ x
$fast = xyes
] ; then
177 echo "#define WITH_FAST 1"
179 echo "#define WITH_FAST 0"
183 echo "/* WITH_SCACHE_PBB_${CPU}: non-zero if the pbb engine was selected. */"
184 if [ x
$pbb = xyes
] ; then
185 echo "#define WITH_SCACHE_PBB_${CPU} 1"
187 echo "#define WITH_SCACHE_PBB_${CPU} 0"
191 echo "/* HAVE_PARALLEL_INSNS: non-zero if cpu can parallelly execute > 1 insn. */"
192 if [ x
$parallel != xno
] ; then
193 echo "#define HAVE_PARALLEL_INSNS 1"
194 if [ x
$parallel = xread
] ; then
195 echo "/* Parallel execution is supported by read-before-exec. */"
196 echo "#define WITH_PARALLEL_READ 1"
197 echo "#define WITH_PARALLEL_WRITE 0"
199 echo "/* Parallel execution is supported by write-after-exec. */"
200 echo "#define WITH_PARALLEL_READ 0"
201 echo "#define WITH_PARALLEL_WRITE 1"
204 echo "#define HAVE_PARALLEL_INSNS 0"
205 echo "#define WITH_PARALLEL_READ 0"
206 echo "#define WITH_PARALLEL_WRITE 0"
209 if [ "x$switch" != x
] ; then
211 echo "/* WITH_SEM_SWITCH_FULL: non-zero if full-featured engine is"
212 echo " implemented as a switch(). */"
213 if [ x
$fast != xyes
-o x
$full_switch = xyes
] ; then
214 echo "#define WITH_SEM_SWITCH_FULL 1"
216 echo "#define WITH_SEM_SWITCH_FULL 0"
219 echo "/* WITH_SEM_SWITCH_FAST: non-zero if fast engine is"
220 echo " implemented as a switch(). */"
221 if [ x
$fast = xyes
] ; then
222 echo "#define WITH_SEM_SWITCH_FAST 1"
224 echo "#define WITH_SEM_SWITCH_FAST 0"
228 # Decls of functions we define.
231 echo "/* Functions defined in the generated mainloop.c file"
232 echo " (which doesn't necessarily have that file name). */"
234 echo "extern ENGINE_FN ${cpu}_engine_run_full;"
235 echo "extern ENGINE_FN ${cpu}_engine_run_fast;"
237 if [ x
$pbb = xyes
] ; then
239 echo "extern SEM_PC ${cpu}_pbb_begin (SIM_CPU *, int);"
240 echo "extern SEM_PC ${cpu}_pbb_chain (SIM_CPU *, SEM_ARG);"
241 echo "extern SEM_PC ${cpu}_pbb_cti_chain (SIM_CPU *, SEM_ARG, SEM_BRANCH_TYPE, PCADDR);"
242 echo "extern void ${cpu}_pbb_before (SIM_CPU *, SCACHE *);"
243 echo "extern void ${cpu}_pbb_after (SIM_CPU *, SCACHE *);"
246 ##########################################################################
248 rm -f tmp-mloop.cin mloop.cin
251 # We use @cpu@ instead of ${cpu} because we still need to run sed to handle
252 # transformation of @cpu@ for mainloop.in, so there's no need to use ${cpu}
256 /* This file is generated by the genmloop script. DO NOT EDIT! */
258 /* Enable switch() support in cgen headers. */
259 #define SEM_IN_SWITCH
261 #define WANT_CPU @cpu@
262 #define WANT_CPU_@CPU@
264 #include "sim-main.h"
266 #include "cgen-mem.h"
267 #include "cgen-ops.h"
268 #include "sim-assert.h"
270 /* Fill in the administrative ARGBUF fields required by all insns,
274 @cpu@_fill_argbuf (const SIM_CPU *cpu, ARGBUF *abuf, const IDESC *idesc,
275 PCADDR pc, int fast_p)
278 SEM_SET_CODE (abuf, idesc, fast_p);
279 ARGBUF_ADDR (abuf) = pc;
281 ARGBUF_IDESC (abuf) = idesc;
284 /* Fill in tracing/profiling fields of an ARGBUF. */
287 @cpu@_fill_argbuf_tp (const SIM_CPU *cpu, ARGBUF *abuf,
288 int trace_p, int profile_p)
290 ARGBUF_TRACE_P (abuf) = trace_p;
291 ARGBUF_PROFILE_P (abuf) = profile_p;
296 /* Emit the "x-before" handler.
297 x-before is emitted before each insn (serial or parallel).
298 This is as opposed to x-after which is only emitted at the end of a group
299 of parallel insns. */
302 @cpu@_emit_before (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc, int first_p)
304 ARGBUF *abuf = &sc[0].argbuf;
305 const IDESC *id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEFORE];
307 abuf->fields.before.first_p = first_p;
308 @cpu@_fill_argbuf (current_cpu, abuf, id, pc, 0);
309 /* no need to set trace_p,profile_p */
312 /* Emit the "x-after" handler.
313 x-after is emitted after a serial insn or at the end of a group of
317 @cpu@_emit_after (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc)
319 ARGBUF *abuf = &sc[0].argbuf;
320 const IDESC *id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_AFTER];
322 @cpu@_fill_argbuf (current_cpu, abuf, id, pc, 0);
323 /* no need to set trace_p,profile_p */
326 #endif /* WITH_SCACHE_PBB */
330 ${SHELL} $infile support
332 ##########################################################################
334 # Simple engine: fetch an instruction, execute the instruction.
336 # Instruction fields are not extracted into ARGBUF, they are extracted in
337 # the semantic routines themselves. However, there is still a need to pass
338 # and return misc. information to the semantic routines so we still use ARGBUF.
339 # [One could certainly implement things differently and remove ARGBUF.
340 # It's not clear this is necessarily always a win.]
341 # ??? The use of the SCACHE struct is for consistency with the with-scache
342 # case though it might be a source of confusion.
344 if [ x
$scache != xyes
-a x
$pbb != xyes
] ; then
351 @cpu@_engine_run_full (SIM_CPU *current_cpu)
354 SIM_DESC current_state = CPU_STATE (current_cpu);
355 /* ??? Use of SCACHE is a bit of a hack as we don't actually use the scache.
356 We do however use ARGBUF so for consistency with the other engine flavours
357 the SCACHE type is used. */
358 SCACHE cache[MAX_LIW_INSNS];
359 SCACHE *sc = &cache[0];
363 if [ x
$parallel != xno
] ; then
365 PAREXEC pbufs[MAX_PARALLEL_INSNS];
371 # Any initialization code before looping starts.
372 # Note that this code may declare some locals.
373 ${SHELL} $infile init
375 if [ x
$parallel = xread
] ; then
378 #if defined (__GNUC__)
380 if (! CPU_IDESC_READ_INIT_P (current_cpu))
382 /* ??? Later maybe paste read.c in when building mainloop.c. */
383 #define DEFINE_LABELS
385 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
395 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
397 #if WITH_SEM_SWITCH_FULL
398 #if defined (__GNUC__)
399 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
400 #define DEFINE_LABELS
404 @cpu@_sem_init_idesc_table (current_cpu);
406 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
411 /* begin full-exec-simple */
414 ${SHELL} $infile full-exec-simple
417 /* end full-exec-simple */
419 ++ CPU_INSN_COUNT (current_cpu);
421 while (0 /*CPU_RUNNING_P (current_cpu)*/);
428 ####################################
430 # Simple engine: fast version.
431 # ??? A somewhat dubious effort, but for completeness' sake.
433 if [ x
$fast = xyes
] ; then
439 FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh."
449 ##########################################################################
451 # Non-parallel scache engine: lookup insn in scache, fetch if missing,
454 if [ x
$scache = xyes
-a x
$parallel = xno
] ; then
458 static INLINE SCACHE *
459 @cpu@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
460 unsigned int hash_mask, int FAST_P)
462 /* First step: look up current insn in hash table. */
463 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
465 /* If the entry isn't the one we want (cache miss),
466 fetch and decode the instruction. */
467 if (sc->argbuf.addr != vpc)
470 PROFILE_COUNT_SCACHE_MISS (current_cpu);
472 /* begin extract-scache */
475 ${SHELL} $infile extract-scache
478 /* end extract-scache */
482 PROFILE_COUNT_SCACHE_HIT (current_cpu);
483 /* Make core access statistics come out right.
484 The size is a guess, but it's currently not used either. */
485 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
494 @cpu@_engine_run_full (SIM_CPU *current_cpu)
496 SIM_DESC current_state = CPU_STATE (current_cpu);
497 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
498 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
503 # Any initialization code before looping starts.
504 # Note that this code may declare some locals.
505 ${SHELL} $infile init
509 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
511 #if ! WITH_SEM_SWITCH_FULL
512 @cpu@_sem_init_idesc_table (current_cpu);
514 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
523 sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
525 /* begin full-exec-scache */
528 ${SHELL} $infile full-exec-scache
531 /* end full-exec-scache */
535 ++ CPU_INSN_COUNT (current_cpu);
537 while (0 /*CPU_RUNNING_P (current_cpu)*/);
544 ####################################
546 # Non-parallel scache engine: fast version.
548 if [ x
$fast = xyes
] ; then
555 @cpu@_engine_run_fast (SIM_CPU *current_cpu)
557 SIM_DESC current_state = CPU_STATE (current_cpu);
558 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
559 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
564 # Any initialization code before looping starts.
565 # Note that this code may declare some locals.
566 ${SHELL} $infile init
570 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
572 #if WITH_SEM_SWITCH_FAST
573 #if defined (__GNUC__)
574 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
575 #define DEFINE_LABELS
579 @cpu@_semf_init_idesc_table (current_cpu);
581 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
590 sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
592 /* begin fast-exec-scache */
595 ${SHELL} $infile fast-exec-scache
598 /* end fast-exec-scache */
602 ++ CPU_INSN_COUNT (current_cpu);
604 while (0 /*CPU_RUNNING_P (current_cpu)*/);
613 fi # -scache && ! parallel
615 ##########################################################################
617 # Parallel scache engine: lookup insn in scache, fetch if missing,
619 # For the parallel case we give the target more flexibility.
621 if [ x
$scache = xyes
-a x
$parallel != xno
] ; then
625 static INLINE SCACHE *
626 @cpu@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
627 unsigned int hash_mask, int *last_insn_p, int FAST_P)
629 /* First step: look up current insn in hash table. */
630 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
632 /* If the entry isn't the one we want (cache miss),
633 fetch and decode the instruction. */
634 if (sc->argbuf.addr != vpc)
637 PROFILE_COUNT_SCACHE_MISS (current_cpu);
639 #define SET_LAST_INSN_P(last_p) do { *last_insn_p = (last_p); } while (0)
640 /* begin extract-scache */
643 ${SHELL} $infile extract-scache
646 /* end extract-scache */
647 #undef SET_LAST_INSN_P
651 PROFILE_COUNT_SCACHE_HIT (current_cpu);
652 /* Make core access statistics come out right.
653 The size is a guess, but it's currently not used either. */
654 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
663 @cpu@_engine_run_full (SIM_CPU *current_cpu)
665 SIM_DESC current_state = CPU_STATE (current_cpu);
666 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
667 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
672 # Any initialization code before looping starts.
673 # Note that this code may declare some locals.
674 ${SHELL} $infile init
676 if [ x
$parallel = xread
] ; then
678 #if defined (__GNUC__)
680 if (! CPU_IDESC_READ_INIT_P (current_cpu))
682 /* ??? Later maybe paste read.c in when building mainloop.c. */
683 #define DEFINE_LABELS
685 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
695 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
697 #if ! WITH_SEM_SWITCH_FULL
698 @cpu@_sem_init_idesc_table (current_cpu);
700 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
707 /* begin full-exec-scache */
710 ${SHELL} $infile full-exec-scache
713 /* end full-exec-scache */
715 while (0 /*CPU_RUNNING_P (current_cpu)*/);
722 ####################################
724 # Parallel scache engine: fast version.
726 if [ x
$fast = xyes
] ; then
733 @cpu@_engine_run_fast (SIM_CPU *current_cpu)
735 SIM_DESC current_state = CPU_STATE (current_cpu);
736 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
737 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
739 PAREXEC pbufs[MAX_PARALLEL_INSNS];
744 # Any initialization code before looping starts.
745 # Note that this code may declare some locals.
746 ${SHELL} $infile init
748 if [ x
$parallel = xread
] ; then
751 #if defined (__GNUC__)
753 if (! CPU_IDESC_READ_INIT_P (current_cpu))
755 /* ??? Later maybe paste read.c in when building mainloop.c. */
756 #define DEFINE_LABELS
758 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
768 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
770 #if WITH_SEM_SWITCH_FAST
771 #if defined (__GNUC__)
772 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
773 #define DEFINE_LABELS
777 @cpu@_semf_init_idesc_table (current_cpu);
779 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
786 /* begin fast-exec-scache */
789 ${SHELL} $infile fast-exec-scache
792 /* end fast-exec-scache */
794 while (0 /*CPU_RUNNING_P (current_cpu)*/);
803 fi # -scache && parallel
805 ##########################################################################
807 # Compilation engine: lookup insn in scache, extract a pbb
808 # (pseudo-basic-block) if missing, then execute the pbb.
809 # A "pbb" is a sequence of insns up to the next cti insn or until
810 # some prespecified maximum.
811 # CTI: control transfer instruction.
813 if [ x
$pbb = xyes
] ; then
817 /* Record address of cti terminating a pbb. */
818 #define SET_CTI_VPC(sc) do { _cti_sc = (sc); } while (0)
819 /* Record number of [real] insns in pbb. */
820 #define SET_INSN_COUNT(n) do { _insn_count = (n); } while (0)
822 /* Fetch and extract a pseudo-basic-block.
823 FAST_P is non-zero if no tracing/profiling/etc. is wanted. */
826 @cpu@_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
831 int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu);
835 new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
838 /* Leading '_' to avoid collision with mainloop.in. */
840 SCACHE *orig_sc = sc;
841 SCACHE *_cti_sc = NULL;
842 int slice_insns = CPU_MAX_SLICE_INSNS (current_cpu);
844 /* First figure out how many instructions to compile.
845 MAX_INSNS is the size of the allocated buffer, which includes space
846 for before/after handlers if they're being used.
847 SLICE_INSNS is the maxinum number of real insns that can be
848 executed. Zero means "as many as we want". */
849 /* ??? max_insns is serving two incompatible roles.
850 1) Number of slots available in scache buffer.
851 2) Number of real insns to execute.
852 They're incompatible because there are virtual insns emitted too
853 (chain,cti-chain,before,after handlers). */
855 if (slice_insns == 1)
857 /* No need to worry about extra slots required for virtual insns
858 and parallel exec support because MAX_CHAIN_LENGTH is
859 guaranteed to be big enough to execute at least 1 insn! */
864 /* Allow enough slop so that while compiling insns, if max_insns > 0
865 then there's guaranteed to be enough space to emit one real insn.
866 MAX_CHAIN_LENGTH is typically much longer than
867 the normal number of insns between cti's anyway. */
868 max_insns -= (1 /* one for the trailing chain insn */
871 : (1 + MAX_PARALLEL_INSNS) /* before+after */)
872 + (MAX_PARALLEL_INSNS > 1
873 ? (MAX_PARALLEL_INSNS * 2)
876 /* Account for before/after handlers. */
881 && slice_insns < max_insns)
882 max_insns = slice_insns;
887 /* SC,PC must be updated to point passed the last entry used.
888 SET_CTI_VPC must be called if pbb is terminated by a cti.
889 SET_INSN_COUNT must be called to record number of real insns in
890 pbb [could be computed by us of course, extra cpu but perhaps
891 negligible enough]. */
893 /* begin extract-pbb */
896 ${SHELL} $infile extract-pbb
899 /* end extract-pbb */
901 /* The last one is a pseudo-insn to link to the next chain.
902 It is also used to record the insn count for this chain. */
906 /* Was pbb terminated by a cti? */
909 id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_CTI_CHAIN];
913 id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_CHAIN];
915 SEM_SET_CODE (&sc->argbuf, id, FAST_P);
916 sc->argbuf.idesc = id;
917 sc->argbuf.addr = pc;
918 sc->argbuf.fields.chain.insn_count = _insn_count;
919 sc->argbuf.fields.chain.next = 0;
920 sc->argbuf.fields.chain.branch_target = 0;
924 /* Update the pointer to the next free entry, may not have used as
925 many entries as was asked for. */
926 CPU_SCACHE_NEXT_FREE (current_cpu) = sc;
927 /* Record length of chain if profiling.
928 This includes virtual insns since they count against
931 PROFILE_COUNT_SCACHE_CHAIN_LENGTH (current_cpu, sc - orig_sc);
937 /* Chain to the next block from a non-cti terminated previous block. */
940 @cpu@_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
942 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
944 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
946 SET_H_PC (abuf->addr);
948 /* If not running forever, exit back to main loop. */
949 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
950 /* Also exit back to main loop if there's an event.
951 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
952 at the "right" time, but then that was what was asked for.
953 There is no silver bullet for simulator engines.
954 ??? Clearly this needs a cleaner interface.
955 At present it's just so Ctrl-C works. */
956 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
957 CPU_RUNNING_P (current_cpu) = 0;
959 /* If chained to next block, go straight to it. */
960 if (abuf->fields.chain.next)
961 return abuf->fields.chain.next;
962 /* See if next block has already been compiled. */
963 abuf->fields.chain.next = scache_lookup (current_cpu, abuf->addr);
964 if (abuf->fields.chain.next)
965 return abuf->fields.chain.next;
966 /* Nope, so next insn is a virtual insn to invoke the compiler
968 return CPU_SCACHE_PBB_BEGIN (current_cpu);
971 /* Chain to the next block from a cti terminated previous block.
972 BR_TYPE indicates whether the branch was taken and whether we can cache
973 the vpc of the branch target.
974 NEW_PC is the target's branch address, and is only valid if
975 BR_TYPE != SEM_BRANCH_UNTAKEN. */
978 @cpu@_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
979 SEM_BRANCH_TYPE br_type, PCADDR new_pc)
983 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
985 /* If not running forever, exit back to main loop. */
986 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
987 /* Also exit back to main loop if there's an event.
988 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
989 at the "right" time, but then that was what was asked for.
990 There is no silver bullet for simulator engines.
991 ??? Clearly this needs a cleaner interface.
992 At present it's just so Ctrl-C works. */
993 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
994 CPU_RUNNING_P (current_cpu) = 0;
996 /* Restart compiler if we branched to an uncacheable address
998 if (br_type == SEM_BRANCH_UNCACHEABLE)
1001 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1004 /* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our
1006 if (br_type == SEM_BRANCH_UNTAKEN)
1008 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1009 new_pc = abuf->addr;
1011 new_vpc_ptr = &abuf->fields.chain.next;
1015 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1017 new_vpc_ptr = &abuf->fields.chain.branch_target;
1020 /* If chained to next block, go straight to it. */
1022 return *new_vpc_ptr;
1023 /* See if next block has already been compiled. */
1024 *new_vpc_ptr = scache_lookup (current_cpu, new_pc);
1026 return *new_vpc_ptr;
1027 /* Nope, so next insn is a virtual insn to invoke the compiler
1029 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1032 /* x-before handler.
1033 This is called before each insn. */
1036 @cpu@_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
1038 SEM_ARG sem_arg = sc;
1039 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1040 int first_p = abuf->fields.before.first_p;
1041 const ARGBUF *cur_abuf = SEM_ARGBUF (sc + 1);
1042 const IDESC *cur_idesc = cur_abuf->idesc;
1043 PCADDR pc = cur_abuf->addr;
1045 if (ARGBUF_PROFILE_P (cur_abuf))
1046 PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
1048 /* If this isn't the first insn, finish up the previous one. */
1052 if (PROFILE_MODEL_P (current_cpu))
1054 const SEM_ARG prev_sem_arg = sc - 1;
1055 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1056 const IDESC *prev_idesc = prev_abuf->idesc;
1059 /* ??? May want to measure all insns if doing insn tracing. */
1060 if (ARGBUF_PROFILE_P (prev_abuf))
1062 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1063 @cpu@_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
1067 TRACE_INSN_FINI (current_cpu, cur_abuf, 0 /*last_p*/);
1070 /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */
1071 if (PROFILE_MODEL_P (current_cpu)
1072 && ARGBUF_PROFILE_P (cur_abuf))
1073 @cpu@_model_insn_before (current_cpu, first_p);
1075 TRACE_INSN_INIT (current_cpu, cur_abuf, first_p);
1076 TRACE_INSN (current_cpu, cur_idesc->idata, cur_abuf, pc);
1080 This is called after a serial insn or at the end of a group of parallel
1084 @cpu@_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
1086 SEM_ARG sem_arg = sc;
1087 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1088 const SEM_ARG prev_sem_arg = sc - 1;
1089 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1091 /* ??? May want to measure all insns if doing insn tracing. */
1092 if (PROFILE_MODEL_P (current_cpu)
1093 && ARGBUF_PROFILE_P (prev_abuf))
1095 const IDESC *prev_idesc = prev_abuf->idesc;
1098 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1099 @cpu@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
1101 TRACE_INSN_FINI (current_cpu, prev_abuf, 1 /*last_p*/);
1107 @cpu@_engine_run_full (SIM_CPU *current_cpu)
1109 SIM_DESC current_state = CPU_STATE (current_cpu);
1110 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1111 /* virtual program counter */
1113 #if WITH_SEM_SWITCH_FULL
1114 /* For communication between cti's and cti-chain. */
1115 SEM_BRANCH_TYPE pbb_br_type;
1121 if [ x
$parallel != xno
] ; then
1123 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1124 PAREXEC *par_exec = &pbufs[0];
1129 # Any initialization code before looping starts.
1130 # Note that this code may declare some locals.
1131 ${SHELL} $infile init
1135 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1137 /* ??? 'twould be nice to move this up a level and only call it once.
1138 On the other hand, in the "let's go fast" case the test is only done
1139 once per pbb (since we only return to the main loop at the end of
1140 a pbb). And in the "let's run until we're done" case we don't return
1141 until the program exits. */
1143 #if WITH_SEM_SWITCH_FULL
1144 #if defined (__GNUC__)
1145 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1146 #define DEFINE_LABELS
1150 @cpu@_sem_init_idesc_table (current_cpu);
1153 /* Initialize the "begin (compile) a pbb" virtual insn. */
1154 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1155 SEM_SET_FULL_CODE (SEM_ARGBUF (vpc),
1156 & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN]);
1157 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN];
1159 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1162 CPU_RUNNING_P (current_cpu) = 1;
1163 /* ??? In the case where we're returning to the main loop after every
1164 pbb we don't want to call pbb_begin each time (which hashes on the pc
1165 and does a table lookup). A way to speed this up is to save vpc
1167 vpc = @cpu@_pbb_begin (current_cpu, FAST_P);
1171 /* begin full-exec-pbb */
1174 ${SHELL} $infile full-exec-pbb
1177 /* end full-exec-pbb */
1179 while (CPU_RUNNING_P (current_cpu));
1186 ####################################
1188 # Compile engine: fast version.
1190 if [ x
$fast = xyes
] ; then
1197 @cpu@_engine_run_fast (SIM_CPU *current_cpu)
1199 SIM_DESC current_state = CPU_STATE (current_cpu);
1200 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1201 /* virtual program counter */
1203 #if WITH_SEM_SWITCH_FAST
1204 /* For communication between cti's and cti-chain. */
1205 SEM_BRANCH_TYPE pbb_br_type;
1211 if [ x
$parallel != xno
] ; then
1213 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1214 PAREXEC *par_exec = &pbufs[0];
1219 # Any initialization code before looping starts.
1220 # Note that this code may declare some locals.
1221 ${SHELL} $infile init
1225 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1227 /* ??? 'twould be nice to move this up a level and only call it once.
1228 On the other hand, in the "let's go fast" case the test is only done
1229 once per pbb (since we only return to the main loop at the end of
1230 a pbb). And in the "let's run until we're done" case we don't return
1231 until the program exits. */
1233 #if WITH_SEM_SWITCH_FAST
1234 #if defined (__GNUC__)
1235 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1236 #define DEFINE_LABELS
1240 @cpu@_semf_init_idesc_table (current_cpu);
1243 /* Initialize the "begin (compile) a pbb" virtual insn. */
1244 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1245 SEM_SET_FAST_CODE (SEM_ARGBUF (vpc),
1246 & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN]);
1247 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN];
1249 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1252 CPU_RUNNING_P (current_cpu) = 1;
1253 /* ??? In the case where we're returning to the main loop after every
1254 pbb we don't want to call pbb_begin each time (which hashes on the pc
1255 and does a table lookup). A way to speed this up is to save vpc
1257 vpc = @cpu@_pbb_begin (current_cpu, FAST_P);
1261 /* begin fast-exec-pbb */
1264 ${SHELL} $infile fast-exec-pbb
1267 /* end fast-exec-pbb */
1269 while (CPU_RUNNING_P (current_cpu));
1279 # Process @cpu@,@CPU@ appearing in mainloop.in.
1280 sed -e "s/@cpu@/$cpu/g" -e "s/@CPU@/$CPU/g" < tmp-mloop.cin
> mloop.cin
This page took 0.059485 seconds and 5 git commands to generate.