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