1# Simulator main loop for m32r2. -*- C -*-
2#
3# Copyright 1996, 1997, 1998, 2003, 2004, 2007 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
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
51static INLINE void
52emit_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
71static INLINE const IDESC *
72emit_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
84static INLINE const IDESC *
85emit_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
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  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
166static INLINE const IDESC *
167emit_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
178static INLINE const IDESC *
179emit_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
192EOF
193
194;;
195
196xinit)
197
198# Nothing needed.
199
200;;
201
202xextract-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
212cat <<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                  int up_count;
293
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;
420
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    }
509
510 Finish:
511  SET_INSN_COUNT (icount);
512}
513EOF
514
515;;
516
517xfull-exec-pbb)
518
519# Inputs: current_cpu, vpc, FAST_P
520# Outputs: vpc
521# vpc is the virtual program counter.
522
523cat <<EOF
524#define DEFINE_SWITCH
525#include "sem2-switch.c"
526EOF
527
528;;
529
530*)
531  echo "Invalid argument to mainloop.in: $1" >&2
532  exit 1
533  ;;
534
535esac
536