* Contribute CGEN simulator build support code.
[binutils-gdb.git] / sim / common / genmloop.sh
blobd3e17b085dfcd2eca6e1d3f314c46ccba3f16c3f
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)
10 # 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 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]
33 # Options:
35 # -mono | -multi
36 # - specify single cpu or multiple cpus (number specifyable at runtime),
37 # maximum number is a configuration parameter
38 # - -multi wip
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
49 # here).
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
89 # writes.
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
95 # in the result.
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()
105 # -cpu <cpu-family>
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.
116 ####
118 # TODO
119 # - build mainloop.in from .cpu file
121 type=mono
122 #scache=
123 #fast=
124 #full_switch=
125 #pbb=
126 parallel=no
127 parallel_only=no
128 switch=
129 cpu="unknown"
130 infile=""
132 while test $# -gt 0
134 case $1 in
135 -mono) type=mono ;;
136 -multi) type=multi ;;
137 -no-fast) ;;
138 -fast) fast=yes ;;
139 -full-switch) full_switch=yes ;;
140 -simple) ;;
141 -scache) scache=yes ;;
142 -pbb) pbb=yes ;;
143 -no-parallel) ;;
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 ;;
152 esac
153 shift
154 done
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
160 exit 1
163 if [ "x$cpu" = xunknown ] ; then
164 echo "cpu family not specified" >&2
165 exit 1
168 if [ "x$infile" = x ] ; then
169 echo "mainloop.in not specified" >&2
170 exit 1
173 lowercase='abcdefghijklmnopqrstuvwxyz'
174 uppercase='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
175 CPU=`echo ${cpu} | tr "${lowercase}" "${uppercase}"`
177 ##########################################################################
179 rm -f eng.hin
180 exec 1>eng.hin
182 echo "/* engine configuration for ${cpu} */"
183 echo ""
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"
189 else
190 echo "#define WITH_FAST 0"
193 echo ""
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"
197 else
198 echo "#define WITH_SCACHE_PBB_${CPU} 0"
201 echo ""
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
204 case x$parallel in
205 xno)
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"
211 xread)
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"
218 xwrite)
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"
225 xgenwrite)
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"
232 esac
234 if [ "x$switch" != x ] ; then
235 echo ""
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"
240 else
241 echo "#define WITH_SEM_SWITCH_FULL 0"
243 echo ""
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"
248 else
249 echo "#define WITH_SEM_SWITCH_FAST 0"
253 # Decls of functions we define.
255 echo ""
256 echo "/* Functions defined in the generated mainloop.c file"
257 echo " (which doesn't necessarily have that file name). */"
258 echo ""
259 echo "extern ENGINE_FN ${cpu}_engine_run_full;"
260 echo "extern ENGINE_FN ${cpu}_engine_run_fast;"
262 if [ x$pbb = xyes ] ; then
263 echo ""
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
274 exec 1>tmp-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}
278 # here.
280 cat << EOF
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"
290 #include "bfd.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,
296 virtual and real. */
298 static INLINE void
299 @cpu@_fill_argbuf (const SIM_CPU *cpu, ARGBUF *abuf, const IDESC *idesc,
300 PCADDR pc, int fast_p)
302 #if WITH_SCACHE
303 SEM_SET_CODE (abuf, idesc, fast_p);
304 ARGBUF_ADDR (abuf) = pc;
305 #endif
306 ARGBUF_IDESC (abuf) = idesc;
309 /* Fill in tracing/profiling fields of an ARGBUF. */
311 static INLINE void
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;
319 #if WITH_SCACHE_PBB
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. */
326 static INLINE void
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
339 parallel insns. */
341 static INLINE void
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
371 cat << EOF
373 #define FAST_P 0
375 void
376 @cpu@_engine_run_full (SIM_CPU *current_cpu)
378 #define FAST_P 0
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];
388 case x$parallel in
389 xread | xwrite)
390 cat << EOF
391 PAREXEC pbufs[MAX_PARALLEL_INSNS];
392 PAREXEC *par_exec;
396 esac
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
403 cat << EOF
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
411 #include "readx.c"
412 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
415 #endif
420 cat << EOF
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
428 #include "$switch"
429 #endif
430 #else
431 @cpu@_sem_init_idesc_table (current_cpu);
432 #endif
433 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
438 /* begin full-exec-simple */
441 ${SHELL} $infile full-exec-simple
443 cat << EOF
444 /* end full-exec-simple */
446 ++ CPU_INSN_COUNT (current_cpu);
448 while (0 /*CPU_RUNNING_P (current_cpu)*/);
451 #undef FAST_P
455 ####################################
457 # Simple engine: fast version.
458 # ??? A somewhat dubious effort, but for completeness' sake.
460 if [ x$fast = xyes ] ; then
462 cat << EOF
464 #define FAST_P 1
466 FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh."
468 #undef FAST_P
472 fi # -fast
474 fi # simple engine
476 ##########################################################################
478 # Non-parallel scache engine: lookup insn in scache, fetch if missing,
479 # then execute it.
481 if [ x$scache = xyes -a x$parallel = xno ] ; then
483 cat << EOF
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)
496 if (! FAST_P)
497 PROFILE_COUNT_SCACHE_MISS (current_cpu);
499 /* begin extract-scache */
502 ${SHELL} $infile extract-scache
504 cat << EOF
505 /* end extract-scache */
507 else if (! FAST_P)
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);
515 return sc;
518 #define FAST_P 0
520 void
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);
526 SEM_PC vpc;
530 # Any initialization code before looping starts.
531 # Note that this code may declare some locals.
532 ${SHELL} $infile init
534 cat << EOF
536 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
538 #if ! WITH_SEM_SWITCH_FULL
539 @cpu@_sem_init_idesc_table (current_cpu);
540 #endif
541 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
544 vpc = GET_H_PC ();
548 SCACHE *sc;
550 sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
552 /* begin full-exec-scache */
555 ${SHELL} $infile full-exec-scache
557 cat << EOF
558 /* end full-exec-scache */
560 SET_H_PC (vpc);
562 ++ CPU_INSN_COUNT (current_cpu);
564 while (0 /*CPU_RUNNING_P (current_cpu)*/);
567 #undef FAST_P
571 ####################################
573 # Non-parallel scache engine: fast version.
575 if [ x$fast = xyes ] ; then
577 cat << EOF
579 #define FAST_P 1
581 void
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);
587 SEM_PC vpc;
591 # Any initialization code before looping starts.
592 # Note that this code may declare some locals.
593 ${SHELL} $infile init
595 cat << EOF
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
603 #include "$switch"
604 #endif
605 #else
606 @cpu@_semf_init_idesc_table (current_cpu);
607 #endif
608 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
611 vpc = GET_H_PC ();
615 SCACHE *sc;
617 sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
619 /* begin fast-exec-scache */
622 ${SHELL} $infile fast-exec-scache
624 cat << EOF
625 /* end fast-exec-scache */
627 SET_H_PC (vpc);
629 ++ CPU_INSN_COUNT (current_cpu);
631 while (0 /*CPU_RUNNING_P (current_cpu)*/);
634 #undef FAST_P
638 fi # -fast
640 fi # -scache && ! parallel
642 ##########################################################################
644 # Parallel scache engine: lookup insn in scache, fetch if missing,
645 # then execute it.
646 # For the parallel case we give the target more flexibility.
648 if [ x$scache = xyes -a x$parallel != xno ] ; then
650 cat << EOF
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)
663 if (! FAST_P)
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
672 cat << EOF
673 /* end extract-scache */
674 #undef SET_LAST_INSN_P
676 else if (! FAST_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);
684 return sc;
687 #define FAST_P 0
689 void
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);
695 SEM_PC vpc;
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
704 cat << EOF
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
711 #include "readx.c"
712 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
715 #endif
720 cat << EOF
722 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
724 #if ! WITH_SEM_SWITCH_FULL
725 @cpu@_sem_init_idesc_table (current_cpu);
726 #endif
727 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
730 vpc = GET_H_PC ();
734 /* begin full-exec-scache */
737 ${SHELL} $infile full-exec-scache
739 cat << EOF
740 /* end full-exec-scache */
742 while (0 /*CPU_RUNNING_P (current_cpu)*/);
745 #undef FAST_P
749 ####################################
751 # Parallel scache engine: fast version.
753 if [ x$fast = xyes ] ; then
755 cat << EOF
757 #define FAST_P 1
759 void
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);
765 SEM_PC vpc;
766 PAREXEC pbufs[MAX_PARALLEL_INSNS];
767 PAREXEC *par_exec;
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
776 cat << EOF
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
784 #include "readx.c"
785 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
788 #endif
793 cat << EOF
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
801 #include "$switch"
802 #endif
803 #else
804 @cpu@_semf_init_idesc_table (current_cpu);
805 #endif
806 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
809 vpc = GET_H_PC ();
813 /* begin fast-exec-scache */
816 ${SHELL} $infile fast-exec-scache
818 cat << EOF
819 /* end fast-exec-scache */
821 while (0 /*CPU_RUNNING_P (current_cpu)*/);
824 #undef FAST_P
828 fi # -fast
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
842 cat << EOF
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. */
852 INLINE SEM_PC
853 @cpu@_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
855 SEM_PC new_vpc;
856 PCADDR pc;
857 SCACHE *sc;
858 int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu);
860 pc = GET_H_PC ();
862 new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
863 if (! new_vpc)
865 /* Leading '_' to avoid collision with mainloop.in. */
866 int _insn_count = 0;
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! */
887 max_insns = 1;
889 else
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 */
896 + (FAST_P
898 : (1 + MAX_PARALLEL_INSNS) /* before+after */)
899 + (MAX_PARALLEL_INSNS > 1
900 ? (MAX_PARALLEL_INSNS * 2)
901 : 0));
903 /* Account for before/after handlers. */
904 if (! FAST_P)
905 slice_insns *= 3;
907 if (slice_insns > 0
908 && slice_insns < max_insns)
909 max_insns = slice_insns;
912 new_vpc = sc;
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
925 cat << EOF
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. */
931 const IDESC *id;
933 /* Was pbb terminated by a cti? */
934 if (_cti_sc)
936 id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_CTI_CHAIN];
938 else
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;
948 ++sc;
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
956 max_insns too. */
957 if (! FAST_P)
958 PROFILE_COUNT_SCACHE_CHAIN_LENGTH (current_cpu, sc - orig_sc);
961 return new_vpc;
964 /* Chain to the next block from a non-cti terminated previous block. */
966 INLINE SEM_PC
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
994 (begin a pbb). */
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. */
1004 INLINE SEM_PC
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
1024 (e.g. "j reg"). */
1025 if (br_type == SEM_BRANCH_UNCACHEABLE)
1027 SET_H_PC (new_pc);
1028 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1031 /* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our
1032 next chain ptr. */
1033 if (br_type == SEM_BRANCH_UNTAKEN)
1035 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1036 new_pc = abuf->addr;
1037 SET_H_PC (new_pc);
1038 new_vpc_ptr = &abuf->fields.chain.next;
1040 else
1042 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1043 SET_H_PC (new_pc);
1044 new_vpc_ptr = &abuf->fields.chain.branch_target;
1047 /* If chained to next block, go straight to it. */
1048 if (*new_vpc_ptr)
1049 return *new_vpc_ptr;
1050 /* See if next block has already been compiled. */
1051 *new_vpc_ptr = scache_lookup (current_cpu, new_pc);
1052 if (*new_vpc_ptr)
1053 return *new_vpc_ptr;
1054 /* Nope, so next insn is a virtual insn to invoke the compiler
1055 (begin a pbb). */
1056 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1059 /* x-before handler.
1060 This is called before each insn. */
1062 void
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. */
1077 if (! first_p)
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;
1084 int cycles;
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);
1106 /* x-after handler.
1107 This is called after a serial insn or at the end of a group of parallel
1108 insns. */
1110 void
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;
1123 int cycles;
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*/);
1131 #define FAST_P 0
1133 void
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 */
1139 SEM_PC vpc;
1140 #if WITH_SEM_SWITCH_FULL
1141 /* For communication between cti's and cti-chain. */
1142 SEM_BRANCH_TYPE pbb_br_type;
1143 PCADDR pbb_br_npc;
1144 #endif
1148 case x$parallel in
1149 xread | xwrite)
1150 cat << EOF
1151 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1152 PAREXEC *par_exec = &pbufs[0];
1156 esac
1158 # Any initialization code before looping starts.
1159 # Note that this code may declare some locals.
1160 ${SHELL} $infile init
1162 cat << EOF
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
1176 #include "$switch"
1177 #endif
1178 #else
1179 @cpu@_sem_init_idesc_table (current_cpu);
1180 #endif
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
1195 between calls. */
1196 vpc = @cpu@_pbb_begin (current_cpu, FAST_P);
1200 /* begin full-exec-pbb */
1203 ${SHELL} $infile full-exec-pbb
1205 cat << EOF
1206 /* end full-exec-pbb */
1208 while (CPU_RUNNING_P (current_cpu));
1211 #undef FAST_P
1215 ####################################
1217 # Compile engine: fast version.
1219 if [ x$fast = xyes ] ; then
1221 cat << EOF
1223 #define FAST_P 1
1225 void
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 */
1231 SEM_PC vpc;
1232 #if WITH_SEM_SWITCH_FAST
1233 /* For communication between cti's and cti-chain. */
1234 SEM_BRANCH_TYPE pbb_br_type;
1235 PCADDR pbb_br_npc;
1236 #endif
1240 case x$parallel in
1241 xread | xwrite)
1242 cat << EOF
1243 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1244 PAREXEC *par_exec = &pbufs[0];
1248 esac
1250 # Any initialization code before looping starts.
1251 # Note that this code may declare some locals.
1252 ${SHELL} $infile init
1254 cat << EOF
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
1268 #include "$switch"
1269 #endif
1270 #else
1271 @cpu@_semf_init_idesc_table (current_cpu);
1272 #endif
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
1287 between calls. */
1288 vpc = @cpu@_pbb_begin (current_cpu, FAST_P);
1292 /* begin fast-exec-pbb */
1295 ${SHELL} $infile fast-exec-pbb
1297 cat << EOF
1298 /* end fast-exec-pbb */
1300 while (CPU_RUNNING_P (current_cpu));
1303 #undef FAST_P
1306 fi # -fast
1308 fi # -pbb
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
1312 rc=$?
1313 rm -f tmp-mloop.cin
1315 exit $rc