mloopx.in 14 KB

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