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