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