Update
[gdb.git] / sim / m32r / mloopx.in
blob5305d2764731c6696162723b6cd76c8b5109ce37
1 # Simulator main loop for m32rx. -*- C -*-
3 # Copyright 1996, 1997, 1998, 2004, 2007, 2008 Free Software Foundation, Inc.
5 # This file is part of the GNU Simulators.
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 # Syntax:
21 # /bin/sh mainloop.in command
23 # Command is one of:
25 # init
26 # support
27 # extract-{simple,scache,pbb}
28 # {full,fast}-exec-{simple,scache,pbb}
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.
36 # ??? After a few more ports are done, revisit.
37 # Will eventually need to machine generate a lot of this.
39 case "x$1" in
41 xsupport)
43 cat <<EOF
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).  */
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)
55   ARGBUF *abuf;
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
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)
75   ARGBUF *abuf = &sc->argbuf;
76   const IDESC *id = @cpu@_decode (current_cpu, pc, insn, insn, abuf);
78   if (parallel_p)
79     id = id->par_idesc;
80   @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
81   return id;
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)
88   const IDESC *id;
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;
98 static INLINE const IDESC *
99 emit_parallel (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn,
100                SCACHE *sc, int fast_p)
102   const IDESC *id,*id2;
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.  */
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);
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);
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);
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);
124   return id;
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)
131   const IDESC *id,*id2;
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.  */
139   @cpu@_emit_before (current_cpu, sc, pc, 1);
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;
146   @cpu@_emit_before (current_cpu, sc + 2, pc, 0);
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;
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);
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);
161   @cpu@_emit_after (current_cpu, sc + 5, pc);
163   return id;
166 static INLINE const IDESC *
167 emit_32 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn,
168          SCACHE *sc, int fast_p)
170   ARGBUF *abuf = &sc->argbuf;
171   const IDESC *id = @cpu@_decode (current_cpu, pc,
172                                   (USI) insn >> 16, insn, abuf);
174   @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
175   return id;
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)
182   const IDESC *id;
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;
196 xinit)
198 # Nothing needed.
202 xextract-pbb)
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.
212 cat <<EOF
214   const IDESC *idesc;
215   int icount = 0;
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 */
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
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     }
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.  */
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                   int up_count;
294                   if (((insn >> 16) & 0xfff0) == 0x10f0)
295                     {
296                       /* FIXME: No need to handle this sequentially if system
297                          calls will be able to execute after second insn in
298                          parallel. ( trap #num || insn ) */
299                       /* insn */
300                       idesc = emit_16 (current_cpu, pc + 2, insn & 0x7fff,
301                                        sc, 1, 0);
302                       /* trap */
303                       emit_16 (current_cpu, pc, insn >> 16, sc + 1, 1, 0);
304                       up_count = 2;
305                     }
306                   else
307                     {
308                       /* Yep.  Here's the "interesting" [sic] part.  */
309                       idesc = emit_parallel (current_cpu, pc, insn, sc, 1);
310                       up_count = 3;
311                     }
312                   sc += up_count;
313                   max_insns -= up_count;
314                   icount += 2;
315                   pc += 4;
316                   if (IDESC_CTI_P (idesc))
317                     {
318                       SET_CTI_VPC (sc - up_count);
319                       break;
320                     }
321                 }
322               else /* 2 serial 16 bit insns */
323                 {
324                   idesc = emit_16 (current_cpu, pc, insn >> 16, sc, 1, 0);
325                   ++sc;
326                   --max_insns;
327                   ++icount;
328                   pc += 2;
329                   if (IDESC_CTI_P (idesc))
330                     {
331                       SET_CTI_VPC (sc - 1);
332                       break;
333                     }
334                   /* While we're guaranteed that there's room to extract the
335                      insn, when single stepping we can't; the pbb must stop
336                      after the first insn.  */
337                   if (max_insns == 0)
338                     break;
339                   idesc = emit_16 (current_cpu, pc, insn & 0x7fff, sc, 1, 0);
340                   ++sc;
341                   --max_insns;
342                   ++icount;
343                   pc += 2;
344                   if (IDESC_CTI_P (idesc))
345                     {
346                       SET_CTI_VPC (sc - 1);
347                       break;
348                     }
349                 }
350             }
351         }
352     }
353   else /* ! FAST_P */
354     {
355       while (max_insns > 0)
356         {
357           USI insn = GETIMEMUSI (current_cpu, pc);
358           int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc);
359           int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc);
360           SCACHE *cti_sc; /* ??? tmp hack */
361           if ((SI) insn < 0)
362             {
363               /* 32 bit insn
364                  Only emit before/after handlers if necessary.  */
365               if (trace_p || profile_p)
366                 {
367                   idesc = emit_full32 (current_cpu, pc, insn, sc,
368                                        trace_p, profile_p);
369                   cti_sc = sc + 1;
370                   sc += 3;
371                   max_insns -= 3;
372                 }
373               else
374                 {
375                   idesc = emit_32 (current_cpu, pc, insn, sc, 0);
376                   cti_sc = sc;
377                   ++sc;
378                   --max_insns;
379                 }
380               ++icount;
381               pc += 4;
382               if (IDESC_CTI_P (idesc))
383                 {
384                   SET_CTI_VPC (cti_sc);
385                   break;
386                 }
387             }
388           else
389             {
390               if ((insn & 0x8000) != 0) /* parallel? */
391                 {
392                   /* Yep.  Here's the "interesting" [sic] part.
393                      Only emit before/after handlers if necessary.  */
394                   if (trace_p || profile_p)
395                     {
396                       if (((insn >> 16) & 0xfff0) == 0x10f0)
397                         {
398                           /* FIXME: No need to handle this sequentially if
399                              system calls will be able to execute after second
400                              insn in parallel. ( trap #num || insn ) */
401                           /* insn */
402                           idesc = emit_full16 (current_cpu, pc + 2,
403                                                insn & 0x7fff, sc, 0, 0);
404                           /* trap */
405                           emit_full16 (current_cpu, pc, insn >> 16, sc + 3,
406                                        0, 0);
407                         }
408                       else
409                         {
410                           idesc = emit_full_parallel (current_cpu, pc, insn,
411                                                       sc, trace_p, profile_p);
412                         }
413                       cti_sc = sc + 1;
414                       sc += 6;
415                       max_insns -= 6;
416                     }
417                   else
418                     {
419                       int up_count;
421                       if (((insn >> 16) & 0xfff0) == 0x10f0)
422                         {
423                           /* FIXME: No need to handle this sequentially if
424                              system calls will be able to execute after second
425                              insn in parallel. ( trap #num || insn ) */
426                           /* insn */
427                           idesc = emit_16 (current_cpu, pc + 2, insn & 0x7fff,
428                                            sc, 0, 0);
429                           /* trap */
430                           emit_16 (current_cpu, pc, insn >> 16, sc + 1, 0, 0);
431                           up_count = 2;
432                         }
433                       else
434                         {
435                           idesc = emit_parallel (current_cpu, pc, insn, sc, 0);
436                           up_count = 3;
437                         }
438                       cti_sc = sc;
439                       sc += up_count;
440                       max_insns -= up_count;
441                     }
442                   icount += 2;
443                   pc += 4;
444                   if (IDESC_CTI_P (idesc))
445                     {
446                       SET_CTI_VPC (cti_sc);
447                       break;
448                     }
449                 }
450               else /* 2 serial 16 bit insns */
451                 {
452                   /* Only emit before/after handlers if necessary.  */
453                   if (trace_p || profile_p)
454                     {
455                       idesc = emit_full16 (current_cpu, pc, insn >> 16, sc,
456                                            trace_p, profile_p);
457                       cti_sc = sc + 1;
458                       sc += 3;
459                       max_insns -= 3;
460                     }
461                   else
462                     {
463                       idesc = emit_16 (current_cpu, pc, insn >> 16, sc, 0, 0);
464                       cti_sc = sc;
465                       ++sc;
466                       --max_insns;
467                     }
468                   ++icount;
469                   pc += 2;
470                   if (IDESC_CTI_P (idesc))
471                     {
472                       SET_CTI_VPC (cti_sc);
473                       break;
474                     }
475                   /* While we're guaranteed that there's room to extract the
476                      insn, when single stepping we can't; the pbb must stop
477                      after the first insn.  */
478                   if (max_insns <= 0)
479                     break;
480                   /* Use the same trace/profile address for the 2nd insn.
481                      Saves us having to compute it and they come in pairs
482                      anyway (e.g. can never branch to the 2nd insn).  */
483                   if (trace_p || profile_p)
484                     {
485                       idesc = emit_full16 (current_cpu, pc, insn & 0x7fff, sc,
486                                            trace_p, profile_p);
487                       cti_sc = sc + 1;
488                       sc += 3;
489                       max_insns -= 3;
490                     }
491                   else
492                     {
493                       idesc = emit_16 (current_cpu, pc, insn & 0x7fff, sc, 0, 0);
494                       cti_sc = sc;
495                       ++sc;
496                       --max_insns;
497                     }
498                   ++icount;
499                   pc += 2;
500                   if (IDESC_CTI_P (idesc))
501                     {
502                       SET_CTI_VPC (cti_sc);
503                       break;
504                     }
505                 }
506             }
507         }
508     }
510  Finish:
511   SET_INSN_COUNT (icount);
517 xfull-exec-pbb)
519 # Inputs: current_cpu, vpc, FAST_P
520 # Outputs: vpc
521 # vpc is the virtual program counter.
523 cat <<EOF
524 #define DEFINE_SWITCH
525 #include "semx-switch.c"
531   echo "Invalid argument to mainloop.in: $1" >&2
532   exit 1
533   ;;
535 esac