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