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