+/* GET_LOOP_BOUNDS {EXTENDED}
+ These two functions compute the actual starting and ending point
+ of the repeat loop, based on the RS and RE registers (repeat start,
+ repeat stop). The extended version is called for LDRC, and the
+ regular version is called for SETRC. The difference is that for
+ LDRC, the loop start and end instructions are literally the ones
+ pointed to by RS and RE -- for SETRC, they're not (see docs). */
+
+static struct loop_bounds
+get_loop_bounds_ext (int rs, int re, unsigned char *memory,
+ unsigned char *mem_end, int maskw, int endianw)
+{
+ struct loop_bounds loop;
+
+ /* FIXME: should I verify RS < RE? */
+ loop.start = PT2H (RS); /* FIXME not using the params? */
+ loop.end = PT2H (RE & ~1); /* Ignore bit 0 of RE. */
+ SKIP_INSN (loop.end);
+ if (loop.end >= mem_end)
+ loop.end = PT2H (0);
+ return loop;
+}
+
+static struct loop_bounds
+get_loop_bounds (int rs, int re, unsigned char *memory, unsigned char *mem_end,
+ int maskw, int endianw)
+{
+ struct loop_bounds loop;
+
+ if (SR_RC)
+ {
+ if (RS >= RE)
+ {
+ loop.start = PT2H (RE - 4);
+ SKIP_INSN (loop.start);
+ loop.end = loop.start;
+ if (RS - RE == 0)
+ SKIP_INSN (loop.end);
+ if (RS - RE <= 2)
+ SKIP_INSN (loop.end);
+ SKIP_INSN (loop.end);
+ }
+ else
+ {
+ loop.start = PT2H (RS);
+ loop.end = PT2H (RE - 4);
+ SKIP_INSN (loop.end);
+ SKIP_INSN (loop.end);
+ SKIP_INSN (loop.end);
+ SKIP_INSN (loop.end);
+ }
+ if (loop.end >= mem_end)
+ loop.end = PT2H (0);
+ }
+ else
+ loop.end = PT2H (0);
+
+ return loop;
+}
+
+static void ppi_insn ();
+
+#include "ppi.c"
+
+/* Provide calloc / free versions that use an anonymous mmap. This can
+ significantly cut the start-up time when a large simulator memory is
+ required, because pages are only zeroed on demand. */
+#ifdef MAP_ANONYMOUS
+static void *
+mcalloc (size_t nmemb, size_t size)
+{
+ void *page;
+
+ if (nmemb != 1)
+ size *= nmemb;
+ return mmap (0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
+ -1, 0);
+}
+
+#define mfree(start,length) munmap ((start), (length))
+#else
+#define mcalloc calloc
+#define mfree(start,length) free(start)
+#endif
+
+/* Set the memory size to the power of two provided. */
+
+static void
+sim_size (int power)
+{
+ sim_memory_size = power;
+
+ if (saved_state.asregs.memory)
+ {
+ mfree (saved_state.asregs.memory, saved_state.asregs.msize);
+ }
+
+ saved_state.asregs.msize = 1 << power;
+
+ saved_state.asregs.memory =
+ (unsigned char *) mcalloc (1, saved_state.asregs.msize);
+
+ if (!saved_state.asregs.memory)
+ {
+ fprintf (stderr,
+ "Not enough VM for simulation of %d bytes of RAM\n",
+ saved_state.asregs.msize);
+
+ saved_state.asregs.msize = 1;
+ saved_state.asregs.memory = (unsigned char *) mcalloc (1, 1);
+ }
+}
+
+static void
+init_dsp (struct bfd *abfd)
+{
+ int was_dsp = target_dsp;
+ unsigned long mach = bfd_get_mach (abfd);
+
+ if (mach == bfd_mach_sh_dsp ||
+ mach == bfd_mach_sh4al_dsp ||
+ mach == bfd_mach_sh3_dsp)
+ {
+ int ram_area_size, xram_start, yram_start;
+ int new_select;
+
+ target_dsp = 1;
+ if (mach == bfd_mach_sh_dsp)
+ {
+ /* SH7410 (orig. sh-sdp):
+ 4KB each for X & Y memory;
+ On-chip X RAM 0x0800f000-0x0800ffff
+ On-chip Y RAM 0x0801f000-0x0801ffff */
+ xram_start = 0x0800f000;
+ ram_area_size = 0x1000;
+ }
+ if (mach == bfd_mach_sh3_dsp || mach == bfd_mach_sh4al_dsp)
+ {
+ /* SH7612:
+ 8KB each for X & Y memory;
+ On-chip X RAM 0x1000e000-0x1000ffff
+ On-chip Y RAM 0x1001e000-0x1001ffff */
+ xram_start = 0x1000e000;
+ ram_area_size = 0x2000;
+ }
+ yram_start = xram_start + 0x10000;
+ new_select = ~(ram_area_size - 1);
+ if (saved_state.asregs.xyram_select != new_select)
+ {
+ saved_state.asregs.xyram_select = new_select;
+ free (saved_state.asregs.xmem);
+ free (saved_state.asregs.ymem);
+ saved_state.asregs.xmem =
+ (unsigned char *) calloc (1, ram_area_size);
+ saved_state.asregs.ymem =
+ (unsigned char *) calloc (1, ram_area_size);
+
+ /* Disable use of X / Y mmeory if not allocated. */
+ if (! saved_state.asregs.xmem || ! saved_state.asregs.ymem)
+ {
+ saved_state.asregs.xyram_select = 0;
+ if (saved_state.asregs.xmem)
+ free (saved_state.asregs.xmem);
+ if (saved_state.asregs.ymem)
+ free (saved_state.asregs.ymem);
+ }
+ }
+ saved_state.asregs.xram_start = xram_start;
+ saved_state.asregs.yram_start = yram_start;
+ saved_state.asregs.xmem_offset = saved_state.asregs.xmem - xram_start;
+ saved_state.asregs.ymem_offset = saved_state.asregs.ymem - yram_start;
+ }
+ else
+ {
+ target_dsp = 0;
+ if (saved_state.asregs.xyram_select)
+ {
+ saved_state.asregs.xyram_select = 0;
+ free (saved_state.asregs.xmem);
+ free (saved_state.asregs.ymem);
+ }
+ }
+
+ if (! saved_state.asregs.xyram_select)
+ {
+ saved_state.asregs.xram_start = 1;
+ saved_state.asregs.yram_start = 1;
+ }
+
+ if (saved_state.asregs.regstack == NULL)
+ saved_state.asregs.regstack =
+ calloc (512, sizeof *saved_state.asregs.regstack);
+
+ if (target_dsp != was_dsp)
+ {
+ int i, tmp;
+
+ for (i = ARRAY_SIZE (sh_dsp_table) - 1; i >= 0; i--)
+ {
+ tmp = sh_jump_table[0xf000 + i];
+ sh_jump_table[0xf000 + i] = sh_dsp_table[i];
+ sh_dsp_table[i] = tmp;
+ }
+ }
+}
+
+static void
+init_pointers (void)
+{
+ if (saved_state.asregs.msize != 1 << sim_memory_size)
+ {
+ sim_size (sim_memory_size);
+ }
+
+ if (saved_state.asregs.profile && !profile_file)
+ {
+ profile_file = fopen ("gmon.out", "wb");
+ /* Seek to where to put the call arc data */
+ nsamples = (1 << sim_profile_size);
+
+ fseek (profile_file, nsamples * 2 + 12, 0);
+
+ if (!profile_file)