* cgen-mem.h, cgen-scache.[ch], cgen-sem.h, cgen-sim.h: New files.
[external/binutils.git] / sim / common / cgen-utils.c
1 /* Support code for various pieces of CGEN simulators.
2    Copyright (C) 1996, 1997 Free Software Foundation, Inc.
3    Contributed by Cygnus Support.
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 2, or (at your option)
10 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 along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #include "sim-main.h"
22 #include "dis-asm.h"
23 #include "cpu-opc.h"
24 #include "decode.h"
25
26 #define MEMOPS_DEFINE_INLINE
27 #include "cgen-mem.h"
28
29 #define SEMOPS_DEFINE_INLINE
30 #include "cgen-sem.h"
31
32 const char *mode_names[] = {
33   "VM",
34   "BI",
35   "QI",
36   "HI",
37   "SI",
38   "DI",
39   "UBI",
40   "UQI",
41   "UHI",
42   "USI",
43   "UDI",
44   "SF",
45   "DF",
46   "XF",
47   "TF",
48 };
49
50 void
51 engine_halt (cpu, reason, sigrc)
52      sim_cpu *cpu;
53      enum exec_state reason;
54      int sigrc;
55 {
56   CPU_EXEC_STATE (cpu) = reason;
57   CPU_HALT_SIGRC (cpu) = sigrc;
58
59   longjmp (STATE_HALT_JMP_BUF (CPU_STATE (cpu)), 1);
60 }
61
62 void
63 engine_signal (cpu, sig)
64      sim_cpu *cpu;
65      enum sim_signal_type sig;
66 {
67   engine_halt (cpu, EXEC_STATE_STOPPED, sig);
68 }
69
70 /* Convert SIM_SIGFOO to SIGFOO.  */
71
72 int
73 sim_signal_to_host (sig)
74      int sig;
75 {
76   switch (sig)
77     {
78     case SIM_SIGILL :
79 #ifdef SIGILL
80       return SIGILL;
81 #endif
82       break;
83
84     case SIM_SIGTRAP :
85 #ifdef SIGTRAP
86       return SIGTRAP;
87 #else
88 #ifdef _MSC_VER
89       /* Wingdb uses this value.  */
90       return 5;
91 #endif
92 #endif
93       break;
94
95     case SIM_SIGALIGN :
96     case SIM_SIGACCESS :
97 #ifdef SIGSEGV
98       return SIGSEGV;
99 #endif
100       break;
101
102     case SIM_SIGXCPU :
103 #ifdef SIGXCPU
104       return SIGXCPU;
105 #endif
106       break;
107     }
108   return 1;
109 }
110 \f
111 /* FIXME: Add "no return" attribute to illegal insn handlers.
112    They all call longjmp.  */
113 /* FIXME: May wish to call a target supplied routine which can then call
114    sim_halt if it wants: to allow target to gain control for moment.  */
115
116 void
117 ex_illegal (SIM_CPU *cpu, PCADDR pc, insn_t insn, ARGBUF *abuf)
118 {
119   abuf->length = CGEN_BASE_INSN_SIZE;
120   abuf->addr = pc;
121   /* Leave signalling to semantic fn.  */
122 }
123
124 void
125 exc_illegal (SIM_CPU *cpu, PCADDR pc, insn_t insn, ARGBUF *abuf)
126 {
127   abuf->length = CGEN_BASE_INSN_SIZE;
128   abuf->addr = pc;
129   /* Leave signalling to semantic fn.  */
130 }
131
132 PCADDR
133 sem_illegal (current_cpu, sem_arg)
134      SIM_CPU *current_cpu;
135      struct argbuf *sem_arg;
136 {
137   engine_halt (current_cpu, EXEC_STATE_SIGNALLED, SIM_SIGILL);
138   return 0;
139 }
140
141 PCADDR
142 semc_illegal (current_cpu, sem_arg)
143      SIM_CPU *current_cpu;
144      struct scache *sem_arg;
145 {
146   engine_halt (current_cpu, EXEC_STATE_SIGNALLED, SIM_SIGILL);
147   return 0;
148 }
149 \f
150 /* Disassembly support.
151    ??? While executing an instruction, the insn has been decoded and all its
152    fields have been extracted.  It is certainly possible to do the disassembly
153    with that data.  This seems simpler, but maybe in the future the already
154    extracted fields will be used.  */
155
156 /* Pseudo FILE object for strings.  */
157 typedef struct {
158   char *buffer;
159   char *current;
160 } SFILE;
161
162 /* sprintf to a "stream" */
163
164 static int
165 disasm_sprintf VPARAMS ((SFILE *f, const char *format, ...))
166 {
167 #ifndef __STDC__
168   SFILE *f;
169   const char *format;
170 #endif
171   int n;
172   va_list args;
173
174   VA_START (args, format);
175 #ifndef __STDC__
176   f = va_arg (args, SFILE *);
177   format = va_arg (args, char *);
178 #endif
179   vsprintf (f->current, format, args);
180   f->current += n = strlen (f->current);
181   va_end (args);
182   return n;
183 }
184
185 void
186 sim_disassemble_insn (insn, abuf, pc, buf)
187      const struct cgen_insn *insn;
188      const struct argbuf *abuf;
189      PCADDR pc;
190      char *buf;
191 {
192   int length;
193   unsigned long insn_value;
194   struct disassemble_info disasm_info;
195   struct cgen_fields fields;
196   SFILE sfile;
197   char insn_buf[20];
198   STATE state = current_state;
199
200   sfile.buffer = sfile.current = buf;
201   INIT_DISASSEMBLE_INFO (disasm_info, (FILE *) &sfile,
202                          (fprintf_ftype) disasm_sprintf);
203   disasm_info.endian =
204     (bfd_big_endian (STATE_PROG_BFD (state)) ? BFD_ENDIAN_BIG
205      : bfd_little_endian (STATE_PROG_BFD (state)) ? BFD_ENDIAN_LITTLE
206      : BFD_ENDIAN_UNKNOWN);
207
208 /*  (*STATE_MEM_READ (state)) (state, pc, insn_buf, abuf->length);*/
209
210   switch (abuf->length)
211     {
212     case 1 :
213       insn_value = insn_buf[0];
214       break;
215     case 2 :
216       insn_value = disasm_info.endian == BFD_ENDIAN_BIG ? bfd_getb16 (insn_buf) : bfd_getl16 (insn_buf);
217       break;
218     case 4 :
219       insn_value = disasm_info.endian == BFD_ENDIAN_BIG ? bfd_getb32 (insn_buf) : bfd_getl32 (insn_buf);
220       break;
221     default:
222       abort ();
223     }
224
225   length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, &fields);
226   if (length != abuf->length)
227     {
228       (*CGEN_PRINT_FN (insn)) (&disasm_info, insn, &fields, pc, length);
229     }
230   else
231     {
232       /* This shouldn't happen, but aborting is too drastic.  */
233       strcpy (buf, "***unknown***");
234     }
235 }
236 \f
237 #ifdef DI_FN_SUPPORT
238
239 DI
240 make_struct_di (hi, lo)
241      SI hi, lo;
242 {
243   DI result;
244
245   result.hi = hi;
246   result.lo = lo;
247   return result;
248 }
249
250 DI
251 ANDDI (a, b)
252      DI a, b;
253 {
254   SI ahi = GETHIDI (a);
255   SI alo = GETLODI (a);
256   SI bhi = GETHIDI (b);
257   SI blo = GETLODI (b);
258   return MAKEDI (ahi & bhi, alo & blo);
259 }
260
261 DI
262 ORDI (a, b)
263      DI a, b;
264 {
265   SI ahi = GETHIDI (a);
266   SI alo = GETLODI (a);
267   SI bhi = GETHIDI (b);
268   SI blo = GETLODI (b);
269   return MAKEDI (ahi | bhi, alo | blo);
270 }
271
272 DI
273 ADDDI (a, b)
274      DI a, b;
275 {
276   USI ahi = GETHIDI (a);
277   USI alo = GETLODI (a);
278   USI bhi = GETHIDI (b);
279   USI blo = GETLODI (b);
280   USI x = alo + blo;
281   return MAKEDI (ahi + bhi + (x < alo), x);
282 }
283
284 DI
285 MULDI (a, b)
286      DI a, b;
287 {
288   USI ahi = GETHIDI (a);
289   USI alo = GETLODI (a);
290   USI bhi = GETHIDI (b);
291   USI blo = GETLODI (b);
292   USI rhi,rlo;
293   USI x0, x1, x2, x3;
294
295   x0 = alo * blo;
296   x1 = alo * bhi;
297   x2 = ahi * blo;
298   x3 = ahi * bhi;
299
300 #define SI_TYPE_SIZE 32
301 #define BITS4 (SI_TYPE_SIZE / 4)
302 #define ll_B (1L << (SI_TYPE_SIZE / 2))
303 #define ll_lowpart(t) ((USI) (t) % ll_B)
304 #define ll_highpart(t) ((USI) (t) / ll_B)
305   x1 += ll_highpart (x0);       /* this can't give carry */
306   x1 += x2;                     /* but this indeed can */
307   if (x1 < x2)                  /* did we get it? */
308     x3 += ll_B;                 /* yes, add it in the proper pos. */
309
310   rhi = x3 + ll_highpart (x1);
311   rlo = ll_lowpart (x1) * ll_B + ll_lowpart (x0);
312   return MAKEDI (rhi + (alo * bhi) + (ahi * blo), rlo);
313 }
314
315 DI
316 SHLDI (val, shift)
317      DI val;
318      SI shift;
319 {
320   USI hi = GETHIDI (val);
321   USI lo = GETLODI (val);
322   /* FIXME: Need to worry about shift < 0 || shift >= 32.  */
323   return MAKEDI ((hi << shift) | (lo >> (32 - shift)), lo << shift);
324 }
325
326 DI
327 SLADI (val, shift)
328      DI val;
329      SI shift;
330 {
331   SI hi = GETHIDI (val);
332   USI lo = GETLODI (val);
333   /* FIXME: Need to worry about shift < 0 || shift >= 32.  */
334   return MAKEDI ((hi << shift) | (lo >> (32 - shift)), lo << shift);
335 }
336
337 DI
338 SRADI (val, shift)
339      DI val;
340      SI shift;
341 {
342   SI hi = GETHIDI (val);
343   USI lo = GETLODI (val);
344   /* We use SRASI because the result is implementation defined if hi < 0.  */
345   /* FIXME: Need to worry about shift < 0 || shift >= 32.  */
346   return MAKEDI (SRASI (hi, shift), (hi << (32 - shift)) | (lo >> shift));
347 }
348
349 int
350 GEDI (a, b)
351      DI a, b;
352 {
353   SI ahi = GETHIDI (a);
354   USI alo = GETLODI (a);
355   SI bhi = GETHIDI (b);
356   USI blo = GETLODI (b);
357   if (ahi > bhi)
358     return 1;
359   if (ahi == bhi)
360     return alo >= blo;
361   return 0;
362 }
363
364 int
365 LEDI (a, b)
366      DI a, b;
367 {
368   SI ahi = GETHIDI (a);
369   USI alo = GETLODI (a);
370   SI bhi = GETHIDI (b);
371   USI blo = GETLODI (b);
372   if (ahi < bhi)
373     return 1;
374   if (ahi == bhi)
375     return alo <= blo;
376   return 0;
377 }
378
379 DI
380 CONVHIDI (val)
381      HI val;
382 {
383   if (val < 0)
384     return MAKEDI (-1, val);
385   else
386     return MAKEDI (0, val);
387 }
388
389 DI
390 CONVSIDI (val)
391      SI val;
392 {
393   if (val < 0)
394     return MAKEDI (-1, val);
395   else
396     return MAKEDI (0, val);
397 }
398
399 SI
400 CONVDISI (val)
401      DI val;
402 {
403   return GETLODI (val);
404 }
405
406 #endif /* DI_FN_SUPPORT */