xref: /netbsd-src/external/gpl3/gdb.old/dist/sim/common/genmloop.sh (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
1# Generate the main loop of the simulator.
2# Copyright (C) 1996-2023 Free Software Foundation, Inc.
3# Contributed by Cygnus Support.
4#
5# This file is part of the GNU simulators.
6#
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.
11#
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.
16#
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/>.
19#
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.
24#
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?
29#
30# Syntax: genmloop.sh [options]
31#
32# Options:
33#
34# -mono | -multi
35#    - specify single cpu or multiple cpus (number specifyable at runtime),
36#      maximum number is a configuration parameter
37#    - -multi wip
38#
39# -fast: include support for fast execution in addition to full featured mode
40#
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).
49#
50# -full-switch: same as -fast but for full featured version of -switch
51#	Only needed if -fast present.
52#
53# -simple: simple execution engine (the default)
54#
55#	This engine fetches and executes one instruction at a time.
56#	Field extraction is done in the semantic routines.
57#
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.
69#
70# -scache: use the scache to speed things up (not always a win)
71#
72#	This engine caches the extracted instruction before executing it.
73#	When executing instructions they are first looked up in the scache.
74#
75# -pbb: same as -scache but extract a (pseudo-) basic block at a time
76#
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.
84#
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.
89#
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.
95#
96# -parallel-only: semantic code only supports parallel version of insn
97#
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.
101#
102# -prefix: string to prepend to function names in mloop.c/eng.h.
103#
104#       If no prefix is specified, the cpu type is used.
105#
106# -switch file: specify file containing semantics implemented as a switch()
107#
108# -cpu <cpu-family>
109#
110#	Specify the cpu family name.
111#
112# -infile <input-file>
113#
114#	Specify the mainloop.in input file.
115#
116# -outfile-suffix <output-file-suffix>
117#
118#	Specify the suffix to append to output files.
119#
120# -shell <shell>
121#
122#	Specify the shell to use to execute <input-file>
123#
124# Only one of -scache/-pbb may be selected.
125# -simple is the default.
126#
127####
128#
129# TODO
130# - build mainloop.in from .cpu file
131
132type=mono
133#scache=
134#fast=
135#full_switch=
136#pbb=
137parallel=no
138parallel_only=no
139switch=
140cpu="unknown"
141infile=""
142prefix="unknown"
143outprefix=""
144outsuffix=""
145
146while test $# -gt 0
147do
148	case $1 in
149	-mono) type=mono ;;
150	-multi) type=multi ;;
151	-no-fast) ;;
152	-fast) fast=yes ;;
153	-full-switch) full_switch=yes ;;
154	-simple) ;;
155	-scache) scache=yes ;;
156	-pbb) pbb=yes ;;
157	-no-parallel) ;;
158	-outfile-prefix) shift ; outprefix=$1 ;;
159	-outfile-suffix) shift ; outsuffix=$1 ;;
160	-parallel-read) parallel=read ;;
161	-parallel-write) parallel=write ;;
162	-parallel-generic-write) parallel=genwrite ;;
163	-parallel-only) parallel_only=yes ;;
164	-prefix) shift ; prefix=$1 ;;
165	-switch) shift ; switch=$1 ;;
166	-cpu) shift ; cpu=$1 ;;
167	-infile) shift ; infile=$1 ;;
168	-shell) shift ; SHELL=$1 ;;
169	*) echo "unknown option: $1" >&2 ; exit 1 ;;
170	esac
171	shift
172done
173
174# Argument validation.
175
176if [ x$scache = xyes -a x$pbb = xyes ] ; then
177    echo "only one of -scache and -pbb may be selected" >&2
178    exit 1
179fi
180
181if [ "x$cpu" = xunknown ] ; then
182    echo "cpu family not specified" >&2
183    exit 1
184fi
185
186if [ "x$infile" = x ] ; then
187    echo "mainloop.in not specified" >&2
188    exit 1
189fi
190
191if [ "x$prefix" = xunknown ] ; then
192    prefix=$cpu
193fi
194
195lowercase='abcdefghijklmnopqrstuvwxyz'
196uppercase='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
197CPU=`echo ${cpu} | tr "${lowercase}" "${uppercase}"`
198PREFIX=`echo ${prefix} | tr "${lowercase}" "${uppercase}"`
199
200##########################################################################
201
202rm -f ${outprefix}eng${outsuffix}.hin
203exec 1>${outprefix}eng${outsuffix}.hin
204
205echo "/* engine configuration for ${cpu} */"
206echo ""
207
208echo "/* WITH_FAST: non-zero if a fast version of the engine is available"
209echo "   in addition to the full-featured version.  */"
210if [ x$fast = xyes ] ; then
211	echo "#define WITH_FAST 1"
212else
213	echo "#define WITH_FAST 0"
214fi
215
216echo ""
217echo "/* WITH_SCACHE_PBB_${PREFIX}: non-zero if the pbb engine was selected.  */"
218if [ x$pbb = xyes ] ; then
219	echo "#define WITH_SCACHE_PBB_${PREFIX} 1"
220else
221	echo "#define WITH_SCACHE_PBB_${PREFIX} 0"
222fi
223
224echo ""
225echo "/* HAVE_PARALLEL_INSNS: non-zero if cpu can parallelly execute > 1 insn.  */"
226# blah blah blah, other ways to do this, blah blah blah
227case x$parallel in
228xno)
229    echo "#define HAVE_PARALLEL_INSNS 0"
230    echo "#define WITH_PARALLEL_READ 0"
231    echo "#define WITH_PARALLEL_WRITE 0"
232    echo "#define WITH_PARALLEL_GENWRITE 0"
233    ;;
234xread)
235    echo "#define HAVE_PARALLEL_INSNS 1"
236    echo "/* Parallel execution is supported by read-before-exec.  */"
237    echo "#define WITH_PARALLEL_READ 1"
238    echo "#define WITH_PARALLEL_WRITE 0"
239    echo "#define WITH_PARALLEL_GENWRITE 0"
240    ;;
241xwrite)
242    echo "#define HAVE_PARALLEL_INSNS 1"
243    echo "/* Parallel execution is supported by write-after-exec.  */"
244    echo "#define WITH_PARALLEL_READ 0"
245    echo "#define WITH_PARALLEL_WRITE 1"
246    echo "#define WITH_PARALLEL_GENWRITE 0"
247    ;;
248xgenwrite)
249    echo "#define HAVE_PARALLEL_INSNS 1"
250    echo "/* Parallel execution is supported by generic write-after-exec.  */"
251    echo "#define WITH_PARALLEL_READ 0"
252    echo "#define WITH_PARALLEL_WRITE 0"
253    echo "#define WITH_PARALLEL_GENWRITE 1"
254    ;;
255esac
256
257if [ "x$switch" != x ] ; then
258	echo ""
259	echo "/* WITH_SEM_SWITCH_FULL: non-zero if full-featured engine is"
260	echo "   implemented as a switch().  */"
261	if [ x$fast != xyes -o x$full_switch = xyes ] ; then
262		echo "#define WITH_SEM_SWITCH_FULL 1"
263	else
264		echo "#define WITH_SEM_SWITCH_FULL 0"
265	fi
266	echo ""
267	echo "/* WITH_SEM_SWITCH_FAST: non-zero if fast engine is"
268	echo "   implemented as a switch().  */"
269	if [ x$fast = xyes ] ; then
270		echo "#define WITH_SEM_SWITCH_FAST 1"
271	else
272		echo "#define WITH_SEM_SWITCH_FAST 0"
273	fi
274fi
275
276# Decls of functions we define.
277
278echo ""
279echo "/* Functions defined in the generated mainloop.c file"
280echo "   (which doesn't necessarily have that file name).  */"
281echo ""
282echo "extern ENGINE_FN ${prefix}_engine_run_full;"
283echo "extern ENGINE_FN ${prefix}_engine_run_fast;"
284
285if [ x$pbb = xyes ] ; then
286	echo ""
287	echo "extern SEM_PC ${prefix}_pbb_begin (SIM_CPU *, int);"
288	echo "extern SEM_PC ${prefix}_pbb_chain (SIM_CPU *, SEM_ARG);"
289	echo "extern SEM_PC ${prefix}_pbb_cti_chain (SIM_CPU *, SEM_ARG, SEM_BRANCH_TYPE, PCADDR);"
290	echo "extern void ${prefix}_pbb_before (SIM_CPU *, SCACHE *);"
291	echo "extern void ${prefix}_pbb_after (SIM_CPU *, SCACHE *);"
292fi
293
294##########################################################################
295
296rm -f ${outprefix}tmp-mloop-$$.cin ${outprefix}mloop${outsuffix}.cin
297exec 1>${outprefix}tmp-mloop-$$.cin
298
299# We use @cpu@ instead of ${cpu} because we still need to run sed to handle
300# transformation of @cpu@ for mainloop.in, so there's no need to use ${cpu}
301# here.
302
303cat << EOF
304/* This file is generated by the genmloop script.  DO NOT EDIT! */
305
306/* This must come before any other includes.  */
307#include "defs.h"
308
309/* Enable switch() support in cgen headers.  */
310#define SEM_IN_SWITCH
311
312#define WANT_CPU @cpu@
313#define WANT_CPU_@CPU@
314
315#include "ansidecl.h"
316#include "bfd.h"
317
318#include "sim-main.h"
319#include "cgen-mem.h"
320#include "cgen-ops.h"
321#include "sim-assert.h"
322
323/* Fill in the administrative ARGBUF fields required by all insns,
324   virtual and real.  */
325
326static INLINE void
327@prefix@_fill_argbuf (const SIM_CPU *cpu, ARGBUF *abuf, const IDESC *idesc,
328		    PCADDR pc, int fast_p)
329{
330#if WITH_SCACHE
331  SEM_SET_CODE (abuf, idesc, fast_p);
332  ARGBUF_ADDR (abuf) = pc;
333#endif
334  ARGBUF_IDESC (abuf) = idesc;
335}
336
337/* Fill in tracing/profiling fields of an ARGBUF.  */
338
339static INLINE void
340@prefix@_fill_argbuf_tp (const SIM_CPU *cpu, ARGBUF *abuf,
341		       int trace_p, int profile_p)
342{
343  ARGBUF_TRACE_P (abuf) = trace_p;
344  ARGBUF_PROFILE_P (abuf) = profile_p;
345}
346
347#if WITH_SCACHE_PBB
348
349/* Emit the "x-before" handler.
350   x-before is emitted before each insn (serial or parallel).
351   This is as opposed to x-after which is only emitted at the end of a group
352   of parallel insns.  */
353
354ATTRIBUTE_UNUSED static INLINE void
355@prefix@_emit_before (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc, int first_p)
356{
357  ARGBUF *abuf = &sc[0].argbuf;
358  const IDESC *id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEFORE];
359
360  abuf->fields.before.first_p = first_p;
361  @prefix@_fill_argbuf (current_cpu, abuf, id, pc, 0);
362  /* no need to set trace_p,profile_p */
363}
364
365/* Emit the "x-after" handler.
366   x-after is emitted after a serial insn or at the end of a group of
367   parallel insns.  */
368
369ATTRIBUTE_UNUSED static INLINE void
370@prefix@_emit_after (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc)
371{
372  ARGBUF *abuf = &sc[0].argbuf;
373  const IDESC *id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_AFTER];
374
375  @prefix@_fill_argbuf (current_cpu, abuf, id, pc, 0);
376  /* no need to set trace_p,profile_p */
377}
378
379#endif /* WITH_SCACHE_PBB */
380
381EOF
382
383${SHELL} $infile support
384
385##########################################################################
386
387# Simple engine: fetch an instruction, execute the instruction.
388#
389# Instruction fields are not extracted into ARGBUF, they are extracted in
390# the semantic routines themselves.  However, there is still a need to pass
391# and return misc. information to the semantic routines so we still use ARGBUF.
392# [One could certainly implement things differently and remove ARGBUF.
393# It's not clear this is necessarily always a win.]
394# ??? The use of the SCACHE struct is for consistency with the with-scache
395# case though it might be a source of confusion.
396
397if [ x$scache != xyes -a x$pbb != xyes ] ; then
398
399    cat << EOF
400
401#define FAST_P 0
402
403void
404@prefix@_engine_run_full (SIM_CPU *current_cpu)
405{
406#define FAST_P 0
407  SIM_DESC current_state = CPU_STATE (current_cpu);
408  /* ??? Use of SCACHE is a bit of a hack as we don't actually use the scache.
409     We do however use ARGBUF so for consistency with the other engine flavours
410     the SCACHE type is used.  */
411  SCACHE cache[MAX_LIW_INSNS];
412  SCACHE *sc = &cache[0];
413
414EOF
415
416case x$parallel in
417xread | xwrite)
418    cat << EOF
419  PAREXEC pbufs[MAX_PARALLEL_INSNS];
420  PAREXEC *par_exec;
421
422EOF
423    ;;
424esac
425
426# Any initialization code before looping starts.
427# Note that this code may declare some locals.
428${SHELL} $infile init
429
430if [ x$parallel = xread ] ; then
431  cat << EOF
432
433#if defined (__GNUC__)
434  {
435    if (! CPU_IDESC_READ_INIT_P (current_cpu))
436      {
437/* ??? Later maybe paste read.c in when building mainloop.c.  */
438#define DEFINE_LABELS
439#include "readx.c"
440	CPU_IDESC_READ_INIT_P (current_cpu) = 1;
441      }
442  }
443#endif
444
445EOF
446fi
447
448cat << EOF
449
450  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
451    {
452#if WITH_SEM_SWITCH_FULL
453#if defined (__GNUC__)
454/* ??? Later maybe paste sem-switch.c in when building mainloop.c.  */
455#define DEFINE_LABELS
456#include "$switch"
457#endif
458#else
459      @prefix@_sem_init_idesc_table (current_cpu);
460#endif
461      CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
462    }
463
464  do
465    {
466/* begin full-exec-simple */
467EOF
468
469${SHELL} $infile full-exec-simple
470
471cat << EOF
472/* end full-exec-simple */
473
474      ++ CPU_INSN_COUNT (current_cpu);
475    }
476  while (0 /*CPU_RUNNING_P (current_cpu)*/);
477}
478
479#undef FAST_P
480
481EOF
482
483####################################
484
485# Simple engine: fast version.
486# ??? A somewhat dubious effort, but for completeness' sake.
487
488if [ x$fast = xyes ] ; then
489
490    cat << EOF
491
492#define FAST_P 1
493
494FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh."
495
496#undef FAST_P
497
498EOF
499
500fi # -fast
501
502fi # simple engine
503
504##########################################################################
505
506# Non-parallel scache engine: lookup insn in scache, fetch if missing,
507# then execute it.
508
509if [ x$scache = xyes -a x$parallel = xno ] ; then
510
511    cat << EOF
512
513static INLINE SCACHE *
514@prefix@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
515                     unsigned int hash_mask, int FAST_P)
516{
517  /* First step: look up current insn in hash table.  */
518  SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
519
520  /* If the entry isn't the one we want (cache miss),
521     fetch and decode the instruction.  */
522  if (sc->argbuf.addr != vpc)
523    {
524      if (! FAST_P)
525	PROFILE_COUNT_SCACHE_MISS (current_cpu);
526
527/* begin extract-scache */
528EOF
529
530${SHELL} $infile extract-scache
531
532cat << EOF
533/* end extract-scache */
534    }
535  else if (! FAST_P)
536    {
537      PROFILE_COUNT_SCACHE_HIT (current_cpu);
538      /* Make core access statistics come out right.
539	 The size is a guess, but it's currently not used either.  */
540      PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
541    }
542
543  return sc;
544}
545
546#define FAST_P 0
547
548void
549@prefix@_engine_run_full (SIM_CPU *current_cpu)
550{
551  SIM_DESC current_state = CPU_STATE (current_cpu);
552  SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
553  unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
554  SEM_PC vpc;
555
556EOF
557
558# Any initialization code before looping starts.
559# Note that this code may declare some locals.
560${SHELL} $infile init
561
562cat << EOF
563
564  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
565    {
566#if ! WITH_SEM_SWITCH_FULL
567      @prefix@_sem_init_idesc_table (current_cpu);
568#endif
569      CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
570    }
571
572  vpc = GET_H_PC ();
573
574  do
575    {
576      SCACHE *sc;
577
578      sc = @prefix@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
579
580/* begin full-exec-scache */
581EOF
582
583${SHELL} $infile full-exec-scache
584
585cat << EOF
586/* end full-exec-scache */
587
588      SET_H_PC (vpc);
589
590      ++ CPU_INSN_COUNT (current_cpu);
591    }
592  while (0 /*CPU_RUNNING_P (current_cpu)*/);
593}
594
595#undef FAST_P
596
597EOF
598
599####################################
600
601# Non-parallel scache engine: fast version.
602
603if [ x$fast = xyes ] ; then
604
605    cat << EOF
606
607#define FAST_P 1
608
609void
610@prefix@_engine_run_fast (SIM_CPU *current_cpu)
611{
612  SIM_DESC current_state = CPU_STATE (current_cpu);
613  SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
614  unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
615  SEM_PC vpc;
616
617EOF
618
619# Any initialization code before looping starts.
620# Note that this code may declare some locals.
621${SHELL} $infile init
622
623cat << EOF
624
625  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
626    {
627#if WITH_SEM_SWITCH_FAST
628#if defined (__GNUC__)
629/* ??? Later maybe paste sem-switch.c in when building mainloop.c.  */
630#define DEFINE_LABELS
631#include "$switch"
632#endif
633#else
634      @prefix@_semf_init_idesc_table (current_cpu);
635#endif
636      CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
637    }
638
639  vpc = GET_H_PC ();
640
641  do
642    {
643      SCACHE *sc;
644
645      sc = @prefix@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
646
647/* begin fast-exec-scache */
648EOF
649
650${SHELL} $infile fast-exec-scache
651
652cat << EOF
653/* end fast-exec-scache */
654
655      SET_H_PC (vpc);
656
657      ++ CPU_INSN_COUNT (current_cpu);
658    }
659  while (0 /*CPU_RUNNING_P (current_cpu)*/);
660}
661
662#undef FAST_P
663
664EOF
665
666fi # -fast
667
668fi # -scache && ! parallel
669
670##########################################################################
671
672# Parallel scache engine: lookup insn in scache, fetch if missing,
673# then execute it.
674# For the parallel case we give the target more flexibility.
675
676if [ x$scache = xyes -a x$parallel != xno ] ; then
677
678    cat << EOF
679
680static INLINE SCACHE *
681@prefix@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
682                     unsigned int hash_mask, int FAST_P)
683{
684  /* First step: look up current insn in hash table.  */
685  SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
686
687  /* If the entry isn't the one we want (cache miss),
688     fetch and decode the instruction.  */
689  if (sc->argbuf.addr != vpc)
690    {
691      if (! FAST_P)
692	PROFILE_COUNT_SCACHE_MISS (current_cpu);
693
694#define SET_LAST_INSN_P(last_p) do { sc->last_insn_p = (last_p); } while (0)
695/* begin extract-scache */
696EOF
697
698${SHELL} $infile extract-scache
699
700cat << EOF
701/* end extract-scache */
702#undef SET_LAST_INSN_P
703    }
704  else if (! FAST_P)
705    {
706      PROFILE_COUNT_SCACHE_HIT (current_cpu);
707      /* Make core access statistics come out right.
708	 The size is a guess, but it's currently not used either.  */
709      PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
710    }
711
712  return sc;
713}
714
715#define FAST_P 0
716
717void
718@prefix@_engine_run_full (SIM_CPU *current_cpu)
719{
720  SIM_DESC current_state = CPU_STATE (current_cpu);
721  SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
722  unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
723  SEM_PC vpc;
724
725EOF
726
727# Any initialization code before looping starts.
728# Note that this code may declare some locals.
729${SHELL} $infile init
730
731if [ x$parallel = xread ] ; then
732cat << EOF
733#if defined (__GNUC__)
734  {
735    if (! CPU_IDESC_READ_INIT_P (current_cpu))
736      {
737/* ??? Later maybe paste read.c in when building mainloop.c.  */
738#define DEFINE_LABELS
739#include "readx.c"
740	CPU_IDESC_READ_INIT_P (current_cpu) = 1;
741      }
742  }
743#endif
744
745EOF
746fi
747
748cat << EOF
749
750  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
751    {
752#if ! WITH_SEM_SWITCH_FULL
753      @prefix@_sem_init_idesc_table (current_cpu);
754#endif
755      CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
756    }
757
758  vpc = GET_H_PC ();
759
760  do
761    {
762/* begin full-exec-scache */
763EOF
764
765${SHELL} $infile full-exec-scache
766
767cat << EOF
768/* end full-exec-scache */
769    }
770  while (0 /*CPU_RUNNING_P (current_cpu)*/);
771}
772
773#undef FAST_P
774
775EOF
776
777####################################
778
779# Parallel scache engine: fast version.
780
781if [ x$fast = xyes ] ; then
782
783    cat << EOF
784
785#define FAST_P 1
786
787void
788@prefix@_engine_run_fast (SIM_CPU *current_cpu)
789{
790  SIM_DESC current_state = CPU_STATE (current_cpu);
791  SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
792  unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
793  SEM_PC vpc;
794  PAREXEC pbufs[MAX_PARALLEL_INSNS];
795  PAREXEC *par_exec;
796
797EOF
798
799# Any initialization code before looping starts.
800# Note that this code may declare some locals.
801${SHELL} $infile init
802
803if [ x$parallel = xread ] ; then
804cat << EOF
805
806#if defined (__GNUC__)
807  {
808    if (! CPU_IDESC_READ_INIT_P (current_cpu))
809      {
810/* ??? Later maybe paste read.c in when building mainloop.c.  */
811#define DEFINE_LABELS
812#include "readx.c"
813	CPU_IDESC_READ_INIT_P (current_cpu) = 1;
814      }
815  }
816#endif
817
818EOF
819fi
820
821cat << EOF
822
823  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
824    {
825#if WITH_SEM_SWITCH_FAST
826#if defined (__GNUC__)
827/* ??? Later maybe paste sem-switch.c in when building mainloop.c.  */
828#define DEFINE_LABELS
829#include "$switch"
830#endif
831#else
832      @prefix@_semf_init_idesc_table (current_cpu);
833#endif
834      CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
835    }
836
837  vpc = GET_H_PC ();
838
839  do
840    {
841/* begin fast-exec-scache */
842EOF
843
844${SHELL} $infile fast-exec-scache
845
846cat << EOF
847/* end fast-exec-scache */
848    }
849  while (0 /*CPU_RUNNING_P (current_cpu)*/);
850}
851
852#undef FAST_P
853
854EOF
855
856fi # -fast
857
858fi # -scache && parallel
859
860##########################################################################
861
862# Compilation engine: lookup insn in scache, extract a pbb
863# (pseudo-basic-block) if missing, then execute the pbb.
864# A "pbb" is a sequence of insns up to the next cti insn or until
865# some prespecified maximum.
866# CTI: control transfer instruction.
867
868if [ x$pbb = xyes ] ; then
869
870    cat << EOF
871
872/* Record address of cti terminating a pbb.  */
873#define SET_CTI_VPC(sc) do { _cti_sc = (sc); } while (0)
874/* Record number of [real] insns in pbb.  */
875#define SET_INSN_COUNT(n) do { _insn_count = (n); } while (0)
876
877/* Fetch and extract a pseudo-basic-block.
878   FAST_P is non-zero if no tracing/profiling/etc. is wanted.  */
879
880INLINE SEM_PC
881@prefix@_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
882{
883  SEM_PC new_vpc;
884  PCADDR pc;
885  SCACHE *sc;
886  int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu);
887
888  pc = GET_H_PC ();
889
890  new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
891  if (! new_vpc)
892    {
893      /* Leading '_' to avoid collision with mainloop.in.  */
894      int _insn_count = 0;
895      SCACHE *orig_sc = sc;
896      SCACHE *_cti_sc = NULL;
897      int slice_insns = CPU_MAX_SLICE_INSNS (current_cpu);
898
899      /* First figure out how many instructions to compile.
900	 MAX_INSNS is the size of the allocated buffer, which includes space
901	 for before/after handlers if they're being used.
902	 SLICE_INSNS is the maxinum number of real insns that can be
903	 executed.  Zero means "as many as we want".  */
904      /* ??? max_insns is serving two incompatible roles.
905	 1) Number of slots available in scache buffer.
906	 2) Number of real insns to execute.
907	 They're incompatible because there are virtual insns emitted too
908	 (chain,cti-chain,before,after handlers).  */
909
910      if (slice_insns == 1)
911	{
912	  /* No need to worry about extra slots required for virtual insns
913	     and parallel exec support because MAX_CHAIN_LENGTH is
914	     guaranteed to be big enough to execute at least 1 insn!  */
915	  max_insns = 1;
916	}
917      else
918	{
919	  /* Allow enough slop so that while compiling insns, if max_insns > 0
920	     then there's guaranteed to be enough space to emit one real insn.
921	     MAX_CHAIN_LENGTH is typically much longer than
922	     the normal number of insns between cti's anyway.  */
923	  max_insns -= (1 /* one for the trailing chain insn */
924			+ (FAST_P
925			   ? 0
926			   : (1 + MAX_PARALLEL_INSNS) /* before+after */)
927			+ (MAX_PARALLEL_INSNS > 1
928			   ? (MAX_PARALLEL_INSNS * 2)
929			   : 0));
930
931	  /* Account for before/after handlers.  */
932	  if (! FAST_P)
933	    slice_insns *= 3;
934
935	  if (slice_insns > 0
936	      && slice_insns < max_insns)
937	    max_insns = slice_insns;
938	}
939
940      new_vpc = sc;
941
942      /* SC,PC must be updated to point passed the last entry used.
943	 SET_CTI_VPC must be called if pbb is terminated by a cti.
944	 SET_INSN_COUNT must be called to record number of real insns in
945	 pbb [could be computed by us of course, extra cpu but perhaps
946	 negligible enough].  */
947
948/* begin extract-pbb */
949EOF
950
951${SHELL} $infile extract-pbb
952
953cat << EOF
954/* end extract-pbb */
955
956      /* The last one is a pseudo-insn to link to the next chain.
957	 It is also used to record the insn count for this chain.  */
958      {
959	const IDESC *id;
960
961	/* Was pbb terminated by a cti?  */
962	if (_cti_sc)
963	  {
964	    id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_CTI_CHAIN];
965	  }
966	else
967	  {
968	    id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_CHAIN];
969	  }
970	SEM_SET_CODE (&sc->argbuf, id, FAST_P);
971	sc->argbuf.idesc = id;
972	sc->argbuf.addr = pc;
973	sc->argbuf.fields.chain.insn_count = _insn_count;
974	sc->argbuf.fields.chain.next = 0;
975	sc->argbuf.fields.chain.branch_target = 0;
976	++sc;
977      }
978
979      /* Update the pointer to the next free entry, may not have used as
980	 many entries as was asked for.  */
981      CPU_SCACHE_NEXT_FREE (current_cpu) = sc;
982      /* Record length of chain if profiling.
983	 This includes virtual insns since they count against
984	 max_insns too.  */
985      if (! FAST_P)
986	PROFILE_COUNT_SCACHE_CHAIN_LENGTH (current_cpu, sc - orig_sc);
987    }
988
989  return new_vpc;
990}
991
992/* Chain to the next block from a non-cti terminated previous block.  */
993
994INLINE SEM_PC
995@prefix@_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
996{
997  ARGBUF *abuf = SEM_ARGBUF (sem_arg);
998
999  PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
1000
1001  SET_H_PC (abuf->addr);
1002
1003  /* If not running forever, exit back to main loop.  */
1004  if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
1005      /* Also exit back to main loop if there's an event.
1006         Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
1007	 at the "right" time, but then that was what was asked for.
1008	 There is no silver bullet for simulator engines.
1009         ??? Clearly this needs a cleaner interface.
1010	 At present it's just so Ctrl-C works.  */
1011      || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
1012    CPU_RUNNING_P (current_cpu) = 0;
1013
1014  /* If chained to next block, go straight to it.  */
1015  if (abuf->fields.chain.next)
1016    return abuf->fields.chain.next;
1017  /* See if next block has already been compiled.  */
1018  abuf->fields.chain.next = scache_lookup (current_cpu, abuf->addr);
1019  if (abuf->fields.chain.next)
1020    return abuf->fields.chain.next;
1021  /* Nope, so next insn is a virtual insn to invoke the compiler
1022     (begin a pbb).  */
1023  return CPU_SCACHE_PBB_BEGIN (current_cpu);
1024}
1025
1026/* Chain to the next block from a cti terminated previous block.
1027   BR_TYPE indicates whether the branch was taken and whether we can cache
1028   the vpc of the branch target.
1029   NEW_PC is the target's branch address, and is only valid if
1030   BR_TYPE != SEM_BRANCH_UNTAKEN.  */
1031
1032INLINE SEM_PC
1033@prefix@_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
1034		     SEM_BRANCH_TYPE br_type, PCADDR new_pc)
1035{
1036  SEM_PC *new_vpc_ptr;
1037
1038  PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
1039
1040  /* If not running forever, exit back to main loop.  */
1041  if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
1042      /* Also exit back to main loop if there's an event.
1043         Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
1044	 at the "right" time, but then that was what was asked for.
1045	 There is no silver bullet for simulator engines.
1046         ??? Clearly this needs a cleaner interface.
1047	 At present it's just so Ctrl-C works.  */
1048      || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
1049    CPU_RUNNING_P (current_cpu) = 0;
1050
1051  /* Restart compiler if we branched to an uncacheable address
1052     (e.g. "j reg").  */
1053  if (br_type == SEM_BRANCH_UNCACHEABLE)
1054    {
1055      SET_H_PC (new_pc);
1056      return CPU_SCACHE_PBB_BEGIN (current_cpu);
1057    }
1058
1059  /* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our
1060     next chain ptr.  */
1061  if (br_type == SEM_BRANCH_UNTAKEN)
1062    {
1063      ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1064      new_pc = abuf->addr;
1065      SET_H_PC (new_pc);
1066      new_vpc_ptr = &abuf->fields.chain.next;
1067    }
1068  else
1069    {
1070      ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1071      SET_H_PC (new_pc);
1072      new_vpc_ptr = &abuf->fields.chain.branch_target;
1073    }
1074
1075  /* If chained to next block, go straight to it.  */
1076  if (*new_vpc_ptr)
1077    return *new_vpc_ptr;
1078  /* See if next block has already been compiled.  */
1079  *new_vpc_ptr = scache_lookup (current_cpu, new_pc);
1080  if (*new_vpc_ptr)
1081    return *new_vpc_ptr;
1082  /* Nope, so next insn is a virtual insn to invoke the compiler
1083     (begin a pbb).  */
1084  return CPU_SCACHE_PBB_BEGIN (current_cpu);
1085}
1086
1087/* x-before handler.
1088   This is called before each insn.  */
1089
1090void
1091@prefix@_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
1092{
1093  SEM_ARG sem_arg = sc;
1094  const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1095  int first_p = abuf->fields.before.first_p;
1096  const ARGBUF *cur_abuf = SEM_ARGBUF (sc + 1);
1097  const IDESC *cur_idesc = cur_abuf->idesc;
1098  PCADDR pc = cur_abuf->addr;
1099
1100  if (ARGBUF_PROFILE_P (cur_abuf))
1101    PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
1102
1103  /* If this isn't the first insn, finish up the previous one.  */
1104
1105  if (! first_p)
1106    {
1107      if (PROFILE_MODEL_P (current_cpu))
1108	{
1109	  const SEM_ARG prev_sem_arg = sc - 1;
1110	  const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1111	  const IDESC *prev_idesc = prev_abuf->idesc;
1112	  int cycles;
1113
1114	  /* ??? May want to measure all insns if doing insn tracing.  */
1115	  if (ARGBUF_PROFILE_P (prev_abuf))
1116	    {
1117	      cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1118	      @prefix@_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
1119	    }
1120	}
1121
1122      CGEN_TRACE_INSN_FINI (current_cpu, cur_abuf, 0 /*last_p*/);
1123    }
1124
1125  /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}.  */
1126  if (PROFILE_MODEL_P (current_cpu)
1127      && ARGBUF_PROFILE_P (cur_abuf))
1128    @prefix@_model_insn_before (current_cpu, first_p);
1129
1130  CGEN_TRACE_INSN_INIT (current_cpu, cur_abuf, first_p);
1131  CGEN_TRACE_INSN (current_cpu, cur_idesc->idata, cur_abuf, pc);
1132}
1133
1134/* x-after handler.
1135   This is called after a serial insn or at the end of a group of parallel
1136   insns.  */
1137
1138void
1139@prefix@_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
1140{
1141  SEM_ARG sem_arg = sc;
1142  const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1143  const SEM_ARG prev_sem_arg = sc - 1;
1144  const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1145
1146  /* ??? May want to measure all insns if doing insn tracing.  */
1147  if (PROFILE_MODEL_P (current_cpu)
1148      && ARGBUF_PROFILE_P (prev_abuf))
1149    {
1150      const IDESC *prev_idesc = prev_abuf->idesc;
1151      int cycles;
1152
1153      cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1154      @prefix@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
1155    }
1156  CGEN_TRACE_INSN_FINI (current_cpu, prev_abuf, 1 /*last_p*/);
1157}
1158
1159#define FAST_P 0
1160
1161void
1162@prefix@_engine_run_full (SIM_CPU *current_cpu)
1163{
1164  SIM_DESC current_state = CPU_STATE (current_cpu);
1165  SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1166  /* virtual program counter */
1167  SEM_PC vpc;
1168#if WITH_SEM_SWITCH_FULL
1169  /* For communication between cti's and cti-chain.  */
1170  SEM_BRANCH_TYPE pbb_br_type = SEM_BRANCH_UNTAKEN;
1171  PCADDR pbb_br_npc = 0;
1172#endif
1173
1174EOF
1175
1176case x$parallel in
1177xread | xwrite)
1178    cat << EOF
1179  PAREXEC pbufs[MAX_PARALLEL_INSNS];
1180  PAREXEC *par_exec = &pbufs[0];
1181
1182EOF
1183    ;;
1184esac
1185
1186# Any initialization code before looping starts.
1187# Note that this code may declare some locals.
1188${SHELL} $infile init
1189
1190cat << EOF
1191
1192  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1193    {
1194      /* ??? 'twould be nice to move this up a level and only call it once.
1195	 On the other hand, in the "let's go fast" case the test is only done
1196	 once per pbb (since we only return to the main loop at the end of
1197	 a pbb).  And in the "let's run until we're done" case we don't return
1198	 until the program exits.  */
1199
1200#if WITH_SEM_SWITCH_FULL
1201#if defined (__GNUC__)
1202/* ??? Later maybe paste sem-switch.c in when building mainloop.c.  */
1203#define DEFINE_LABELS
1204#include "$switch"
1205#endif
1206#else
1207      @prefix@_sem_init_idesc_table (current_cpu);
1208#endif
1209
1210      /* Initialize the "begin (compile) a pbb" virtual insn.  */
1211      vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1212      SEM_SET_FULL_CODE (SEM_ARGBUF (vpc),
1213			 & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN]);
1214      vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN];
1215
1216      CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1217    }
1218
1219  CPU_RUNNING_P (current_cpu) = 1;
1220  /* ??? In the case where we're returning to the main loop after every
1221     pbb we don't want to call pbb_begin each time (which hashes on the pc
1222     and does a table lookup).  A way to speed this up is to save vpc
1223     between calls.  */
1224  vpc = @prefix@_pbb_begin (current_cpu, FAST_P);
1225
1226  do
1227    {
1228/* begin full-exec-pbb */
1229EOF
1230
1231${SHELL} $infile full-exec-pbb
1232
1233cat << EOF
1234/* end full-exec-pbb */
1235    }
1236  while (CPU_RUNNING_P (current_cpu));
1237}
1238
1239#undef FAST_P
1240
1241EOF
1242
1243####################################
1244
1245# Compile engine: fast version.
1246
1247if [ x$fast = xyes ] ; then
1248
1249    cat << EOF
1250
1251#define FAST_P 1
1252
1253void
1254@prefix@_engine_run_fast (SIM_CPU *current_cpu)
1255{
1256  SIM_DESC current_state = CPU_STATE (current_cpu);
1257  SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1258  /* virtual program counter */
1259  SEM_PC vpc;
1260#if WITH_SEM_SWITCH_FAST
1261  /* For communication between cti's and cti-chain.  */
1262  SEM_BRANCH_TYPE pbb_br_type = SEM_BRANCH_UNTAKEN;
1263  PCADDR pbb_br_npc = 0;
1264#endif
1265
1266EOF
1267
1268case x$parallel in
1269xread | xwrite)
1270    cat << EOF
1271  PAREXEC pbufs[MAX_PARALLEL_INSNS];
1272  PAREXEC *par_exec = &pbufs[0];
1273
1274EOF
1275    ;;
1276esac
1277
1278# Any initialization code before looping starts.
1279# Note that this code may declare some locals.
1280${SHELL} $infile init
1281
1282cat << EOF
1283
1284  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1285    {
1286      /* ??? 'twould be nice to move this up a level and only call it once.
1287	 On the other hand, in the "let's go fast" case the test is only done
1288	 once per pbb (since we only return to the main loop at the end of
1289	 a pbb).  And in the "let's run until we're done" case we don't return
1290	 until the program exits.  */
1291
1292#if WITH_SEM_SWITCH_FAST
1293#if defined (__GNUC__)
1294/* ??? Later maybe paste sem-switch.c in when building mainloop.c.  */
1295#define DEFINE_LABELS
1296#include "$switch"
1297#endif
1298#else
1299      @prefix@_semf_init_idesc_table (current_cpu);
1300#endif
1301
1302      /* Initialize the "begin (compile) a pbb" virtual insn.  */
1303      vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1304      SEM_SET_FAST_CODE (SEM_ARGBUF (vpc),
1305			 & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN]);
1306      vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEGIN];
1307
1308      CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1309    }
1310
1311  CPU_RUNNING_P (current_cpu) = 1;
1312  /* ??? In the case where we're returning to the main loop after every
1313     pbb we don't want to call pbb_begin each time (which hashes on the pc
1314     and does a table lookup).  A way to speed this up is to save vpc
1315     between calls.  */
1316  vpc = @prefix@_pbb_begin (current_cpu, FAST_P);
1317
1318  do
1319    {
1320/* begin fast-exec-pbb */
1321EOF
1322
1323${SHELL} $infile fast-exec-pbb
1324
1325cat << EOF
1326/* end fast-exec-pbb */
1327    }
1328  while (CPU_RUNNING_P (current_cpu));
1329}
1330
1331#undef FAST_P
1332
1333EOF
1334fi # -fast
1335
1336fi # -pbb
1337
1338# Expand @..@ macros appearing in tmp-mloop-{pid}.cin.
1339sed \
1340  -e "s/@cpu@/$cpu/g" -e "s/@CPU@/$CPU/g" \
1341  -e "s/@prefix@/$prefix/g" -e "s/@PREFIX@/$PREFIX/g" \
1342  < ${outprefix}tmp-mloop-$$.cin > ${outprefix}mloop${outsuffix}.cin
1343rc=$?
1344rm -f ${outprefix}tmp-mloop-$$.cin
1345
1346exit $rc
1347