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