genmloop.sh revision 1.11 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