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