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