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