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