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