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