xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/genmloop.sh (revision 88241920d21b339bf319c0e979ffda80c49a2936)
1# Generate the main loop of the simulator.
2# Copyright (C) 1996-2024 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=""
145lineno=""
146
147while test $# -gt 0
148do
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
175done
176
177# Argument validation.
178
179if [ x$scache = xyes -a x$pbb = xyes ] ; then
180    echo "only one of -scache and -pbb may be selected" >&2
181    exit 1
182fi
183
184if [ "x$cpu" = xunknown ] ; then
185    echo "cpu family not specified" >&2
186    exit 1
187fi
188
189if [ "x$infile" = x ] ; then
190    echo "mainloop.in not specified" >&2
191    exit 1
192fi
193
194if [ "x$prefix" = xunknown ] ; then
195    prefix=$cpu
196fi
197
198lowercase='abcdefghijklmnopqrstuvwxyz'
199uppercase='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
200CPU=`echo ${cpu} | tr "${lowercase}" "${uppercase}"`
201PREFIX=`echo ${prefix} | tr "${lowercase}" "${uppercase}"`
202
203##########################################################################
204
205load_infile_section() {
206  if [ -n "${lineno}" ]; then
207    ${SHELL} ${lineno} \
208      "${infile}" "${outprefix}mloop${outsuffix}.tmp" \
209      "$@"
210  else
211    ${SHELL} ${infile} "$@"
212  fi
213}
214
215rm -f ${outprefix}eng${outsuffix}.hin
216exec 1>${outprefix}eng${outsuffix}.hin
217
218echo "/* engine configuration for ${cpu} */"
219echo ""
220
221echo "/* WITH_FAST: non-zero if a fast version of the engine is available"
222echo "   in addition to the full-featured version.  */"
223if [ x$fast = xyes ] ; then
224	echo "#define WITH_FAST 1"
225else
226	echo "#define WITH_FAST 0"
227fi
228
229echo ""
230echo "/* WITH_SCACHE_PBB_${PREFIX}: non-zero if the pbb engine was selected.  */"
231if [ x$pbb = xyes ] ; then
232	echo "#define WITH_SCACHE_PBB_${PREFIX} 1"
233else
234	echo "#define WITH_SCACHE_PBB_${PREFIX} 0"
235fi
236
237echo ""
238echo "/* HAVE_PARALLEL_INSNS: non-zero if cpu can parallelly execute > 1 insn.  */"
239# blah blah blah, other ways to do this, blah blah blah
240case x$parallel in
241xno)
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"
246    ;;
247xread)
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"
253    ;;
254xwrite)
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"
260    ;;
261xgenwrite)
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"
267    ;;
268esac
269
270if [ "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"
278	fi
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"
286	fi
287fi
288
289# Decls of functions we define.
290
291echo ""
292echo "/* Functions defined in the generated mainloop.c file"
293echo "   (which doesn't necessarily have that file name).  */"
294echo ""
295echo "extern ENGINE_FN ${prefix}_engine_run_full;"
296echo "extern ENGINE_FN ${prefix}_engine_run_fast;"
297
298if [ 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 *);"
305fi
306
307##########################################################################
308
309rm -f ${outprefix}tmp-mloop-$$.cin ${outprefix}mloop${outsuffix}.cin
310exec 1>${outprefix}tmp-mloop-$$.cin
311
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.
315
316cat << EOF
317#line $LINENO "$0"
318/* This file is generated by the genmloop script.  DO NOT EDIT! */
319
320/* This must come before any other includes.  */
321#include "defs.h"
322
323/* Enable switch() support in cgen headers.  */
324#define SEM_IN_SWITCH
325
326#define WANT_CPU @cpu@
327#define WANT_CPU_@CPU@
328
329#include "ansidecl.h"
330#include "bfd.h"
331
332#include "sim-main.h"
333#include "cgen-mem.h"
334#include "cgen-ops.h"
335#include "sim-assert.h"
336
337/* Fill in the administrative ARGBUF fields required by all insns,
338   virtual and real.  */
339
340static INLINE void
341@prefix@_fill_argbuf (const SIM_CPU *cpu, ARGBUF *abuf, const IDESC *idesc,
342		    PCADDR pc, int fast_p)
343{
344#if WITH_SCACHE
345  SEM_SET_CODE (abuf, idesc, fast_p);
346  ARGBUF_ADDR (abuf) = pc;
347#endif
348  ARGBUF_IDESC (abuf) = idesc;
349}
350
351/* Fill in tracing/profiling fields of an ARGBUF.  */
352
353static INLINE void
354@prefix@_fill_argbuf_tp (const SIM_CPU *cpu, ARGBUF *abuf,
355		       int trace_p, int profile_p)
356{
357  ARGBUF_TRACE_P (abuf) = trace_p;
358  ARGBUF_PROFILE_P (abuf) = profile_p;
359}
360
361#if WITH_SCACHE_PBB
362
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.  */
367
368ATTRIBUTE_UNUSED static INLINE void
369@prefix@_emit_before (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc, int first_p)
370{
371  ARGBUF *abuf = &sc[0].argbuf;
372  const IDESC *id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_BEFORE];
373
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 */
377}
378
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.  */
382
383ATTRIBUTE_UNUSED static INLINE void
384@prefix@_emit_after (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc)
385{
386  ARGBUF *abuf = &sc[0].argbuf;
387  const IDESC *id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_AFTER];
388
389  @prefix@_fill_argbuf (current_cpu, abuf, id, pc, 0);
390  /* no need to set trace_p,profile_p */
391}
392
393#endif /* WITH_SCACHE_PBB */
394
395EOF
396
397load_infile_section support
398
399##########################################################################
400
401# Simple engine: fetch an instruction, execute the instruction.
402#
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.
410
411if [ x$scache != xyes -a x$pbb != xyes ] ; then
412
413    cat << EOF
414#line $LINENO "$0"
415
416#define FAST_P 0
417
418void
419@prefix@_engine_run_full (SIM_CPU *current_cpu)
420{
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];
428
429EOF
430
431case x$parallel in
432xread | xwrite)
433    cat << EOF
434#line $LINENO "$0"
435  PAREXEC pbufs[MAX_PARALLEL_INSNS];
436  PAREXEC *par_exec;
437
438EOF
439    ;;
440esac
441
442# Any initialization code before looping starts.
443# Note that this code may declare some locals.
444load_infile_section init
445
446if [ x$parallel = xread ] ; then
447  cat << EOF
448#line $LINENO "$0"
449
450#if defined (__GNUC__)
451  {
452    if (! CPU_IDESC_READ_INIT_P (current_cpu))
453      {
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;
458      }
459  }
460#endif
461
462EOF
463fi
464
465cat << EOF
466#line $LINENO "$0"
467
468  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
469    {
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;
480    }
481
482  do
483    {
484/* begin full-exec-simple */
485EOF
486
487load_infile_section full-exec-simple
488
489cat << EOF
490#line $LINENO "$0"
491/* end full-exec-simple */
492
493      ++ CPU_INSN_COUNT (current_cpu);
494    }
495  while (0 /*CPU_RUNNING_P (current_cpu)*/);
496}
497
498#undef FAST_P
499
500EOF
501
502####################################
503
504# Simple engine: fast version.
505# ??? A somewhat dubious effort, but for completeness' sake.
506
507if [ x$fast = xyes ] ; then
508
509    cat << EOF
510#line $LINENO "$0"
511
512#define FAST_P 1
513
514FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh."
515
516#undef FAST_P
517
518EOF
519
520fi # -fast
521
522fi # simple engine
523
524##########################################################################
525
526# Non-parallel scache engine: lookup insn in scache, fetch if missing,
527# then execute it.
528
529if [ x$scache = xyes -a x$parallel = xno ] ; then
530
531    cat << EOF
532#line $LINENO "$0"
533
534static INLINE SCACHE *
535@prefix@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
536                     unsigned int hash_mask, int FAST_P)
537{
538  /* First step: look up current insn in hash table.  */
539  SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
540
541  /* If the entry isn't the one we want (cache miss),
542     fetch and decode the instruction.  */
543  if (sc->argbuf.addr != vpc)
544    {
545      if (! FAST_P)
546	PROFILE_COUNT_SCACHE_MISS (current_cpu);
547
548/* begin extract-scache */
549EOF
550
551load_infile_section extract-scache
552
553cat << EOF
554#line $LINENO "$0"
555/* end extract-scache */
556    }
557  else if (! FAST_P)
558    {
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);
563    }
564
565  return sc;
566}
567
568#define FAST_P 0
569
570void
571@prefix@_engine_run_full (SIM_CPU *current_cpu)
572{
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;
577
578EOF
579
580# Any initialization code before looping starts.
581# Note that this code may declare some locals.
582load_infile_section init
583
584cat << EOF
585#line $LINENO "$0"
586
587  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
588    {
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;
593    }
594
595  vpc = GET_H_PC ();
596
597  do
598    {
599      SCACHE *sc;
600
601      sc = @prefix@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
602
603/* begin full-exec-scache */
604EOF
605
606load_infile_section full-exec-scache
607
608cat << EOF
609#line $LINENO "$0"
610/* end full-exec-scache */
611
612      SET_H_PC (vpc);
613
614      ++ CPU_INSN_COUNT (current_cpu);
615    }
616  while (0 /*CPU_RUNNING_P (current_cpu)*/);
617}
618
619#undef FAST_P
620
621EOF
622
623####################################
624
625# Non-parallel scache engine: fast version.
626
627if [ x$fast = xyes ] ; then
628
629    cat << EOF
630#line $LINENO "$0"
631
632#define FAST_P 1
633
634void
635@prefix@_engine_run_fast (SIM_CPU *current_cpu)
636{
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;
641
642EOF
643
644# Any initialization code before looping starts.
645# Note that this code may declare some locals.
646load_infile_section init
647
648cat << EOF
649#line $LINENO "$0"
650
651  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
652    {
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;
663    }
664
665  vpc = GET_H_PC ();
666
667  do
668    {
669      SCACHE *sc;
670
671      sc = @prefix@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
672
673/* begin fast-exec-scache */
674EOF
675
676load_infile_section fast-exec-scache
677
678cat << EOF
679#line $LINENO "$0"
680/* end fast-exec-scache */
681
682      SET_H_PC (vpc);
683
684      ++ CPU_INSN_COUNT (current_cpu);
685    }
686  while (0 /*CPU_RUNNING_P (current_cpu)*/);
687}
688
689#undef FAST_P
690
691EOF
692
693fi # -fast
694
695fi # -scache && ! parallel
696
697##########################################################################
698
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.
702
703if [ x$scache = xyes -a x$parallel != xno ] ; then
704
705    cat << EOF
706#line $LINENO "$0"
707
708static INLINE SCACHE *
709@prefix@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
710                     unsigned int hash_mask, int FAST_P)
711{
712  /* First step: look up current insn in hash table.  */
713  SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
714
715  /* If the entry isn't the one we want (cache miss),
716     fetch and decode the instruction.  */
717  if (sc->argbuf.addr != vpc)
718    {
719      if (! FAST_P)
720	PROFILE_COUNT_SCACHE_MISS (current_cpu);
721
722#define SET_LAST_INSN_P(last_p) do { sc->last_insn_p = (last_p); } while (0)
723/* begin extract-scache */
724EOF
725
726load_infile_section extract-scache
727
728cat << EOF
729#line $LINENO "$0"
730/* end extract-scache */
731#undef SET_LAST_INSN_P
732    }
733  else if (! FAST_P)
734    {
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);
739    }
740
741  return sc;
742}
743
744#define FAST_P 0
745
746void
747@prefix@_engine_run_full (SIM_CPU *current_cpu)
748{
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;
753
754EOF
755
756# Any initialization code before looping starts.
757# Note that this code may declare some locals.
758load_infile_section init
759
760if [ x$parallel = xread ] ; then
761cat << EOF
762#line $LINENO "$0"
763#if defined (__GNUC__)
764  {
765    if (! CPU_IDESC_READ_INIT_P (current_cpu))
766      {
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;
771      }
772  }
773#endif
774
775EOF
776fi
777
778cat << EOF
779#line $LINENO "$0"
780
781  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
782    {
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;
787    }
788
789  vpc = GET_H_PC ();
790
791  do
792    {
793/* begin full-exec-scache */
794EOF
795
796load_infile_section full-exec-scache
797
798cat << EOF
799#line $LINENO "$0"
800/* end full-exec-scache */
801    }
802  while (0 /*CPU_RUNNING_P (current_cpu)*/);
803}
804
805#undef FAST_P
806
807EOF
808
809####################################
810
811# Parallel scache engine: fast version.
812
813if [ x$fast = xyes ] ; then
814
815    cat << EOF
816#line $LINENO "$0"
817
818#define FAST_P 1
819
820void
821@prefix@_engine_run_fast (SIM_CPU *current_cpu)
822{
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;
829
830EOF
831
832# Any initialization code before looping starts.
833# Note that this code may declare some locals.
834load_infile_section init
835
836if [ x$parallel = xread ] ; then
837cat << EOF
838#line $LINENO "$0"
839
840#if defined (__GNUC__)
841  {
842    if (! CPU_IDESC_READ_INIT_P (current_cpu))
843      {
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;
848      }
849  }
850#endif
851
852EOF
853fi
854
855cat << EOF
856#line $LINENO "$0"
857
858  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
859    {
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;
870    }
871
872  vpc = GET_H_PC ();
873
874  do
875    {
876/* begin fast-exec-scache */
877EOF
878
879load_infile_section fast-exec-scache
880
881cat << EOF
882#line $LINENO "$0"
883/* end fast-exec-scache */
884    }
885  while (0 /*CPU_RUNNING_P (current_cpu)*/);
886}
887
888#undef FAST_P
889
890EOF
891
892fi # -fast
893
894fi # -scache && parallel
895
896##########################################################################
897
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.
903
904if [ x$pbb = xyes ] ; then
905
906    cat << EOF
907#line $LINENO "$0"
908
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)
913
914/* Fetch and extract a pseudo-basic-block.
915   FAST_P is non-zero if no tracing/profiling/etc. is wanted.  */
916
917INLINE SEM_PC
918@prefix@_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
919{
920  SEM_PC new_vpc;
921  PCADDR pc;
922  SCACHE *sc;
923  int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu);
924
925  pc = GET_H_PC ();
926
927  new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
928  if (! new_vpc)
929    {
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);
935
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).  */
946
947      if (slice_insns == 1)
948	{
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;
953	}
954      else
955	{
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
962			   ? 0
963			   : (1 + MAX_PARALLEL_INSNS) /* before+after */)
964			+ (MAX_PARALLEL_INSNS > 1
965			   ? (MAX_PARALLEL_INSNS * 2)
966			   : 0));
967
968	  /* Account for before/after handlers.  */
969	  if (! FAST_P)
970	    slice_insns *= 3;
971
972	  if (slice_insns > 0
973	      && slice_insns < max_insns)
974	    max_insns = slice_insns;
975	}
976
977      new_vpc = sc;
978
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].  */
984
985/* begin extract-pbb */
986EOF
987
988load_infile_section extract-pbb
989
990cat << EOF
991#line $LINENO "$0"
992/* end extract-pbb */
993
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.  */
996      {
997	const IDESC *id;
998
999	/* Was pbb terminated by a cti?  */
1000	if (_cti_sc)
1001	  {
1002	    id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_CTI_CHAIN];
1003	  }
1004	else
1005	  {
1006	    id = & CPU_IDESC (current_cpu) [@PREFIX@_INSN_X_CHAIN];
1007	  }
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;
1015      }
1016
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);
1025    }
1026
1027  return new_vpc;
1028}
1029
1030/* Chain to the next block from a non-cti terminated previous block.  */
1031
1032INLINE SEM_PC
1033@prefix@_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
1034{
1035  ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1036
1037  PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
1038
1039  SET_H_PC (abuf->addr);
1040
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;
1051
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);
1062}
1063
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.  */
1069
1070INLINE SEM_PC
1071@prefix@_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
1072		     SEM_BRANCH_TYPE br_type, PCADDR new_pc)
1073{
1074  SEM_PC *new_vpc_ptr;
1075
1076  PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
1077
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;
1088
1089  /* Restart compiler if we branched to an uncacheable address
1090     (e.g. "j reg").  */
1091  if (br_type == SEM_BRANCH_UNCACHEABLE)
1092    {
1093      SET_H_PC (new_pc);
1094      return CPU_SCACHE_PBB_BEGIN (current_cpu);
1095    }
1096
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)
1100    {
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;
1105    }
1106  else
1107    {
1108      ARGBUF *abuf = SEM_ARGBUF (sem_arg);
1109      SET_H_PC (new_pc);
1110      new_vpc_ptr = &abuf->fields.chain.branch_target;
1111    }
1112
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);
1123}
1124
1125/* x-before handler.
1126   This is called before each insn.  */
1127
1128void
1129@prefix@_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
1130{
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;
1137
1138  if (ARGBUF_PROFILE_P (cur_abuf))
1139    PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
1140
1141  /* If this isn't the first insn, finish up the previous one.  */
1142
1143  if (! first_p)
1144    {
1145      if (PROFILE_MODEL_P (current_cpu))
1146	{
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;
1151
1152	  /* ??? May want to measure all insns if doing insn tracing.  */
1153	  if (ARGBUF_PROFILE_P (prev_abuf))
1154	    {
1155	      cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1156	      @prefix@_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
1157	    }
1158	}
1159
1160      CGEN_TRACE_INSN_FINI (current_cpu, cur_abuf, 0 /*last_p*/);
1161    }
1162
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);
1167
1168  CGEN_TRACE_INSN_INIT (current_cpu, cur_abuf, first_p);
1169  CGEN_TRACE_INSN (current_cpu, cur_idesc->idata, cur_abuf, pc);
1170}
1171
1172/* x-after handler.
1173   This is called after a serial insn or at the end of a group of parallel
1174   insns.  */
1175
1176void
1177@prefix@_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
1178{
1179  const SEM_ARG prev_sem_arg = sc - 1;
1180  const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
1181
1182  /* ??? May want to measure all insns if doing insn tracing.  */
1183  if (PROFILE_MODEL_P (current_cpu)
1184      && ARGBUF_PROFILE_P (prev_abuf))
1185    {
1186      const IDESC *prev_idesc = prev_abuf->idesc;
1187      int cycles;
1188
1189      cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
1190      @prefix@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
1191    }
1192  CGEN_TRACE_INSN_FINI (current_cpu, prev_abuf, 1 /*last_p*/);
1193}
1194
1195#define FAST_P 0
1196
1197void
1198@prefix@_engine_run_full (SIM_CPU *current_cpu)
1199{
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
1207
1208EOF
1209
1210case x$parallel in
1211xread | xwrite)
1212    cat << EOF
1213#line $LINENO "$0"
1214  PAREXEC pbufs[MAX_PARALLEL_INSNS];
1215  PAREXEC *par_exec = &pbufs[0];
1216
1217EOF
1218    ;;
1219esac
1220
1221# Any initialization code before looping starts.
1222# Note that this code may declare some locals.
1223load_infile_section init
1224
1225cat << EOF
1226#line $LINENO "$0"
1227
1228  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1229    {
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.  */
1235
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
1245
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];
1251
1252      CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1253    }
1254
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);
1261
1262  do
1263    {
1264/* begin full-exec-pbb */
1265EOF
1266
1267load_infile_section full-exec-pbb
1268
1269cat << EOF
1270#line $LINENO "$0"
1271/* end full-exec-pbb */
1272    }
1273  while (CPU_RUNNING_P (current_cpu));
1274}
1275
1276#undef FAST_P
1277
1278EOF
1279
1280####################################
1281
1282# Compile engine: fast version.
1283
1284if [ x$fast = xyes ] ; then
1285
1286    cat << EOF
1287#line $LINENO "$0"
1288
1289#define FAST_P 1
1290
1291void
1292@prefix@_engine_run_fast (SIM_CPU *current_cpu)
1293{
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
1301
1302EOF
1303
1304case x$parallel in
1305xread | xwrite)
1306    cat << EOF
1307#line $LINENO "$0"
1308  PAREXEC pbufs[MAX_PARALLEL_INSNS];
1309  PAREXEC *par_exec = &pbufs[0];
1310
1311EOF
1312    ;;
1313esac
1314
1315# Any initialization code before looping starts.
1316# Note that this code may declare some locals.
1317load_infile_section init
1318
1319cat << EOF
1320#line $LINENO "$0"
1321
1322  if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1323    {
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.  */
1329
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
1339
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];
1345
1346      CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1347    }
1348
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);
1355
1356  do
1357    {
1358/* begin fast-exec-pbb */
1359EOF
1360
1361load_infile_section fast-exec-pbb
1362
1363cat << EOF
1364#line $LINENO "$0"
1365/* end fast-exec-pbb */
1366    }
1367  while (CPU_RUNNING_P (current_cpu));
1368}
1369
1370#undef FAST_P
1371
1372EOF
1373fi # -fast
1374
1375fi # -pbb
1376
1377# Expand @..@ macros appearing in tmp-mloop-{pid}.cin.
1378sed \
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
1382rc=$?
1383rm -f ${outprefix}tmp-mloop-$$.cin
1384
1385exit $rc
1386