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/>.
21 # /bin/sh mainloop.in command
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
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.
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
48 SC1/ID1 is the first insn (left slot, lower address).
49 SC2/ID2 is the second insn (right slot, higher address). */
52 emit_par_finish (SIM_CPU *current_cpu, PCADDR pc, SCACHE *sc,
53 SCACHE *sc1, const IDESC *id1, SCACHE *sc2, const IDESC *id2)
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 */
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 */
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);
80 @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
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)
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;
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);
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);
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);
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)
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;
204 # Inputs: current_cpu, pc, sc, max_insns, FAST_P
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.
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. */
230 if ((insn & 0x8000) != 0
231 && (insn & 0x7fff) != 0x7000) /* parallel nops are ok */
232 sim_engine_invalid_insn (current_cpu, pc, 0);
235 /* Only emit before/after handlers if necessary. */
236 if (FAST_P || (! trace_p && ! profile_p))
238 idesc = emit_16 (current_cpu, pc, insn & 0x7fff, sc, FAST_P, 0);
245 idesc = emit_full16 (current_cpu, pc, insn & 0x7fff, sc,
253 if (IDESC_CTI_P (idesc))
255 SET_CTI_VPC (cti_sc);
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. */
271 while (max_insns > 0)
273 USI insn = GETIMEMUSI (current_cpu, pc);
277 idesc = emit_32 (current_cpu, pc, insn, sc, 1);
282 if (IDESC_CTI_P (idesc))
284 SET_CTI_VPC (sc - 1);
290 if ((insn & 0x8000) != 0) /* parallel? */
294 if (((insn >> 16) & 0xfff0) == 0x10f0)
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 ) */
300 idesc = emit_16 (current_cpu, pc + 2, insn & 0x7fff,
303 emit_16 (current_cpu, pc, insn >> 16, sc + 1, 1, 0);
308 /* Yep. Here's the "interesting" [sic] part. */
309 idesc = emit_parallel (current_cpu, pc, insn, sc, 1);
313 max_insns -= up_count;
316 if (IDESC_CTI_P (idesc))
318 SET_CTI_VPC (sc - up_count);
322 else /* 2 serial 16 bit insns */
324 idesc = emit_16 (current_cpu, pc, insn >> 16, sc, 1, 0);
329 if (IDESC_CTI_P (idesc))
331 SET_CTI_VPC (sc - 1);
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. */
339 idesc = emit_16 (current_cpu, pc, insn & 0x7fff, sc, 1, 0);
344 if (IDESC_CTI_P (idesc))
346 SET_CTI_VPC (sc - 1);
355 while (max_insns > 0)
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 */
364 Only emit before/after handlers if necessary. */
365 if (trace_p || profile_p)
367 idesc = emit_full32 (current_cpu, pc, insn, sc,
375 idesc = emit_32 (current_cpu, pc, insn, sc, 0);
382 if (IDESC_CTI_P (idesc))
384 SET_CTI_VPC (cti_sc);
390 if ((insn & 0x8000) != 0) /* parallel? */
392 /* Yep. Here's the "interesting" [sic] part.
393 Only emit before/after handlers if necessary. */
394 if (trace_p || profile_p)
396 if (((insn >> 16) & 0xfff0) == 0x10f0)
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 ) */
402 idesc = emit_full16 (current_cpu, pc + 2,
403 insn & 0x7fff, sc, 0, 0);
405 emit_full16 (current_cpu, pc, insn >> 16, sc + 3,
410 idesc = emit_full_parallel (current_cpu, pc, insn,
411 sc, trace_p, profile_p);
421 if (((insn >> 16) & 0xfff0) == 0x10f0)
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 ) */
427 idesc = emit_16 (current_cpu, pc + 2, insn & 0x7fff,
430 emit_16 (current_cpu, pc, insn >> 16, sc + 1, 0, 0);
435 idesc = emit_parallel (current_cpu, pc, insn, sc, 0);
440 max_insns -= up_count;
444 if (IDESC_CTI_P (idesc))
446 SET_CTI_VPC (cti_sc);
450 else /* 2 serial 16 bit insns */
452 /* Only emit before/after handlers if necessary. */
453 if (trace_p || profile_p)
455 idesc = emit_full16 (current_cpu, pc, insn >> 16, sc,
463 idesc = emit_16 (current_cpu, pc, insn >> 16, sc, 0, 0);
470 if (IDESC_CTI_P (idesc))
472 SET_CTI_VPC (cti_sc);
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. */
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)
485 idesc = emit_full16 (current_cpu, pc, insn & 0x7fff, sc,
493 idesc = emit_16 (current_cpu, pc, insn & 0x7fff, sc, 0, 0);
500 if (IDESC_CTI_P (idesc))
502 SET_CTI_VPC (cti_sc);
511 SET_INSN_COUNT (icount);
519 # Inputs: current_cpu, vpc, FAST_P
521 # vpc is the virtual program counter.
524 #define DEFINE_SWITCH
525 #include "semx-switch.c"
531 echo "Invalid argument to mainloop.in: $1" >&2