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