1 /* Engine header for Cpu tools GENerated simulators. 2 Copyright (C) 1998, 1999, 2007, 2008, 2009, 2010, 2011 3 Free Software Foundation, Inc. 4 Contributed by Cygnus Support. 5 6 This file is part of GDB, the GNU debugger. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 20 21 /* This file is included by ${cpu}.h. 22 It needs CGEN_INSN_WORD which is defined by ${cpu}.h. 23 ??? A lot of this could be moved to genmloop.sh to be put in eng.h 24 and thus remove some conditional compilation. We'd still need 25 CGEN_INSN_WORD though. */ 26 27 /* Semantic functions come in six versions on two axes: 28 fast/full-featured, and using one of the simple/scache/compilation engines. 29 A full featured simulator is always provided. --enable-sim-fast includes 30 support for fast execution by duplicating the semantic code but leaving 31 out all features like tracing and profiling. 32 Using the scache is selected with --enable-sim-scache. */ 33 /* FIXME: --enable-sim-fast not implemented yet. */ 34 /* FIXME: undecided how to handle WITH_SCACHE_PBB. */ 35 36 /* There are several styles of engines, all generally supported by the 37 same code: 38 39 WITH_SCACHE && WITH_SCACHE_PBB - pseudo-basic-block scaching 40 WITH_SCACHE && !WITH_SCACHE_PBB - scaching on an insn by insn basis 41 !WITH_SCACHE - simple engine: fetch an insn, execute an insn 42 43 The !WITH_SCACHE case can also be broken up into two flavours: 44 extract the fields of the insn into an ARGBUF struct, or defer the 45 extraction to the semantic handler. The former can be viewed as the 46 WITH_SCACHE case with a cache size of 1 (thus there's no need for a 47 WITH_EXTRACTION macro). The WITH_SCACHE case always extracts the fields 48 into an ARGBUF struct. */ 49 50 #ifndef CGEN_ENGINE_H 51 #define CGEN_ENGINE_H 52 53 /* Instruction field support macros. */ 54 55 #define EXTRACT_MSB0_SINT(val, total, start, length) \ 56 (((INT) (val) << ((sizeof (INT) * 8) - (total) + (start))) \ 57 >> ((sizeof (INT) * 8) - (length))) 58 #define EXTRACT_MSB0_UINT(val, total, start, length) \ 59 (((UINT) (val) << ((sizeof (UINT) * 8) - (total) + (start))) \ 60 >> ((sizeof (UINT) * 8) - (length))) 61 62 #define EXTRACT_LSB0_SINT(val, total, start, length) \ 63 (((INT) (val) << ((sizeof (INT) * 8) - (start) - 1)) \ 64 >> ((sizeof (INT) * 8) - (length))) 65 #define EXTRACT_LSB0_UINT(val, total, start, length) \ 66 (((UINT) (val) << ((sizeof (UINT) * 8) - (start) - 1)) \ 67 >> ((sizeof (UINT) * 8) - (length))) 68 69 #define EXTRACT_MSB0_LGSINT(val, total, start, length) \ 70 (((CGEN_INSN_LGSINT) (val) << ((sizeof (CGEN_INSN_LGSINT) * 8) - (total) + (start))) \ 71 >> ((sizeof (CGEN_INSN_LGSINT) * 8) - (length))) 72 #define EXTRACT_MSB0_LGUINT(val, total, start, length) \ 73 (((CGEN_INSN_UINT) (val) << ((sizeof (CGEN_INSN_LGUINT) * 8) - (total) + (start))) \ 74 >> ((sizeof (CGEN_INSN_LGUINT) * 8) - (length))) 75 76 #define EXTRACT_LSB0_LGSINT(val, total, start, length) \ 77 (((CGEN_INSN_LGSINT) (val) << ((sizeof (CGEN_INSN_LGSINT) * 8) - (start) - 1)) \ 78 >> ((sizeof (CGEN_INSN_LGSINT) * 8) - (length))) 79 #define EXTRACT_LSB0_LGUINT(val, total, start, length) \ 80 (((CGEN_INSN_LGUINT) (val) << ((sizeof (CGEN_INSN_LGUINT) * 8) - (start) - 1)) \ 81 >> ((sizeof (CGEN_INSN_LGUINT) * 8) - (length))) 82 83 /* Semantic routines. */ 84 85 /* Type of the machine generated extraction fns. */ 86 /* ??? No longer used. */ 87 typedef void (EXTRACT_FN) (SIM_CPU *, IADDR, CGEN_INSN_WORD, ARGBUF *); 88 89 /* Type of the machine generated semantic fns. */ 90 91 #if WITH_SCACHE 92 93 /* Instruction fields are extracted into ARGBUF before calling the 94 semantic routine. */ 95 #if HAVE_PARALLEL_INSNS && ! WITH_PARALLEL_GENWRITE 96 typedef SEM_PC (SEMANTIC_FN) (SIM_CPU *, SEM_ARG, PAREXEC *); 97 #else 98 typedef SEM_PC (SEMANTIC_FN) (SIM_CPU *, SEM_ARG); 99 #endif 100 101 #else 102 103 /* Result of semantic routines is a status indicator (wip). */ 104 typedef unsigned int SEM_STATUS; 105 106 /* Instruction fields are extracted by the semantic routine. 107 ??? TODO: multi word insns. */ 108 #if HAVE_PARALLEL_INSNS && ! WITH_PARALLEL_GENWRITE 109 typedef SEM_STATUS (SEMANTIC_FN) (SIM_CPU *, SEM_ARG, PAREXEC *, CGEN_INSN_WORD); 110 #else 111 typedef SEM_STATUS (SEMANTIC_FN) (SIM_CPU *, SEM_ARG, CGEN_INSN_WORD); 112 #endif 113 114 #endif 115 116 /* In the ARGBUF struct, a pointer to the semantic routine for the insn. */ 117 118 union sem { 119 #if ! WITH_SEM_SWITCH_FULL 120 SEMANTIC_FN *sem_full; 121 #endif 122 #if ! WITH_SEM_SWITCH_FAST 123 SEMANTIC_FN *sem_fast; 124 #endif 125 #if WITH_SEM_SWITCH_FULL || WITH_SEM_SWITCH_FAST 126 #ifdef __GNUC__ 127 void *sem_case; 128 #else 129 int sem_case; 130 #endif 131 #endif 132 }; 133 134 /* Set the appropriate semantic handler in ABUF. */ 135 136 #if WITH_SEM_SWITCH_FULL 137 #ifdef __GNUC__ 138 #define SEM_SET_FULL_CODE(abuf, idesc) \ 139 do { (abuf)->semantic.sem_case = (idesc)->sem_full_lab; } while (0) 140 #else 141 #define SEM_SET_FULL_CODE(abuf, idesc) \ 142 do { (abuf)->semantic.sem_case = (idesc)->num; } while (0) 143 #endif 144 #else 145 #define SEM_SET_FULL_CODE(abuf, idesc) \ 146 do { (abuf)->semantic.sem_full = (idesc)->sem_full; } while (0) 147 #endif 148 149 #if WITH_SEM_SWITCH_FAST 150 #ifdef __GNUC__ 151 #define SEM_SET_FAST_CODE(abuf, idesc) \ 152 do { (abuf)->semantic.sem_case = (idesc)->sem_fast_lab; } while (0) 153 #else 154 #define SEM_SET_FAST_CODE(abuf, idesc) \ 155 do { (abuf)->semantic.sem_case = (idesc)->num; } while (0) 156 #endif 157 #else 158 #define SEM_SET_FAST_CODE(abuf, idesc) \ 159 do { (abuf)->semantic.sem_fast = (idesc)->sem_fast; } while (0) 160 #endif 161 162 #define SEM_SET_CODE(abuf, idesc, fast_p) \ 163 do { \ 164 if (fast_p) \ 165 SEM_SET_FAST_CODE ((abuf), (idesc)); \ 166 else \ 167 SEM_SET_FULL_CODE ((abuf), (idesc)); \ 168 } while (0) 169 170 /* Return non-zero if IDESC is a conditional or unconditional CTI. */ 171 172 #define IDESC_CTI_P(idesc) \ 173 ((CGEN_ATTR_BOOLS (CGEN_INSN_ATTRS ((idesc)->idata)) \ 174 & (CGEN_ATTR_MASK (CGEN_INSN_COND_CTI) \ 175 | CGEN_ATTR_MASK (CGEN_INSN_UNCOND_CTI))) \ 176 != 0) 177 178 /* Return non-zero if IDESC is a skip insn. */ 179 180 #define IDESC_SKIP_P(idesc) \ 181 ((CGEN_ATTR_BOOLS (CGEN_INSN_ATTRS ((idesc)->idata)) \ 182 & CGEN_ATTR_MASK (CGEN_INSN_SKIP_CTI)) \ 183 != 0) 184 185 /* Return pointer to ARGBUF given ptr to SCACHE. */ 186 #define SEM_ARGBUF(sem_arg) (& (sem_arg) -> argbuf) 187 188 #if WITH_SCACHE 189 190 #define CIA_ADDR(cia) (cia) 191 192 #if WITH_SCACHE_PBB 193 194 /* Return the scache pointer of the current insn. */ 195 #define SEM_SEM_ARG(vpc, sc) (vpc) 196 197 /* Return the virtual pc of the next insn to execute 198 (assuming this isn't a cti or the branch isn't taken). */ 199 #define SEM_NEXT_VPC(sem_arg, pc, len) ((sem_arg) + 1) 200 201 /* Update the instruction counter. */ 202 #define PBB_UPDATE_INSN_COUNT(cpu,sc) \ 203 (CPU_INSN_COUNT (cpu) += SEM_ARGBUF (sc) -> fields.chain.insn_count) 204 205 /* Do not append a `;' to invocations of this. 206 npc,br_type are for communication between the cti insn and cti-chain. */ 207 #define SEM_BRANCH_INIT \ 208 IADDR npc = 0; /* assign a value for -Wall */ \ 209 SEM_BRANCH_TYPE br_type = SEM_BRANCH_UNTAKEN; 210 211 /* SEM_IN_SWITCH is defined at the top of the mainloop.c files 212 generated by genmloop.sh. It exists so generated semantic code needn't 213 care whether it's being put in a switch or in a function. */ 214 #ifdef SEM_IN_SWITCH 215 #define SEM_BRANCH_FINI(pcvar) \ 216 do { \ 217 pbb_br_npc = npc; \ 218 pbb_br_type = br_type; \ 219 } while (0) 220 #else /* 1 semantic function per instruction */ 221 #define SEM_BRANCH_FINI(pcvar) \ 222 do { \ 223 CPU_PBB_BR_NPC (current_cpu) = npc; \ 224 CPU_PBB_BR_TYPE (current_cpu) = br_type; \ 225 } while (0) 226 #endif 227 228 #define SEM_BRANCH_VIA_CACHE(cpu, sc, newval, pcvar) \ 229 do { \ 230 npc = (newval); \ 231 br_type = SEM_BRANCH_CACHEABLE; \ 232 } while (0) 233 234 #define SEM_BRANCH_VIA_ADDR(cpu, sc, newval, pcvar) \ 235 do { \ 236 npc = (newval); \ 237 br_type = SEM_BRANCH_UNCACHEABLE; \ 238 } while (0) 239 240 #define SEM_SKIP_COMPILE(cpu, sc, skip) \ 241 do { \ 242 SEM_ARGBUF (sc) -> skip_count = (skip); \ 243 } while (0) 244 245 #define SEM_SKIP_INSN(cpu, sc, vpcvar) \ 246 do { \ 247 (vpcvar) += SEM_ARGBUF (sc) -> skip_count; \ 248 } while (0) 249 250 #else /* ! WITH_SCACHE_PBB */ 251 252 #define SEM_SEM_ARG(vpc, sc) (sc) 253 254 #define SEM_NEXT_VPC(sem_arg, pc, len) ((pc) + (len)) 255 256 /* ??? May wish to move taken_p out of here and make it explicit. */ 257 #define SEM_BRANCH_INIT \ 258 int taken_p = 0; 259 260 #ifndef TARGET_SEM_BRANCH_FINI 261 #define TARGET_SEM_BRANCH_FINI(pcvar, taken_p) 262 #endif 263 #define SEM_BRANCH_FINI(pcvar) \ 264 do { TARGET_SEM_BRANCH_FINI (pcvar, taken_p); } while (0) 265 266 #define SEM_BRANCH_VIA_CACHE(cpu, sc, newval, pcvar) \ 267 do { \ 268 (pcvar) = (newval); \ 269 taken_p = 1; \ 270 } while (0) 271 272 #define SEM_BRANCH_VIA_ADDR(cpu, sc, newval, pcvar) \ 273 do { \ 274 (pcvar) = (newval); \ 275 taken_p = 1; \ 276 } while (0) 277 278 #endif /* ! WITH_SCACHE_PBB */ 279 280 #else /* ! WITH_SCACHE */ 281 282 /* This is the "simple" engine case. */ 283 284 #define CIA_ADDR(cia) (cia) 285 286 #define SEM_SEM_ARG(vpc, sc) (sc) 287 288 #define SEM_NEXT_VPC(sem_arg, pc, len) ((pc) + (len)) 289 290 #define SEM_BRANCH_INIT \ 291 int taken_p = 0; 292 293 #define SEM_BRANCH_VIA_CACHE(cpu, abuf, newval, pcvar) \ 294 do { \ 295 (pcvar) = (newval); \ 296 taken_p = 1; \ 297 } while (0) 298 299 #define SEM_BRANCH_VIA_ADDR(cpu, abuf, newval, pcvar) \ 300 do { \ 301 (pcvar) = (newval); \ 302 taken_p = 1; \ 303 } while (0) 304 305 /* Finish off branch insns. 306 The target must define TARGET_SEM_BRANCH_FINI. 307 ??? This can probably go away when define-execute is finished. */ 308 #define SEM_BRANCH_FINI(pcvar, bool_attrs) \ 309 do { TARGET_SEM_BRANCH_FINI ((pcvar), (bool_attrs), taken_p); } while (0) 310 311 /* Finish off non-branch insns. 312 The target must define TARGET_SEM_NBRANCH_FINI. 313 ??? This can probably go away when define-execute is finished. */ 314 #define SEM_NBRANCH_FINI(pcvar, bool_attrs) \ 315 do { TARGET_SEM_NBRANCH_FINI ((pcvar), (bool_attrs)); } while (0) 316 317 #endif /* ! WITH_SCACHE */ 318 319 /* Instruction information. */ 320 321 /* Sanity check, at most one of these may be true. */ 322 #if WITH_PARALLEL_READ + WITH_PARALLEL_WRITE + WITH_PARALLEL_GENWRITE > 1 323 #error "At most one of WITH_PARALLEL_{READ,WRITE,GENWRITE} can be true." 324 #endif 325 326 /* Compile time computable instruction data. */ 327 328 struct insn_sem { 329 /* The instruction type (a number that identifies each insn over the 330 entire architecture). */ 331 CGEN_INSN_TYPE type; 332 333 /* Index in IDESC table. */ 334 int index; 335 336 /* Semantic format number. */ 337 int sfmt; 338 339 #if HAVE_PARALLEL_INSNS && ! WITH_PARALLEL_ONLY 340 /* Index in IDESC table of parallel handler. */ 341 int par_index; 342 #endif 343 344 #if WITH_PARALLEL_READ 345 /* Index in IDESC table of read handler. */ 346 int read_index; 347 #endif 348 349 #if WITH_PARALLEL_WRITE 350 /* Index in IDESC table of writeback handler. */ 351 int write_index; 352 #endif 353 }; 354 355 /* Entry in semantic function table. 356 This information is copied to the insn descriptor table at run-time. */ 357 358 struct sem_fn_desc { 359 /* Index in IDESC table. */ 360 int index; 361 362 /* Function to perform the semantics of the insn. */ 363 SEMANTIC_FN *fn; 364 }; 365 366 /* Run-time computed instruction descriptor. */ 367 368 struct idesc { 369 #if WITH_SEM_SWITCH_FAST 370 #ifdef __GNUC__ 371 void *sem_fast_lab; 372 #else 373 /* nothing needed, switch's on `num' member */ 374 #endif 375 #else 376 SEMANTIC_FN *sem_fast; 377 #endif 378 379 #if WITH_SEM_SWITCH_FULL 380 #ifdef __GNUC__ 381 void *sem_full_lab; 382 #else 383 /* nothing needed, switch's on `num' member */ 384 #endif 385 #else 386 SEMANTIC_FN *sem_full; 387 #endif 388 389 /* Parallel support. */ 390 #if HAVE_PARALLEL_INSNS && (! WITH_PARALLEL_ONLY || (WITH_PARALLEL_ONLY && ! WITH_PARALLEL_GENWRITE)) 391 /* Pointer to parallel handler if serial insn. 392 Pointer to readahead/writeback handler if parallel insn. */ 393 struct idesc *par_idesc; 394 #endif 395 396 /* Instruction number (index in IDESC table, profile table). 397 Also used to switch on in non-gcc semantic switches. */ 398 int num; 399 400 /* Semantic format id. */ 401 int sfmt; 402 403 /* instruction data (name, attributes, size, etc.) */ 404 const CGEN_INSN *idata; 405 406 /* instruction attributes, copied from `idata' for speed */ 407 const CGEN_INSN_ATTR_TYPE *attrs; 408 409 /* instruction length in bytes, copied from `idata' for speed */ 410 int length; 411 412 /* profiling/modelling support */ 413 const INSN_TIMING *timing; 414 }; 415 416 /* Tracing/profiling. */ 417 418 /* Return non-zero if a before/after handler is needed. 419 When tracing/profiling a selected range there's no need to slow 420 down simulation of the other insns (except to get more accurate data!). 421 422 ??? May wish to profile all insns if doing insn tracing, or to 423 get more accurate cycle data. 424 425 First test ANY_P so we avoid a potentially expensive HIT_P call 426 [if there are lots of address ranges]. */ 427 428 #define PC_IN_TRACE_RANGE_P(cpu, pc) \ 429 (TRACE_ANY_P (cpu) \ 430 && ADDR_RANGE_HIT_P (TRACE_RANGE (CPU_TRACE_DATA (cpu)), (pc))) 431 #define PC_IN_PROFILE_RANGE_P(cpu, pc) \ 432 (PROFILE_ANY_P (cpu) \ 433 && ADDR_RANGE_HIT_P (PROFILE_RANGE (CPU_PROFILE_DATA (cpu)), (pc))) 434 435 #endif /* CGEN_ENGINE_H */ 436