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