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