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