1/* Support code for various pieces of CGEN simulators.
2   Copyright (C) 1996, 1997, 1998, 1999, 2007, 2008, 2009, 2010, 2011
3   Free Software Foundation, Inc.
4   Contributed by Cygnus Support.
5
6This file is part of GDB, the GNU debugger.
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 3 of the License, or
11(at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21#include "bfd.h"
22#include "sim-main.h"
23#include "dis-asm.h"
24
25#define MEMOPS_DEFINE_INLINE
26#include "cgen-mem.h"
27
28#define SEMOPS_DEFINE_INLINE
29#include "cgen-ops.h"
30
31#undef min
32#define min(a,b) ((a) < (b) ? (a) : (b))
33
34const char *mode_names[] = {
35  "VOID",
36  "BI",
37  "QI",
38  "HI",
39  "SI",
40  "DI",
41  "UQI",
42  "UHI",
43  "USI",
44  "UDI",
45  "SF",
46  "DF",
47  "XF",
48  "TF",
49  0, /* MODE_TARGET_MAX */
50  "INT",
51  "UINT",
52  "PTR"
53};
54
55/* Opcode table for virtual insns used by the simulator.  */
56
57#define V CGEN_ATTR_MASK (CGEN_INSN_VIRTUAL)
58
59static const CGEN_IBASE virtual_insn_entries[] =
60{
61  {
62    VIRTUAL_INSN_X_INVALID, "--invalid--", NULL, 0, { V, { 0 } }
63  },
64  {
65    VIRTUAL_INSN_X_BEFORE, "--before--", NULL, 0, { V, { 0 } }
66  },
67  {
68    VIRTUAL_INSN_X_AFTER, "--after--", NULL, 0, { V, { 0 } }
69  },
70  {
71    VIRTUAL_INSN_X_BEGIN, "--begin--", NULL, 0, { V, { 0 } }
72  },
73  {
74    VIRTUAL_INSN_X_CHAIN, "--chain--", NULL, 0, { V, { 0 } }
75  },
76  {
77    VIRTUAL_INSN_X_CTI_CHAIN, "--cti-chain--", NULL, 0, { V, { 0 } }
78  }
79};
80
81#undef V
82
83const CGEN_INSN cgen_virtual_insn_table[] =
84{
85  { & virtual_insn_entries[0] },
86  { & virtual_insn_entries[1] },
87  { & virtual_insn_entries[2] },
88  { & virtual_insn_entries[3] },
89  { & virtual_insn_entries[4] },
90  { & virtual_insn_entries[5] }
91};
92
93/* Initialize cgen things.
94   This is called after sim_post_argv_init.  */
95
96void
97cgen_init (SIM_DESC sd)
98{
99  int i, c;
100
101  /* If no profiling or tracing has been enabled, run in fast mode.  */
102  {
103    int run_fast_p = 1;
104
105    for (c = 0; c < MAX_NR_PROCESSORS; ++c)
106      {
107	SIM_CPU *cpu = STATE_CPU (sd, c);
108
109	for (i = 0; i < MAX_PROFILE_VALUES; ++i)
110	  if (CPU_PROFILE_FLAGS (cpu) [i])
111	    {
112	      run_fast_p = 0;
113	      break;
114	    }
115	for (i = 0; i < MAX_TRACE_VALUES; ++i)
116	  if (CPU_TRACE_FLAGS (cpu) [i])
117	    {
118	      run_fast_p = 0;
119	      break;
120	    }
121	if (! run_fast_p)
122	  break;
123      }
124    STATE_RUN_FAST_P (sd) = run_fast_p;
125  }
126}
127
128/* Return the name of insn number I.  */
129
130const char *
131cgen_insn_name (SIM_CPU *cpu, int i)
132{
133  return CGEN_INSN_NAME ((* CPU_GET_IDATA (cpu)) ((cpu), (i)));
134}
135
136/* Return the maximum number of extra bytes required for a SIM_CPU struct.  */
137
138int
139cgen_cpu_max_extra_bytes (void)
140{
141  int i;
142  int extra = 0;
143
144  for (i = 0; sim_machs[i] != 0; ++i)
145    {
146      int size = IMP_PROPS_SIM_CPU_SIZE (MACH_IMP_PROPS (sim_machs[i]));
147      if (size > extra)
148	extra = size;
149    }
150  return extra;
151}
152
153#ifdef DI_FN_SUPPORT
154
155DI
156make_struct_di (hi, lo)
157     SI hi, lo;
158{
159  DI result;
160
161  result.hi = hi;
162  result.lo = lo;
163  return result;
164}
165
166DI
167ANDDI (a, b)
168     DI a, b;
169{
170  SI ahi = GETHIDI (a);
171  SI alo = GETLODI (a);
172  SI bhi = GETHIDI (b);
173  SI blo = GETLODI (b);
174  return MAKEDI (ahi & bhi, alo & blo);
175}
176
177DI
178ORDI (a, b)
179     DI a, b;
180{
181  SI ahi = GETHIDI (a);
182  SI alo = GETLODI (a);
183  SI bhi = GETHIDI (b);
184  SI blo = GETLODI (b);
185  return MAKEDI (ahi | bhi, alo | blo);
186}
187
188DI
189ADDDI (a, b)
190     DI a, b;
191{
192  USI ahi = GETHIDI (a);
193  USI alo = GETLODI (a);
194  USI bhi = GETHIDI (b);
195  USI blo = GETLODI (b);
196  USI x = alo + blo;
197  return MAKEDI (ahi + bhi + (x < alo), x);
198}
199
200DI
201MULDI (a, b)
202     DI a, b;
203{
204  USI ahi = GETHIDI (a);
205  USI alo = GETLODI (a);
206  USI bhi = GETHIDI (b);
207  USI blo = GETLODI (b);
208  USI rhi,rlo;
209  USI x0, x1, x2, x3;
210
211  x0 = alo * blo;
212  x1 = alo * bhi;
213  x2 = ahi * blo;
214  x3 = ahi * bhi;
215
216#define SI_TYPE_SIZE 32
217#define BITS4 (SI_TYPE_SIZE / 4)
218#define ll_B (1L << (SI_TYPE_SIZE / 2))
219#define ll_lowpart(t) ((USI) (t) % ll_B)
220#define ll_highpart(t) ((USI) (t) / ll_B)
221  x1 += ll_highpart (x0);	/* this can't give carry */
222  x1 += x2;			/* but this indeed can */
223  if (x1 < x2)			/* did we get it? */
224    x3 += ll_B;			/* yes, add it in the proper pos. */
225
226  rhi = x3 + ll_highpart (x1);
227  rlo = ll_lowpart (x1) * ll_B + ll_lowpart (x0);
228  return MAKEDI (rhi + (alo * bhi) + (ahi * blo), rlo);
229}
230
231DI
232SHLDI (val, shift)
233     DI val;
234     SI shift;
235{
236  USI hi = GETHIDI (val);
237  USI lo = GETLODI (val);
238  /* FIXME: Need to worry about shift < 0 || shift >= 32.  */
239  return MAKEDI ((hi << shift) | (lo >> (32 - shift)), lo << shift);
240}
241
242DI
243SLADI (val, shift)
244     DI val;
245     SI shift;
246{
247  SI hi = GETHIDI (val);
248  USI lo = GETLODI (val);
249  /* FIXME: Need to worry about shift < 0 || shift >= 32.  */
250  return MAKEDI ((hi << shift) | (lo >> (32 - shift)), lo << shift);
251}
252
253DI
254SRADI (val, shift)
255     DI val;
256     SI shift;
257{
258  SI hi = GETHIDI (val);
259  USI lo = GETLODI (val);
260  /* We use SRASI because the result is implementation defined if hi < 0.  */
261  /* FIXME: Need to worry about shift < 0 || shift >= 32.  */
262  return MAKEDI (SRASI (hi, shift), (hi << (32 - shift)) | (lo >> shift));
263}
264
265int
266GEDI (a, b)
267     DI a, b;
268{
269  SI ahi = GETHIDI (a);
270  USI alo = GETLODI (a);
271  SI bhi = GETHIDI (b);
272  USI blo = GETLODI (b);
273  if (ahi > bhi)
274    return 1;
275  if (ahi == bhi)
276    return alo >= blo;
277  return 0;
278}
279
280int
281LEDI (a, b)
282     DI a, b;
283{
284  SI ahi = GETHIDI (a);
285  USI alo = GETLODI (a);
286  SI bhi = GETHIDI (b);
287  USI blo = GETLODI (b);
288  if (ahi < bhi)
289    return 1;
290  if (ahi == bhi)
291    return alo <= blo;
292  return 0;
293}
294
295DI
296CONVHIDI (val)
297     HI val;
298{
299  if (val < 0)
300    return MAKEDI (-1, val);
301  else
302    return MAKEDI (0, val);
303}
304
305DI
306CONVSIDI (val)
307     SI val;
308{
309  if (val < 0)
310    return MAKEDI (-1, val);
311  else
312    return MAKEDI (0, val);
313}
314
315SI
316CONVDISI (val)
317     DI val;
318{
319  return GETLODI (val);
320}
321
322#endif /* DI_FN_SUPPORT */
323
324QI
325RORQI (val, shift)
326     QI  val;
327     int shift;
328{
329  if (shift != 0)
330    {
331      int remain = 8 - shift;
332      int mask = (1 << shift) - 1;
333      QI result = (val & mask) << remain;
334      mask = (1 << remain) - 1;
335      result |= (val >> shift) & mask;
336      return result;
337    }
338  return val;
339}
340
341QI
342ROLQI (val, shift)
343     QI  val;
344     int shift;
345{
346  if (shift != 0)
347    {
348      int remain = 8 - shift;
349      int mask = (1 << remain) - 1;
350      QI result = (val & mask) << shift;
351      mask = (1 << shift) - 1;
352      result |= (val >> remain) & mask;
353      return result;
354    }
355  return val;
356}
357
358HI
359RORHI (val, shift)
360     HI  val;
361     int shift;
362{
363  if (shift != 0)
364    {
365      int remain = 16 - shift;
366      int mask = (1 << shift) - 1;
367      HI result = (val & mask) << remain;
368      mask = (1 << remain) - 1;
369      result |= (val >> shift) & mask;
370      return result;
371    }
372  return val;
373}
374
375HI
376ROLHI (val, shift)
377     HI  val;
378     int shift;
379{
380  if (shift != 0)
381    {
382      int remain = 16 - shift;
383      int mask = (1 << remain) - 1;
384      HI result = (val & mask) << shift;
385      mask = (1 << shift) - 1;
386      result |= (val >> remain) & mask;
387      return result;
388    }
389  return val;
390}
391
392SI
393RORSI (val, shift)
394     SI  val;
395     int shift;
396{
397  if (shift != 0)
398    {
399      int remain = 32 - shift;
400      int mask = (1 << shift) - 1;
401      SI result = (val & mask) << remain;
402      mask = (1 << remain) - 1;
403      result |= (val >> shift) & mask;
404      return result;
405    }
406  return val;
407}
408
409SI
410ROLSI (val, shift)
411     SI  val;
412     int shift;
413{
414  if (shift != 0)
415    {
416      int remain = 32 - shift;
417      int mask = (1 << remain) - 1;
418      SI result = (val & mask) << shift;
419      mask = (1 << shift) - 1;
420      result |= (val >> remain) & mask;
421      return result;
422    }
423
424  return val;
425}
426
427/* Emit an error message from CGEN RTL.  */
428
429void
430cgen_rtx_error (SIM_CPU *cpu, const char * msg)
431{
432  SIM_DESC sd = CPU_STATE (cpu);
433
434  sim_io_printf (sd, msg);
435  sim_io_printf (sd, "\n");
436
437  sim_engine_halt (sd, cpu, NULL, CIA_GET (cpu), sim_stopped, SIM_SIGTRAP);
438}
439