1# Simulator main loop for m32r2. -*- C -*- 2# 3# Copyright 1996, 1997, 1998, 2003, 2004, 2007 Free Software Foundation, Inc. 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 3 of the License, or 10# (at your option) 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 18# along with this program. If not, see <http://www.gnu.org/licenses/>. 19 20# Syntax: 21# /bin/sh mainloop.in command 22# 23# Command is one of: 24# 25# init 26# support 27# extract-{simple,scache,pbb} 28# {full,fast}-exec-{simple,scache,pbb} 29# 30# A target need only provide a "full" version of one of simple,scache,pbb. 31# If the target wants it can also provide a fast version of same, or if 32# the slow (full featured) version is `simple', then the fast version can be 33# one of scache/pbb. 34# A target can't provide more than this. 35 36# ??? After a few more ports are done, revisit. 37# Will eventually need to machine generate a lot of this. 38 39case "x$1" in 40 41xsupport) 42 43cat <<EOF 44 45/* Emit insns to write back the results of insns executed in parallel. 46 SC points to a sufficient number of scache entries for the writeback 47 handlers. 48 SC1/ID1 is the first insn (left slot, lower address). 49 SC2/ID2 is the second insn (right slot, higher address). */ 50 51static INLINE void 52emit_par_finish (SIM_CPU *current_cpu, PCADDR pc, SCACHE *sc, 53 SCACHE *sc1, const IDESC *id1, SCACHE *sc2, const IDESC *id2) 54{ 55 ARGBUF *abuf; 56 57 abuf = &sc->argbuf; 58 id1 = id1->par_idesc; 59 abuf->fields.write.abuf = &sc1->argbuf; 60 @cpu@_fill_argbuf (current_cpu, abuf, id1, pc, 0); 61 /* no need to set trace_p,profile_p */ 62#if 0 /* not currently needed for id2 since results written directly */ 63 abuf = &sc[1].argbuf; 64 id2 = id2->par_idesc; 65 abuf->fields.write.abuf = &sc2->argbuf; 66 @cpu@_fill_argbuf (current_cpu, abuf, id2, pc + 2, 0); 67 /* no need to set trace_p,profile_p */ 68#endif 69} 70 71static INLINE const IDESC * 72emit_16 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, 73 SCACHE *sc, int fast_p, int parallel_p) 74{ 75 ARGBUF *abuf = &sc->argbuf; 76 const IDESC *id = @cpu@_decode (current_cpu, pc, insn, insn, abuf); 77 78 if (parallel_p) 79 id = id->par_idesc; 80 @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p); 81 return id; 82} 83 84static INLINE const IDESC * 85emit_full16 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, SCACHE *sc, 86 int trace_p, int profile_p) 87{ 88 const IDESC *id; 89 90 @cpu@_emit_before (current_cpu, sc, pc, 1); 91 id = emit_16 (current_cpu, pc, insn, sc + 1, 0, 0); 92 @cpu@_emit_after (current_cpu, sc + 2, pc); 93 sc[1].argbuf.trace_p = trace_p; 94 sc[1].argbuf.profile_p = profile_p; 95 return id; 96} 97 98static INLINE const IDESC * 99emit_parallel (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, 100 SCACHE *sc, int fast_p) 101{ 102 const IDESC *id,*id2; 103 104 /* Emit both insns, then emit a finisher-upper. 105 We speed things up by handling the second insn serially 106 [not parallelly]. Then the writeback only has to deal 107 with the first insn. */ 108 /* ??? Revisit to handle exceptions right. */ 109 110 /* FIXME: No need to handle this parallely if second is nop. */ 111 id = emit_16 (current_cpu, pc, insn >> 16, sc, fast_p, 1); 112 113 /* Note that this can never be a cti. No cti's go in the S pipeline. */ 114 id2 = emit_16 (current_cpu, pc + 2, insn & 0x7fff, sc + 1, fast_p, 0); 115 116 /* Set sc/snc insns notion of where to skip to. */ 117 if (IDESC_SKIP_P (id)) 118 SEM_SKIP_COMPILE (current_cpu, sc, 1); 119 120 /* Emit code to finish executing the semantics 121 (write back the results). */ 122 emit_par_finish (current_cpu, pc, sc + 2, sc, id, sc + 1, id2); 123 124 return id; 125} 126 127static INLINE const IDESC * 128emit_full_parallel (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, 129 SCACHE *sc, int trace_p, int profile_p) 130{ 131 const IDESC *id,*id2; 132 133 /* Emit both insns, then emit a finisher-upper. 134 We speed things up by handling the second insn serially 135 [not parallelly]. Then the writeback only has to deal 136 with the first insn. */ 137 /* ??? Revisit to handle exceptions right. */ 138 139 @cpu@_emit_before (current_cpu, sc, pc, 1); 140 141 /* FIXME: No need to handle this parallelly if second is nop. */ 142 id = emit_16 (current_cpu, pc, insn >> 16, sc + 1, 0, 1); 143 sc[1].argbuf.trace_p = trace_p; 144 sc[1].argbuf.profile_p = profile_p; 145 146 @cpu@_emit_before (current_cpu, sc + 2, pc, 0); 147 148 /* Note that this can never be a cti. No cti's go in the S pipeline. */ 149 id2 = emit_16 (current_cpu, pc + 2, insn & 0x7fff, sc + 3, 0, 0); 150 sc[3].argbuf.trace_p = trace_p; 151 sc[3].argbuf.profile_p = profile_p; 152 153 /* Set sc/snc insns notion of where to skip to. */ 154 if (IDESC_SKIP_P (id)) 155 SEM_SKIP_COMPILE (current_cpu, sc, 4); 156 157 /* Emit code to finish executing the semantics 158 (write back the results). */ 159 emit_par_finish (current_cpu, pc, sc + 4, sc + 1, id, sc + 3, id2); 160 161 @cpu@_emit_after (current_cpu, sc + 5, pc); 162 163 return id; 164} 165 166static INLINE const IDESC * 167emit_32 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, 168 SCACHE *sc, int fast_p) 169{ 170 ARGBUF *abuf = &sc->argbuf; 171 const IDESC *id = @cpu@_decode (current_cpu, pc, 172 (USI) insn >> 16, insn, abuf); 173 174 @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p); 175 return id; 176} 177 178static INLINE const IDESC * 179emit_full32 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, SCACHE *sc, 180 int trace_p, int profile_p) 181{ 182 const IDESC *id; 183 184 @cpu@_emit_before (current_cpu, sc, pc, 1); 185 id = emit_32 (current_cpu, pc, insn, sc + 1, 0); 186 @cpu@_emit_after (current_cpu, sc + 2, pc); 187 sc[1].argbuf.trace_p = trace_p; 188 sc[1].argbuf.profile_p = profile_p; 189 return id; 190} 191 192EOF 193 194;; 195 196xinit) 197 198# Nothing needed. 199 200;; 201 202xextract-pbb) 203 204# Inputs: current_cpu, pc, sc, max_insns, FAST_P 205# Outputs: sc, pc 206# sc must be left pointing past the last created entry. 207# pc must be left pointing past the last created entry. 208# If the pbb is terminated by a cti insn, SET_CTI_VPC(sc) must be called 209# to record the vpc of the cti insn. 210# SET_INSN_COUNT(n) must be called to record number of real insns. 211 212cat <<EOF 213{ 214 const IDESC *idesc; 215 int icount = 0; 216 217 if ((pc & 3) != 0) 218 { 219 /* This occurs when single stepping and when compiling the not-taken 220 part of conditional branches. */ 221 UHI insn = GETIMEMUHI (current_cpu, pc); 222 int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc); 223 int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc); 224 SCACHE *cti_sc; /* ??? tmp hack */ 225 226 /* A parallel insn isn't allowed here, but we don't mind nops. 227 ??? We need to wait until the insn is executed before signalling 228 the error, for situations where such signalling is wanted. */ 229#if 0 230 if ((insn & 0x8000) != 0 231 && (insn & 0x7fff) != 0x7000) /* parallel nops are ok */ 232 sim_engine_invalid_insn (current_cpu, pc, 0); 233#endif 234 235 /* Only emit before/after handlers if necessary. */ 236 if (FAST_P || (! trace_p && ! profile_p)) 237 { 238 idesc = emit_16 (current_cpu, pc, insn & 0x7fff, sc, FAST_P, 0); 239 cti_sc = sc; 240 ++sc; 241 --max_insns; 242 } 243 else 244 { 245 idesc = emit_full16 (current_cpu, pc, insn & 0x7fff, sc, 246 trace_p, profile_p); 247 cti_sc = sc + 1; 248 sc += 3; 249 max_insns -= 3; 250 } 251 ++icount; 252 pc += 2; 253 if (IDESC_CTI_P (idesc)) 254 { 255 SET_CTI_VPC (cti_sc); 256 goto Finish; 257 } 258 } 259 260 /* There are two copies of the compiler: full(!fast) and fast. 261 The "full" case emits before/after handlers for each insn. 262 Having two copies of this code is a tradeoff, having one copy 263 seemed a bit more difficult to read (due to constantly testing 264 FAST_P). ??? On the other hand, with address ranges we'll want to 265 omit before/after handlers for unwanted insns. Having separate loops 266 for FAST/!FAST avoids constantly doing the test in the loop, but 267 typically FAST_P is a constant and such tests will get optimized out. */ 268 269 if (FAST_P) 270 { 271 while (max_insns > 0) 272 { 273 USI insn = GETIMEMUSI (current_cpu, pc); 274 if ((SI) insn < 0) 275 { 276 /* 32 bit insn */ 277 idesc = emit_32 (current_cpu, pc, insn, sc, 1); 278 ++sc; 279 --max_insns; 280 ++icount; 281 pc += 4; 282 if (IDESC_CTI_P (idesc)) 283 { 284 SET_CTI_VPC (sc - 1); 285 break; 286 } 287 } 288 else 289 { 290 if ((insn & 0x8000) != 0) /* parallel? */ 291 { 292 int up_count; 293 294 if (((insn >> 16) & 0xfff0) == 0x10f0) 295 { 296 /* FIXME: No need to handle this sequentially if system 297 calls will be able to execute after second insn in 298 parallel. ( trap #num || insn ) */ 299 /* insn */ 300 idesc = emit_16 (current_cpu, pc + 2, insn & 0x7fff, 301 sc, 1, 0); 302 /* trap */ 303 emit_16 (current_cpu, pc, insn >> 16, sc + 1, 1, 0); 304 up_count = 2; 305 } 306 else 307 { 308 /* Yep. Here's the "interesting" [sic] part. */ 309 idesc = emit_parallel (current_cpu, pc, insn, sc, 1); 310 up_count = 3; 311 } 312 sc += up_count; 313 max_insns -= up_count; 314 icount += 2; 315 pc += 4; 316 if (IDESC_CTI_P (idesc)) 317 { 318 SET_CTI_VPC (sc - up_count); 319 break; 320 } 321 } 322 else /* 2 serial 16 bit insns */ 323 { 324 idesc = emit_16 (current_cpu, pc, insn >> 16, sc, 1, 0); 325 ++sc; 326 --max_insns; 327 ++icount; 328 pc += 2; 329 if (IDESC_CTI_P (idesc)) 330 { 331 SET_CTI_VPC (sc - 1); 332 break; 333 } 334 /* While we're guaranteed that there's room to extract the 335 insn, when single stepping we can't; the pbb must stop 336 after the first insn. */ 337 if (max_insns == 0) 338 break; 339 idesc = emit_16 (current_cpu, pc, insn & 0x7fff, sc, 1, 0); 340 ++sc; 341 --max_insns; 342 ++icount; 343 pc += 2; 344 if (IDESC_CTI_P (idesc)) 345 { 346 SET_CTI_VPC (sc - 1); 347 break; 348 } 349 } 350 } 351 } 352 } 353 else /* ! FAST_P */ 354 { 355 while (max_insns > 0) 356 { 357 USI insn = GETIMEMUSI (current_cpu, pc); 358 int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc); 359 int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc); 360 SCACHE *cti_sc; /* ??? tmp hack */ 361 if ((SI) insn < 0) 362 { 363 /* 32 bit insn 364 Only emit before/after handlers if necessary. */ 365 if (trace_p || profile_p) 366 { 367 idesc = emit_full32 (current_cpu, pc, insn, sc, 368 trace_p, profile_p); 369 cti_sc = sc + 1; 370 sc += 3; 371 max_insns -= 3; 372 } 373 else 374 { 375 idesc = emit_32 (current_cpu, pc, insn, sc, 0); 376 cti_sc = sc; 377 ++sc; 378 --max_insns; 379 } 380 ++icount; 381 pc += 4; 382 if (IDESC_CTI_P (idesc)) 383 { 384 SET_CTI_VPC (cti_sc); 385 break; 386 } 387 } 388 else 389 { 390 if ((insn & 0x8000) != 0) /* parallel? */ 391 { 392 /* Yep. Here's the "interesting" [sic] part. 393 Only emit before/after handlers if necessary. */ 394 if (trace_p || profile_p) 395 { 396 if (((insn >> 16) & 0xfff0) == 0x10f0) 397 { 398 /* FIXME: No need to handle this sequentially if 399 system calls will be able to execute after second 400 insn in parallel. ( trap #num || insn ) */ 401 /* insn */ 402 idesc = emit_full16 (current_cpu, pc + 2, 403 insn & 0x7fff, sc, 0, 0); 404 /* trap */ 405 emit_full16 (current_cpu, pc, insn >> 16, sc + 3, 406 0, 0); 407 } 408 else 409 { 410 idesc = emit_full_parallel (current_cpu, pc, insn, 411 sc, trace_p, profile_p); 412 } 413 cti_sc = sc + 1; 414 sc += 6; 415 max_insns -= 6; 416 } 417 else 418 { 419 int up_count; 420 421 if (((insn >> 16) & 0xfff0) == 0x10f0) 422 { 423 /* FIXME: No need to handle this sequentially if 424 system calls will be able to execute after second 425 insn in parallel. ( trap #num || insn ) */ 426 /* insn */ 427 idesc = emit_16 (current_cpu, pc + 2, insn & 0x7fff, 428 sc, 0, 0); 429 /* trap */ 430 emit_16 (current_cpu, pc, insn >> 16, sc + 1, 0, 0); 431 up_count = 2; 432 } 433 else 434 { 435 idesc = emit_parallel (current_cpu, pc, insn, sc, 0); 436 up_count = 3; 437 } 438 cti_sc = sc; 439 sc += up_count; 440 max_insns -= up_count; 441 } 442 icount += 2; 443 pc += 4; 444 if (IDESC_CTI_P (idesc)) 445 { 446 SET_CTI_VPC (cti_sc); 447 break; 448 } 449 } 450 else /* 2 serial 16 bit insns */ 451 { 452 /* Only emit before/after handlers if necessary. */ 453 if (trace_p || profile_p) 454 { 455 idesc = emit_full16 (current_cpu, pc, insn >> 16, sc, 456 trace_p, profile_p); 457 cti_sc = sc + 1; 458 sc += 3; 459 max_insns -= 3; 460 } 461 else 462 { 463 idesc = emit_16 (current_cpu, pc, insn >> 16, sc, 0, 0); 464 cti_sc = sc; 465 ++sc; 466 --max_insns; 467 } 468 ++icount; 469 pc += 2; 470 if (IDESC_CTI_P (idesc)) 471 { 472 SET_CTI_VPC (cti_sc); 473 break; 474 } 475 /* While we're guaranteed that there's room to extract the 476 insn, when single stepping we can't; the pbb must stop 477 after the first insn. */ 478 if (max_insns <= 0) 479 break; 480 /* Use the same trace/profile address for the 2nd insn. 481 Saves us having to compute it and they come in pairs 482 anyway (e.g. can never branch to the 2nd insn). */ 483 if (trace_p || profile_p) 484 { 485 idesc = emit_full16 (current_cpu, pc, insn & 0x7fff, sc, 486 trace_p, profile_p); 487 cti_sc = sc + 1; 488 sc += 3; 489 max_insns -= 3; 490 } 491 else 492 { 493 idesc = emit_16 (current_cpu, pc, insn & 0x7fff, sc, 0, 0); 494 cti_sc = sc; 495 ++sc; 496 --max_insns; 497 } 498 ++icount; 499 pc += 2; 500 if (IDESC_CTI_P (idesc)) 501 { 502 SET_CTI_VPC (cti_sc); 503 break; 504 } 505 } 506 } 507 } 508 } 509 510 Finish: 511 SET_INSN_COUNT (icount); 512} 513EOF 514 515;; 516 517xfull-exec-pbb) 518 519# Inputs: current_cpu, vpc, FAST_P 520# Outputs: vpc 521# vpc is the virtual program counter. 522 523cat <<EOF 524#define DEFINE_SWITCH 525#include "sem2-switch.c" 526EOF 527 528;; 529 530*) 531 echo "Invalid argument to mainloop.in: $1" >&2 532 exit 1 533 ;; 534 535esac 536