Commit | Line | Data |
---|---|---|
b9c8cd10 | 1 | /* Support code for various pieces of CGEN simulators. |
b500809f | 2 | Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. |
b9c8cd10 DE |
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" | |
b9c8cd10 DE |
24 | |
25 | #define MEMOPS_DEFINE_INLINE | |
b500809f | 26 | #include "cgen-mem.h" |
b9c8cd10 DE |
27 | |
28 | #define SEMOPS_DEFINE_INLINE | |
b500809f | 29 | #include "cgen-ops.h" |
b9c8cd10 DE |
30 | |
31 | const char *mode_names[] = { | |
32 | "VM", | |
33 | "BI", | |
34 | "QI", | |
35 | "HI", | |
36 | "SI", | |
37 | "DI", | |
38 | "UBI", | |
39 | "UQI", | |
40 | "UHI", | |
41 | "USI", | |
42 | "UDI", | |
43 | "SF", | |
44 | "DF", | |
45 | "XF", | |
46 | "TF", | |
47 | }; | |
48 | ||
260b2c47 DE |
49 | /* Initialize cgen things. |
50 | This is called after sim_post_argv_init. */ | |
51 | ||
52 | void | |
53 | cgen_init (SIM_DESC sd) | |
54 | { | |
55 | int i, c; | |
56 | int run_fast_p = 1; | |
57 | ||
58 | /* If no profiling or tracing has been enabled, run in fast mode. */ | |
59 | for (c = 0; c < MAX_NR_PROCESSORS; ++c) | |
60 | { | |
61 | sim_cpu *cpu = STATE_CPU (sd, c); | |
62 | ||
63 | for (i = 0; i < MAX_PROFILE_VALUES; ++i) | |
64 | if (CPU_PROFILE_FLAGS (cpu) [i]) | |
65 | { | |
66 | run_fast_p = 0; | |
67 | break; | |
68 | } | |
69 | for (i = 0; i < MAX_TRACE_VALUES; ++i) | |
70 | if (CPU_TRACE_FLAGS (cpu) [i]) | |
71 | { | |
72 | run_fast_p = 0; | |
73 | break; | |
74 | } | |
75 | if (! run_fast_p) | |
76 | break; | |
77 | } | |
78 | STATE_RUN_FAST_P (sd) = run_fast_p; | |
79 | } | |
80 | \f | |
b9c8cd10 DE |
81 | /* Disassembly support. |
82 | ??? While executing an instruction, the insn has been decoded and all its | |
83 | fields have been extracted. It is certainly possible to do the disassembly | |
84 | with that data. This seems simpler, but maybe in the future the already | |
85 | extracted fields will be used. */ | |
86 | ||
87 | /* Pseudo FILE object for strings. */ | |
88 | typedef struct { | |
89 | char *buffer; | |
90 | char *current; | |
91 | } SFILE; | |
92 | ||
93 | /* sprintf to a "stream" */ | |
94 | ||
95 | static int | |
96 | disasm_sprintf VPARAMS ((SFILE *f, const char *format, ...)) | |
97 | { | |
98 | #ifndef __STDC__ | |
99 | SFILE *f; | |
100 | const char *format; | |
101 | #endif | |
102 | int n; | |
103 | va_list args; | |
104 | ||
105 | VA_START (args, format); | |
106 | #ifndef __STDC__ | |
107 | f = va_arg (args, SFILE *); | |
108 | format = va_arg (args, char *); | |
109 | #endif | |
110 | vsprintf (f->current, format, args); | |
111 | f->current += n = strlen (f->current); | |
112 | va_end (args); | |
113 | return n; | |
114 | } | |
115 | ||
116 | void | |
260b2c47 DE |
117 | sim_disassemble_insn (SIM_CPU *cpu, const struct cgen_insn *insn, |
118 | const struct argbuf *abuf, PCADDR pc, char *buf) | |
b9c8cd10 | 119 | { |
b500809f | 120 | unsigned int length; |
b9c8cd10 DE |
121 | unsigned long insn_value; |
122 | struct disassemble_info disasm_info; | |
123 | struct cgen_fields fields; | |
124 | SFILE sfile; | |
b500809f DE |
125 | union { |
126 | unsigned8 bytes[16]; | |
127 | unsigned16 shorts[8]; | |
128 | unsigned32 words[4]; | |
129 | } insn_buf; | |
260b2c47 | 130 | SIM_DESC sd = CPU_STATE (cpu); |
b9c8cd10 DE |
131 | |
132 | sfile.buffer = sfile.current = buf; | |
133 | INIT_DISASSEMBLE_INFO (disasm_info, (FILE *) &sfile, | |
134 | (fprintf_ftype) disasm_sprintf); | |
135 | disasm_info.endian = | |
260b2c47 DE |
136 | (bfd_big_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_BIG |
137 | : bfd_little_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_LITTLE | |
b9c8cd10 DE |
138 | : BFD_ENDIAN_UNKNOWN); |
139 | ||
b500809f DE |
140 | length = sim_core_read_buffer (sd, cpu, sim_core_read_map, &insn_buf, pc, |
141 | CGEN_INSN_BITSIZE (insn) / 8); | |
142 | ||
143 | switch (length) | |
b9c8cd10 | 144 | { |
b500809f DE |
145 | case 1 : insn_value = insn_buf.bytes[0]; break; |
146 | case 2 : insn_value = T2H_2 (insn_buf.shorts[0]); break; | |
147 | case 4 : insn_value = T2H_4 (insn_buf.words[0]); break; | |
148 | default: abort (); | |
b9c8cd10 DE |
149 | } |
150 | ||
151 | length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, &fields); | |
b500809f DE |
152 | /* Result of extract fn is in bits. */ |
153 | /* ??? This assumes that each instruction has a fixed length (and thus | |
154 | for insns with multiple versions of variable lengths they would each | |
155 | have their own table entry). */ | |
156 | if (length == CGEN_INSN_BITSIZE (insn)) | |
b9c8cd10 DE |
157 | { |
158 | (*CGEN_PRINT_FN (insn)) (&disasm_info, insn, &fields, pc, length); | |
159 | } | |
160 | else | |
161 | { | |
162 | /* This shouldn't happen, but aborting is too drastic. */ | |
163 | strcpy (buf, "***unknown***"); | |
164 | } | |
165 | } | |
166 | \f | |
167 | #ifdef DI_FN_SUPPORT | |
168 | ||
169 | DI | |
170 | make_struct_di (hi, lo) | |
171 | SI hi, lo; | |
172 | { | |
173 | DI result; | |
174 | ||
175 | result.hi = hi; | |
176 | result.lo = lo; | |
177 | return result; | |
178 | } | |
179 | ||
180 | DI | |
181 | ANDDI (a, b) | |
182 | DI a, b; | |
183 | { | |
184 | SI ahi = GETHIDI (a); | |
185 | SI alo = GETLODI (a); | |
186 | SI bhi = GETHIDI (b); | |
187 | SI blo = GETLODI (b); | |
188 | return MAKEDI (ahi & bhi, alo & blo); | |
189 | } | |
190 | ||
191 | DI | |
192 | ORDI (a, b) | |
193 | DI a, b; | |
194 | { | |
195 | SI ahi = GETHIDI (a); | |
196 | SI alo = GETLODI (a); | |
197 | SI bhi = GETHIDI (b); | |
198 | SI blo = GETLODI (b); | |
199 | return MAKEDI (ahi | bhi, alo | blo); | |
200 | } | |
201 | ||
202 | DI | |
203 | ADDDI (a, b) | |
204 | DI a, b; | |
205 | { | |
206 | USI ahi = GETHIDI (a); | |
207 | USI alo = GETLODI (a); | |
208 | USI bhi = GETHIDI (b); | |
209 | USI blo = GETLODI (b); | |
210 | USI x = alo + blo; | |
211 | return MAKEDI (ahi + bhi + (x < alo), x); | |
212 | } | |
213 | ||
214 | DI | |
215 | MULDI (a, b) | |
216 | DI a, b; | |
217 | { | |
218 | USI ahi = GETHIDI (a); | |
219 | USI alo = GETLODI (a); | |
220 | USI bhi = GETHIDI (b); | |
221 | USI blo = GETLODI (b); | |
222 | USI rhi,rlo; | |
223 | USI x0, x1, x2, x3; | |
224 | ||
225 | x0 = alo * blo; | |
226 | x1 = alo * bhi; | |
227 | x2 = ahi * blo; | |
228 | x3 = ahi * bhi; | |
229 | ||
230 | #define SI_TYPE_SIZE 32 | |
231 | #define BITS4 (SI_TYPE_SIZE / 4) | |
232 | #define ll_B (1L << (SI_TYPE_SIZE / 2)) | |
233 | #define ll_lowpart(t) ((USI) (t) % ll_B) | |
234 | #define ll_highpart(t) ((USI) (t) / ll_B) | |
235 | x1 += ll_highpart (x0); /* this can't give carry */ | |
236 | x1 += x2; /* but this indeed can */ | |
237 | if (x1 < x2) /* did we get it? */ | |
238 | x3 += ll_B; /* yes, add it in the proper pos. */ | |
239 | ||
240 | rhi = x3 + ll_highpart (x1); | |
241 | rlo = ll_lowpart (x1) * ll_B + ll_lowpart (x0); | |
242 | return MAKEDI (rhi + (alo * bhi) + (ahi * blo), rlo); | |
243 | } | |
244 | ||
245 | DI | |
246 | SHLDI (val, shift) | |
247 | DI val; | |
248 | SI shift; | |
249 | { | |
250 | USI hi = GETHIDI (val); | |
251 | USI lo = GETLODI (val); | |
252 | /* FIXME: Need to worry about shift < 0 || shift >= 32. */ | |
253 | return MAKEDI ((hi << shift) | (lo >> (32 - shift)), lo << shift); | |
254 | } | |
255 | ||
256 | DI | |
257 | SLADI (val, shift) | |
258 | DI val; | |
259 | SI shift; | |
260 | { | |
261 | SI hi = GETHIDI (val); | |
262 | USI lo = GETLODI (val); | |
263 | /* FIXME: Need to worry about shift < 0 || shift >= 32. */ | |
264 | return MAKEDI ((hi << shift) | (lo >> (32 - shift)), lo << shift); | |
265 | } | |
266 | ||
267 | DI | |
268 | SRADI (val, shift) | |
269 | DI val; | |
270 | SI shift; | |
271 | { | |
272 | SI hi = GETHIDI (val); | |
273 | USI lo = GETLODI (val); | |
274 | /* We use SRASI because the result is implementation defined if hi < 0. */ | |
275 | /* FIXME: Need to worry about shift < 0 || shift >= 32. */ | |
276 | return MAKEDI (SRASI (hi, shift), (hi << (32 - shift)) | (lo >> shift)); | |
277 | } | |
278 | ||
279 | int | |
280 | GEDI (a, b) | |
281 | DI a, b; | |
282 | { | |
283 | SI ahi = GETHIDI (a); | |
284 | USI alo = GETLODI (a); | |
285 | SI bhi = GETHIDI (b); | |
286 | USI blo = GETLODI (b); | |
287 | if (ahi > bhi) | |
288 | return 1; | |
289 | if (ahi == bhi) | |
290 | return alo >= blo; | |
291 | return 0; | |
292 | } | |
293 | ||
294 | int | |
295 | LEDI (a, b) | |
296 | DI a, b; | |
297 | { | |
298 | SI ahi = GETHIDI (a); | |
299 | USI alo = GETLODI (a); | |
300 | SI bhi = GETHIDI (b); | |
301 | USI blo = GETLODI (b); | |
302 | if (ahi < bhi) | |
303 | return 1; | |
304 | if (ahi == bhi) | |
305 | return alo <= blo; | |
306 | return 0; | |
307 | } | |
308 | ||
309 | DI | |
310 | CONVHIDI (val) | |
311 | HI val; | |
312 | { | |
313 | if (val < 0) | |
314 | return MAKEDI (-1, val); | |
315 | else | |
316 | return MAKEDI (0, val); | |
317 | } | |
318 | ||
319 | DI | |
320 | CONVSIDI (val) | |
321 | SI val; | |
322 | { | |
323 | if (val < 0) | |
324 | return MAKEDI (-1, val); | |
325 | else | |
326 | return MAKEDI (0, val); | |
327 | } | |
328 | ||
329 | SI | |
330 | CONVDISI (val) | |
331 | DI val; | |
332 | { | |
333 | return GETLODI (val); | |
334 | } | |
335 | ||
336 | #endif /* DI_FN_SUPPORT */ |