import gdb-1999-10-11 snapshot
[deliverable/binutils-gdb.git] / sim / m32r / mloopx.in
1 # Simulator main loop for m32rx. -*- C -*-
2 # Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
3 #
4 # This file is part of the GNU Simulators.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2, or (at your option)
9 # any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along
17 # with this program; if not, write to the Free Software Foundation, Inc.,
18 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 # Syntax:
21 # /bin/sh mainloop.in command
22 #
23 # Command is one of:
24 #
25 # init
26 # support
27 # extract-{simple,scache,pbb}
28 # {full,fast}-exec-{simple,scache,pbb}
29 #
30 # A target need only provide a "full" version of one of simple,scache,pbb.
31 # If the target wants it can also provide a fast version of same, or if
32 # the slow (full featured) version is `simple', then the fast version can be
33 # one of scache/pbb.
34 # A target can't provide more than this.
35
36 # ??? After a few more ports are done, revisit.
37 # Will eventually need to machine generate a lot of this.
38
39 case "x$1" in
40
41 xsupport)
42
43 cat <<EOF
44
45 /* Emit insns to write back the results of insns executed in parallel.
46 SC points to a sufficient number of scache entries for the writeback
47 handlers.
48 SC1/ID1 is the first insn (left slot, lower address).
49 SC2/ID2 is the second insn (right slot, higher address). */
50
51 static INLINE void
52 emit_par_finish (SIM_CPU *current_cpu, PCADDR pc, SCACHE *sc,
53 SCACHE *sc1, const IDESC *id1, SCACHE *sc2, const IDESC *id2)
54 {
55 ARGBUF *abuf;
56
57 abuf = &sc->argbuf;
58 id1 = id1->par_idesc;
59 abuf->fields.write.abuf = &sc1->argbuf;
60 @cpu@_fill_argbuf (current_cpu, abuf, id1, pc, 0);
61 /* no need to set trace_p,profile_p */
62 #if 0 /* not currently needed for id2 since results written directly */
63 abuf = &sc[1].argbuf;
64 id2 = id2->par_idesc;
65 abuf->fields.write.abuf = &sc2->argbuf;
66 @cpu@_fill_argbuf (current_cpu, abuf, id2, pc + 2, 0);
67 /* no need to set trace_p,profile_p */
68 #endif
69 }
70
71 static INLINE const IDESC *
72 emit_16 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn,
73 SCACHE *sc, int fast_p, int parallel_p)
74 {
75 ARGBUF *abuf = &sc->argbuf;
76 const IDESC *id = @cpu@_decode (current_cpu, pc, insn, insn, abuf);
77
78 if (parallel_p)
79 id = id->par_idesc;
80 @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
81 return id;
82 }
83
84 static INLINE const IDESC *
85 emit_full16 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, SCACHE *sc,
86 int trace_p, int profile_p)
87 {
88 const IDESC *id;
89
90 @cpu@_emit_before (current_cpu, sc, pc, 1);
91 id = emit_16 (current_cpu, pc, insn, sc + 1, 0, 0);
92 @cpu@_emit_after (current_cpu, sc + 2, pc);
93 sc[1].argbuf.trace_p = trace_p;
94 sc[1].argbuf.profile_p = profile_p;
95 return id;
96 }
97
98 static INLINE const IDESC *
99 emit_parallel (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn,
100 SCACHE *sc, int fast_p)
101 {
102 const IDESC *id,*id2;
103
104 /* Emit both insns, then emit a finisher-upper.
105 We speed things up by handling the second insn serially
106 [not parallelly]. Then the writeback only has to deal
107 with the first insn. */
108 /* ??? Revisit to handle exceptions right. */
109
110 /* FIXME: No need to handle this parallely if second is nop. */
111 id = emit_16 (current_cpu, pc, insn >> 16, sc, fast_p, 1);
112
113 /* Note that this can never be a cti. No cti's go in the S pipeline. */
114 id2 = emit_16 (current_cpu, pc + 2, insn & 0x7fff, sc + 1, fast_p, 0);
115
116 /* Set sc/snc insns notion of where to skip to. */
117 if (IDESC_SKIP_P (id))
118 SEM_SKIP_COMPILE (current_cpu, sc, 1);
119
120 /* Emit code to finish executing the semantics
121 (write back the results). */
122 emit_par_finish (current_cpu, pc, sc + 2, sc, id, sc + 1, id2);
123
124 return id;
125 }
126
127 static INLINE const IDESC *
128 emit_full_parallel (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn,
129 SCACHE *sc, int trace_p, int profile_p)
130 {
131 const IDESC *id,*id2;
132
133 /* Emit both insns, then emit a finisher-upper.
134 We speed things up by handling the second insn serially
135 [not parallelly]. Then the writeback only has to deal
136 with the first insn. */
137 /* ??? Revisit to handle exceptions right. */
138
139 @cpu@_emit_before (current_cpu, sc, pc, 1);
140
141 /* FIXME: No need to handle this parallelly if second is nop. */
142 id = emit_16 (current_cpu, pc, insn >> 16, sc + 1, 0, 1);
143 sc[1].argbuf.trace_p = trace_p;
144 sc[1].argbuf.profile_p = profile_p;
145
146 @cpu@_emit_before (current_cpu, sc + 2, pc, 0);
147
148 /* Note that this can never be a cti. No cti's go in the S pipeline. */
149 id2 = emit_16 (current_cpu, pc + 2, insn & 0x7fff, sc + 3, 0, 0);
150 sc[3].argbuf.trace_p = trace_p;
151 sc[3].argbuf.profile_p = profile_p;
152
153 /* Set sc/snc insns notion of where to skip to. */
154 if (IDESC_SKIP_P (id))
155 SEM_SKIP_COMPILE (current_cpu, sc, 4);
156
157 /* Emit code to finish executing the semantics
158 (write back the results). */
159 emit_par_finish (current_cpu, pc, sc + 4, sc + 1, id, sc + 3, id2);
160
161 @cpu@_emit_after (current_cpu, sc + 5, pc);
162
163 return id;
164 }
165
166 static INLINE const IDESC *
167 emit_32 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn,
168 SCACHE *sc, int fast_p)
169 {
170 ARGBUF *abuf = &sc->argbuf;
171 const IDESC *id = @cpu@_decode (current_cpu, pc,
172 (USI) insn >> 16, insn, abuf);
173
174 @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
175 return id;
176 }
177
178 static INLINE const IDESC *
179 emit_full32 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, SCACHE *sc,
180 int trace_p, int profile_p)
181 {
182 const IDESC *id;
183
184 @cpu@_emit_before (current_cpu, sc, pc, 1);
185 id = emit_32 (current_cpu, pc, insn, sc + 1, 0);
186 @cpu@_emit_after (current_cpu, sc + 2, pc);
187 sc[1].argbuf.trace_p = trace_p;
188 sc[1].argbuf.profile_p = profile_p;
189 return id;
190 }
191
192 EOF
193
194 ;;
195
196 xinit)
197
198 # Nothing needed.
199
200 ;;
201
202 xextract-pbb)
203
204 # Inputs: current_cpu, pc, sc, max_insns, FAST_P
205 # Outputs: sc, pc
206 # sc must be left pointing past the last created entry.
207 # pc must be left pointing past the last created entry.
208 # If the pbb is terminated by a cti insn, SET_CTI_VPC(sc) must be called
209 # to record the vpc of the cti insn.
210 # SET_INSN_COUNT(n) must be called to record number of real insns.
211
212 cat <<EOF
213 {
214 const IDESC *idesc;
215 int icount = 0;
216
217 if ((pc & 3) != 0)
218 {
219 /* This occurs when single stepping and when compiling the not-taken
220 part of conditional branches. */
221 UHI insn = GETIMEMUHI (current_cpu, pc);
222 int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc);
223 int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc);
224 SCACHE *cti_sc; /* ??? tmp hack */
225
226 /* A parallel insn isn't allowed here, but we don't mind nops.
227 ??? We need to wait until the insn is executed before signalling
228 the error, for situations where such signalling is wanted. */
229 #if 0
230 if ((insn & 0x8000) != 0
231 && (insn & 0x7fff) != 0x7000) /* parallel nops are ok */
232 sim_engine_invalid_insn (current_cpu, pc, 0);
233 #endif
234
235 /* Only emit before/after handlers if necessary. */
236 if (FAST_P || (! trace_p && ! profile_p))
237 {
238 idesc = emit_16 (current_cpu, pc, insn & 0x7fff, sc, FAST_P, 0);
239 cti_sc = sc;
240 ++sc;
241 --max_insns;
242 }
243 else
244 {
245 idesc = emit_full16 (current_cpu, pc, insn & 0x7fff, sc,
246 trace_p, profile_p);
247 cti_sc = sc + 1;
248 sc += 3;
249 max_insns -= 3;
250 }
251 ++icount;
252 pc += 2;
253 if (IDESC_CTI_P (idesc))
254 {
255 SET_CTI_VPC (cti_sc);
256 goto Finish;
257 }
258 }
259
260 /* There are two copies of the compiler: full(!fast) and fast.
261 The "full" case emits before/after handlers for each insn.
262 Having two copies of this code is a tradeoff, having one copy
263 seemed a bit more difficult to read (due to constantly testing
264 FAST_P). ??? On the other hand, with address ranges we'll want to
265 omit before/after handlers for unwanted insns. Having separate loops
266 for FAST/!FAST avoids constantly doing the test in the loop, but
267 typically FAST_P is a constant and such tests will get optimized out. */
268
269 if (FAST_P)
270 {
271 while (max_insns > 0)
272 {
273 USI insn = GETIMEMUSI (current_cpu, pc);
274 if ((SI) insn < 0)
275 {
276 /* 32 bit insn */
277 idesc = emit_32 (current_cpu, pc, insn, sc, 1);
278 ++sc;
279 --max_insns;
280 ++icount;
281 pc += 4;
282 if (IDESC_CTI_P (idesc))
283 {
284 SET_CTI_VPC (sc - 1);
285 break;
286 }
287 }
288 else
289 {
290 if ((insn & 0x8000) != 0) /* parallel? */
291 {
292 /* Yep. Here's the "interesting" [sic] part. */
293 idesc = emit_parallel (current_cpu, pc, insn, sc, 1);
294 sc += 3;
295 max_insns -= 3;
296 icount += 2;
297 pc += 4;
298 if (IDESC_CTI_P (idesc))
299 {
300 SET_CTI_VPC (sc - 3);
301 break;
302 }
303 }
304 else /* 2 serial 16 bit insns */
305 {
306 idesc = emit_16 (current_cpu, pc, insn >> 16, sc, 1, 0);
307 ++sc;
308 --max_insns;
309 ++icount;
310 pc += 2;
311 if (IDESC_CTI_P (idesc))
312 {
313 SET_CTI_VPC (sc - 1);
314 break;
315 }
316 /* While we're guaranteed that there's room to extract the
317 insn, when single stepping we can't; the pbb must stop
318 after the first insn. */
319 if (max_insns == 0)
320 break;
321 idesc = emit_16 (current_cpu, pc, insn & 0x7fff, sc, 1, 0);
322 ++sc;
323 --max_insns;
324 ++icount;
325 pc += 2;
326 if (IDESC_CTI_P (idesc))
327 {
328 SET_CTI_VPC (sc - 1);
329 break;
330 }
331 }
332 }
333 }
334 }
335 else /* ! FAST_P */
336 {
337 while (max_insns > 0)
338 {
339 USI insn = GETIMEMUSI (current_cpu, pc);
340 int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc);
341 int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc);
342 SCACHE *cti_sc; /* ??? tmp hack */
343 if ((SI) insn < 0)
344 {
345 /* 32 bit insn
346 Only emit before/after handlers if necessary. */
347 if (trace_p || profile_p)
348 {
349 idesc = emit_full32 (current_cpu, pc, insn, sc,
350 trace_p, profile_p);
351 cti_sc = sc + 1;
352 sc += 3;
353 max_insns -= 3;
354 }
355 else
356 {
357 idesc = emit_32 (current_cpu, pc, insn, sc, 0);
358 cti_sc = sc;
359 ++sc;
360 --max_insns;
361 }
362 ++icount;
363 pc += 4;
364 if (IDESC_CTI_P (idesc))
365 {
366 SET_CTI_VPC (cti_sc);
367 break;
368 }
369 }
370 else
371 {
372 if ((insn & 0x8000) != 0) /* parallel? */
373 {
374 /* Yep. Here's the "interesting" [sic] part.
375 Only emit before/after handlers if necessary. */
376 if (trace_p || profile_p)
377 {
378 idesc = emit_full_parallel (current_cpu, pc, insn, sc,
379 trace_p, profile_p);
380 cti_sc = sc + 1;
381 sc += 6;
382 max_insns -= 6;
383 }
384 else
385 {
386 idesc = emit_parallel (current_cpu, pc, insn, sc, 0);
387 cti_sc = sc;
388 sc += 3;
389 max_insns -= 3;
390 }
391 icount += 2;
392 pc += 4;
393 if (IDESC_CTI_P (idesc))
394 {
395 SET_CTI_VPC (cti_sc);
396 break;
397 }
398 }
399 else /* 2 serial 16 bit insns */
400 {
401 /* Only emit before/after handlers if necessary. */
402 if (trace_p || profile_p)
403 {
404 idesc = emit_full16 (current_cpu, pc, insn >> 16, sc,
405 trace_p, profile_p);
406 cti_sc = sc + 1;
407 sc += 3;
408 max_insns -= 3;
409 }
410 else
411 {
412 idesc = emit_16 (current_cpu, pc, insn >> 16, sc, 0, 0);
413 cti_sc = sc;
414 ++sc;
415 --max_insns;
416 }
417 ++icount;
418 pc += 2;
419 if (IDESC_CTI_P (idesc))
420 {
421 SET_CTI_VPC (cti_sc);
422 break;
423 }
424 /* While we're guaranteed that there's room to extract the
425 insn, when single stepping we can't; the pbb must stop
426 after the first insn. */
427 if (max_insns <= 0)
428 break;
429 /* Use the same trace/profile address for the 2nd insn.
430 Saves us having to compute it and they come in pairs
431 anyway (e.g. can never branch to the 2nd insn). */
432 if (trace_p || profile_p)
433 {
434 idesc = emit_full16 (current_cpu, pc, insn & 0x7fff, sc,
435 trace_p, profile_p);
436 cti_sc = sc + 1;
437 sc += 3;
438 max_insns -= 3;
439 }
440 else
441 {
442 idesc = emit_16 (current_cpu, pc, insn & 0x7fff, sc, 0, 0);
443 cti_sc = sc;
444 ++sc;
445 --max_insns;
446 }
447 ++icount;
448 pc += 2;
449 if (IDESC_CTI_P (idesc))
450 {
451 SET_CTI_VPC (cti_sc);
452 break;
453 }
454 }
455 }
456 }
457 }
458
459 Finish:
460 SET_INSN_COUNT (icount);
461 }
462 EOF
463
464 ;;
465
466 xfull-exec-pbb)
467
468 # Inputs: current_cpu, vpc, FAST_P
469 # Outputs: vpc
470 # vpc is the virtual program counter.
471
472 cat <<EOF
473 #define DEFINE_SWITCH
474 #include "semx-switch.c"
475 EOF
476
477 ;;
478
479 *)
480 echo "Invalid argument to mainloop.in: $1" >&2
481 exit 1
482 ;;
483
484 esac
This page took 0.059094 seconds and 4 git commands to generate.