binutils/
[external/binutils.git] / sim / sh64 / mloop-compact.c
1 /* This file is generated by the genmloop script.  DO NOT EDIT! */
2
3 /* Enable switch() support in cgen headers.  */
4 #define SEM_IN_SWITCH
5
6 #define WANT_CPU sh64
7 #define WANT_CPU_SH64
8
9 #include "sim-main.h"
10 #include "bfd.h"
11 #include "cgen-mem.h"
12 #include "cgen-ops.h"
13 #include "sim-assert.h"
14
15 /* Fill in the administrative ARGBUF fields required by all insns,
16    virtual and real.  */
17
18 static INLINE void
19 sh64_compact_fill_argbuf (const SIM_CPU *cpu, ARGBUF *abuf, const IDESC *idesc,
20                     PCADDR pc, int fast_p)
21 {
22 #if WITH_SCACHE
23   SEM_SET_CODE (abuf, idesc, fast_p);
24   ARGBUF_ADDR (abuf) = pc;
25 #endif
26   ARGBUF_IDESC (abuf) = idesc;
27 }
28
29 /* Fill in tracing/profiling fields of an ARGBUF.  */
30
31 static INLINE void
32 sh64_compact_fill_argbuf_tp (const SIM_CPU *cpu, ARGBUF *abuf,
33                        int trace_p, int profile_p)
34 {
35   ARGBUF_TRACE_P (abuf) = trace_p;
36   ARGBUF_PROFILE_P (abuf) = profile_p;
37 }
38
39 #if WITH_SCACHE_PBB
40
41 /* Emit the "x-before" handler.
42    x-before is emitted before each insn (serial or parallel).
43    This is as opposed to x-after which is only emitted at the end of a group
44    of parallel insns.  */
45
46 static INLINE void
47 sh64_compact_emit_before (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc, int first_p)
48 {
49   ARGBUF *abuf = &sc[0].argbuf;
50   const IDESC *id = & CPU_IDESC (current_cpu) [SH64_COMPACT_INSN_X_BEFORE];
51
52   abuf->fields.before.first_p = first_p;
53   sh64_compact_fill_argbuf (current_cpu, abuf, id, pc, 0);
54   /* no need to set trace_p,profile_p */
55 }
56
57 /* Emit the "x-after" handler.
58    x-after is emitted after a serial insn or at the end of a group of
59    parallel insns.  */
60
61 static INLINE void
62 sh64_compact_emit_after (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc)
63 {
64   ARGBUF *abuf = &sc[0].argbuf;
65   const IDESC *id = & CPU_IDESC (current_cpu) [SH64_COMPACT_INSN_X_AFTER];
66
67   sh64_compact_fill_argbuf (current_cpu, abuf, id, pc, 0);
68   /* no need to set trace_p,profile_p */
69 }
70
71 #endif /* WITH_SCACHE_PBB */
72
73
74 static INLINE const IDESC *
75 extract (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, ARGBUF *abuf,
76          int fast_p)
77 {
78   const IDESC *id = sh64_compact_decode (current_cpu, pc, insn, insn, abuf);
79
80   sh64_compact_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
81   if (! fast_p)
82     {
83       int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc);
84       int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc);
85       sh64_compact_fill_argbuf_tp (current_cpu, abuf, trace_p, profile_p);
86     }
87   return id;
88 }
89
90 static INLINE SEM_PC
91 execute (SIM_CPU *current_cpu, SCACHE *sc, int fast_p)
92 {
93   SEM_PC vpc;
94
95   if (fast_p)
96     {
97 #if ! WITH_SEM_SWITCH_FAST
98 #if WITH_SCACHE
99       vpc = (*sc->argbuf.semantic.sem_fast) (current_cpu, sc);
100 #else
101       vpc = (*sc->argbuf.semantic.sem_fast) (current_cpu, &sc->argbuf);
102 #endif
103 #else
104       abort ();
105 #endif /* WITH_SEM_SWITCH_FAST */
106     }
107   else
108     {
109 #if ! WITH_SEM_SWITCH_FULL
110       ARGBUF *abuf = &sc->argbuf;
111       const IDESC *idesc = abuf->idesc;
112 #if WITH_SCACHE_PBB
113       int virtual_p = CGEN_ATTR_VALUE (NULL, idesc->attrs, CGEN_INSN_VIRTUAL);
114 #else
115       int virtual_p = 0;
116 #endif
117
118       if (! virtual_p)
119         {
120           /* FIXME: call x-before */
121           if (ARGBUF_PROFILE_P (abuf))
122             PROFILE_COUNT_INSN (current_cpu, abuf->addr, idesc->num);
123           /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}.  */
124           if (PROFILE_MODEL_P (current_cpu)
125               && ARGBUF_PROFILE_P (abuf))
126             sh64_compact_model_insn_before (current_cpu, 1 /*first_p*/);
127           TRACE_INSN_INIT (current_cpu, abuf, 1);
128           TRACE_INSN (current_cpu, idesc->idata,
129                       (const struct argbuf *) abuf, abuf->addr);
130         }
131 #if WITH_SCACHE
132       vpc = (*sc->argbuf.semantic.sem_full) (current_cpu, sc);
133 #else
134       vpc = (*sc->argbuf.semantic.sem_full) (current_cpu, abuf);
135 #endif
136       if (! virtual_p)
137         {
138           /* FIXME: call x-after */
139           if (PROFILE_MODEL_P (current_cpu)
140               && ARGBUF_PROFILE_P (abuf))
141             {
142               int cycles;
143
144               cycles = (*idesc->timing->model_fn) (current_cpu, sc);
145               sh64_compact_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
146             }
147           TRACE_INSN_FINI (current_cpu, abuf, 1);
148         }
149 #else
150       abort ();
151 #endif /* WITH_SEM_SWITCH_FULL */
152     }
153
154   return vpc;
155 }
156
157
158 /* Record address of cti terminating a pbb.  */
159 #define SET_CTI_VPC(sc) do { _cti_sc = (sc); } while (0)
160 /* Record number of [real] insns in pbb.  */
161 #define SET_INSN_COUNT(n) do { _insn_count = (n); } while (0)
162
163 /* Fetch and extract a pseudo-basic-block.
164    FAST_P is non-zero if no tracing/profiling/etc. is wanted.  */
165
166 INLINE SEM_PC
167 sh64_compact_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
168 {
169   SEM_PC new_vpc;
170   PCADDR pc;
171   SCACHE *sc;
172   int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu);
173
174   pc = GET_H_PC ();
175
176   new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
177   if (! new_vpc)
178     {
179       /* Leading '_' to avoid collision with mainloop.in.  */
180       int _insn_count = 0;
181       SCACHE *orig_sc = sc;
182       SCACHE *_cti_sc = NULL;
183       int slice_insns = CPU_MAX_SLICE_INSNS (current_cpu);
184
185       /* First figure out how many instructions to compile.
186          MAX_INSNS is the size of the allocated buffer, which includes space
187          for before/after handlers if they're being used.
188          SLICE_INSNS is the maxinum number of real insns that can be
189          executed.  Zero means "as many as we want".  */
190       /* ??? max_insns is serving two incompatible roles.
191          1) Number of slots available in scache buffer.
192          2) Number of real insns to execute.
193          They're incompatible because there are virtual insns emitted too
194          (chain,cti-chain,before,after handlers).  */
195
196       if (slice_insns == 1)
197         {
198           /* No need to worry about extra slots required for virtual insns
199              and parallel exec support because MAX_CHAIN_LENGTH is
200              guaranteed to be big enough to execute at least 1 insn!  */
201           max_insns = 1;
202         }
203       else
204         {
205           /* Allow enough slop so that while compiling insns, if max_insns > 0
206              then there's guaranteed to be enough space to emit one real insn.
207              MAX_CHAIN_LENGTH is typically much longer than
208              the normal number of insns between cti's anyway.  */
209           max_insns -= (1 /* one for the trailing chain insn */
210                         + (FAST_P
211                            ? 0
212                            : (1 + MAX_PARALLEL_INSNS) /* before+after */)
213                         + (MAX_PARALLEL_INSNS > 1
214                            ? (MAX_PARALLEL_INSNS * 2)
215                            : 0));
216
217           /* Account for before/after handlers.  */
218           if (! FAST_P)
219             slice_insns *= 3;
220
221           if (slice_insns > 0
222               && slice_insns < max_insns)
223             max_insns = slice_insns;
224         }
225
226       new_vpc = sc;
227
228       /* SC,PC must be updated to point passed the last entry used.
229          SET_CTI_VPC must be called if pbb is terminated by a cti.
230          SET_INSN_COUNT must be called to record number of real insns in
231          pbb [could be computed by us of course, extra cpu but perhaps
232          negligible enough].  */
233
234 /* begin extract-pbb */
235 {
236   const IDESC *idesc;
237   int icount = 0;
238
239  while (max_insns > 0)
240     {
241       UHI insn = GETIMEMUHI (current_cpu, pc);
242       
243       idesc = extract (current_cpu, pc, insn, &sc->argbuf, FAST_P);
244       SEM_SKIP_COMPILE (current_cpu, sc, 1);
245       ++sc;
246       --max_insns;
247       ++icount;
248       pc += idesc->length;
249
250       if (IDESC_CTI_P (idesc))
251         {
252           SET_CTI_VPC (sc - 1);
253
254           if (CGEN_ATTR_VALUE (NULL, idesc->attrs, CGEN_INSN_DELAY_SLOT))
255             {
256               USI insn = GETIMEMUHI (current_cpu, pc);
257               idesc = extract (current_cpu, pc, insn, &sc->argbuf, FAST_P);
258
259               if (IDESC_CTI_P (idesc) ||
260                   CGEN_ATTR_VALUE (NULL, idesc->attrs, CGEN_INSN_ILLSLOT))
261                 {
262                   SIM_DESC sd = CPU_STATE (current_cpu);
263                   sim_io_eprintf (CPU_STATE (current_cpu),
264                     "malformed program, `%s' insn in delay slot\n",
265                     CGEN_INSN_NAME (idesc->idata));    
266                   sim_engine_halt (sd, current_cpu, NULL, pc,
267                                    sim_stopped, SIM_SIGILL);
268                 }
269               else
270                 { 
271                   ++sc;
272                   --max_insns;
273                   ++icount;
274                   pc += idesc->length;
275                 }
276             }
277           break;
278       }
279     }
280
281  Finish:
282   SET_INSN_COUNT (icount);
283 }
284 /* end extract-pbb */
285
286       /* The last one is a pseudo-insn to link to the next chain.
287          It is also used to record the insn count for this chain.  */
288       {
289         const IDESC *id;
290
291         /* Was pbb terminated by a cti?  */
292         if (_cti_sc)
293           {
294             id = & CPU_IDESC (current_cpu) [SH64_COMPACT_INSN_X_CTI_CHAIN];
295           }
296         else
297           {
298             id = & CPU_IDESC (current_cpu) [SH64_COMPACT_INSN_X_CHAIN];
299           }
300         SEM_SET_CODE (&sc->argbuf, id, FAST_P);
301         sc->argbuf.idesc = id;
302         sc->argbuf.addr = pc;
303         sc->argbuf.fields.chain.insn_count = _insn_count;
304         sc->argbuf.fields.chain.next = 0;
305         sc->argbuf.fields.chain.branch_target = 0;
306         ++sc;
307       }
308
309       /* Update the pointer to the next free entry, may not have used as
310          many entries as was asked for.  */
311       CPU_SCACHE_NEXT_FREE (current_cpu) = sc;
312       /* Record length of chain if profiling.
313          This includes virtual insns since they count against
314          max_insns too.  */
315       if (! FAST_P)
316         PROFILE_COUNT_SCACHE_CHAIN_LENGTH (current_cpu, sc - orig_sc);
317     }
318
319   return new_vpc;
320 }
321
322 /* Chain to the next block from a non-cti terminated previous block.  */
323
324 INLINE SEM_PC
325 sh64_compact_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
326 {
327   ARGBUF *abuf = SEM_ARGBUF (sem_arg);
328
329   PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
330
331   SET_H_PC (abuf->addr);
332
333
334   /* If not running forever, exit back to main loop.  */
335   if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
336       /* Also exit back to main loop if there's an event.
337          Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
338          at the "right" time, but then that was what was asked for.
339          There is no silver bullet for simulator engines.
340          ??? Clearly this needs a cleaner interface.
341          At present it's just so Ctrl-C works.  */
342       || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
343     CPU_RUNNING_P (current_cpu) = 0;
344
345   /* If chained to next block, go straight to it.  */
346   if (abuf->fields.chain.next)
347     return abuf->fields.chain.next;
348   /* See if next block has already been compiled.  */
349   abuf->fields.chain.next = scache_lookup (current_cpu, abuf->addr);
350   if (abuf->fields.chain.next)
351     return abuf->fields.chain.next;
352   /* Nope, so next insn is a virtual insn to invoke the compiler
353      (begin a pbb).  */
354   return CPU_SCACHE_PBB_BEGIN (current_cpu);
355 }
356
357 /* Chain to the next block from a cti terminated previous block.
358    BR_TYPE indicates whether the branch was taken and whether we can cache
359    the vpc of the branch target.
360    NEW_PC is the target's branch address, and is only valid if
361    BR_TYPE != SEM_BRANCH_UNTAKEN.  */
362
363 INLINE SEM_PC
364 sh64_compact_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
365                      SEM_BRANCH_TYPE br_type, PCADDR new_pc)
366 {
367   SEM_PC *new_vpc_ptr;
368
369   PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
370
371   /* If we have switched ISAs, exit back to main loop.
372      Set idesc to 0 to cause the engine to point to the right insn table.  */
373   if (new_pc & 1)
374   {
375     /* Switch to SHmedia.  */
376     CPU_IDESC_SEM_INIT_P (current_cpu) = 0;
377     CPU_RUNNING_P (current_cpu) = 0;
378   }
379
380   /* If not running forever, exit back to main loop.  */
381   if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
382       /* Also exit back to main loop if there's an event.
383          Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
384          at the "right" time, but then that was what was asked for.
385          There is no silver bullet for simulator engines.
386          ??? Clearly this needs a cleaner interface.
387          At present it's just so Ctrl-C works.  */
388       || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
389     CPU_RUNNING_P (current_cpu) = 0;
390
391   /* Restart compiler if we branched to an uncacheable address
392      (e.g. "j reg").  */
393   if (br_type == SEM_BRANCH_UNCACHEABLE)
394     {
395       SET_H_PC (new_pc);
396       return CPU_SCACHE_PBB_BEGIN (current_cpu);
397     }
398
399   /* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our
400      next chain ptr.  */
401   if (br_type == SEM_BRANCH_UNTAKEN)
402     {
403       ARGBUF *abuf = SEM_ARGBUF (sem_arg);
404       new_pc = abuf->addr;
405       SET_H_PC (new_pc);
406       new_vpc_ptr = &abuf->fields.chain.next;
407     }
408   else
409     {
410       ARGBUF *abuf = SEM_ARGBUF (sem_arg);
411       SET_H_PC (new_pc);
412       new_vpc_ptr = &abuf->fields.chain.branch_target;
413     }
414
415   /* If chained to next block, go straight to it.  */
416   if (*new_vpc_ptr)
417     return *new_vpc_ptr;
418   /* See if next block has already been compiled.  */
419   *new_vpc_ptr = scache_lookup (current_cpu, new_pc);
420   if (*new_vpc_ptr)
421     return *new_vpc_ptr;
422   /* Nope, so next insn is a virtual insn to invoke the compiler
423      (begin a pbb).  */
424   return CPU_SCACHE_PBB_BEGIN (current_cpu);
425 }
426
427 /* x-before handler.
428    This is called before each insn.  */
429
430 void
431 sh64_compact_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
432 {
433   SEM_ARG sem_arg = sc;
434   const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
435   int first_p = abuf->fields.before.first_p;
436   const ARGBUF *cur_abuf = SEM_ARGBUF (sc + 1);
437   const IDESC *cur_idesc = cur_abuf->idesc;
438   PCADDR pc = cur_abuf->addr;
439
440   if (ARGBUF_PROFILE_P (cur_abuf))
441     PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
442
443   /* If this isn't the first insn, finish up the previous one.  */
444
445   if (! first_p)
446     {
447       if (PROFILE_MODEL_P (current_cpu))
448         {
449           const SEM_ARG prev_sem_arg = sc - 1;
450           const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
451           const IDESC *prev_idesc = prev_abuf->idesc;
452           int cycles;
453
454           /* ??? May want to measure all insns if doing insn tracing.  */
455           if (ARGBUF_PROFILE_P (prev_abuf))
456             {
457               cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
458               sh64_compact_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
459             }
460         }
461
462       TRACE_INSN_FINI (current_cpu, cur_abuf, 0 /*last_p*/);
463     }
464
465   /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}.  */
466   if (PROFILE_MODEL_P (current_cpu)
467       && ARGBUF_PROFILE_P (cur_abuf))
468     sh64_compact_model_insn_before (current_cpu, first_p);
469
470   TRACE_INSN_INIT (current_cpu, cur_abuf, first_p);
471   TRACE_INSN (current_cpu, cur_idesc->idata, cur_abuf, pc);
472 }
473
474 /* x-after handler.
475    This is called after a serial insn or at the end of a group of parallel
476    insns.  */
477
478 void
479 sh64_compact_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
480 {
481   SEM_ARG sem_arg = sc;
482   const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
483   const SEM_ARG prev_sem_arg = sc - 1;
484   const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
485
486   /* ??? May want to measure all insns if doing insn tracing.  */
487   if (PROFILE_MODEL_P (current_cpu)
488       && ARGBUF_PROFILE_P (prev_abuf))
489     {
490       const IDESC *prev_idesc = prev_abuf->idesc;
491       int cycles;
492
493       cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
494       sh64_compact_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
495     }
496   TRACE_INSN_FINI (current_cpu, prev_abuf, 1 /*last_p*/);
497 }
498
499 #define FAST_P 0
500
501 void
502 sh64_compact_engine_run_full (SIM_CPU *current_cpu)
503 {
504   SIM_DESC current_state = CPU_STATE (current_cpu);
505   SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
506   /* virtual program counter */
507   SEM_PC vpc;
508 #if WITH_SEM_SWITCH_FULL
509   /* For communication between cti's and cti-chain.  */
510   SEM_BRANCH_TYPE pbb_br_type;
511   PCADDR pbb_br_npc;
512 #endif
513
514
515   if (! CPU_IDESC_SEM_INIT_P (current_cpu))
516     {
517       /* ??? 'twould be nice to move this up a level and only call it once.
518          On the other hand, in the "let's go fast" case the test is only done
519          once per pbb (since we only return to the main loop at the end of
520          a pbb).  And in the "let's run until we're done" case we don't return
521          until the program exits.  */
522
523 #if WITH_SEM_SWITCH_FULL
524 #if defined (__GNUC__)
525 /* ??? Later maybe paste sem-switch.c in when building mainloop.c.  */
526 #define DEFINE_LABELS
527 #include "sem-compact-switch.c"
528 #endif
529 #else
530       sh64_compact_sem_init_idesc_table (current_cpu);
531 #endif
532
533       /* Initialize the "begin (compile) a pbb" virtual insn.  */
534       vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
535       SEM_SET_FULL_CODE (SEM_ARGBUF (vpc),
536                          & CPU_IDESC (current_cpu) [SH64_COMPACT_INSN_X_BEGIN]);
537       vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [SH64_COMPACT_INSN_X_BEGIN];
538
539       CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
540     }
541
542   CPU_RUNNING_P (current_cpu) = 1;
543   /* ??? In the case where we're returning to the main loop after every
544      pbb we don't want to call pbb_begin each time (which hashes on the pc
545      and does a table lookup).  A way to speed this up is to save vpc
546      between calls.  */
547   vpc = sh64_compact_pbb_begin (current_cpu, FAST_P);
548
549   do
550     {
551 /* begin full-exec-pbb */
552 {
553 #if (! FAST_P && WITH_SEM_SWITCH_FULL) || (FAST_P && WITH_SEM_SWITCH_FAST)
554 #define DEFINE_SWITCH
555 #include "sem-compact-switch.c"
556 #else
557   vpc = execute (current_cpu, vpc, FAST_P);
558 #endif
559 }
560 /* end full-exec-pbb */
561     }
562   while (CPU_RUNNING_P (current_cpu));
563 }
564
565 #undef FAST_P
566
567
568 #define FAST_P 1
569
570 void
571 sh64_compact_engine_run_fast (SIM_CPU *current_cpu)
572 {
573   SIM_DESC current_state = CPU_STATE (current_cpu);
574   SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
575   /* virtual program counter */
576   SEM_PC vpc;
577 #if WITH_SEM_SWITCH_FAST
578   /* For communication between cti's and cti-chain.  */
579   SEM_BRANCH_TYPE pbb_br_type;
580   PCADDR pbb_br_npc;
581 #endif
582
583
584   if (! CPU_IDESC_SEM_INIT_P (current_cpu))
585     {
586       /* ??? 'twould be nice to move this up a level and only call it once.
587          On the other hand, in the "let's go fast" case the test is only done
588          once per pbb (since we only return to the main loop at the end of
589          a pbb).  And in the "let's run until we're done" case we don't return
590          until the program exits.  */
591
592 #if WITH_SEM_SWITCH_FAST
593 #if defined (__GNUC__)
594 /* ??? Later maybe paste sem-switch.c in when building mainloop.c.  */
595 #define DEFINE_LABELS
596 #include "sem-compact-switch.c"
597 #endif
598 #else
599       sh64_compact_semf_init_idesc_table (current_cpu);
600 #endif
601
602       /* Initialize the "begin (compile) a pbb" virtual insn.  */
603       vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
604       SEM_SET_FAST_CODE (SEM_ARGBUF (vpc),
605                          & CPU_IDESC (current_cpu) [SH64_COMPACT_INSN_X_BEGIN]);
606       vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [SH64_COMPACT_INSN_X_BEGIN];
607
608       CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
609     }
610
611   CPU_RUNNING_P (current_cpu) = 1;
612   /* ??? In the case where we're returning to the main loop after every
613      pbb we don't want to call pbb_begin each time (which hashes on the pc
614      and does a table lookup).  A way to speed this up is to save vpc
615      between calls.  */
616   vpc = sh64_compact_pbb_begin (current_cpu, FAST_P);
617
618   do
619     {
620 /* begin fast-exec-pbb */
621 {
622 #if (! FAST_P && WITH_SEM_SWITCH_FULL) || (FAST_P && WITH_SEM_SWITCH_FAST)
623 #define DEFINE_SWITCH
624 #include "sem-compact-switch.c"
625 #else
626   vpc = execute (current_cpu, vpc, FAST_P);
627 #endif
628 }
629 /* end fast-exec-pbb */
630     }
631   while (CPU_RUNNING_P (current_cpu));
632 }
633
634 #undef FAST_P
635