arm: Support pac_key_* register operand for MRS/MSR in Armv8.1-M Mainline
[binutils-gdb.git] / sim / common / genmloop.sh
blob7fb48fd16d494f2013c9ca35959f036b63ba0e53
1 # Generate the main loop of the simulator.
2 # Copyright (C) 1996-2024 Free Software Foundation, Inc.
3 # Contributed by Cygnus Support.
5 # This file is part of the GNU simulators.
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 # This file creates two files: eng.hin and mloop.cin.
21 # eng.hin defines a few macros that specify what kind of engine was selected
22 # based on the arguments to this script.
23 # mloop.cin contains the engine.
25 # ??? Rename mloop.c to eng.c?
26 # ??? Rename mainloop.in to engine.in?
27 # ??? Add options to specify output file names?
28 # ??? Rename this file to genengine.sh?
30 # Syntax: genmloop.sh [options]
32 # Options:
34 # -mono | -multi
35 # - specify single cpu or multiple cpus (number specifyable at runtime),
36 # maximum number is a configuration parameter
37 # - -multi wip
39 # -fast: include support for fast execution in addition to full featured mode
41 # Full featured mode is for tracing, profiling, etc. and is always
42 # provided. Fast mode contains no frills, except speed.
43 # A target need only provide a "full" version of one of
44 # simple,scache,pbb. If the target wants it can also provide a fast
45 # version of same. It can't provide more than this.
46 # ??? Later add ability to have another set of full/fast semantics
47 # for use in with-devices/with-smp situations (pbb can be inappropriate
48 # here).
50 # -full-switch: same as -fast but for full featured version of -switch
51 # Only needed if -fast present.
53 # -simple: simple execution engine (the default)
55 # This engine fetches and executes one instruction at a time.
56 # Field extraction is done in the semantic routines.
58 # ??? There are two possible flavours of -simple. One that extracts
59 # fields in the semantic routine (which is what is implemented here),
60 # and one that stores the extracted fields in ARGBUF before calling the
61 # semantic routine. The latter is essentially the -scache case with a
62 # cache size of one (and the scache lookup code removed). There are no
63 # current uses of this and it's not clear when doing this would be a win.
64 # More complicated ISA's that want to use -simple may find this a win.
65 # Should this ever be desirable, implement a new engine style here and
66 # call it -extract (or some such). It's believed that the CGEN-generated
67 # code for the -scache case would be usable here, so no new code
68 # generation option would be needed for CGEN.
70 # -scache: use the scache to speed things up (not always a win)
72 # This engine caches the extracted instruction before executing it.
73 # When executing instructions they are first looked up in the scache.
75 # -pbb: same as -scache but extract a (pseudo-) basic block at a time
77 # This engine is basically identical to the scache version except that
78 # extraction is done a pseudo-basic-block at a time and the address of
79 # the scache entry of a branch target is recorded as well.
80 # Additional speedups are then possible by defering Ctrl-C checking
81 # to the end of basic blocks and by threading the insns together.
82 # We call them pseudo-basic-block's instead of just basic-blocks because
83 # they're not necessarily basic-blocks, though normally are.
85 # -parallel-read: support parallel execution with read-before-exec support.
86 # -parallel-write: support parallel execution with write-after-exec support.
87 # -parallel-generic-write: support parallel execution with generic queued
88 # writes.
90 # One of these options is specified in addition to -simple, -scache,
91 # -pbb. Note that while the code can determine if the cpu supports
92 # parallel execution with HAVE_PARALLEL_INSNS [and thus this option is
93 # technically unnecessary], having this option cuts down on the clutter
94 # in the result.
96 # -parallel-only: semantic code only supports parallel version of insn
98 # Semantic code only supports parallel versions of each insn.
99 # Things can be sped up by generating both serial and parallel versions
100 # and is better suited to mixed parallel architectures like the m32r.
102 # -prefix: string to prepend to function names in mloop.c/eng.h.
104 # If no prefix is specified, the cpu type is used.
106 # -switch file: specify file containing semantics implemented as a switch()
108 # -cpu <cpu-family>
110 # Specify the cpu family name.
112 # -infile <input-file>
114 # Specify the mainloop.in input file.
116 # -outfile-suffix <output-file-suffix>
118 # Specify the suffix to append to output files.
120 # -shell <shell>
122 # Specify the shell to use to execute <input-file>
124 # Only one of -scache/-pbb may be selected.
125 # -simple is the default.
127 ####
129 # TODO
130 # - build mainloop.in from .cpu file
132 type=mono
133 #scache=
134 #fast=
135 #full_switch=
136 #pbb=
137 parallel=no
138 parallel_only=no
139 switch=
140 cpu="unknown"
141 infile=""
142 prefix="unknown"
143 outprefix=""
144 outsuffix=""
145 lineno=""
147 while test $# -gt 0
149 case $1 in
150 -mono) type=mono ;;
151 -multi) type=multi ;;
152 -no-fast) ;;
153 -fast) fast=yes ;;
154 -full-switch) full_switch=yes ;;
155 -simple) ;;
156 -scache) scache=yes ;;
157 -pbb) pbb=yes ;;
158 -no-parallel) ;;
159 -outfile-prefix) shift ; outprefix=$1 ;;
160 -outfile-suffix) shift ; outsuffix=$1 ;;
161 -parallel-read) parallel=read ;;
162 -parallel-write) parallel=write ;;
163 -parallel-generic-write) parallel=genwrite ;;
164 -parallel-only) parallel_only=yes ;;
165 -prefix) shift ; prefix=$1 ;;
166 -switch) shift ; switch=$1 ;;
167 -cpu) shift ; cpu=$1 ;;
168 -infile) shift ; infile=$1 ;;
169 -shell) shift ; SHELL=$1 ;;
170 -awk) shift ; AWK=$1 ; export AWK ;;
171 -lineno) shift ; lineno=$1 ;;
172 *) echo "unknown option: $1" >&2 ; exit 1 ;;
173 esac
174 shift
175 done
177 # Argument validation.
179 if [ x$scache = xyes -a x$pbb = xyes ] ; then
180 echo "only one of -scache and -pbb may be selected" >&2
181 exit 1
184 if [ "x$cpu" = xunknown ] ; then
185 echo "cpu family not specified" >&2
186 exit 1
189 if [ "x$infile" = x ] ; then
190 echo "mainloop.in not specified" >&2
191 exit 1
194 if [ "x$prefix" = xunknown ] ; then
195 prefix=$cpu
198 lowercase='abcdefghijklmnopqrstuvwxyz'
199 uppercase='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
200 CPU=`echo ${cpu} | tr "${lowercase}" "${uppercase}"`
201 PREFIX=`echo ${prefix} | tr "${lowercase}" "${uppercase}"`
203 ##########################################################################
205 load_infile_section() {
206 if [ -n "${lineno}" ]; then
207 ${SHELL} ${lineno} \
208 "${infile}" "${outprefix}mloop${outsuffix}.tmp" \
209 "$@"
210 else
211 ${SHELL} ${infile} "$@"
215 rm -f ${outprefix}eng${outsuffix}.hin
216 exec 1>${outprefix}eng${outsuffix}.hin
218 echo "/* engine configuration for ${cpu} */"
219 echo ""
221 echo "/* WITH_FAST: non-zero if a fast version of the engine is available"
222 echo " in addition to the full-featured version. */"
223 if [ x$fast = xyes ] ; then
224 echo "#define WITH_FAST 1"
225 else
226 echo "#define WITH_FAST 0"
229 echo ""
230 echo "/* WITH_SCACHE_PBB_${PREFIX}: non-zero if the pbb engine was selected. */"
231 if [ x$pbb = xyes ] ; then
232 echo "#define WITH_SCACHE_PBB_${PREFIX} 1"
233 else
234 echo "#define WITH_SCACHE_PBB_${PREFIX} 0"
237 echo ""
238 echo "/* HAVE_PARALLEL_INSNS: non-zero if cpu can parallelly execute > 1 insn. */"
239 # blah blah blah, other ways to do this, blah blah blah
240 case x$parallel in
241 xno)
242 echo "#define HAVE_PARALLEL_INSNS 0"
243 echo "#define WITH_PARALLEL_READ 0"
244 echo "#define WITH_PARALLEL_WRITE 0"
245 echo "#define WITH_PARALLEL_GENWRITE 0"
247 xread)
248 echo "#define HAVE_PARALLEL_INSNS 1"
249 echo "/* Parallel execution is supported by read-before-exec. */"
250 echo "#define WITH_PARALLEL_READ 1"
251 echo "#define WITH_PARALLEL_WRITE 0"
252 echo "#define WITH_PARALLEL_GENWRITE 0"
254 xwrite)
255 echo "#define HAVE_PARALLEL_INSNS 1"
256 echo "/* Parallel execution is supported by write-after-exec. */"
257 echo "#define WITH_PARALLEL_READ 0"
258 echo "#define WITH_PARALLEL_WRITE 1"
259 echo "#define WITH_PARALLEL_GENWRITE 0"
261 xgenwrite)
262 echo "#define HAVE_PARALLEL_INSNS 1"
263 echo "/* Parallel execution is supported by generic write-after-exec. */"
264 echo "#define WITH_PARALLEL_READ 0"
265 echo "#define WITH_PARALLEL_WRITE 0"
266 echo "#define WITH_PARALLEL_GENWRITE 1"
268 esac
270 if [ "x$switch" != x ] ; then
271 echo ""
272 echo "/* WITH_SEM_SWITCH_FULL: non-zero if full-featured engine is"
273 echo " implemented as a switch(). */"
274 if [ x$fast != xyes -o x$full_switch = xyes ] ; then
275 echo "#define WITH_SEM_SWITCH_FULL 1"
276 else
277 echo "#define WITH_SEM_SWITCH_FULL 0"
279 echo ""
280 echo "/* WITH_SEM_SWITCH_FAST: non-zero if fast engine is"
281 echo " implemented as a switch(). */"
282 if [ x$fast = xyes ] ; then
283 echo "#define WITH_SEM_SWITCH_FAST 1"
284 else
285 echo "#define WITH_SEM_SWITCH_FAST 0"
289 # Decls of functions we define.
291 echo ""
292 echo "/* Functions defined in the generated mainloop.c file"
293 echo " (which doesn't necessarily have that file name). */"
294 echo ""
295 echo "extern ENGINE_FN ${prefix}_engine_run_full;"
296 echo "extern ENGINE_FN ${prefix}_engine_run_fast;"
298 if [ x$pbb = xyes ] ; then
299 echo ""
300 echo "extern SEM_PC ${prefix}_pbb_begin (SIM_CPU *, int);"
301 echo "extern SEM_PC ${prefix}_pbb_chain (SIM_CPU *, SEM_ARG);"
302 echo "extern SEM_PC ${prefix}_pbb_cti_chain (SIM_CPU *, SEM_ARG, SEM_BRANCH_TYPE, PCADDR);"
303 echo "extern void ${prefix}_pbb_before (SIM_CPU *, SCACHE *);"
304 echo "extern void ${prefix}_pbb_after (SIM_CPU *, SCACHE *);"
307 ##########################################################################
309 rm -f ${outprefix}tmp-mloop-$$.cin ${outprefix}mloop${outsuffix}.cin
310 exec 1>${outprefix}tmp-mloop-$$.cin
312 # We use @cpu@ instead of ${cpu} because we still need to run sed to handle
313 # transformation of @cpu@ for mainloop.in, so there's no need to use ${cpu}
314 # here.
316 cat << EOF
317 #line $LINENO "$0"
318 /* This file is generated by the genmloop script. DO NOT EDIT! */
320 /* This must come before any other includes. */
321 #include "defs.h"
323 /* Enable switch() support in cgen headers. */
324 #define SEM_IN_SWITCH
326 #define WANT_CPU @cpu@
327 #define WANT_CPU_@CPU@
329 #include "ansidecl.h"
330 #include "bfd.h"
332 #include "sim-main.h"
333 #include "cgen-mem.h"
334 #include "cgen-ops.h"
335 #include "sim-assert.h"
337 /* Fill in the administrative ARGBUF fields required by all insns,
338 virtual and real. */
340 static INLINE void
341 @prefix@_fill_argbuf (const SIM_CPU *cpu, ARGBUF *abuf, const IDESC *idesc,
342 PCADDR pc, int fast_p)
344 #if WITH_SCACHE
345 SEM_SET_CODE (abuf, idesc, fast_p);
346 ARGBUF_ADDR (abuf) = pc;
347 #endif
348 ARGBUF_IDESC (abuf) = idesc;
351 /* Fill in tracing/profiling fields of an ARGBUF. */
353 static INLINE void
354 @prefix@_fill_argbuf_tp (const SIM_CPU *cpu, ARGBUF *abuf,
355 int trace_p, int profile_p)
357 ARGBUF_TRACE_P (abuf) = trace_p;
358 ARGBUF_PROFILE_P (abuf) = profile_p;
361 #if WITH_SCACHE_PBB
363 /* Emit the "x-before" handler.
364 x-before is emitted before each insn (serial or parallel).
365 This is as opposed to x-after which is only emitted at the end of a group
366 of parallel insns. */
368 ATTRIBUTE_UNUSED static INLINE void
369 @prefix@_emit_before (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc, int first_p)
371 ARGBUF *abuf = &sc[0].argbuf;
372 const IDESC *id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEFORE];
374 abuf->fields.before.first_p = first_p;
375 @prefix@_fill_argbuf (current_cpu, abuf, id, pc, 0);
376 /* no need to set trace_p,profile_p */
379 /* Emit the "x-after" handler.
380 x-after is emitted after a serial insn or at the end of a group of
381 parallel insns. */
383 ATTRIBUTE_UNUSED static INLINE void
384 @prefix@_emit_after (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc)
386 ARGBUF *abuf = &sc[0].argbuf;
387 const IDESC *id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_AFTER];
389 @prefix@_fill_argbuf (current_cpu, abuf, id, pc, 0);
390 /* no need to set trace_p,profile_p */
393 #endif /* WITH_SCACHE_PBB */
397 load_infile_section support
399 ##########################################################################
401 # Simple engine: fetch an instruction, execute the instruction.
403 # Instruction fields are not extracted into ARGBUF, they are extracted in
404 # the semantic routines themselves. However, there is still a need to pass
405 # and return misc. information to the semantic routines so we still use ARGBUF.
406 # [One could certainly implement things differently and remove ARGBUF.
407 # It's not clear this is necessarily always a win.]
408 # ??? The use of the SCACHE struct is for consistency with the with-scache
409 # case though it might be a source of confusion.
411 if [ x$scache != xyes -a x$pbb != xyes ] ; then
413 cat << EOF
414 #line $LINENO "$0"
416 #define FAST_P 0
418 void
419 @prefix@_engine_run_full (SIM_CPU *current_cpu)
421 #define FAST_P 0
422 SIM_DESC current_state = CPU_STATE (current_cpu);
423 /* ??? Use of SCACHE is a bit of a hack as we don't actually use the scache.
424 We do however use ARGBUF so for consistency with the other engine flavours
425 the SCACHE type is used. */
426 SCACHE cache[MAX_LIW_INSNS];
427 SCACHE *sc = &cache[0];
431 case x$parallel in
432 xread | xwrite)
433 cat << EOF
434 #line $LINENO "$0"
435 PAREXEC pbufs[MAX_PARALLEL_INSNS];
436 PAREXEC *par_exec;
440 esac
442 # Any initialization code before looping starts.
443 # Note that this code may declare some locals.
444 load_infile_section init
446 if [ x$parallel = xread ] ; then
447 cat << EOF
448 #line $LINENO "$0"
450 #if defined (__GNUC__)
452 if (! CPU_IDESC_READ_INIT_P (current_cpu))
454 /* ??? Later maybe paste read.c in when building mainloop.c. */
455 #define DEFINE_LABELS
456 #include "readx.c"
457 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
460 #endif
465 cat << EOF
466 #line $LINENO "$0"
468 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
470 #if WITH_SEM_SWITCH_FULL
471 #if defined (__GNUC__)
472 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
473 #define DEFINE_LABELS
474 #include "$switch"
475 #endif
476 #else
477 @prefix@_sem_init_idesc_table (current_cpu);
478 #endif
479 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
484 /* begin full-exec-simple */
487 load_infile_section full-exec-simple
489 cat << EOF
490 #line $LINENO "$0"
491 /* end full-exec-simple */
493 ++ CPU_INSN_COUNT (current_cpu);
495 while (0 /*CPU_RUNNING_P (current_cpu)*/);
498 #undef FAST_P
502 ####################################
504 # Simple engine: fast version.
505 # ??? A somewhat dubious effort, but for completeness' sake.
507 if [ x$fast = xyes ] ; then
509 cat << EOF
510 #line $LINENO "$0"
512 #define FAST_P 1
514 FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh."
516 #undef FAST_P
520 fi # -fast
522 fi # simple engine
524 ##########################################################################
526 # Non-parallel scache engine: lookup insn in scache, fetch if missing,
527 # then execute it.
529 if [ x$scache = xyes -a x$parallel = xno ] ; then
531 cat << EOF
532 #line $LINENO "$0"
534 static INLINE SCACHE *
535 @prefix@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
536 unsigned int hash_mask, int FAST_P)
538 /* First step: look up current insn in hash table. */
539 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
541 /* If the entry isn't the one we want (cache miss),
542 fetch and decode the instruction. */
543 if (sc->argbuf.addr != vpc)
545 if (! FAST_P)
546 PROFILE_COUNT_SCACHE_MISS (current_cpu);
548 /* begin extract-scache */
551 load_infile_section extract-scache
553 cat << EOF
554 #line $LINENO "$0"
555 /* end extract-scache */
557 else if (! FAST_P)
559 PROFILE_COUNT_SCACHE_HIT (current_cpu);
560 /* Make core access statistics come out right.
561 The size is a guess, but it's currently not used either. */
562 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
565 return sc;
568 #define FAST_P 0
570 void
571 @prefix@_engine_run_full (SIM_CPU *current_cpu)
573 SIM_DESC current_state = CPU_STATE (current_cpu);
574 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
575 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
576 SEM_PC vpc;
580 # Any initialization code before looping starts.
581 # Note that this code may declare some locals.
582 load_infile_section init
584 cat << EOF
585 #line $LINENO "$0"
587 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
589 #if ! WITH_SEM_SWITCH_FULL
590 @prefix@_sem_init_idesc_table (current_cpu);
591 #endif
592 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
595 vpc = GET_H_PC ();
599 SCACHE *sc;
601 sc = @prefix@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
603 /* begin full-exec-scache */
606 load_infile_section full-exec-scache
608 cat << EOF
609 #line $LINENO "$0"
610 /* end full-exec-scache */
612 SET_H_PC (vpc);
614 ++ CPU_INSN_COUNT (current_cpu);
616 while (0 /*CPU_RUNNING_P (current_cpu)*/);
619 #undef FAST_P
623 ####################################
625 # Non-parallel scache engine: fast version.
627 if [ x$fast = xyes ] ; then
629 cat << EOF
630 #line $LINENO "$0"
632 #define FAST_P 1
634 void
635 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
637 SIM_DESC current_state = CPU_STATE (current_cpu);
638 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
639 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
640 SEM_PC vpc;
644 # Any initialization code before looping starts.
645 # Note that this code may declare some locals.
646 load_infile_section init
648 cat << EOF
649 #line $LINENO "$0"
651 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
653 #if WITH_SEM_SWITCH_FAST
654 #if defined (__GNUC__)
655 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
656 #define DEFINE_LABELS
657 #include "$switch"
658 #endif
659 #else
660 @prefix@_semf_init_idesc_table (current_cpu);
661 #endif
662 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
665 vpc = GET_H_PC ();
669 SCACHE *sc;
671 sc = @prefix@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
673 /* begin fast-exec-scache */
676 load_infile_section fast-exec-scache
678 cat << EOF
679 #line $LINENO "$0"
680 /* end fast-exec-scache */
682 SET_H_PC (vpc);
684 ++ CPU_INSN_COUNT (current_cpu);
686 while (0 /*CPU_RUNNING_P (current_cpu)*/);
689 #undef FAST_P
693 fi # -fast
695 fi # -scache && ! parallel
697 ##########################################################################
699 # Parallel scache engine: lookup insn in scache, fetch if missing,
700 # then execute it.
701 # For the parallel case we give the target more flexibility.
703 if [ x$scache = xyes -a x$parallel != xno ] ; then
705 cat << EOF
706 #line $LINENO "$0"
708 static INLINE SCACHE *
709 @prefix@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
710 unsigned int hash_mask, int FAST_P)
712 /* First step: look up current insn in hash table. */
713 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
715 /* If the entry isn't the one we want (cache miss),
716 fetch and decode the instruction. */
717 if (sc->argbuf.addr != vpc)
719 if (! FAST_P)
720 PROFILE_COUNT_SCACHE_MISS (current_cpu);
722 #define SET_LAST_INSN_P(last_p) do { sc->last_insn_p = (last_p); } while (0)
723 /* begin extract-scache */
726 load_infile_section extract-scache
728 cat << EOF
729 #line $LINENO "$0"
730 /* end extract-scache */
731 #undef SET_LAST_INSN_P
733 else if (! FAST_P)
735 PROFILE_COUNT_SCACHE_HIT (current_cpu);
736 /* Make core access statistics come out right.
737 The size is a guess, but it's currently not used either. */
738 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
741 return sc;
744 #define FAST_P 0
746 void
747 @prefix@_engine_run_full (SIM_CPU *current_cpu)
749 SIM_DESC current_state = CPU_STATE (current_cpu);
750 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
751 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
752 SEM_PC vpc;
756 # Any initialization code before looping starts.
757 # Note that this code may declare some locals.
758 load_infile_section init
760 if [ x$parallel = xread ] ; then
761 cat << EOF
762 #line $LINENO "$0"
763 #if defined (__GNUC__)
765 if (! CPU_IDESC_READ_INIT_P (current_cpu))
767 /* ??? Later maybe paste read.c in when building mainloop.c. */
768 #define DEFINE_LABELS
769 #include "readx.c"
770 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
773 #endif
778 cat << EOF
779 #line $LINENO "$0"
781 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
783 #if ! WITH_SEM_SWITCH_FULL
784 @prefix@_sem_init_idesc_table (current_cpu);
785 #endif
786 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
789 vpc = GET_H_PC ();
793 /* begin full-exec-scache */
796 load_infile_section full-exec-scache
798 cat << EOF
799 #line $LINENO "$0"
800 /* end full-exec-scache */
802 while (0 /*CPU_RUNNING_P (current_cpu)*/);
805 #undef FAST_P
809 ####################################
811 # Parallel scache engine: fast version.
813 if [ x$fast = xyes ] ; then
815 cat << EOF
816 #line $LINENO "$0"
818 #define FAST_P 1
820 void
821 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
823 SIM_DESC current_state = CPU_STATE (current_cpu);
824 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
825 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
826 SEM_PC vpc;
827 PAREXEC pbufs[MAX_PARALLEL_INSNS];
828 PAREXEC *par_exec;
832 # Any initialization code before looping starts.
833 # Note that this code may declare some locals.
834 load_infile_section init
836 if [ x$parallel = xread ] ; then
837 cat << EOF
838 #line $LINENO "$0"
840 #if defined (__GNUC__)
842 if (! CPU_IDESC_READ_INIT_P (current_cpu))
844 /* ??? Later maybe paste read.c in when building mainloop.c. */
845 #define DEFINE_LABELS
846 #include "readx.c"
847 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
850 #endif
855 cat << EOF
856 #line $LINENO "$0"
858 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
860 #if WITH_SEM_SWITCH_FAST
861 #if defined (__GNUC__)
862 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
863 #define DEFINE_LABELS
864 #include "$switch"
865 #endif
866 #else
867 @prefix@_semf_init_idesc_table (current_cpu);
868 #endif
869 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
872 vpc = GET_H_PC ();
876 /* begin fast-exec-scache */
879 load_infile_section fast-exec-scache
881 cat << EOF
882 #line $LINENO "$0"
883 /* end fast-exec-scache */
885 while (0 /*CPU_RUNNING_P (current_cpu)*/);
888 #undef FAST_P
892 fi # -fast
894 fi # -scache && parallel
896 ##########################################################################
898 # Compilation engine: lookup insn in scache, extract a pbb
899 # (pseudo-basic-block) if missing, then execute the pbb.
900 # A "pbb" is a sequence of insns up to the next cti insn or until
901 # some prespecified maximum.
902 # CTI: control transfer instruction.
904 if [ x$pbb = xyes ] ; then
906 cat << EOF
907 #line $LINENO "$0"
909 /* Record address of cti terminating a pbb. */
910 #define SET_CTI_VPC(sc) do { _cti_sc = (sc); } while (0)
911 /* Record number of [real] insns in pbb. */
912 #define SET_INSN_COUNT(n) do { _insn_count = (n); } while (0)
914 /* Fetch and extract a pseudo-basic-block.
915 FAST_P is non-zero if no tracing/profiling/etc. is wanted. */
917 INLINE SEM_PC
918 @prefix@_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
920 SEM_PC new_vpc;
921 PCADDR pc;
922 SCACHE *sc;
923 int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu);
925 pc = GET_H_PC ();
927 new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
928 if (! new_vpc)
930 /* Leading '_' to avoid collision with mainloop.in. */
931 int _insn_count = 0;
932 SCACHE *orig_sc = sc;
933 SCACHE *_cti_sc = NULL;
934 int slice_insns = CPU_MAX_SLICE_INSNS (current_cpu);
936 /* First figure out how many instructions to compile.
937 MAX_INSNS is the size of the allocated buffer, which includes space
938 for before/after handlers if they're being used.
939 SLICE_INSNS is the maxinum number of real insns that can be
940 executed. Zero means "as many as we want". */
941 /* ??? max_insns is serving two incompatible roles.
942 1) Number of slots available in scache buffer.
943 2) Number of real insns to execute.
944 They're incompatible because there are virtual insns emitted too
945 (chain,cti-chain,before,after handlers). */
947 if (slice_insns == 1)
949 /* No need to worry about extra slots required for virtual insns
950 and parallel exec support because MAX_CHAIN_LENGTH is
951 guaranteed to be big enough to execute at least 1 insn! */
952 max_insns = 1;
954 else
956 /* Allow enough slop so that while compiling insns, if max_insns > 0
957 then there's guaranteed to be enough space to emit one real insn.
958 MAX_CHAIN_LENGTH is typically much longer than
959 the normal number of insns between cti's anyway. */
960 max_insns -= (1 /* one for the trailing chain insn */
961 + (FAST_P
963 : (1 + MAX_PARALLEL_INSNS) /* before+after */)
964 + (MAX_PARALLEL_INSNS > 1
965 ? (MAX_PARALLEL_INSNS * 2)
966 : 0));
968 /* Account for before/after handlers. */
969 if (! FAST_P)
970 slice_insns *= 3;
972 if (slice_insns > 0
973 && slice_insns < max_insns)
974 max_insns = slice_insns;
977 new_vpc = sc;
979 /* SC,PC must be updated to point passed the last entry used.
980 SET_CTI_VPC must be called if pbb is terminated by a cti.
981 SET_INSN_COUNT must be called to record number of real insns in
982 pbb [could be computed by us of course, extra cpu but perhaps
983 negligible enough]. */
985 /* begin extract-pbb */
988 load_infile_section extract-pbb
990 cat << EOF
991 #line $LINENO "$0"
992 /* end extract-pbb */
994 /* The last one is a pseudo-insn to link to the next chain.
995 It is also used to record the insn count for this chain. */
997 const IDESC *id;
999 /* Was pbb terminated by a cti? */
1000 if (_cti_sc)
1002 id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_CTI_CHAIN];
1004 else
1006 id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_CHAIN];
1008 SEM_SET_CODE (&sc->argbuf, id, FAST_P);
1009 sc->argbuf.idesc = id;
1010 sc->argbuf.addr = pc;
1011 sc->argbuf.fields.chain.insn_count = _insn_count;
1012 sc->argbuf.fields.chain.next = 0;
1013 sc->argbuf.fields.chain.branch_target = 0;
1014 ++sc;
1017 /* Update the pointer to the next free entry, may not have used as
1018 many entries as was asked for. */
1019 CPU_SCACHE_NEXT_FREE (current_cpu) = sc;
1020 /* Record length of chain if profiling.
1021 This includes virtual insns since they count against
1022 max_insns too. */
1023 if (! FAST_P)
1024 PROFILE_COUNT_SCACHE_CHAIN_LENGTH (current_cpu, sc - orig_sc);
1027 return new_vpc;
1030 /* Chain to the next block from a non-cti terminated previous block. */
1032 INLINE SEM_PC
1033 @prefix@_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
1035 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1037 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
1039 SET_H_PC (abuf->addr);
1041 /* If not running forever, exit back to main loop. */
1042 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
1043 /* Also exit back to main loop if there's an event.
1044 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
1045 at the "right" time, but then that was what was asked for.
1046 There is no silver bullet for simulator engines.
1047 ??? Clearly this needs a cleaner interface.
1048 At present it's just so Ctrl-C works. */
1049 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
1050 CPU_RUNNING_P (current_cpu) = 0;
1052 /* If chained to next block, go straight to it. */
1053 if (abuf->fields.chain.next)
1054 return abuf->fields.chain.next;
1055 /* See if next block has already been compiled. */
1056 abuf->fields.chain.next = scache_lookup (current_cpu, abuf->addr);
1057 if (abuf->fields.chain.next)
1058 return abuf->fields.chain.next;
1059 /* Nope, so next insn is a virtual insn to invoke the compiler
1060 (begin a pbb). */
1061 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1064 /* Chain to the next block from a cti terminated previous block.
1065 BR_TYPE indicates whether the branch was taken and whether we can cache
1066 the vpc of the branch target.
1067 NEW_PC is the target's branch address, and is only valid if
1068 BR_TYPE != SEM_BRANCH_UNTAKEN. */
1070 INLINE SEM_PC
1071 @prefix@_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
1072 SEM_BRANCH_TYPE br_type, PCADDR new_pc)
1074 SEM_PC *new_vpc_ptr;
1076 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
1078 /* If not running forever, exit back to main loop. */
1079 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
1080 /* Also exit back to main loop if there's an event.
1081 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
1082 at the "right" time, but then that was what was asked for.
1083 There is no silver bullet for simulator engines.
1084 ??? Clearly this needs a cleaner interface.
1085 At present it's just so Ctrl-C works. */
1086 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
1087 CPU_RUNNING_P (current_cpu) = 0;
1089 /* Restart compiler if we branched to an uncacheable address
1090 (e.g. "j reg"). */
1091 if (br_type == SEM_BRANCH_UNCACHEABLE)
1093 SET_H_PC (new_pc);
1094 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1097 /* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our
1098 next chain ptr. */
1099 if (br_type == SEM_BRANCH_UNTAKEN)
1101 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1102 new_pc = abuf->addr;
1103 SET_H_PC (new_pc);
1104 new_vpc_ptr = &abuf->fields.chain.next;
1106 else
1108 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1109 SET_H_PC (new_pc);
1110 new_vpc_ptr = &abuf->fields.chain.branch_target;
1113 /* If chained to next block, go straight to it. */
1114 if (*new_vpc_ptr)
1115 return *new_vpc_ptr;
1116 /* See if next block has already been compiled. */
1117 *new_vpc_ptr = scache_lookup (current_cpu, new_pc);
1118 if (*new_vpc_ptr)
1119 return *new_vpc_ptr;
1120 /* Nope, so next insn is a virtual insn to invoke the compiler
1121 (begin a pbb). */
1122 return CPU_SCACHE_PBB_BEGIN (current_cpu);
1125 /* x-before handler.
1126 This is called before each insn. */
1128 void
1129 @prefix@_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
1131 SEM_ARG sem_arg = sc;
1132 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1133 int first_p = abuf->fields.before.first_p;
1134 const ARGBUF *cur_abuf = SEM_ARGBUF (sc + 1);
1135 const IDESC *cur_idesc = cur_abuf->idesc;
1136 PCADDR pc = cur_abuf->addr;
1138 if (ARGBUF_PROFILE_P (cur_abuf))
1139 PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
1141 /* If this isn't the first insn, finish up the previous one. */
1143 if (! first_p)
1145 if (PROFILE_MODEL_P (current_cpu))
1147 const SEM_ARG prev_sem_arg = sc - 1;
1148 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1149 const IDESC *prev_idesc = prev_abuf->idesc;
1150 int cycles;
1152 /* ??? May want to measure all insns if doing insn tracing. */
1153 if (ARGBUF_PROFILE_P (prev_abuf))
1155 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1156 @prefix@_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
1160 CGEN_TRACE_INSN_FINI (current_cpu, cur_abuf, 0 /*last_p*/);
1163 /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */
1164 if (PROFILE_MODEL_P (current_cpu)
1165 && ARGBUF_PROFILE_P (cur_abuf))
1166 @prefix@_model_insn_before (current_cpu, first_p);
1168 CGEN_TRACE_INSN_INIT (current_cpu, cur_abuf, first_p);
1169 CGEN_TRACE_INSN (current_cpu, cur_idesc->idata, cur_abuf, pc);
1172 /* x-after handler.
1173 This is called after a serial insn or at the end of a group of parallel
1174 insns. */
1176 void
1177 @prefix@_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
1179 const SEM_ARG prev_sem_arg = sc - 1;
1180 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1182 /* ??? May want to measure all insns if doing insn tracing. */
1183 if (PROFILE_MODEL_P (current_cpu)
1184 && ARGBUF_PROFILE_P (prev_abuf))
1186 const IDESC *prev_idesc = prev_abuf->idesc;
1187 int cycles;
1189 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1190 @prefix@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
1192 CGEN_TRACE_INSN_FINI (current_cpu, prev_abuf, 1 /*last_p*/);
1195 #define FAST_P 0
1197 void
1198 @prefix@_engine_run_full (SIM_CPU *current_cpu)
1200 /* virtual program counter */
1201 SEM_PC vpc;
1202 #if WITH_SEM_SWITCH_FULL
1203 /* For communication between cti's and cti-chain. */
1204 SEM_BRANCH_TYPE pbb_br_type = SEM_BRANCH_UNTAKEN;
1205 PCADDR pbb_br_npc = 0;
1206 #endif
1210 case x$parallel in
1211 xread | xwrite)
1212 cat << EOF
1213 #line $LINENO "$0"
1214 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1215 PAREXEC *par_exec = &pbufs[0];
1219 esac
1221 # Any initialization code before looping starts.
1222 # Note that this code may declare some locals.
1223 load_infile_section init
1225 cat << EOF
1226 #line $LINENO "$0"
1228 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1230 /* ??? 'twould be nice to move this up a level and only call it once.
1231 On the other hand, in the "let's go fast" case the test is only done
1232 once per pbb (since we only return to the main loop at the end of
1233 a pbb). And in the "let's run until we're done" case we don't return
1234 until the program exits. */
1236 #if WITH_SEM_SWITCH_FULL
1237 #if defined (__GNUC__)
1238 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1239 #define DEFINE_LABELS
1240 #include "$switch"
1241 #endif
1242 #else
1243 @prefix@_sem_init_idesc_table (current_cpu);
1244 #endif
1246 /* Initialize the "begin (compile) a pbb" virtual insn. */
1247 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1248 SEM_SET_FULL_CODE (SEM_ARGBUF (vpc),
1249 & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN]);
1250 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN];
1252 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1255 CPU_RUNNING_P (current_cpu) = 1;
1256 /* ??? In the case where we're returning to the main loop after every
1257 pbb we don't want to call pbb_begin each time (which hashes on the pc
1258 and does a table lookup). A way to speed this up is to save vpc
1259 between calls. */
1260 vpc = @prefix@_pbb_begin (current_cpu, FAST_P);
1264 /* begin full-exec-pbb */
1267 load_infile_section full-exec-pbb
1269 cat << EOF
1270 #line $LINENO "$0"
1271 /* end full-exec-pbb */
1273 while (CPU_RUNNING_P (current_cpu));
1276 #undef FAST_P
1280 ####################################
1282 # Compile engine: fast version.
1284 if [ x$fast = xyes ] ; then
1286 cat << EOF
1287 #line $LINENO "$0"
1289 #define FAST_P 1
1291 void
1292 @prefix@_engine_run_fast (SIM_CPU *current_cpu)
1294 /* virtual program counter */
1295 SEM_PC vpc;
1296 #if WITH_SEM_SWITCH_FAST
1297 /* For communication between cti's and cti-chain. */
1298 SEM_BRANCH_TYPE pbb_br_type = SEM_BRANCH_UNTAKEN;
1299 PCADDR pbb_br_npc = 0;
1300 #endif
1304 case x$parallel in
1305 xread | xwrite)
1306 cat << EOF
1307 #line $LINENO "$0"
1308 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1309 PAREXEC *par_exec = &pbufs[0];
1313 esac
1315 # Any initialization code before looping starts.
1316 # Note that this code may declare some locals.
1317 load_infile_section init
1319 cat << EOF
1320 #line $LINENO "$0"
1322 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1324 /* ??? 'twould be nice to move this up a level and only call it once.
1325 On the other hand, in the "let's go fast" case the test is only done
1326 once per pbb (since we only return to the main loop at the end of
1327 a pbb). And in the "let's run until we're done" case we don't return
1328 until the program exits. */
1330 #if WITH_SEM_SWITCH_FAST
1331 #if defined (__GNUC__)
1332 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1333 #define DEFINE_LABELS
1334 #include "$switch"
1335 #endif
1336 #else
1337 @prefix@_semf_init_idesc_table (current_cpu);
1338 #endif
1340 /* Initialize the "begin (compile) a pbb" virtual insn. */
1341 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1342 SEM_SET_FAST_CODE (SEM_ARGBUF (vpc),
1343 & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN]);
1344 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN];
1346 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1349 CPU_RUNNING_P (current_cpu) = 1;
1350 /* ??? In the case where we're returning to the main loop after every
1351 pbb we don't want to call pbb_begin each time (which hashes on the pc
1352 and does a table lookup). A way to speed this up is to save vpc
1353 between calls. */
1354 vpc = @prefix@_pbb_begin (current_cpu, FAST_P);
1358 /* begin fast-exec-pbb */
1361 load_infile_section fast-exec-pbb
1363 cat << EOF
1364 #line $LINENO "$0"
1365 /* end fast-exec-pbb */
1367 while (CPU_RUNNING_P (current_cpu));
1370 #undef FAST_P
1373 fi # -fast
1375 fi # -pbb
1377 # Expand @..@ macros appearing in tmp-mloop-{pid}.cin.
1378 sed \
1379 -e "s/@cpu@/$cpu/g" -e "s/@CPU@/$CPU/g" \
1380 -e "s/@prefix@/$prefix/g" -e "s/@PREFIX@/$PREFIX/g" \
1381 < ${outprefix}tmp-mloop-$$.cin > ${outprefix}mloop${outsuffix}.cin
1382 rc=$?
1383 rm -f ${outprefix}tmp-mloop-$$.cin
1385 exit $rc