arm: Support pac_key_* register operand for MRS/MSR in Armv8.1-M Mainline
[binutils-gdb.git] / sim / m32r / mloop2.in
blob202bdd1d5040486061ee2dc731ef719f898f7bb4
1 # Simulator main loop for m32r2. -*- C -*-
3 # Copyright 1996-2024 Free Software Foundation, Inc.
5 # This file is part of GDB, the GNU debugger.
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
44 #line $LINENO "$0"
46 /* Emit insns to write back the results of insns executed in parallel.
47    SC points to a sufficient number of scache entries for the writeback
48    handlers.
49    SC1/ID1 is the first insn (left slot, lower address).
50    SC2/ID2 is the second insn (right slot, higher address).  */
52 static INLINE void
53 emit_par_finish (SIM_CPU *current_cpu, PCADDR pc, SCACHE *sc,
54                  SCACHE *sc1, const IDESC *id1, SCACHE *sc2, const IDESC *id2)
56   ARGBUF *abuf;
58   abuf = &sc->argbuf;
59   id1 = id1->par_idesc;
60   abuf->fields.write.abuf = &sc1->argbuf;
61   @cpu@_fill_argbuf (current_cpu, abuf, id1, pc, 0);
62   /* no need to set trace_p,profile_p */
63 #if 0 /* not currently needed for id2 since results written directly */
64   abuf = &sc[1].argbuf;
65   id2 = id2->par_idesc;
66   abuf->fields.write.abuf = &sc2->argbuf;
67   @cpu@_fill_argbuf (current_cpu, abuf, id2, pc + 2, 0);
68   /* no need to set trace_p,profile_p */
69 #endif
72 static INLINE const IDESC *
73 emit_16 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn,
74          SCACHE *sc, int fast_p, int parallel_p)
76   ARGBUF *abuf = &sc->argbuf;
77   const IDESC *id = @cpu@_decode (current_cpu, pc, insn, insn, abuf);
79   if (parallel_p)
80     id = id->par_idesc;
81   @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
82   return id;
85 static INLINE const IDESC *
86 emit_full16 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, SCACHE *sc,
87              int trace_p, int profile_p)
89   const IDESC *id;
91   @cpu@_emit_before (current_cpu, sc, pc, 1);
92   id = emit_16 (current_cpu, pc, insn, sc + 1, 0, 0);
93   @cpu@_emit_after (current_cpu, sc + 2, pc);
94   @cpu@_fill_argbuf_tp (current_cpu, &sc[1].argbuf, trace_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   @cpu@_fill_argbuf_tp (current_cpu, &sc[1].argbuf, trace_p, profile_p);
145   @cpu@_emit_before (current_cpu, sc + 2, pc, 0);
147   /* Note that this can never be a cti.  No cti's go in the S pipeline.  */
148   id2 = emit_16 (current_cpu, pc + 2, insn & 0x7fff, sc + 3, 0, 0);
149   @cpu@_fill_argbuf_tp (current_cpu, &sc[3].argbuf, trace_p, profile_p);
151   /* Set sc/snc insns notion of where to skip to.  */
152   if (IDESC_SKIP_P (id))
153     SEM_SKIP_COMPILE (current_cpu, sc, 4);
155   /* Emit code to finish executing the semantics
156      (write back the results).  */
157   emit_par_finish (current_cpu, pc, sc + 4, sc + 1, id, sc + 3, id2);
159   @cpu@_emit_after (current_cpu, sc + 5, pc);
161   return id;
164 static INLINE const IDESC *
165 emit_32 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn,
166          SCACHE *sc, int fast_p)
168   ARGBUF *abuf = &sc->argbuf;
169   const IDESC *id = @cpu@_decode (current_cpu, pc,
170                                   (USI) insn >> 16, insn, abuf);
172   @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
173   return id;
176 static INLINE const IDESC *
177 emit_full32 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, SCACHE *sc,
178              int trace_p, int profile_p)
180   const IDESC *id;
182   @cpu@_emit_before (current_cpu, sc, pc, 1);
183   id = emit_32 (current_cpu, pc, insn, sc + 1, 0);
184   @cpu@_emit_after (current_cpu, sc + 2, pc);
185   @cpu@_fill_argbuf_tp (current_cpu, &sc[1].argbuf, trace_p, profile_p);
186   return id;
193 xinit)
195 # Nothing needed.
199 xextract-pbb)
201 # Inputs:  current_cpu, pc, sc, max_insns, FAST_P
202 # Outputs: sc, pc
203 # sc must be left pointing past the last created entry.
204 # pc must be left pointing past the last created entry.
205 # If the pbb is terminated by a cti insn, SET_CTI_VPC(sc) must be called
206 # to record the vpc of the cti insn.
207 # SET_INSN_COUNT(n) must be called to record number of real insns.
209 cat <<EOF
210 #line $LINENO "$0"
212   const IDESC *idesc;
213   int icount = 0;
215   if ((pc & 3) != 0)
216     {
217       /* This occurs when single stepping and when compiling the not-taken
218          part of conditional branches.  */
219       UHI insn = GETIMEMUHI (current_cpu, pc);
220       int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc);
221       int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc);
222       SCACHE *cti_sc; /* ??? tmp hack */
224       /* A parallel insn isn't allowed here, but we don't mind nops.
225          ??? We need to wait until the insn is executed before signalling
226          the error, for situations where such signalling is wanted.  */
227 #if 0
228       if ((insn & 0x8000) != 0
229           && (insn & 0x7fff) != 0x7000) /* parallel nops are ok */
230         sim_engine_invalid_insn (current_cpu, pc, 0);
231 #endif
233       /* Only emit before/after handlers if necessary.  */
234       if (FAST_P || (! trace_p && ! profile_p))
235         {
236           idesc = emit_16 (current_cpu, pc, insn & 0x7fff, sc, FAST_P, 0);
237           cti_sc = sc;
238           ++sc;
239           --max_insns;
240         }
241       else
242         {
243           idesc = emit_full16 (current_cpu, pc, insn & 0x7fff, sc,
244                                trace_p, profile_p);
245           cti_sc = sc + 1;
246           sc += 3;
247           max_insns -= 3;
248         }
249       ++icount;
250       pc += 2;
251       if (IDESC_CTI_P (idesc))
252         {
253           SET_CTI_VPC (cti_sc);
254           goto Finish;
255         }
256     }
258   /* There are two copies of the compiler: full(!fast) and fast.
259      The "full" case emits before/after handlers for each insn.
260      Having two copies of this code is a tradeoff, having one copy
261      seemed a bit more difficult to read (due to constantly testing
262      FAST_P).  ??? On the other hand, with address ranges we'll want to
263      omit before/after handlers for unwanted insns.  Having separate loops
264      for FAST/!FAST avoids constantly doing the test in the loop, but
265      typically FAST_P is a constant and such tests will get optimized out.  */
267   if (FAST_P)
268     {
269       while (max_insns > 0)
270         {
271           USI insn = GETIMEMUSI (current_cpu, pc);
272           if ((SI) insn < 0)
273             {
274               /* 32 bit insn */
275               idesc = emit_32 (current_cpu, pc, insn, sc, 1);
276               ++sc;
277               --max_insns;
278               ++icount;
279               pc += 4;
280               if (IDESC_CTI_P (idesc))
281                 {
282                   SET_CTI_VPC (sc - 1);
283                   break;
284                 }
285             }
286           else
287             {
288               if ((insn & 0x8000) != 0) /* parallel? */
289                 {
290                   int up_count;
292                   if (((insn >> 16) & 0xfff0) == 0x10f0)
293                     {
294                       /* FIXME: No need to handle this sequentially if system
295                          calls will be able to execute after second insn in
296                          parallel. ( trap #num || insn ) */
297                       /* insn */
298                       idesc = emit_16 (current_cpu, pc + 2, insn & 0x7fff,
299                                        sc, 1, 0);
300                       /* trap */
301                       emit_16 (current_cpu, pc, insn >> 16, sc + 1, 1, 0);
302                       up_count = 2;
303                     }
304                   else
305                     {
306                       /* Yep.  Here's the "interesting" [sic] part.  */
307                       idesc = emit_parallel (current_cpu, pc, insn, sc, 1);
308                       up_count = 3;
309                     }
310                   sc += up_count;
311                   max_insns -= up_count;
312                   icount += 2;
313                   pc += 4;
314                   if (IDESC_CTI_P (idesc))
315                     {
316                       SET_CTI_VPC (sc - up_count);
317                       break;
318                     }
319                 }
320               else /* 2 serial 16 bit insns */
321                 {
322                   idesc = emit_16 (current_cpu, pc, insn >> 16, sc, 1, 0);
323                   ++sc;
324                   --max_insns;
325                   ++icount;
326                   pc += 2;
327                   if (IDESC_CTI_P (idesc))
328                     {
329                       SET_CTI_VPC (sc - 1);
330                       break;
331                     }
332                   /* While we're guaranteed that there's room to extract the
333                      insn, when single stepping we can't; the pbb must stop
334                      after the first insn.  */
335                   if (max_insns == 0)
336                     break;
337                   idesc = emit_16 (current_cpu, pc, insn & 0x7fff, sc, 1, 0);
338                   ++sc;
339                   --max_insns;
340                   ++icount;
341                   pc += 2;
342                   if (IDESC_CTI_P (idesc))
343                     {
344                       SET_CTI_VPC (sc - 1);
345                       break;
346                     }
347                 }
348             }
349         }
350     }
351   else /* ! FAST_P */
352     {
353       while (max_insns > 0)
354         {
355           USI insn = GETIMEMUSI (current_cpu, pc);
356           int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc);
357           int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc);
358           SCACHE *cti_sc; /* ??? tmp hack */
359           if ((SI) insn < 0)
360             {
361               /* 32 bit insn
362                  Only emit before/after handlers if necessary.  */
363               if (trace_p || profile_p)
364                 {
365                   idesc = emit_full32 (current_cpu, pc, insn, sc,
366                                        trace_p, profile_p);
367                   cti_sc = sc + 1;
368                   sc += 3;
369                   max_insns -= 3;
370                 }
371               else
372                 {
373                   idesc = emit_32 (current_cpu, pc, insn, sc, 0);
374                   cti_sc = sc;
375                   ++sc;
376                   --max_insns;
377                 }
378               ++icount;
379               pc += 4;
380               if (IDESC_CTI_P (idesc))
381                 {
382                   SET_CTI_VPC (cti_sc);
383                   break;
384                 }
385             }
386           else
387             {
388               if ((insn & 0x8000) != 0) /* parallel? */
389                 {
390                   /* Yep.  Here's the "interesting" [sic] part.
391                      Only emit before/after handlers if necessary.  */
392                   if (trace_p || profile_p)
393                     {
394                       if (((insn >> 16) & 0xfff0) == 0x10f0)
395                         {
396                           /* FIXME: No need to handle this sequentially if
397                              system calls will be able to execute after second
398                              insn in parallel. ( trap #num || insn ) */
399                           /* insn */
400                           idesc = emit_full16 (current_cpu, pc + 2,
401                                                insn & 0x7fff, sc, 0, 0);
402                           /* trap */
403                           emit_full16 (current_cpu, pc, insn >> 16, sc + 3,
404                                        0, 0);
405                         }
406                       else
407                         {
408                           idesc = emit_full_parallel (current_cpu, pc, insn,
409                                                       sc, trace_p, profile_p);
410                         }
411                       cti_sc = sc + 1;
412                       sc += 6;
413                       max_insns -= 6;
414                     }
415                   else
416                     {
417                       int up_count;
419                       if (((insn >> 16) & 0xfff0) == 0x10f0)
420                         {
421                           /* FIXME: No need to handle this sequentially if
422                              system calls will be able to execute after second
423                              insn in parallel. ( trap #num || insn ) */
424                           /* insn */
425                           idesc = emit_16 (current_cpu, pc + 2, insn & 0x7fff,
426                                            sc, 0, 0);
427                           /* trap */
428                           emit_16 (current_cpu, pc, insn >> 16, sc + 1, 0, 0);
429                           up_count = 2;
430                         }
431                       else
432                         {
433                           idesc = emit_parallel (current_cpu, pc, insn, sc, 0);
434                           up_count = 3;
435                         }
436                       cti_sc = sc;
437                       sc += up_count;
438                       max_insns -= up_count;
439                     }
440                   icount += 2;
441                   pc += 4;
442                   if (IDESC_CTI_P (idesc))
443                     {
444                       SET_CTI_VPC (cti_sc);
445                       break;
446                     }
447                 }
448               else /* 2 serial 16 bit insns */
449                 {
450                   /* Only emit before/after handlers if necessary.  */
451                   if (trace_p || profile_p)
452                     {
453                       idesc = emit_full16 (current_cpu, pc, insn >> 16, sc,
454                                            trace_p, profile_p);
455                       cti_sc = sc + 1;
456                       sc += 3;
457                       max_insns -= 3;
458                     }
459                   else
460                     {
461                       idesc = emit_16 (current_cpu, pc, insn >> 16, sc, 0, 0);
462                       cti_sc = sc;
463                       ++sc;
464                       --max_insns;
465                     }
466                   ++icount;
467                   pc += 2;
468                   if (IDESC_CTI_P (idesc))
469                     {
470                       SET_CTI_VPC (cti_sc);
471                       break;
472                     }
473                   /* While we're guaranteed that there's room to extract the
474                      insn, when single stepping we can't; the pbb must stop
475                      after the first insn.  */
476                   if (max_insns <= 0)
477                     break;
478                   /* Use the same trace/profile address for the 2nd insn.
479                      Saves us having to compute it and they come in pairs
480                      anyway (e.g. can never branch to the 2nd insn).  */
481                   if (trace_p || profile_p)
482                     {
483                       idesc = emit_full16 (current_cpu, pc, insn & 0x7fff, sc,
484                                            trace_p, profile_p);
485                       cti_sc = sc + 1;
486                       sc += 3;
487                       max_insns -= 3;
488                     }
489                   else
490                     {
491                       idesc = emit_16 (current_cpu, pc, insn & 0x7fff, sc, 0, 0);
492                       cti_sc = sc;
493                       ++sc;
494                       --max_insns;
495                     }
496                   ++icount;
497                   pc += 2;
498                   if (IDESC_CTI_P (idesc))
499                     {
500                       SET_CTI_VPC (cti_sc);
501                       break;
502                     }
503                 }
504             }
505         }
506     }
508  Finish:
509   SET_INSN_COUNT (icount);
515 xfull-exec-pbb)
517 # Inputs: current_cpu, vpc, FAST_P
518 # Outputs: vpc
519 # vpc is the virtual program counter.
521 cat <<EOF
522 #line $LINENO "$0"
523 #define DEFINE_SWITCH
524 #include "sem2-switch.c"
530   echo "Invalid argument to mainloop.in: $1" >&2
531   exit 1
532   ;;
534 esac