xref: /netbsd-src/external/gpl3/gdb/dist/sim/m32r/mloop2.in (revision 05fa08567a80471fd0eb3843a238392874f2577c)
1# Simulator main loop for m32r2. -*- C -*-
2#
3# Copyright 1996-2024 Free Software Foundation, Inc.
4#
5# This file is part of GDB, the GNU debugger.
6#
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.
11#
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.
16#
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/>.
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
39case "x$1" in
40
41xsupport)
42
43cat <<EOF
44#line $LINENO "$0"
45
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).  */
51
52static INLINE void
53emit_par_finish (SIM_CPU *current_cpu, PCADDR pc, SCACHE *sc,
54		 SCACHE *sc1, const IDESC *id1, SCACHE *sc2, const IDESC *id2)
55{
56  ARGBUF *abuf;
57
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
70}
71
72static INLINE const IDESC *
73emit_16 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn,
74	 SCACHE *sc, int fast_p, int parallel_p)
75{
76  ARGBUF *abuf = &sc->argbuf;
77  const IDESC *id = @cpu@_decode (current_cpu, pc, insn, insn, abuf);
78
79  if (parallel_p)
80    id = id->par_idesc;
81  @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
82  return id;
83}
84
85static INLINE const IDESC *
86emit_full16 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, SCACHE *sc,
87	     int trace_p, int profile_p)
88{
89  const IDESC *id;
90
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;
96}
97
98static INLINE const IDESC *
99emit_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
127static INLINE const IDESC *
128emit_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  @cpu@_fill_argbuf_tp (current_cpu, &sc[1].argbuf, trace_p, profile_p);
144
145  @cpu@_emit_before (current_cpu, sc + 2, pc, 0);
146
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);
150
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);
154
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);
158
159  @cpu@_emit_after (current_cpu, sc + 5, pc);
160
161  return id;
162}
163
164static INLINE const IDESC *
165emit_32 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn,
166	 SCACHE *sc, int fast_p)
167{
168  ARGBUF *abuf = &sc->argbuf;
169  const IDESC *id = @cpu@_decode (current_cpu, pc,
170				  (USI) insn >> 16, insn, abuf);
171
172  @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
173  return id;
174}
175
176static INLINE const IDESC *
177emit_full32 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, SCACHE *sc,
178	     int trace_p, int profile_p)
179{
180  const IDESC *id;
181
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;
187}
188
189EOF
190
191;;
192
193xinit)
194
195# Nothing needed.
196
197;;
198
199xextract-pbb)
200
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.
208
209cat <<EOF
210#line $LINENO "$0"
211{
212  const IDESC *idesc;
213  int icount = 0;
214
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 */
223
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
232
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    }
257
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.  */
266
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;
291
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;
418
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    }
507
508 Finish:
509  SET_INSN_COUNT (icount);
510}
511EOF
512
513;;
514
515xfull-exec-pbb)
516
517# Inputs: current_cpu, vpc, FAST_P
518# Outputs: vpc
519# vpc is the virtual program counter.
520
521cat <<EOF
522#line $LINENO "$0"
523#define DEFINE_SWITCH
524#include "sem2-switch.c"
525EOF
526
527;;
528
529*)
530  echo "Invalid argument to mainloop.in: $1" >&2
531  exit 1
532  ;;
533
534esac
535