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