import gdb-1999-10-11 snapshot
[external/binutils.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