Commit | Line | Data |
---|---|---|
c906108c SS |
1 | /* Engine header for Cpu tools GENerated simulators. |
2 | Copyright (C) 1998, 1999 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 | /* This file must be included after eng.h and before ${cpu}.h. */ | |
22 | ||
23 | /* Semantic functions come in six versions on two axes: | |
24 | fast/full-featured, and using one of the simple/scache/compilation engines. | |
25 | A full featured simulator is always provided. --enable-sim-fast includes | |
26 | support for fast execution by duplicating the semantic code but leaving | |
27 | out all features like tracing and profiling. | |
28 | Using the scache is selected with --enable-sim-scache. */ | |
29 | /* FIXME: --enable-sim-fast not implemented yet. */ | |
30 | /* FIXME: undecided how to handle WITH_SCACHE_PBB. */ | |
31 | ||
32 | /* There are several styles of engines, all generally supported by the | |
33 | same code: | |
34 | ||
35 | WITH_SCACHE && WITH_SCACHE_PBB - pseudo-basic-block scaching | |
36 | WITH_SCACHE && !WITH_SCACHE_PBB - scaching on an insn by insn basis | |
37 | !WITH_SCACHE - simple engine: fetch an insn, execute an insn | |
38 | ||
39 | The !WITH_SCACHE case can also be broken up into two flavours: | |
40 | extract the fields of the insn into an ARGBUF struct, or defer the | |
41 | extraction to the semantic handler. The former can be viewed as the | |
42 | WITH_SCACHE case with a cache size of 1 (thus there's no need for a | |
43 | WITH_EXTRACTION macro). The WITH_SCACHE case always extracts the fields | |
44 | into an ARGBUF struct. */ | |
45 | ||
46 | #ifndef CGEN_ENGINE_H | |
47 | #define CGEN_ENGINE_H | |
48 | ||
49 | /* Instruction field support macros. */ | |
50 | ||
51 | #define EXTRACT_MSB0_INT(val, total, start, length) \ | |
52 | (((INT) (val) << ((sizeof (INT) * 8) - (total) + (start))) \ | |
53 | >> ((sizeof (INT) * 8) - (length))) | |
54 | #define EXTRACT_MSB0_UINT(val, total, start, length) \ | |
55 | (((UINT) (val) << ((sizeof (UINT) * 8) - (total) + (start))) \ | |
56 | >> ((sizeof (UINT) * 8) - (length))) | |
57 | ||
58 | #define EXTRACT_LSB0_INT(val, total, start, length) \ | |
59 | (((INT) (val) << ((sizeof (INT) * 8) - (start) - 1)) \ | |
60 | >> ((sizeof (INT) * 8) - (length))) | |
61 | #define EXTRACT_LSB0_UINT(val, total, start, length) \ | |
62 | (((UINT) (val) << ((sizeof (UINT) * 8) - (start) - 1)) \ | |
63 | >> ((sizeof (UINT) * 8) - (length))) | |
64 | ||
65 | #if CGEN_INSN_LSB0_P | |
66 | ||
67 | #define EXTRACT_INT(val, total, start, length) \ | |
68 | EXTRACT_LSB0_INT ((val), (total), (start), (length)) | |
69 | #define EXTRACT_UINT(val, total, start, length) \ | |
70 | EXTRACT_LSB0_UINT ((val), (total), (start), (length)) | |
71 | ||
72 | #else | |
73 | ||
74 | #define EXTRACT_INT(val, total, start, length) \ | |
75 | EXTRACT_MSB0_INT ((val), (total), (start), (length)) | |
76 | #define EXTRACT_UINT(val, total, start, length) \ | |
77 | EXTRACT_MSB0_UINT ((val), (total), (start), (length)) | |
78 | ||
79 | #endif | |
80 | \f | |
81 | /* Semantic routines. */ | |
82 | ||
83 | /* Type of the machine generated extraction fns. */ | |
84 | /* ??? No longer used. */ | |
85 | typedef void (EXTRACT_FN) (SIM_CPU *, IADDR, CGEN_INSN_INT, ARGBUF *); | |
86 | ||
87 | /* Type of the machine generated semantic fns. */ | |
88 | ||
89 | #if WITH_SCACHE | |
90 | ||
91 | /* Instruction fields are extracted into ARGBUF before calling the | |
92 | semantic routine. */ | |
93 | #if HAVE_PARALLEL_INSNS | |
94 | typedef SEM_PC (SEMANTIC_FN) (SIM_CPU *, SEM_ARG, PAREXEC *); | |
95 | #else | |
96 | typedef SEM_PC (SEMANTIC_FN) (SIM_CPU *, SEM_ARG); | |
97 | #endif | |
98 | ||
99 | #else | |
100 | ||
101 | /* Result of semantic routines is a status indicator (wip). */ | |
102 | typedef unsigned int SEM_STATUS; | |
103 | ||
104 | /* Instruction fields are extracted by the semantic routine. | |
105 | ??? TODO: multi word insns. */ | |
106 | #if HAVE_PARALLEL_INSNS | |
107 | typedef SEM_STATUS (SEMANTIC_FN) (SIM_CPU *, SEM_ARG, PAREXEC *, CGEN_INSN_INT); | |
108 | #else | |
109 | typedef SEM_STATUS (SEMANTIC_FN) (SIM_CPU *, SEM_ARG, CGEN_INSN_INT); | |
110 | #endif | |
111 | ||
112 | #endif | |
113 | ||
114 | /* In the ARGBUF struct, a pointer to the semantic routine for the insn. */ | |
115 | ||
116 | union sem { | |
117 | #if ! WITH_SEM_SWITCH_FULL | |
118 | SEMANTIC_FN *sem_full; | |
119 | #endif | |
120 | #if ! WITH_SEM_SWITCH_FAST | |
121 | SEMANTIC_FN *sem_fast; | |
122 | #endif | |
123 | #if WITH_SEM_SWITCH_FULL || WITH_SEM_SWITCH_FAST | |
124 | #ifdef __GNUC__ | |
125 | void *sem_case; | |
126 | #else | |
127 | int sem_case; | |
128 | #endif | |
129 | #endif | |
130 | }; | |
131 | ||
132 | /* Set the appropriate semantic handler in ABUF. */ | |
133 | ||
134 | #if WITH_SEM_SWITCH_FULL | |
135 | #ifdef __GNUC__ | |
136 | #define SEM_SET_FULL_CODE(abuf, idesc) \ | |
137 | do { (abuf)->semantic.sem_case = (idesc)->sem_full_lab; } while (0) | |
138 | #else | |
139 | #define SEM_SET_FULL_CODE(abuf, idesc) \ | |
140 | do { (abuf)->semantic.sem_case = (idesc)->num; } while (0) | |
141 | #endif | |
142 | #else | |
143 | #define SEM_SET_FULL_CODE(abuf, idesc) \ | |
144 | do { (abuf)->semantic.sem_full = (idesc)->sem_full; } while (0) | |
145 | #endif | |
146 | ||
147 | #if WITH_SEM_SWITCH_FAST | |
148 | #ifdef __GNUC__ | |
149 | #define SEM_SET_FAST_CODE(abuf, idesc) \ | |
150 | do { (abuf)->semantic.sem_case = (idesc)->sem_fast_lab; } while (0) | |
151 | #else | |
152 | #define SEM_SET_FAST_CODE(abuf, idesc) \ | |
153 | do { (abuf)->semantic.sem_case = (idesc)->num; } while (0) | |
154 | #endif | |
155 | #else | |
156 | #define SEM_SET_FAST_CODE(abuf, idesc) \ | |
157 | do { (abuf)->semantic.sem_fast = (idesc)->sem_fast; } while (0) | |
158 | #endif | |
159 | ||
160 | #define SEM_SET_CODE(abuf, idesc, fast_p) \ | |
161 | do { \ | |
162 | if (fast_p) \ | |
163 | SEM_SET_FAST_CODE ((abuf), (idesc)); \ | |
164 | else \ | |
165 | SEM_SET_FULL_CODE ((abuf), (idesc)); \ | |
166 | } while (0) | |
167 | \f | |
168 | /* Return non-zero if IDESC is a conditional or unconditional CTI. */ | |
169 | ||
170 | #define IDESC_CTI_P(idesc) \ | |
171 | ((CGEN_ATTR_BOOLS (CGEN_INSN_ATTRS ((idesc)->idata)) \ | |
172 | & (CGEN_ATTR_MASK (CGEN_INSN_COND_CTI) \ | |
173 | | CGEN_ATTR_MASK (CGEN_INSN_UNCOND_CTI))) \ | |
174 | != 0) | |
175 | ||
176 | /* Return non-zero if IDESC is a skip insn. */ | |
177 | ||
178 | #define IDESC_SKIP_P(idesc) \ | |
179 | ((CGEN_ATTR_BOOLS (CGEN_INSN_ATTRS ((idesc)->idata)) \ | |
180 | & CGEN_ATTR_MASK (CGEN_INSN_SKIP_CTI)) \ | |
181 | != 0) | |
182 | ||
183 | /* These are used so that we can compile two copies of the semantic code, | |
184 | one with full feature support and one without that runs fast(er). */ | |
185 | #define SEM_FN_NAME(cpu,fn) XCONCAT3 (cpu,_sem_,fn) | |
186 | #define SEMF_FN_NAME(cpu,fn) XCONCAT3 (cpu,_semf_,fn) | |
187 | ||
188 | /* Return pointer to ARGBUF given ptr to SCACHE. */ | |
189 | #define SEM_ARGBUF(sem_arg) (& (sem_arg) -> argbuf) | |
190 | ||
191 | /* There are several styles of engines, all generally supported by the | |
192 | same code: | |
193 | ||
194 | WITH_SCACHE && WITH_SCACHE_PBB - pseudo-basic-block scaching | |
195 | WITH_SCACHE && !WITH_SCACHE_PBB - scaching on an insn by insn basis | |
196 | !WITH_SCACHE - simple engine: fetch an insn, execute an insn | |
197 | ||
198 | ??? The !WITH_SCACHE case can also be broken up into two flavours: | |
199 | extract the fields of the insn into an ARGBUF struct, or defer the | |
200 | extraction to the semantic handler. The WITH_SCACHE case always | |
201 | extracts the fields into an ARGBUF struct. */ | |
202 | ||
203 | #if WITH_SCACHE | |
204 | ||
205 | #define CIA_ADDR(cia) (cia) | |
206 | ||
207 | #if WITH_SCACHE_PBB | |
208 | ||
209 | /* Return the scache pointer of the current insn. */ | |
210 | #define SEM_SEM_ARG(vpc, sc) (vpc) | |
211 | ||
212 | /* Return the virtual pc of the next insn to execute | |
213 | (assuming this isn't a cti or the branch isn't taken). */ | |
214 | #define SEM_NEXT_VPC(sem_arg, pc, len) ((sem_arg) + 1) | |
215 | ||
216 | /* Update the instruction counter. */ | |
217 | #define PBB_UPDATE_INSN_COUNT(cpu,sc) \ | |
218 | (CPU_INSN_COUNT (cpu) += SEM_ARGBUF (sc) -> fields.chain.insn_count) | |
219 | ||
220 | /* Value for br_addr_ptr indicating branch wasn't taken. */ | |
221 | #define SEM_BRANCH_UNTAKEN ((SEM_PC *) 0) | |
222 | ||
223 | /* Value for br_addr_ptr indicating branch was taken to uncacheable | |
224 | address (e.g. j reg). */ | |
225 | #define SEM_BRANCH_UNCACHEABLE ((SEM_PC *) 1) | |
226 | ||
227 | /* Initialize next-pbb link for SEM_BRANCH_VIA_CACHE. */ | |
228 | #define SEM_BRANCH_INIT_EXTRACT(abuf) \ | |
229 | do { (abuf)->fields.cti.addr_cache = 0; } while (0) | |
230 | ||
231 | /* Do not append a `;' to invocations of this. | |
232 | npc,npc_ptr are for communication between the cti insn and cti-chain. */ | |
233 | #define SEM_BRANCH_INIT \ | |
234 | IADDR npc = 0; /* assign a value for -Wall */ \ | |
235 | SEM_PC *npc_ptr = SEM_BRANCH_UNTAKEN; | |
236 | ||
237 | /* SEM_IN_SWITCH is defined at the top of the mainloop.c files | |
238 | generated by genmloop.sh. It exists so generated semantic code needn't | |
239 | care whether it's being put in a switch or in a function. */ | |
240 | #ifdef SEM_IN_SWITCH | |
241 | #define SEM_BRANCH_FINI(pcvar) \ | |
242 | do { \ | |
243 | pbb_br_npc = npc; \ | |
244 | pbb_br_npc_ptr = npc_ptr; \ | |
245 | } while (0) | |
246 | #else /* 1 semantic function per instruction */ | |
247 | #define SEM_BRANCH_FINI(pcvar) \ | |
248 | do { \ | |
249 | CPU_PBB_BR_NPC (current_cpu) = npc; \ | |
250 | CPU_PBB_BR_NPC_PTR (current_cpu) = npc_ptr; \ | |
251 | } while (0) | |
252 | #endif | |
253 | ||
254 | /* Return address of cached branch address value. */ | |
255 | #define SEM_BRANCH_ADDR_CACHE(sem_arg) \ | |
256 | (& SEM_ARGBUF (sem_arg)->fields.cti.addr_cache) | |
257 | ||
258 | #define SEM_BRANCH_VIA_CACHE(cpu, sc, newval, pcvar, cachevarptr) \ | |
259 | do { \ | |
260 | npc = (newval); \ | |
261 | npc_ptr = (cachevarptr); \ | |
262 | } while (0) | |
263 | ||
264 | #define SEM_BRANCH_VIA_ADDR(cpu, sc, newval, pcvar) \ | |
265 | do { \ | |
266 | npc = (newval); \ | |
267 | npc_ptr = SEM_BRANCH_UNCACHEABLE; \ | |
268 | } while (0) | |
269 | ||
270 | #else /* ! WITH_SCACHE_PBB */ | |
271 | ||
272 | #define SEM_SEM_ARG(vpc, sc) (sc) | |
273 | ||
274 | #define SEM_NEXT_VPC(sem_arg, pc, len) ((pc) + (len)) | |
275 | ||
276 | #define SEM_BRANCH_INIT_EXTRACT(abuf) do { } while (0) | |
277 | ||
278 | /* ??? May wish to move taken_p out of here and make it explicit. */ | |
279 | #define SEM_BRANCH_INIT \ | |
280 | int taken_p = 0; | |
281 | ||
282 | #ifndef TARGET_SEM_BRANCH_FINI(pcvar, taken_p) | |
283 | #define TARGET_SEM_BRANCH_FINI(pcvar, taken_p) | |
284 | #endif | |
285 | #define SEM_BRANCH_FINI(pcvar) \ | |
286 | do { TARGET_SEM_BRANCH_FINI (pcvar, taken_p); } while (0) | |
287 | ||
288 | #define SEM_BRANCH_ADDR_CACHE(sem_arg) shouldnt_be_used | |
289 | ||
290 | #define SEM_BRANCH_VIA_CACHE(cpu, sc, newval, pcvar, cachevar) \ | |
291 | do { \ | |
292 | (pcvar) = (newval); \ | |
293 | taken_p = 1; \ | |
294 | } while (0) | |
295 | ||
296 | #define SEM_BRANCH_VIA_ADDR(cpu, sc, newval, pcvar) \ | |
297 | do { \ | |
298 | (pcvar) = (newval); \ | |
299 | taken_p = 1; \ | |
300 | } while (0) | |
301 | ||
302 | #endif /* ! WITH_SCACHE_PBB */ | |
303 | ||
304 | #else /* ! WITH_SCACHE */ | |
305 | ||
306 | /* This is the "simple" engine case. */ | |
307 | ||
308 | #define CIA_ADDR(cia) (cia) | |
309 | ||
310 | #define SEM_SEM_ARG(vpc, sc) (sc) | |
311 | ||
312 | #define SEM_NEXT_VPC(sem_arg, pc, len) ((pc) + (len)) | |
313 | ||
314 | #define SEM_BRANCH_INIT \ | |
315 | int taken_p = 0; | |
316 | ||
317 | #define SEM_BRANCH_ADDR_CACHE(sem_arg) shouldnt_be_used | |
318 | ||
319 | #define SEM_BRANCH_VIA_CACHE(cpu, abuf, newval, pcvar, cachevar) \ | |
320 | do { \ | |
321 | (pcvar) = (newval); \ | |
322 | taken_p = 1; \ | |
323 | } while (0) | |
324 | ||
325 | #define SEM_BRANCH_VIA_ADDR(cpu, abuf, newval, pcvar) \ | |
326 | do { \ | |
327 | (pcvar) = (newval); \ | |
328 | taken_p = 1; \ | |
329 | } while (0) | |
330 | ||
331 | /* Finish off branch insns. | |
332 | The target must define TARGET_SEM_BRANCH_FINI. | |
333 | ??? This can probably go away when define-execute is finished. */ | |
334 | #define SEM_BRANCH_FINI(pcvar, bool_attrs) \ | |
335 | do { TARGET_SEM_BRANCH_FINI ((pcvar), (bool_attrs), taken_p); } while (0) | |
336 | ||
337 | /* Finish off non-branch insns. | |
338 | The target must define TARGET_SEM_NBRANCH_FINI. | |
339 | ??? This can probably go away when define-execute is finished. */ | |
340 | #define SEM_NBRANCH_FINI(pcvar, bool_attrs) \ | |
341 | do { TARGET_SEM_NBRANCH_FINI ((pcvar), (bool_attrs)); } while (0) | |
342 | ||
343 | #endif /* ! WITH_SCACHE */ | |
344 | \f | |
345 | /* Instruction information. */ | |
346 | ||
347 | /* Compile time computable instruction data. | |
348 | ||
349 | ??? May wish to move parallel execution support into its own struct. | |
350 | It's a fair bit of "clutter" for the "normal" case. */ | |
351 | ||
352 | struct insn_sem { | |
353 | /* The instruction type (a number that identifies each insn over the | |
354 | entire architecture). */ | |
355 | CGEN_INSN_TYPE type; | |
356 | ||
357 | /* Index in IDESC table. */ | |
358 | int index; | |
359 | ||
360 | /* Sanity check, at most one of these may be true. */ | |
361 | #if WITH_PARALLEL_READ && WITH_PARALLEL_WRITE | |
362 | #error "Both WITH_PARALLEL_READ && WITH_PARALLEL_WRITE can't be true." | |
363 | #endif | |
364 | ||
365 | #if WITH_PARALLEL_READ || WITH_PARALLEL_WRITE | |
366 | /* Index in IDESC table of parallel handler. */ | |
367 | int par_index; | |
368 | #endif | |
369 | ||
370 | #if WITH_PARALLEL_READ | |
371 | #ifndef __GNUC__ | |
372 | /* Semantic format number of pre-read handler. | |
373 | Only used by chips that support parallel execution of several insns. | |
374 | It is always implemented as a `switch'. In the case of GNUC we use | |
375 | computed gotos. When not GNUC, this is the argument to `switch'. */ | |
376 | int fmt; | |
377 | #endif | |
378 | #endif | |
379 | ||
380 | #if WITH_PARALLEL_WRITE | |
381 | /* Index in IDESC table of writeback handler. | |
382 | Only used by chips that support parallel execution of several insns. */ | |
383 | int write_index; | |
384 | #endif | |
385 | ||
386 | /* Routines to execute the insn. | |
387 | The full version has all features (profiling,tracing) compiled in. | |
388 | The fast version has none of that. */ | |
389 | #if ! WITH_SEM_SWITCH_FULL | |
390 | SEMANTIC_FN *sem_full; | |
391 | #endif | |
392 | #if WITH_FAST && ! WITH_SEM_SWITCH_FAST | |
393 | SEMANTIC_FN *sem_fast; | |
394 | #endif | |
395 | }; | |
396 | ||
397 | /* Run-time computed instruction descriptor. */ | |
398 | ||
399 | struct idesc { | |
400 | /* Parallel read-before-exec support. */ | |
401 | #if WITH_PARALLEL_READ | |
402 | struct idesc *par_idesc; | |
403 | #ifdef __GNUC__ | |
404 | void *read; | |
405 | #else | |
406 | int fmt; | |
407 | #endif | |
408 | #endif | |
409 | ||
410 | /* Parallel write-after-exec support. */ | |
411 | #if WITH_PARALLEL_WRITE | |
412 | /* Pointer to parallel handler if serial insn. | |
413 | Pointer to writeback handler if parallel insn. */ | |
414 | struct idesc *par_idesc; | |
415 | #endif | |
416 | ||
417 | #if WITH_SEM_SWITCH_FULL | |
418 | #ifdef __GNUC__ | |
419 | void *sem_full_lab; | |
420 | #else | |
421 | /* nothing needed, switch's on `num' member */ | |
422 | #endif | |
423 | #else | |
424 | SEMANTIC_FN *sem_full; | |
425 | #endif | |
426 | ||
427 | #if WITH_SEM_SWITCH_FAST | |
428 | #ifdef __GNUC__ | |
429 | void *sem_fast_lab; | |
430 | #else | |
431 | /* nothing needed, switch's on `num' member */ | |
432 | #endif | |
433 | #else | |
434 | SEMANTIC_FN *sem_fast; | |
435 | #endif | |
436 | ||
437 | /* Instruction number (index in IDESC table, profile table). | |
438 | Also used to switch on in non-gcc semantic switches. */ | |
439 | int num; | |
440 | ||
441 | /* instruction data (name, attributes, size, etc.) */ | |
442 | const CGEN_INSN *idata; | |
443 | ||
444 | /* instruction attributes, copied from `idata' for speed */ | |
445 | const CGEN_INSN_ATTR_TYPE *attrs; | |
446 | ||
447 | /* instruction length in bytes, copied from `idata' for speed */ | |
448 | int length; | |
449 | ||
450 | /* profiling/modelling support */ | |
451 | const INSN_TIMING *timing; | |
452 | }; | |
453 | \f | |
454 | /* Tracing/profiling. */ | |
455 | ||
456 | /* Return non-zero if a before/after handler is needed. | |
457 | When tracing/profiling a selected range there's no need to slow | |
458 | down simulation of the other insns (except to get more accurate data!). | |
459 | ||
460 | ??? May wish to profile all insns if doing insn tracing, or to | |
461 | get more accurate cycle data. | |
462 | ||
463 | First test ANY_P so we avoid a potentially expensive HIT_P call | |
464 | [if there are lots of address ranges]. */ | |
465 | ||
466 | #define PC_IN_TRACE_RANGE_P(cpu, pc) \ | |
467 | (TRACE_ANY_P (cpu) \ | |
468 | && ADDR_RANGE_HIT_P (TRACE_RANGE (CPU_TRACE_DATA (cpu)), (pc))) | |
469 | #define PC_IN_PROFILE_RANGE_P(cpu, pc) \ | |
470 | (PROFILE_ANY_P (cpu) \ | |
471 | && ADDR_RANGE_HIT_P (PROFILE_RANGE (CPU_PROFILE_DATA (cpu)), (pc))) | |
472 | ||
473 | #endif /* CGEN_ENGINE_H */ |