]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/common/genmloop.sh
* config/sh/tm-sh.h (BELIEVE_PCC_PROMOTION): Define, so that
[thirdparty/binutils-gdb.git] / sim / common / genmloop.sh
1 # Generate the main loop of the simulator.
2 # Copyright (C) 1996, 1997, 1998 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 # ??? 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 # ??? The implementation is currently slower than necessary for
57 # simplicity. Instead of storing extract insn fields in ARGBUF,
58 # they should just be extracted from the insn when needed.
59 #
60 # -scache: use the scache to speed things up (not always a win)
61 #
62 # This engine caches the extracted instruction before executing it.
63 # When executing instructions they are first looked up in the scache.
64 #
65 # -pbb: same as -scache but extract a (pseudo-) basic block at a time
66 #
67 # This engine is basically identical to the scache version except that
68 # extraction is done a pseudo-basic-block at a time and the address of
69 # the scache entry of a branch target is recorded as well.
70 # Additional speedups are then possible by defering Ctrl-C checking
71 # to the end of basic blocks and by threading the insns together.
72 # We call them pseudo-basic-block's instead of just basic-blocks because
73 # they're not necessarily basic-blocks, though normally are.
74 #
75 # -parallel: cpu can execute multiple instructions parallely
76 #
77 # This option is specified in addition to -simple, -scache, -pbb.
78 # Note that while the code can determine if the cpu supports parallel
79 # execution with HAVE_PARALLEL_INSNS [and thus this option is
80 # technically unnecessary], having this option cuts down on the clutter
81 # in the result.
82 #
83 # -switch file: specify file containing semantics implemented as a switch()
84 #
85 # -cpu <cpu-family>
86 #
87 # Specify the cpu family name.
88 #
89 # -infile <input-file>
90 #
91 # Specify the mainloop.in input file.
92 #
93 # Only one of -scache/-pbb may be selected.
94 # -simple is the default.
95 #
96 ####
97 #
98 # TODO
99 # - build mainloop.in from .cpu file
100
101 type=mono
102 #scache=
103 #fast=
104 #full_switch=
105 #pbb=
106 #parallel=
107 switch=
108 cpu="unknown"
109 infile=""
110
111 while test $# -gt 0
112 do
113 case $1 in
114 -mono) type=mono ;;
115 -multi) type=multi ;;
116 -no-fast) ;;
117 -fast) fast=yes ;;
118 -full-switch) full_switch=yes ;;
119 -simple) ;;
120 -scache) scache=yes ;;
121 -pbb) pbb=yes ;;
122 -no-parallel) ;;
123 -parallel) parallel=yes ;;
124 -switch) shift ; switch=$1 ;;
125 -cpu) shift ; cpu=$1 ;;
126 -infile) shift ; infile=$1 ;;
127 *) echo "unknown option: $1" >&2 ; exit 1 ;;
128 esac
129 shift
130 done
131
132 # Argument validation.
133
134 if [ x$scache = xyes -a x$pbb = xyes ] ; then
135 echo "only one of -scache and -pbb may be selected" >&2
136 exit 1
137 fi
138
139 if [ "x$cpu" = xunknown ] ; then
140 echo "cpu family not specified" >&2
141 exit 1
142 fi
143
144 if [ "x$infile" = x ] ; then
145 echo "mainloop.in not specified" >&2
146 exit 1
147 fi
148
149 lowercase='abcdefghijklmnopqrstuvwxyz'
150 uppercase='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
151 CPU=`echo ${cpu} | tr "${lowercase}" "${uppercase}"`
152
153 ##########################################################################
154
155 rm -f eng.hin
156 exec 1>eng.hin
157
158 echo "/* engine configuration for ${cpu} */"
159 echo ""
160
161 echo "/* WITH_FAST: non-zero if a fast version of the engine is available"
162 echo " in addition to the full-featured version. */"
163 if [ x$fast = xyes ] ; then
164 echo "#define WITH_FAST 1"
165 else
166 echo "#define WITH_FAST 0"
167 fi
168
169 echo ""
170 echo "/* WITH_SCACHE_PBB_${CPU}: non-zero if the pbb engine was selected. */"
171 if [ x$pbb = xyes ] ; then
172 echo "#define WITH_SCACHE_PBB_${CPU} 1"
173 else
174 echo "#define WITH_SCACHE_PBB_${CPU} 0"
175 fi
176
177 echo ""
178 echo "/* HAVE_PARALLEL_INSNS: non-zero if cpu can parallelly execute > 1 insn. */"
179 if [ x$parallel = xyes ] ; then
180 echo "#define HAVE_PARALLEL_INSNS 1"
181 else
182 echo "#define HAVE_PARALLEL_INSNS 0"
183 fi
184
185 if [ "x$switch" != x ] ; then
186 echo ""
187 echo "/* WITH_SEM_SWITCH_FULL: non-zero if full-featured engine is"
188 echo " implemented as a switch(). */"
189 if [ x$fast != xyes -o x$full_switch = xyes ] ; then
190 echo "#define WITH_SEM_SWITCH_FULL 1"
191 else
192 echo "#define WITH_SEM_SWITCH_FULL 0"
193 fi
194 echo ""
195 echo "/* WITH_SEM_SWITCH_FAST: non-zero if fast engine is"
196 echo " implemented as a switch(). */"
197 if [ x$fast = xyes ] ; then
198 echo "#define WITH_SEM_SWITCH_FAST 1"
199 else
200 echo "#define WITH_SEM_SWITCH_FAST 0"
201 fi
202 fi
203
204 # Decls of functions we define.
205
206 echo ""
207 echo "/* Functions defined in the generated mainloop.c file"
208 echo " (which doesn't necessarily have that file name). */"
209 echo ""
210 echo "extern ENGINE_FN ${cpu}_engine_run_full;"
211 echo "extern ENGINE_FN ${cpu}_engine_run_fast;"
212
213 if [ x$pbb = xyes ] ; then
214 echo ""
215 echo "extern SEM_PC ${cpu}_pbb_begin (SIM_CPU *, int);"
216 echo "extern SEM_PC ${cpu}_pbb_chain (SIM_CPU *, SEM_ARG);"
217 echo "extern SEM_PC ${cpu}_pbb_cti_chain (SIM_CPU *, SEM_ARG, SEM_PC *, PCADDR);"
218 echo "extern void ${cpu}_pbb_before (SIM_CPU *, SCACHE *);"
219 echo "extern void ${cpu}_pbb_after (SIM_CPU *, SCACHE *);"
220 fi
221
222 ##########################################################################
223
224 rm -f tmp-mloop.cin mloop.cin
225 exec 1>tmp-mloop.cin
226
227 # We use @cpu@ instead of ${cpu} because we still want to run sed to handle
228 # transformation of @cpu@ for mainloop.in.
229
230 cat << EOF
231 /* This file is generated by the genmloop script. DO NOT EDIT! */
232
233 /* Enable switch() support in cgen headers. */
234 #define SEM_IN_SWITCH
235
236 #define WANT_CPU
237 #define WANT_CPU_@CPU@
238
239 #include "sim-main.h"
240 #include "bfd.h"
241 #include "cgen-mem.h"
242 #include "cgen-ops.h"
243 #include "cpu-opc.h"
244 #include "cpu-sim.h"
245 #include "sim-assert.h"
246
247 /* Fill in the administrative ARGBUF fields required by all insns,
248 virtual and real. */
249
250 static INLINE void
251 @cpu@_fill_argbuf (const SIM_CPU *cpu, ARGBUF *abuf, const IDESC *idesc,
252 PCADDR pc, int fast_p)
253 {
254 SEM_SET_CODE (abuf, idesc, fast_p);
255 ARGBUF_ADDR (abuf) = pc;
256 ARGBUF_IDESC (abuf) = idesc;
257 }
258
259 /* Fill in tracing/profiling fields of an ARGBUF. */
260
261 static INLINE void
262 @cpu@_fill_argbuf_tp (const SIM_CPU *cpu, ARGBUF *abuf,
263 int trace_p, int profile_p)
264 {
265 ARGBUF_TRACE_P (abuf) = trace_p;
266 ARGBUF_PROFILE_P (abuf) = profile_p;
267 }
268
269 #if WITH_SCACHE_PBB
270
271 /* Emit the "x-before" handler.
272 x-before is emitted before each insn (serial or parallel).
273 This is as opposed to x-after which is only emitted at the end of a group
274 of parallel insns. */
275
276 static INLINE void
277 @cpu@_emit_before (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc, int first_p)
278 {
279 ARGBUF *abuf = &sc[0].argbuf;
280 const IDESC *id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEFORE];
281
282 abuf->fields.before.first_p = first_p;
283 @cpu@_fill_argbuf (current_cpu, abuf, id, pc, 0);
284 /* no need to set trace_p,profile_p */
285 }
286
287 /* Emit the "x-after" handler.
288 x-after is emitted after a serial insn or at the end of a group of
289 parallel insns. */
290
291 static INLINE void
292 @cpu@_emit_after (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc)
293 {
294 ARGBUF *abuf = &sc[0].argbuf;
295 const IDESC *id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_AFTER];
296
297 @cpu@_fill_argbuf (current_cpu, abuf, id, pc, 0);
298 /* no need to set trace_p,profile_p */
299 }
300
301 #endif /* WITH_SCACHE_PBB */
302
303 EOF
304
305 ${SHELL} $infile support
306
307 ##########################################################################
308
309 # Simple engine: fetch an instruction, execute the instruction.
310
311 if [ x$scache != xyes -a x$pbb != xyes ] ; then
312
313 cat << EOF
314
315 #define FAST_P 0
316
317 void
318 @cpu@_engine_run_full (SIM_CPU *current_cpu)
319 {
320 #define FAST_P 0
321 SIM_DESC current_state = CPU_STATE (current_cpu);
322 SCACHE cache[MAX_LIW_INSNS];
323 SCACHE *sc = &cache[0];
324 IADDR pc;
325
326 EOF
327
328 if [ x$parallel = xyes ] ; then
329 cat << EOF
330 PAREXEC pbufs[MAX_PARALLEL_INSNS];
331 PAREXEC *par_exec;
332
333 EOF
334 fi
335
336 # Any initialization code before looping starts.
337 # Note that this code may declare some locals.
338 ${SHELL} $infile init
339
340 if [ x$parallel = xyes ] ; then
341 cat << EOF
342
343 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
344 {
345 if (! CPU_IDESC_READ_INIT_P (current_cpu))
346 {
347 /* ??? Later maybe paste read.c in when building mainloop.c. */
348 #define DEFINE_LABELS
349 #include "readx.c"
350 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
351 }
352 }
353 #endif
354
355 EOF
356 fi
357
358 cat << EOF
359
360 #if WITH_SEM_SWITCH_FULL && defined (__GNUC__)
361 {
362 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
363 {
364 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
365 #define DEFINE_LABELS
366 #include "$switch"
367 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
368 }
369 }
370 #endif
371
372 pc = GET_H_PC ();
373
374 do
375 {
376 /* begin full-{extract,exec}-simple */
377 EOF
378
379 ${SHELL} $infile extract-simple
380 echo ""
381 ${SHELL} $infile full-exec-simple
382
383 cat << EOF
384 /* end full-{extract,exec}-simple */
385
386 ++ CPU_INSN_COUNT (current_cpu);
387 }
388 while (0 /*CPU_RUNNING_P (current_cpu)*/);
389 #undef FAST_P
390 }
391
392 #undef FAST_P
393
394 EOF
395
396 ####################################
397
398 # Simple engine: fast version.
399 # ??? A somewhat dubious effort, but for completeness' sake.
400
401 if [ x$fast = xyes ] ; then
402
403 cat << EOF
404
405 #define FAST_P 1
406
407 FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh."
408
409 #undef FAST_P
410
411 EOF
412
413 fi # -fast
414
415 fi # simple engine
416
417 ##########################################################################
418
419 # Scache engine: lookup insn in scache, fetch if missing, then execute it.
420
421 if [ x$scache = xyes ] ; then
422
423 cat << EOF
424
425 static INLINE SCACHE *
426 @cpu@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
427 unsigned int hash_mask, int FAST_P)
428 {
429 /* First step: look up current insn in hash table. */
430 SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
431
432 /* If the entry isn't the one we want (cache miss),
433 fetch and decode the instruction. */
434 if (sc->argbuf.addr != vpc)
435 {
436 insn_t insn;
437
438 if (FAST_P)
439 PROFILE_COUNT_SCACHE_MISS (current_cpu);
440
441 /* begin extract-scache */
442 EOF
443
444 ${SHELL} $infile extract-scache
445
446 cat << EOF
447 /* end extract-scache */
448 }
449 else if (FAST_P)
450 {
451 PROFILE_COUNT_SCACHE_HIT (current_cpu);
452 /* Make core access statistics come out right.
453 The size is a guess, but it's currently not used either. */
454 PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
455 }
456
457 return sc;
458 }
459
460 #define FAST_P 0
461
462 void
463 @cpu@_engine_run_full (SIM_CPU *current_cpu)
464 {
465 SIM_DESC current_state = CPU_STATE (current_cpu);
466 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
467 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
468 SEM_PC vpc;
469
470 EOF
471
472 if [ x$parallel = xyes ] ; then
473 cat << EOF
474 PAREXEC pbufs[MAX_PARALLEL_INSNS];
475 PAREXEC *par_exec;
476
477 EOF
478 fi
479
480 # Any initialization code before looping starts.
481 # Note that this code may declare some locals.
482 ${SHELL} $infile init
483
484 if [ x$parallel = xyes ] ; then
485 cat << EOF
486
487 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
488 {
489 if (! CPU_IDESC_READ_INIT_P (current_cpu))
490 {
491 /* ??? Later maybe paste read.c in when building mainloop.c. */
492 #define DEFINE_LABELS
493 #include "readx.c"
494 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
495 }
496 }
497 #endif
498
499 EOF
500 fi
501
502 cat << EOF
503
504 vpc = GET_H_PC ();
505
506 do
507 {
508 SCACHE *sc;
509
510 sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
511
512 /* begin full-exec-scache */
513 EOF
514
515 ${SHELL} $infile full-exec-scache
516
517 cat << EOF
518 /* end full-exec-scache */
519
520 SET_H_PC (vpc);
521
522 ++ CPU_INSN_COUNT (current_cpu);
523 }
524 while (0 /*CPU_RUNNING_P (current_cpu)*/);
525 }
526
527 #undef FAST_P
528
529 EOF
530
531 ####################################
532
533 # Scache engine: fast version.
534
535 if [ x$fast = xyes ] ; then
536
537 cat << EOF
538
539 #define FAST_P 1
540
541 void
542 @cpu@_engine_run_fast (SIM_CPU *current_cpu)
543 {
544 SIM_DESC current_state = CPU_STATE (current_cpu);
545 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
546 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
547 SEM_PC vpc;
548
549 EOF
550
551 if [ x$parallel = xyes ] ; then
552 cat << EOF
553 PAREXEC pbufs[MAX_PARALLEL_INSNS];
554 PAREXEC *par_exec;
555
556 EOF
557 fi
558
559 # Any initialization code before looping starts.
560 # Note that this code may declare some locals.
561 ${SHELL} $infile init
562
563 if [ x$parallel = xyes ] ; then
564 cat << EOF
565
566 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
567 {
568 if (! CPU_IDESC_READ_INIT_P (current_cpu))
569 {
570 /* ??? Later maybe paste read.c in when building mainloop.c. */
571 #define DEFINE_LABELS
572 #include "readx.c"
573 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
574 }
575 }
576 #endif
577
578 EOF
579 fi # parallel = yes
580
581 cat << EOF
582
583 #if WITH_SEM_SWITCH_FAST && defined (__GNUC__)
584 {
585 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
586 {
587 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
588 #define DEFINE_LABELS
589 #include "$switch"
590 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
591 }
592 }
593 #endif
594
595 vpc = GET_H_PC ();
596
597 do
598 {
599 SCACHE *sc;
600
601 sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
602
603 /* begin fast-exec-scache */
604 EOF
605
606 ${SHELL} $infile fast-exec-scache
607
608 cat << EOF
609 /* end fast-exec-scache */
610
611 SET_H_PC (vpc);
612
613 ++ CPU_INSN_COUNT (current_cpu);
614 }
615 while (0 /*CPU_RUNNING_P (current_cpu)*/);
616 }
617
618 #undef FAST_P
619
620 EOF
621
622 fi # -fast
623
624 fi # -scache
625
626 ##########################################################################
627
628 # Compilation engine: lookup insn in scache, extract a pbb
629 # (pseudo-basic-block) if missing, then execute the pbb.
630 # A "pbb" is a sequence of insns up to the next cti insn or until
631 # some prespecified maximum.
632 # CTI: control transfer instruction.
633
634 if [ x$pbb = xyes ] ; then
635
636 cat << EOF
637
638 /* Record address of cti terminating a pbb. */
639 #define SET_CTI_VPC(sc) do { _cti_sc = (sc); } while (0)
640 /* Record number of [real] insns in pbb. */
641 #define SET_INSN_COUNT(n) do { _insn_count = (n); } while (0)
642
643 /* Fetch and extract a pseudo-basic-block.
644 FAST_P is non-zero if no tracing/profiling/etc. is wanted. */
645
646 INLINE SEM_PC
647 @cpu@_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
648 {
649 SEM_PC new_vpc;
650 PCADDR pc;
651 SCACHE *sc;
652 int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu);
653
654 pc = GET_H_PC ();
655
656 new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
657 if (! new_vpc)
658 {
659 /* Leading '_' to avoid collision with mainloop.in. */
660 int _insn_count = 0;
661 SCACHE *orig_sc = sc;
662 SCACHE *_cti_sc = NULL;
663 int slice_insns = CPU_MAX_SLICE_INSNS (current_cpu);
664
665 /* First figure out how many instructions to compile.
666 MAX_INSNS is the size of the allocated buffer, which includes space
667 for before/after handlers if they're being used.
668 SLICE_INSNS is the maxinum number of real insns that can be
669 executed. Zero means "as many as we want". */
670 /* ??? max_insns is serving two incompatible roles.
671 1) Number of slots available in scache buffer.
672 2) Number of real insns to execute.
673 They're incompatible because there are virtual insns emitted too
674 (chain,cti-chain,before,after handlers). */
675
676 if (slice_insns == 1)
677 {
678 /* No need to worry about extra slots required for virtual insns
679 and parallel exec support because MAX_CHAIN_LENGTH is
680 guaranteed to be big enough to execute at least 1 insn! */
681 max_insns = 1;
682 }
683 else
684 {
685 /* Allow enough slop so that while compiling insns, if max_insns > 0
686 then there's guaranteed to be enough space to emit one real insn.
687 MAX_CHAIN_LENGTH is typically much longer than
688 the normal number of insns between cti's anyway. */
689 max_insns -= (1 /* one for the trailing chain insn */
690 + (FAST_P
691 ? 0
692 : (1 + MAX_PARALLEL_INSNS) /* before+after */)
693 + (MAX_PARALLEL_INSNS > 1
694 ? (MAX_PARALLEL_INSNS * 2)
695 : 0));
696
697 /* Account for before/after handlers. */
698 if (! FAST_P)
699 slice_insns *= 3;
700
701 if (slice_insns > 0
702 && slice_insns < max_insns)
703 max_insns = slice_insns;
704 }
705
706 new_vpc = sc;
707
708 /* SC,PC must be updated to point passed the last entry used.
709 SET_CTI_VPC must be called if pbb is terminated by a cti.
710 SET_INSN_COUNT must be called to record number of real insns in
711 pbb [could be computed by us of course, extra cpu but perhaps
712 negligible enough]. */
713
714 /* begin extract-pbb */
715 EOF
716
717 ${SHELL} $infile extract-pbb
718
719 cat << EOF
720 /* end extract-pbb */
721
722 /* The last one is a pseudo-insn to link to the next chain.
723 It is also used to record the insn count for this chain. */
724 {
725 const IDESC *id;
726
727 /* Was pbb terminated by a cti? */
728 if (_cti_sc)
729 {
730 id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_CTI_CHAIN];
731 }
732 else
733 {
734 id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_CHAIN];
735 }
736 SEM_SET_CODE (&sc->argbuf, id, FAST_P);
737 sc->argbuf.idesc = id;
738 sc->argbuf.addr = pc;
739 sc->argbuf.fields.chain.insn_count = _insn_count;
740 sc->argbuf.fields.chain.next = 0;
741 ++sc;
742 }
743
744 /* Update the pointer to the next free entry. */
745 CPU_SCACHE_NEXT_FREE (current_cpu) = sc;
746 /* Record length of chain if profiling.
747 This includes virtual insns since they count against
748 max_insns too. */
749 if (! FAST_P)
750 PROFILE_COUNT_SCACHE_CHAIN_LENGTH (current_cpu, sc - orig_sc);
751 }
752
753 return new_vpc;
754 }
755
756 /* Chain to the next block from a non-cti terminated previous block. */
757
758 INLINE SEM_PC
759 @cpu@_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
760 {
761 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
762
763 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
764
765 SET_H_PC (abuf->addr);
766
767 /* If not running forever, exit back to main loop. */
768 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
769 /* Also exit back to main loop if there's an event.
770 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
771 at the "right" time, but then that was what was asked for.
772 There is no silver bullet for simulator engines.
773 ??? Clearly this needs a cleaner interface.
774 At present it's just so Ctrl-C works. */
775 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
776 CPU_RUNNING_P (current_cpu) = 0;
777
778 /* If chained to next block, go straight to it. */
779 if (abuf->fields.chain.next)
780 return abuf->fields.chain.next;
781 /* See if next block has already been compiled. */
782 abuf->fields.chain.next = scache_lookup (current_cpu, abuf->addr);
783 if (abuf->fields.chain.next)
784 return abuf->fields.chain.next;
785 /* Nope, so next insn is a virtual insn to invoke the compiler
786 (begin a pbb). */
787 return CPU_SCACHE_PBB_BEGIN (current_cpu);
788 }
789
790 /* Chain to the next block from a cti terminated previous block.
791 NEW_VPC_PTR is one of SEM_BRANCH_UNTAKEN, SEM_BRANCH_UNCACHEABLE, or
792 a pointer to a location containing the SEM_PC of the branch's address.
793 NEW_PC is the target's branch address, and is only valid if
794 NEW_VPC_PTR != SEM_BRANCH_UNTAKEN. */
795
796 INLINE SEM_PC
797 @cpu@_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
798 SEM_PC *new_vpc_ptr, PCADDR new_pc)
799 {
800 ARGBUF *abuf;
801
802 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
803
804 /* If not running forever, exit back to main loop. */
805 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
806 /* Also exit back to main loop if there's an event.
807 Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
808 at the "right" time, but then that was what was asked for.
809 There is no silver bullet for simulator engines.
810 ??? Clearly this needs a cleaner interface.
811 At present it's just so Ctrl-C works. */
812 || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
813 CPU_RUNNING_P (current_cpu) = 0;
814
815 /* Restart compiler if we branched to an uncacheable address
816 (e.g. "j reg"). */
817 if (new_vpc_ptr == SEM_BRANCH_UNCACHEABLE)
818 {
819 SET_H_PC (new_pc);
820 return CPU_SCACHE_PBB_BEGIN (current_cpu);
821 }
822
823 /* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our
824 next chain ptr. */
825 if (new_vpc_ptr == SEM_BRANCH_UNTAKEN)
826 {
827 abuf = SEM_ARGBUF (sem_arg);
828 SET_H_PC (abuf->addr);
829 new_vpc_ptr = &abuf->fields.chain.next;
830 }
831 else
832 {
833 SET_H_PC (new_pc);
834 }
835
836 /* If chained to next block, go straight to it. */
837 if (*new_vpc_ptr)
838 return *new_vpc_ptr;
839 /* See if next block has already been compiled. */
840 *new_vpc_ptr = scache_lookup (current_cpu, GET_H_PC ());
841 if (*new_vpc_ptr)
842 return *new_vpc_ptr;
843 /* Nope, so next insn is a virtual insn to invoke the compiler
844 (begin a pbb). */
845 return CPU_SCACHE_PBB_BEGIN (current_cpu);
846 }
847
848 /* x-before handler.
849 This is called before each insn. */
850
851 void
852 @cpu@_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
853 {
854 SEM_ARG sem_arg = sc;
855 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
856 int first_p = abuf->fields.before.first_p;
857 const ARGBUF *cur_abuf = SEM_ARGBUF (sc + 1);
858 const IDESC *cur_idesc = cur_abuf->idesc;
859 PCADDR pc = cur_abuf->addr;
860
861 if (ARGBUF_PROFILE_P (cur_abuf))
862 PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
863
864 /* If this isn't the first insn, finish up the previous one. */
865
866 if (! first_p)
867 {
868 if (PROFILE_MODEL_P (current_cpu))
869 {
870 const SEM_ARG prev_sem_arg = sc - 1;
871 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
872 const IDESC *prev_idesc = prev_abuf->idesc;
873 int cycles;
874
875 /* ??? May want to measure all insns if doing insn tracing. */
876 if (ARGBUF_PROFILE_P (prev_abuf))
877 {
878 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
879 @cpu@_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
880 }
881 }
882
883 TRACE_INSN_FINI (current_cpu, cur_abuf, 0 /*last_p*/);
884 }
885
886 /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */
887 if (PROFILE_MODEL_P (current_cpu)
888 && ARGBUF_PROFILE_P (cur_abuf))
889 @cpu@_model_insn_before (current_cpu, first_p);
890
891 TRACE_INSN_INIT (current_cpu, cur_abuf, first_p);
892 TRACE_INSN (current_cpu, cur_idesc->opcode, cur_abuf, cur_abuf->addr);
893 }
894
895 /* x-after handler.
896 This is called after a serial insn or at the end of a group of parallel
897 insns. */
898
899 void
900 @cpu@_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
901 {
902 SEM_ARG sem_arg = sc;
903 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
904 const SEM_ARG prev_sem_arg = sc - 1;
905 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
906
907 /* ??? May want to measure all insns if doing insn tracing. */
908 if (PROFILE_MODEL_P (current_cpu)
909 && ARGBUF_PROFILE_P (prev_abuf))
910 {
911 const IDESC *prev_idesc = prev_abuf->idesc;
912 int cycles;
913
914 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
915 @cpu@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
916 }
917 TRACE_INSN_FINI (current_cpu, prev_abuf, 1 /*last_p*/);
918 }
919
920 #define FAST_P 0
921
922 void
923 @cpu@_engine_run_full (SIM_CPU *current_cpu)
924 {
925 SIM_DESC current_state = CPU_STATE (current_cpu);
926 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
927 /* virtual program counter */
928 SEM_PC vpc;
929 #if WITH_SEM_SWITCH_FULL
930 /* For communication between cti's and cti-chain. */
931 PCADDR pbb_br_npc;
932 SEM_PC *pbb_br_npc_ptr;
933 #endif
934
935 EOF
936
937 if [ x$parallel = xyes ] ; then
938 cat << EOF
939 PAREXEC pbufs[MAX_PARALLEL_INSNS];
940 PAREXEC *par_exec = &pbufs[0];
941
942 EOF
943 fi
944
945 # Any initialization code before looping starts.
946 # Note that this code may declare some locals.
947 ${SHELL} $infile init
948
949 cat << EOF
950
951 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
952 {
953 /* ??? 'twould be nice to move this up a level and only call it once.
954 On the other hand, in the "let's go fast" case the test is only done
955 once per pbb (since we only return to the main loop at the end of
956 a pbb). And in the "let's run until we're done" case we don't return
957 until the program exits. */
958
959 #if WITH_SEM_SWITCH_FULL && defined (__GNUC__)
960 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
961 #define DEFINE_LABELS
962 #include "$switch"
963 #endif
964
965 /* Initialize the "begin (compile) a pbb" virtual insn. */
966 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
967 SEM_SET_FULL_CODE (SEM_ARGBUF (vpc),
968 & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN]);
969 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN];
970
971 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
972 }
973
974 CPU_RUNNING_P (current_cpu) = 1;
975 /* ??? In the case where we're returning to the main loop after every
976 pbb we don't want to call pbb_begin each time (which hashes on the pc
977 and does a table lookup). A way to speed this up is to save vpc
978 between calls. */
979 vpc = @cpu@_pbb_begin (current_cpu, FAST_P);
980
981 do
982 {
983 /* begin full-exec-pbb */
984 EOF
985
986 ${SHELL} $infile full-exec-pbb
987
988 cat << EOF
989 /* end full-exec-pbb */
990 }
991 while (CPU_RUNNING_P (current_cpu));
992 }
993
994 #undef FAST_P
995
996 EOF
997
998 ####################################
999
1000 # Compile engine: fast version.
1001
1002 if [ x$fast = xyes ] ; then
1003
1004 cat << EOF
1005
1006 #define FAST_P 1
1007
1008 void
1009 @cpu@_engine_run_fast (SIM_CPU *current_cpu)
1010 {
1011 SIM_DESC current_state = CPU_STATE (current_cpu);
1012 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
1013 /* virtual program counter */
1014 SEM_PC vpc;
1015 #if WITH_SEM_SWITCH_FAST
1016 /* For communication between cti's and cti-chain. */
1017 PCADDR pbb_br_npc;
1018 SEM_PC *pbb_br_npc_ptr;
1019 #endif
1020
1021 EOF
1022
1023 if [ x$parallel = xyes ] ; then
1024 cat << EOF
1025 PAREXEC pbufs[MAX_PARALLEL_INSNS];
1026 PAREXEC *par_exec = &pbufs[0];
1027
1028 EOF
1029 fi
1030
1031 # Any initialization code before looping starts.
1032 # Note that this code may declare some locals.
1033 ${SHELL} $infile init
1034
1035 cat << EOF
1036
1037 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
1038 {
1039 /* ??? 'twould be nice to move this up a level and only call it once.
1040 On the other hand, in the "let's go fast" case the test is only done
1041 once per pbb (since we only return to the main loop at the end of
1042 a pbb). And in the "let's run until we're done" case we don't return
1043 until the program exits. */
1044
1045 #if WITH_SEM_SWITCH_FAST && defined (__GNUC__)
1046 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
1047 #define DEFINE_LABELS
1048 #include "$switch"
1049 #endif
1050
1051 /* Initialize the "begin (compile) a pbb" virtual insn. */
1052 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
1053 SEM_SET_FAST_CODE (SEM_ARGBUF (vpc),
1054 & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN]);
1055 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN];
1056
1057 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
1058 }
1059
1060 CPU_RUNNING_P (current_cpu) = 1;
1061 /* ??? In the case where we're returning to the main loop after every
1062 pbb we don't want to call pbb_begin each time (which hashes on the pc
1063 and does a table lookup). A way to speed this up is to save vpc
1064 between calls. */
1065 vpc = @cpu@_pbb_begin (current_cpu, FAST_P);
1066
1067 do
1068 {
1069 /* begin fast-exec-pbb */
1070 EOF
1071
1072 ${SHELL} $infile fast-exec-pbb
1073
1074 cat << EOF
1075 /* end fast-exec-pbb */
1076 }
1077 while (CPU_RUNNING_P (current_cpu));
1078 }
1079
1080 #undef FAST_P
1081
1082 EOF
1083 fi # -fast
1084
1085 fi # -pbb
1086
1087 # Process @cpu@,@CPU@ appearing in mainloop.in.
1088 sed -e "s/@cpu@/$cpu/g" -e "s/@CPU@/$CPU/g" < tmp-mloop.cin > mloop.cin
1089 rc=$?
1090 rm -f tmp-mloop.cin
1091
1092 exit $rc