aboutsummaryrefslogtreecommitdiff
path: root/sim/m32c/gdb-if.c
diff options
context:
space:
mode:
Diffstat (limited to 'sim/m32c/gdb-if.c')
-rw-r--r--sim/m32c/gdb-if.c710
1 files changed, 710 insertions, 0 deletions
diff --git a/sim/m32c/gdb-if.c b/sim/m32c/gdb-if.c
new file mode 100644
index 0000000..b9da6e3
--- /dev/null
+++ b/sim/m32c/gdb-if.c
@@ -0,0 +1,710 @@
+/* gdb.c --- sim interface to GDB.
+
+Copyright (C) 2005 Free Software Foundation, Inc.
+Contributed by Red Hat, Inc.
+
+This file is part of the GNU simulators.
+
+The GNU simulators are free software; you can redistribute them and/or
+modify them under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU simulators are distributed in the hope that they will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU simulators; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA */
+
+
+#include <stdio.h>
+#include <assert.h>
+#include <signal.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "ansidecl.h"
+#include "gdb/callback.h"
+#include "gdb/remote-sim.h"
+#include "gdb/signals.h"
+#include "gdb/sim-m32c.h"
+
+#include "cpu.h"
+#include "mem.h"
+#include "load.h"
+#include "syscalls.h"
+
+/* I don't want to wrap up all the minisim's data structures in an
+ object and pass that around. That'd be a big change, and neither
+ GDB nor run needs that ability.
+
+ So we just have one instance, that lives in global variables, and
+ each time we open it, we re-initialize it. */
+struct sim_state
+{
+ const char *message;
+};
+
+static struct sim_state the_minisim = {
+ "This is the sole m32c minisim instance. See libsim.a's global variables."
+};
+
+static int open;
+
+SIM_DESC
+sim_open (SIM_OPEN_KIND kind,
+ struct host_callback_struct *callback,
+ struct bfd *abfd, char **argv)
+{
+ if (open)
+ fprintf (stderr, "m32c minisim: re-opened sim\n");
+
+ /* The 'run' interface doesn't use this function, so we don't care
+ about KIND; it's always SIM_OPEN_DEBUG. */
+ if (kind != SIM_OPEN_DEBUG)
+ fprintf (stderr, "m32c minisim: sim_open KIND != SIM_OPEN_DEBUG: %d\n",
+ kind);
+
+ if (abfd)
+ m32c_set_mach (bfd_get_mach (abfd));
+
+ /* We can use ABFD, if non-NULL to select the appropriate
+ architecture. But we only support the r8c right now. */
+
+ set_callbacks (callback);
+
+ /* We don't expect any command-line arguments. */
+
+ init_mem ();
+ init_regs ();
+
+ open = 1;
+ return &the_minisim;
+}
+
+static void
+check_desc (SIM_DESC sd)
+{
+ if (sd != &the_minisim)
+ fprintf (stderr, "m32c minisim: desc != &the_minisim\n");
+}
+
+void
+sim_close (SIM_DESC sd, int quitting)
+{
+ check_desc (sd);
+
+ /* Not much to do. At least free up our memory. */
+ init_mem ();
+
+ open = 0;
+}
+
+static bfd *
+open_objfile (const char *filename)
+{
+ bfd *prog = bfd_openr (filename, 0);
+
+ if (!prog)
+ {
+ fprintf (stderr, "Can't read %s\n", filename);
+ return 0;
+ }
+
+ if (!bfd_check_format (prog, bfd_object))
+ {
+ fprintf (stderr, "%s not a m32c program\n", filename);
+ return 0;
+ }
+
+ return prog;
+}
+
+
+SIM_RC
+sim_load (SIM_DESC sd, char *prog, struct bfd *abfd, int from_tty)
+{
+ check_desc (sd);
+
+ if (!abfd)
+ abfd = open_objfile (prog);
+ if (!abfd)
+ return SIM_RC_FAIL;
+
+ m32c_load (abfd);
+
+ return SIM_RC_OK;
+}
+
+SIM_RC
+sim_create_inferior (SIM_DESC sd, struct bfd *abfd, char **argv, char **env)
+{
+ check_desc (sd);
+
+ if (abfd)
+ m32c_load (abfd);
+
+ return SIM_RC_OK;
+}
+
+int
+sim_read (SIM_DESC sd, SIM_ADDR mem, unsigned char *buf, int length)
+{
+ check_desc (sd);
+
+ if (mem == 0)
+ return 0;
+
+ mem_get_blk ((int) mem, buf, length);
+
+ return length;
+}
+
+int
+sim_write (SIM_DESC sd, SIM_ADDR mem, unsigned char *buf, int length)
+{
+ check_desc (sd);
+
+ mem_put_blk ((int) mem, buf, length);
+
+ return length;
+}
+
+
+/* Read the LENGTH bytes at BUF as an little-endian value. */
+static DI
+get_le (unsigned char *buf, int length)
+{
+ DI acc = 0;
+ while (--length >= 0)
+ acc = (acc << 8) + buf[length];
+
+ return acc;
+}
+
+/* Store VAL as a little-endian value in the LENGTH bytes at BUF. */
+static void
+put_le (unsigned char *buf, int length, DI val)
+{
+ int i;
+
+ for (i = 0; i < length; i++)
+ {
+ buf[i] = val & 0xff;
+ val >>= 8;
+ }
+}
+
+static int
+check_regno (enum m32c_sim_reg regno)
+{
+ return 0 <= regno && regno < m32c_sim_reg_num_regs;
+}
+
+static size_t
+mask_size (int addr_mask)
+{
+ switch (addr_mask)
+ {
+ case 0xffff:
+ return 2;
+ case 0xfffff:
+ case 0xffffff:
+ return 3;
+ default:
+ fprintf (stderr,
+ "m32c minisim: addr_mask_size: unexpected mask 0x%x\n",
+ addr_mask);
+ return sizeof (addr_mask);
+ }
+}
+
+static size_t
+reg_size (enum m32c_sim_reg regno)
+{
+ switch (regno)
+ {
+ case m32c_sim_reg_r0_bank0:
+ case m32c_sim_reg_r1_bank0:
+ case m32c_sim_reg_r2_bank0:
+ case m32c_sim_reg_r3_bank0:
+ case m32c_sim_reg_r0_bank1:
+ case m32c_sim_reg_r1_bank1:
+ case m32c_sim_reg_r2_bank1:
+ case m32c_sim_reg_r3_bank1:
+ case m32c_sim_reg_flg:
+ case m32c_sim_reg_svf:
+ return 2;
+
+ case m32c_sim_reg_a0_bank0:
+ case m32c_sim_reg_a1_bank0:
+ case m32c_sim_reg_fb_bank0:
+ case m32c_sim_reg_sb_bank0:
+ case m32c_sim_reg_a0_bank1:
+ case m32c_sim_reg_a1_bank1:
+ case m32c_sim_reg_fb_bank1:
+ case m32c_sim_reg_sb_bank1:
+ case m32c_sim_reg_usp:
+ case m32c_sim_reg_isp:
+ return mask_size (addr_mask);
+
+ case m32c_sim_reg_pc:
+ case m32c_sim_reg_intb:
+ case m32c_sim_reg_svp:
+ case m32c_sim_reg_vct:
+ return mask_size (membus_mask);
+
+ case m32c_sim_reg_dmd0:
+ case m32c_sim_reg_dmd1:
+ return 1;
+
+ case m32c_sim_reg_dct0:
+ case m32c_sim_reg_dct1:
+ case m32c_sim_reg_drc0:
+ case m32c_sim_reg_drc1:
+ return 2;
+
+ case m32c_sim_reg_dma0:
+ case m32c_sim_reg_dma1:
+ case m32c_sim_reg_dsa0:
+ case m32c_sim_reg_dsa1:
+ case m32c_sim_reg_dra0:
+ case m32c_sim_reg_dra1:
+ return 3;
+
+ default:
+ fprintf (stderr, "m32c minisim: unrecognized register number: %d\n",
+ regno);
+ return -1;
+ }
+}
+
+int
+sim_fetch_register (SIM_DESC sd, int regno, unsigned char *buf, int length)
+{
+ size_t size;
+
+ check_desc (sd);
+
+ if (!check_regno (regno))
+ return 0;
+
+ size = reg_size (regno);
+ if (length == size)
+ {
+ DI val;
+
+ switch (regno)
+ {
+ case m32c_sim_reg_r0_bank0:
+ val = regs.r[0].r_r0;
+ break;
+ case m32c_sim_reg_r1_bank0:
+ val = regs.r[0].r_r1;
+ break;
+ case m32c_sim_reg_r2_bank0:
+ val = regs.r[0].r_r2;
+ break;
+ case m32c_sim_reg_r3_bank0:
+ val = regs.r[0].r_r3;
+ break;
+ case m32c_sim_reg_a0_bank0:
+ val = regs.r[0].r_a0;
+ break;
+ case m32c_sim_reg_a1_bank0:
+ val = regs.r[0].r_a1;
+ break;
+ case m32c_sim_reg_fb_bank0:
+ val = regs.r[0].r_fb;
+ break;
+ case m32c_sim_reg_sb_bank0:
+ val = regs.r[0].r_sb;
+ break;
+ case m32c_sim_reg_r0_bank1:
+ val = regs.r[1].r_r0;
+ break;
+ case m32c_sim_reg_r1_bank1:
+ val = regs.r[1].r_r1;
+ break;
+ case m32c_sim_reg_r2_bank1:
+ val = regs.r[1].r_r2;
+ break;
+ case m32c_sim_reg_r3_bank1:
+ val = regs.r[1].r_r3;
+ break;
+ case m32c_sim_reg_a0_bank1:
+ val = regs.r[1].r_a0;
+ break;
+ case m32c_sim_reg_a1_bank1:
+ val = regs.r[1].r_a1;
+ break;
+ case m32c_sim_reg_fb_bank1:
+ val = regs.r[1].r_fb;
+ break;
+ case m32c_sim_reg_sb_bank1:
+ val = regs.r[1].r_sb;
+ break;
+
+ case m32c_sim_reg_usp:
+ val = regs.r_usp;
+ break;
+ case m32c_sim_reg_isp:
+ val = regs.r_isp;
+ break;
+ case m32c_sim_reg_pc:
+ val = regs.r_pc;
+ break;
+ case m32c_sim_reg_intb:
+ val = regs.r_intbl * 65536 + regs.r_intbl;
+ break;
+ case m32c_sim_reg_flg:
+ val = regs.r_flags;
+ break;
+
+ /* These registers aren't implemented by the minisim. */
+ case m32c_sim_reg_svf:
+ case m32c_sim_reg_svp:
+ case m32c_sim_reg_vct:
+ case m32c_sim_reg_dmd0:
+ case m32c_sim_reg_dmd1:
+ case m32c_sim_reg_dct0:
+ case m32c_sim_reg_dct1:
+ case m32c_sim_reg_drc0:
+ case m32c_sim_reg_drc1:
+ case m32c_sim_reg_dma0:
+ case m32c_sim_reg_dma1:
+ case m32c_sim_reg_dsa0:
+ case m32c_sim_reg_dsa1:
+ case m32c_sim_reg_dra0:
+ case m32c_sim_reg_dra1:
+ return 0;
+
+ default:
+ fprintf (stderr, "m32c minisim: unrecognized register number: %d\n",
+ regno);
+ return -1;
+ }
+
+ put_le (buf, length, val);
+ }
+
+ return size;
+}
+
+int
+sim_store_register (SIM_DESC sd, int regno, unsigned char *buf, int length)
+{
+ size_t size;
+
+ check_desc (sd);
+
+ if (!check_regno (regno))
+ return 0;
+
+ size = reg_size (regno);
+
+ if (length == size)
+ {
+ DI val = get_le (buf, length);
+
+ switch (regno)
+ {
+ case m32c_sim_reg_r0_bank0:
+ regs.r[0].r_r0 = val & 0xffff;
+ break;
+ case m32c_sim_reg_r1_bank0:
+ regs.r[0].r_r1 = val & 0xffff;
+ break;
+ case m32c_sim_reg_r2_bank0:
+ regs.r[0].r_r2 = val & 0xffff;
+ break;
+ case m32c_sim_reg_r3_bank0:
+ regs.r[0].r_r3 = val & 0xffff;
+ break;
+ case m32c_sim_reg_a0_bank0:
+ regs.r[0].r_a0 = val & addr_mask;
+ break;
+ case m32c_sim_reg_a1_bank0:
+ regs.r[0].r_a1 = val & addr_mask;
+ break;
+ case m32c_sim_reg_fb_bank0:
+ regs.r[0].r_fb = val & addr_mask;
+ break;
+ case m32c_sim_reg_sb_bank0:
+ regs.r[0].r_sb = val & addr_mask;
+ break;
+ case m32c_sim_reg_r0_bank1:
+ regs.r[1].r_r0 = val & 0xffff;
+ break;
+ case m32c_sim_reg_r1_bank1:
+ regs.r[1].r_r1 = val & 0xffff;
+ break;
+ case m32c_sim_reg_r2_bank1:
+ regs.r[1].r_r2 = val & 0xffff;
+ break;
+ case m32c_sim_reg_r3_bank1:
+ regs.r[1].r_r3 = val & 0xffff;
+ break;
+ case m32c_sim_reg_a0_bank1:
+ regs.r[1].r_a0 = val & addr_mask;
+ break;
+ case m32c_sim_reg_a1_bank1:
+ regs.r[1].r_a1 = val & addr_mask;
+ break;
+ case m32c_sim_reg_fb_bank1:
+ regs.r[1].r_fb = val & addr_mask;
+ break;
+ case m32c_sim_reg_sb_bank1:
+ regs.r[1].r_sb = val & addr_mask;
+ break;
+
+ case m32c_sim_reg_usp:
+ regs.r_usp = val & addr_mask;
+ break;
+ case m32c_sim_reg_isp:
+ regs.r_isp = val & addr_mask;
+ break;
+ case m32c_sim_reg_pc:
+ regs.r_pc = val & membus_mask;
+ break;
+ case m32c_sim_reg_intb:
+ regs.r_intbl = (val & membus_mask) & 0xffff;
+ regs.r_intbh = (val & membus_mask) >> 16;
+ break;
+ case m32c_sim_reg_flg:
+ regs.r_flags = val & 0xffff;
+ break;
+
+ /* These registers aren't implemented by the minisim. */
+ case m32c_sim_reg_svf:
+ case m32c_sim_reg_svp:
+ case m32c_sim_reg_vct:
+ case m32c_sim_reg_dmd0:
+ case m32c_sim_reg_dmd1:
+ case m32c_sim_reg_dct0:
+ case m32c_sim_reg_dct1:
+ case m32c_sim_reg_drc0:
+ case m32c_sim_reg_drc1:
+ case m32c_sim_reg_dma0:
+ case m32c_sim_reg_dma1:
+ case m32c_sim_reg_dsa0:
+ case m32c_sim_reg_dsa1:
+ case m32c_sim_reg_dra0:
+ case m32c_sim_reg_dra1:
+ return 0;
+
+ default:
+ fprintf (stderr, "m32c minisim: unrecognized register number: %d\n",
+ regno);
+ return -1;
+ }
+ }
+
+ return size;
+}
+
+void
+sim_info (SIM_DESC sd, int verbose)
+{
+ check_desc (sd);
+
+ printf ("The m32c minisim doesn't collect any statistics.\n");
+}
+
+static volatile int stop;
+static enum sim_stop reason;
+int siggnal;
+
+
+/* Given a signal number used by the M32C bsp (that is, newlib),
+ return a host signal number. (Oddly, the gdb/sim interface uses
+ host signal numbers...) */
+int
+m32c_signal_to_host (int m32c)
+{
+ switch (m32c)
+ {
+ case 4:
+#ifdef SIGILL
+ return SIGILL;
+#else
+ return SIGSEGV;
+#endif
+
+ case 5:
+ return SIGTRAP;
+
+ case 10:
+#ifdef SIGBUS
+ return SIGBUS;
+#else
+ return SIGSEGV;
+#endif
+
+ case 11:
+ return SIGSEGV;
+
+ case 24:
+#ifdef SIGXCPU
+ return SIGXCPU;
+#else
+ break;
+#endif
+
+ case 2:
+ return SIGINT;
+
+ case 8:
+#ifdef SIGFPE
+ return SIGFPE;
+#else
+ break;
+#endif
+
+ case 6:
+ return SIGABRT;
+ }
+
+ return 0;
+}
+
+
+/* Take a step return code RC and set up the variables consulted by
+ sim_stop_reason appropriately. */
+void
+handle_step (int rc)
+{
+ if (M32C_STEPPED (rc) || M32C_HIT_BREAK (rc))
+ {
+ reason = sim_stopped;
+ siggnal = TARGET_SIGNAL_TRAP;
+ }
+ else if (M32C_STOPPED (rc))
+ {
+ reason = sim_stopped;
+ siggnal = m32c_signal_to_host (M32C_STOP_SIG (rc));
+ }
+ else
+ {
+ assert (M32C_EXITED (rc));
+ reason = sim_exited;
+ siggnal = M32C_EXIT_STATUS (rc);
+ }
+}
+
+
+void
+sim_resume (SIM_DESC sd, int step, int sig_to_deliver)
+{
+ check_desc (sd);
+
+ if (sig_to_deliver != 0)
+ {
+ fprintf (stderr,
+ "Warning: the m32c minisim does not implement "
+ "signal delivery yet.\n" "Resuming with no signal.\n");
+ }
+
+ if (step)
+ handle_step (decode_opcode ());
+ else
+ {
+ /* We don't clear 'stop' here, because then we would miss
+ interrupts that arrived on the way here. Instead, we clear
+ the flag in sim_stop_reason, after GDB has disabled the
+ interrupt signal handler. */
+ for (;;)
+ {
+ if (stop)
+ {
+ stop = 0;
+ reason = sim_stopped;
+ siggnal = TARGET_SIGNAL_INT;
+ break;
+ }
+
+ int rc = decode_opcode ();
+
+ if (!M32C_STEPPED (rc))
+ {
+ handle_step (rc);
+ break;
+ }
+ }
+ }
+}
+
+int
+sim_stop (SIM_DESC sd)
+{
+ stop = 1;
+
+ return 1;
+}
+
+void
+sim_stop_reason (SIM_DESC sd, enum sim_stop *reason_p, int *sigrc_p)
+{
+ check_desc (sd);
+
+ *reason_p = reason;
+ *sigrc_p = siggnal;
+}
+
+void
+sim_do_command (SIM_DESC sd, char *cmd)
+{
+ check_desc (sd);
+
+ char *p = cmd;
+
+ /* Skip leading whitespace. */
+ while (isspace (*p))
+ p++;
+
+ /* Find the extent of the command word. */
+ for (p = cmd; *p; p++)
+ if (isspace (*p))
+ break;
+
+ /* Null-terminate the command word, and record the start of any
+ further arguments. */
+ char *args;
+ if (*p)
+ {
+ *p = '\0';
+ args = p + 1;
+ while (isspace (*args))
+ args++;
+ }
+ else
+ args = p;
+
+ if (strcmp (cmd, "trace") == 0)
+ {
+ if (strcmp (args, "on") == 0)
+ trace = 1;
+ else if (strcmp (args, "off") == 0)
+ trace = 0;
+ else
+ printf ("The 'sim trace' command expects 'on' or 'off' "
+ "as an argument.\n");
+ }
+ else if (strcmp (cmd, "verbose") == 0)
+ {
+ if (strcmp (args, "on") == 0)
+ verbose = 1;
+ else if (strcmp (args, "off") == 0)
+ verbose = 0;
+ else
+ printf ("The 'sim verbose' command expects 'on' or 'off'"
+ " as an argument.\n");
+ }
+ else
+ printf ("The 'sim' command expects either 'trace' or 'verbose'"
+ " as a subcommand.\n");
+}