]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/common/genmloop.sh
* genmloop.sh (eng.hin): Rename HAVE_PARALLEL_EXEC to
[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 echo ""
213 echo "extern SEM_PC ${cpu}_pbb_begin (SIM_CPU *, int);"
214 echo "extern SEM_PC ${cpu}_pbb_chain (SIM_CPU *, SEM_ARG);"
215 echo "extern SEM_PC ${cpu}_pbb_cti_chain (SIM_CPU *, SEM_ARG, SEM_PC *, PCADDR);"
216 echo "extern void ${cpu}_pbb_before (SIM_CPU *, SCACHE *);"
217 echo "extern void ${cpu}_pbb_after (SIM_CPU *, SCACHE *);"
218
219 ##########################################################################
220
221 rm -f tmp-mloop.cin mloop.cin
222 exec 1>tmp-mloop.cin
223
224 # We use @cpu@ instead of ${cpu} because we still want to run sed to handle
225 # transformation of @cpu@ for mainloop.in.
226
227 cat << EOF
228 /* This file is generated by the genmloop script. DO NOT EDIT! */
229
230 /* Enable switch() support in cgen headers. */
231 #define SEM_IN_SWITCH
232
233 #define WANT_CPU
234 #define WANT_CPU_${CPU}
235
236 #include "sim-main.h"
237 #include "bfd.h"
238 #include "cgen-mem.h"
239 #include "cgen-ops.h"
240 #include "cpu-opc.h"
241 #include "cpu-sim.h"
242 #include "sim-assert.h"
243
244 EOF
245
246 ${SHELL} $infile support
247
248 ##########################################################################
249
250 # Simple engine: fetch an instruction, execute the instruction.
251
252 if [ x$scache != xyes -a x$pbb != xyes ] ; then
253
254 cat << EOF
255
256 #define FAST_P 0
257
258 void
259 ${cpu}_engine_run_full (SIM_CPU *current_cpu)
260 {
261 #define FAST_P 0
262 SIM_DESC current_state = CPU_STATE (current_cpu);
263 SCACHE cache[MAX_LIW_INSNS];
264 SCACHE *sc = &cache[0];
265
266 EOF
267
268 if [ x$parallel = xyes ] ; then
269 cat << EOF
270 PAREXEC pbufs[MAX_PARALLEL_INSNS];
271 PAREXEC *par_exec;
272
273 EOF
274 fi
275
276 # Any initialization code before looping starts.
277 # Note that this code may declare some locals.
278 ${SHELL} $infile init
279
280 if [ x$parallel = xyes ] ; then
281 cat << EOF
282
283 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
284 {
285 if (! CPU_IDESC_READ_INIT_P (current_cpu))
286 {
287 /* ??? Later maybe paste read.c in when building mainloop.c. */
288 #define DEFINE_LABELS
289 #include "readx.c"
290 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
291 }
292 }
293 #endif
294
295 EOF
296 fi
297
298 cat << EOF
299
300 do
301 {
302 /* begin full-{extract,exec}-simple */
303 EOF
304
305 ${SHELL} $infile extract-simple
306 echo ""
307 ${SHELL} $infile full-exec-simple
308
309 cat << EOF
310 /* end full-{extract,exec}-simple */
311
312 ++ CPU_INSN_COUNT (current_cpu);
313 }
314 while (0 /*CPU_RUNNING_P (current_cpu)*/);
315 #undef FAST_P
316 }
317
318 #undef FAST_P
319
320 EOF
321
322 ####################################
323
324 # Simple engine: fast version.
325 # ??? A somewhat dubious effort, but for completeness' sake.
326
327 if [ x$fast = xyes ] ; then
328
329 cat << EOF
330
331 #define FAST_P 1
332
333 FIXME
334
335 #undef FAST_P
336
337 EOF
338
339 fi # -fast
340
341 fi # simple engine
342
343 ##########################################################################
344
345 # Scache engine: lookup insn in scache, fetch if missing, then execute it.
346
347 if [ x$scache = xyes ] ; then
348
349 cat << EOF
350
351 static INLINE SCACHE *
352 ${cpu}_scache_lookup (SIM_CPU *current_cpu, SCACHE *scache,
353 unsigned int hash_mask, int FAST_P)
354 {
355 /* First step: look up current insn in hash table. */
356 PCADDR pc = PC;
357 SCACHE *sc = scache + SCACHE_HASH_PC (pc, hash_mask);
358
359 /* If the entry isn't the one we want (cache miss),
360 fetch and decode the instruction. */
361 if (sc->argbuf.addr != pc)
362 {
363 insn_t insn;
364
365 if (FAST_P)
366 PROFILE_COUNT_SCACHE_MISS (current_cpu);
367
368 /* begin extract-scache */
369 EOF
370
371 ${SHELL} $infile extract-scache
372
373 cat << EOF
374 /* end extract-scache */
375 }
376 else if (FAST_P)
377 {
378 PROFILE_COUNT_SCACHE_HIT (current_cpu);
379 /* Make core access statistics come out right.
380 The size is a guess, but it's currently not used either. */
381 PROFILE_COUNT_CORE (current_cpu, pc, 2, exec_map);
382 }
383 }
384
385 #define FAST_P 0
386
387 void
388 ${cpu}_engine_run_full (SIM_CPU *current_cpu)
389 {
390 SIM_DESC current_state = CPU_STATE (current_cpu);
391 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
392 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
393
394 EOF
395
396 if [ x$parallel = xyes ] ; then
397 cat << EOF
398 PAREXEC pbufs[MAX_PARALLEL_INSNS];
399 PAREXEC *par_exec;
400
401 EOF
402 fi
403
404 # Any initialization code before looping starts.
405 # Note that this code may declare some locals.
406 ${SHELL} $infile init
407
408 if [ x$parallel = xyes ] ; then
409 cat << EOF
410
411 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
412 {
413 if (! CPU_IDESC_READ_INIT_P (current_cpu))
414 {
415 /* ??? Later maybe paste read.c in when building mainloop.c. */
416 #define DEFINE_LABELS
417 #include "readx.c"
418 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
419 }
420 }
421 #endif
422
423 EOF
424 fi
425
426 cat << EOF
427
428 do
429 {
430 PCADDR new_pc;
431 SCACHE *sc;
432
433 sc = ${cpu}_scache_lookup (current_cpu, scache, hash_mask, FAST_P);
434
435 /* begin full-exec-scache */
436 EOF
437
438 ${SHELL} $infile full-exec-scache
439
440 cat << EOF
441 /* end full-exec-scache */
442
443 CPU (h_pc) = new_pc;
444
445 ++ CPU_INSN_COUNT (current_cpu);
446 }
447 while (0 /*CPU_RUNNING_P (current_cpu)*/);
448 }
449
450 #undef FAST_P
451
452 EOF
453
454 ####################################
455
456 # Scache engine: fast version.
457
458 if [ x$fast = xyes ] ; then
459
460 cat << EOF
461
462 #define FAST_P 1
463
464 void
465 ${cpu}_engine_run_fast (SIM_CPU *current_cpu)
466 {
467 SIM_DESC current_state = CPU_STATE (current_cpu);
468 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
469 unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
470
471 EOF
472
473 if [ x$parallel = xyes ] ; then
474 cat << EOF
475 PAREXEC pbufs[MAX_PARALLEL_INSNS];
476 PAREXEC *par_exec;
477
478 EOF
479 fi
480
481 # Any initialization code before looping starts.
482 # Note that this code may declare some locals.
483 ${SHELL} $infile init
484
485 if [ x$parallel = xyes ] ; then
486 cat << EOF
487
488 #if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
489 {
490 if (! CPU_IDESC_READ_INIT_P (current_cpu))
491 {
492 /* ??? Later maybe paste read.c in when building mainloop.c. */
493 #define DEFINE_LABELS
494 #include "readx.c"
495 CPU_IDESC_READ_INIT_P (current_cpu) = 1;
496 }
497 }
498 #endif
499
500 EOF
501 fi # parallel = yes
502
503 cat << EOF
504
505 #if WITH_SEM_SWITCH_FAST && defined (__GNUC__)
506 {
507 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
508 {
509 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
510 #define DEFINE_LABELS
511 #include "$switch"
512 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
513 }
514 }
515 #endif
516
517 do
518 {
519 PCADDR new_pc;
520 SCACHE *sc;
521
522 sc = ${cpu}_scache_lookup (current_cpu, scache, hash_mask, FAST_P);
523
524 /* begin fast-exec-scache */
525 EOF
526
527 ${SHELL} $infile fast-exec-scache
528
529 cat << EOF
530 /* end fast-exec-scache */
531
532 CPU (h_pc) = new_pc;
533
534 ++ CPU_INSN_COUNT (current_cpu);
535 }
536 while (0 /*CPU_RUNNING_P (current_cpu)*/);
537 }
538
539 #undef FAST_P
540
541 EOF
542
543 fi # -fast
544
545 fi # -scache
546
547 ##########################################################################
548
549 # Compilation engine: lookup insn in scache, extract a pbb
550 # (pseudo-basic-block) if missing, then execute the pbb.
551 # A "pbb" is a sequence of insns up to the next cti insn or until
552 # some prespecified maximum.
553 # CTI: control transfer instruction.
554
555 if [ x$pbb = xyes ] ; then
556
557 cat << EOF
558
559 /* Record address of cti terminating a pbb. */
560 #define SET_CTI_VPC(sc) do { cti_sc = (sc); } while (0)
561 /* Record number of [real] insns in pbb. */
562 #define SET_INSN_COUNT(n) do { insn_count = (n); } while (0)
563
564 /* Fetch and extract a pseudo-basic-block.
565 FAST_P is non-zero if no tracing/profiling/etc. is wanted. */
566
567 INLINE SEM_PC
568 ${cpu}_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
569 {
570 SEM_PC new_vpc;
571 PCADDR pc;
572 SCACHE *sc;
573 int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu);
574
575 pc = GET_H_PC ();
576
577 new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
578 if (! new_vpc)
579 {
580 int insn_count = 0;
581 SCACHE *orig_sc = sc;
582 SCACHE *cti_sc = NULL;
583 int slice_insns = CPU_MAX_SLICE_INSNS (current_cpu);
584
585 /* First figure out how many instructions to compile.
586 MAX_INSNS is the size of the allocated buffer, which includes space
587 for before/after handlers if they're being used.
588 SLICE_INSNS is the maxinum number of real insns that can be
589 executed. Zero means "as many as we want". */
590 /* ??? max_insns is serving two incompatible roles.
591 1) Number of slots available in scache buffer.
592 2) Number of real insns to execute.
593 They're incompatible because there are virtual insns emitted too
594 (chain,cti-chain,before,after handlers). */
595
596 if (slice_insns == 1)
597 {
598 /* No need to worry about extra slots required for virtual insns
599 and parallel exec support because MAX_CHAIN_LENGTH is
600 guaranteed to be big enough to execute at least 1 insn! */
601 max_insns = 1;
602 }
603 else
604 {
605 /* Allow enough slop so that while compiling insns, if max_insns > 0
606 then there's guaranteed to be enough space to emit one real insn.
607 MAX_CHAIN_LENGTH is typically much longer than
608 the normal number of insns between cti's anyway. */
609 max_insns -= (1 /* one for the trailing chain insn */
610 + (FAST_P
611 ? 0
612 : (1 + MAX_PARALLEL_INSNS) /* before+after */)
613 + (MAX_PARALLEL_INSNS > 1
614 ? (MAX_PARALLEL_INSNS * 2)
615 : 0));
616
617 /* Account for before/after handlers. */
618 if (! FAST_P)
619 slice_insns *= 3;
620
621 if (slice_insns > 0
622 && slice_insns < max_insns)
623 max_insns = slice_insns;
624 }
625
626 new_vpc = sc;
627
628 /* SC,PC must be updated to point passed the last entry used.
629 SET_CTI_VPC must be called if pbb is terminated by a cti.
630 SET_INSN_COUNT must be called to record number of real insns in
631 pbb [could be computed by us of course, extra cpu but perhaps
632 negligible enough]. */
633
634 /* begin extract-pbb */
635 EOF
636
637 ${SHELL} $infile extract-pbb
638
639 cat << EOF
640 /* end extract-pbb */
641
642 /* The last one is a pseudo-insn to link to the next chain.
643 It is also used to record the insn count for this chain. */
644 {
645 const IDESC *id;
646
647 /* Was pbb terminated by a cti? */
648 if (cti_sc)
649 {
650 id = & CPU_IDESC (current_cpu) [${CPU}_INSN_X_CTI_CHAIN];
651 }
652 else
653 {
654 id = & CPU_IDESC (current_cpu) [${CPU}_INSN_X_CHAIN];
655 }
656 SEM_SET_CODE (&sc->argbuf, id, FAST_P);
657 sc->argbuf.idesc = id;
658 sc->argbuf.addr = pc;
659 sc->argbuf.fields.chain.insn_count = insn_count;
660 sc->argbuf.fields.chain.next = 0;
661 ++sc;
662 }
663
664 /* Update the pointer to the next free entry. */
665 CPU_SCACHE_NEXT_FREE (current_cpu) = sc;
666 /* Record length of chain if profiling.
667 This includes virtual insns since they count against
668 max_insns too. */
669 if (! FAST_P)
670 PROFILE_COUNT_SCACHE_CHAIN_LENGTH (current_cpu, sc - orig_sc);
671 }
672
673 return new_vpc;
674 }
675
676 /* Chain to the next block from a non-cti terminated previous block. */
677
678 INLINE SEM_PC
679 ${cpu}_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
680 {
681 ARGBUF *abuf = SEM_ARGBUF (sem_arg);
682
683 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
684
685 SET_H_PC (abuf->addr);
686
687 /* If not running forever, exit back to main loop. */
688 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0)
689 CPU_RUNNING_P (current_cpu) = 0;
690
691 /* If chained to next block, go straight to it. */
692 if (abuf->fields.chain.next)
693 return abuf->fields.chain.next;
694 /* See if next block has already been compiled. */
695 abuf->fields.chain.next = scache_lookup (current_cpu, abuf->addr);
696 if (abuf->fields.chain.next)
697 return abuf->fields.chain.next;
698 /* Nope, so next insn is a virtual insn to invoke the compiler
699 (begin a pbb). */
700 return CPU_SCACHE_PBB_BEGIN (current_cpu);
701 }
702
703 /* Chain to the next block from a cti terminated previous block.
704 NEW_VPC_PTR is one of SEM_BRANCH_UNTAKEN, SEM_BRANCH_UNCACHEABLE, or
705 a pointer to a location containing the SEM_PC of the branch's address.
706 NEW_PC is the target's branch address, and is only valid if
707 NEW_VPC_PTR != SEM_BRANCH_UNTAKEN. */
708
709 INLINE SEM_PC
710 ${cpu}_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
711 SEM_PC *new_vpc_ptr, PCADDR new_pc)
712 {
713 ARGBUF *abuf;
714
715 PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
716
717 /* If not running forever, exit back to main loop. */
718 if (CPU_MAX_SLICE_INSNS (current_cpu) != 0)
719 CPU_RUNNING_P (current_cpu) = 0;
720
721 /* Restart compiler if we branched to an uncacheable address
722 (e.g. "j reg"). */
723 if (new_vpc_ptr == SEM_BRANCH_UNCACHEABLE)
724 {
725 SET_H_PC (new_pc);
726 return CPU_SCACHE_PBB_BEGIN (current_cpu);
727 }
728
729 /* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our
730 next chain ptr. */
731 if (new_vpc_ptr == SEM_BRANCH_UNTAKEN)
732 {
733 abuf = SEM_ARGBUF (sem_arg);
734 SET_H_PC (abuf->addr);
735 new_vpc_ptr = &abuf->fields.chain.next;
736 }
737 else
738 {
739 SET_H_PC (new_pc);
740 }
741
742 /* If chained to next block, go straight to it. */
743 if (*new_vpc_ptr)
744 return *new_vpc_ptr;
745 /* See if next block has already been compiled. */
746 *new_vpc_ptr = scache_lookup (current_cpu, GET_H_PC ());
747 if (*new_vpc_ptr)
748 return *new_vpc_ptr;
749 /* Nope, so next insn is a virtual insn to invoke the compiler
750 (begin a pbb). */
751 return CPU_SCACHE_PBB_BEGIN (current_cpu);
752 }
753
754 /* x-before handler.
755 This is called before each insn. */
756
757 void
758 ${cpu}_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
759 {
760 SEM_ARG sem_arg = sc;
761 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
762 int first_p = abuf->fields.before.first_p;
763 const ARGBUF *cur_abuf = SEM_ARGBUF (sc + 1);
764 const IDESC *cur_idesc = cur_abuf->idesc;
765 PCADDR pc = cur_abuf->addr;
766
767 PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
768
769 /* If this isn't the first insn, finish up the previous one. */
770
771 if (! first_p)
772 {
773 if (PROFILE_MODEL_P (current_cpu))
774 {
775 const SEM_ARG prev_sem_arg = sc - 1;
776 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
777 const IDESC *prev_idesc = prev_abuf->idesc;
778 int cycles;
779
780 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
781 ${cpu}_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
782 }
783
784 TRACE_INSN_FINI (current_cpu, 0 /*last_p*/);
785 }
786
787 /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */
788 if (PROFILE_MODEL_P (current_cpu))
789 ${cpu}_model_insn_before (current_cpu, first_p);
790
791 TRACE_INSN_INIT (current_cpu, first_p);
792 TRACE_INSN (current_cpu, cur_idesc->opcode, cur_abuf, cur_abuf->addr);
793 }
794
795 /* x-after handler.
796 This is called after a serial insn or at the end of a group of parallel
797 insns. */
798
799 void
800 ${cpu}_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
801 {
802 SEM_ARG sem_arg = sc;
803 const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
804
805 if (PROFILE_MODEL_P (current_cpu))
806 {
807 const SEM_ARG prev_sem_arg = sc - 1;
808 const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
809 const IDESC *prev_idesc = prev_abuf->idesc;
810 int cycles;
811
812 cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
813 ${cpu}_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
814 }
815 TRACE_INSN_FINI (current_cpu, 1 /*last_p*/);
816 }
817
818 #define FAST_P 0
819
820 void
821 ${cpu}_engine_run_full (SIM_CPU *current_cpu)
822 {
823 SIM_DESC current_state = CPU_STATE (current_cpu);
824 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
825 /* virtual program counter */
826 SEM_PC vpc;
827 #if WITH_SEM_SWITCH_FULL
828 /* For communication between cti's and cti-chain. */
829 PCADDR pbb_br_npc;
830 SEM_PC *pbb_br_npc_ptr;
831 #endif
832
833 EOF
834
835 if [ x$parallel = xyes ] ; then
836 cat << EOF
837 PAREXEC pbufs[MAX_PARALLEL_INSNS];
838 PAREXEC *par_exec = &pbufs[0];
839
840 EOF
841 fi
842
843 # Any initialization code before looping starts.
844 # Note that this code may declare some locals.
845 ${SHELL} $infile init
846
847 cat << EOF
848
849 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
850 {
851 /* ??? 'twould be nice to move this up a level and only call it once.
852 On the other hand, in the "let's go fast" case the test is only done
853 once per pbb (since we only return to the main loop at the end of
854 a pbb). And in the "let's run until we're done" case we don't return
855 until the program exits. */
856
857 #if WITH_SEM_SWITCH_FULL && defined (__GNUC__)
858 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
859 #define DEFINE_LABELS
860 #include "$switch"
861 #endif
862
863 /* Initialize the "begin (compile) a pbb" virtual insn. */
864 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
865 SEM_SET_FULL_CODE (SEM_ARGBUF (vpc),
866 & CPU_IDESC (current_cpu) [${CPU}_INSN_X_BEGIN]);
867 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [${CPU}_INSN_X_BEGIN];
868
869 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
870 }
871
872 CPU_RUNNING_P (current_cpu) = 1;
873 /* ??? In the case where we're returning to the main loop after every
874 pbb we don't want to call pbb_begin each time (which hashes on the pc
875 and does a table lookup). A way to speed this up is to save vpc
876 between calls. */
877 vpc = ${cpu}_pbb_begin (current_cpu, FAST_P);
878
879 do
880 {
881 /* begin full-exec-pbb */
882 EOF
883
884 ${SHELL} $infile full-exec-pbb
885
886 cat << EOF
887 /* end full-exec-pbb */
888 }
889 while (CPU_RUNNING_P (current_cpu));
890 }
891
892 #undef FAST_P
893
894 EOF
895
896 ####################################
897
898 # Compile engine: fast version.
899
900 if [ x$fast = xyes ] ; then
901
902 cat << EOF
903
904 #define FAST_P 1
905
906 void
907 ${cpu}_engine_run_fast (SIM_CPU *current_cpu)
908 {
909 SIM_DESC current_state = CPU_STATE (current_cpu);
910 SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
911 /* virtual program counter */
912 SEM_PC vpc;
913 #if WITH_SEM_SWITCH_FAST
914 /* For communication between cti's and cti-chain. */
915 PCADDR pbb_br_npc;
916 SEM_PC *pbb_br_npc_ptr;
917 #endif
918
919 EOF
920
921 if [ x$parallel = xyes ] ; then
922 cat << EOF
923 PAREXEC pbufs[MAX_PARALLEL_INSNS];
924 PAREXEC *par_exec = &pbufs[0];
925
926 EOF
927 fi
928
929 # Any initialization code before looping starts.
930 # Note that this code may declare some locals.
931 ${SHELL} $infile init
932
933 cat << EOF
934
935 if (! CPU_IDESC_SEM_INIT_P (current_cpu))
936 {
937 /* ??? 'twould be nice to move this up a level and only call it once.
938 On the other hand, in the "let's go fast" case the test is only done
939 once per pbb (since we only return to the main loop at the end of
940 a pbb). And in the "let's run until we're done" case we don't return
941 until the program exits. */
942
943 #if WITH_SEM_SWITCH_FAST && defined (__GNUC__)
944 /* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
945 #define DEFINE_LABELS
946 #include "$switch"
947 #endif
948
949 /* Initialize the "begin (compile) a pbb" virtual insn. */
950 vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
951 SEM_SET_FAST_CODE (SEM_ARGBUF (vpc),
952 & CPU_IDESC (current_cpu) [${CPU}_INSN_X_BEGIN]);
953 vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [${CPU}_INSN_X_BEGIN];
954
955 CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
956 }
957
958 CPU_RUNNING_P (current_cpu) = 1;
959 /* ??? In the case where we're returning to the main loop after every
960 pbb we don't want to call pbb_begin each time (which hashes on the pc
961 and does a table lookup). A way to speed this up is to save vpc
962 between calls. */
963 vpc = ${cpu}_pbb_begin (current_cpu, FAST_P);
964
965 do
966 {
967 /* begin fast-exec-pbb */
968 EOF
969
970 ${SHELL} $infile fast-exec-pbb
971
972 cat << EOF
973 /* end fast-exec-pbb */
974 }
975 while (CPU_RUNNING_P (current_cpu));
976 }
977
978 #undef FAST_P
979
980 EOF
981 fi # -fast
982
983 fi # -pbb
984
985 sed -e "s/@cpu@/$cpu/g" -e "s/@CPU@/$CPU/g" < tmp-mloop.cin > mloop.cin
986 rc=$?
987 rm -f tmp-mloop.cin
988
989 exit $rc