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