This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH] Support for Xilinx MicroBlaze
- From: Michael Eager <eager at eagercon dot com>
- To: "gdb-patches at sourceware dot org" <gdb-patches at sourceware dot org>
- Cc: Joel Brobecker <brobecker at adacore dot com>, Eli Zaretskii <eliz at gnu dot org>
- Date: Mon, 05 Oct 2009 18:35:36 -0700
- Subject: [PATCH] Support for Xilinx MicroBlaze
Revised patch. I believe that I have addressed all of the comments.
2009-10-05 Michael Eager <eager@eagercon.com>
* config/djgpp/fnchange.lst: Add translations for cpu-microblaze.c,
elf32-microblaze.c, microblaze-rom.c, microblaze-linux-tdep.c,
microblaze-tdep.h, microblaze-tdep.c, microblaze-opc.h, microblaze-opcm.h,
microblaze-dis.c, microblaze-dis.h, sim/microblaze, microblaze.h, and
microblaze.isa.
* configure.tgt: Add targets microblaze*-linux-*, microblaze*-xilinx-*.
* doc/gdb.texinfo: Add MicroBlaze.
* MAINTAINERS: Add self as maintainer for MicroBlaze.
* Makefile.in: Build microblaze-tdep.o, microblaze-linux-tdep.o.
HFILES_NO_SRCDIR: Add microblaze-tdep.h.
* microblaze-linux-tdep.c: New.
* microblaze-rom.c: New.
* microblaze-tdep.c: New.
* microblaze-tdep.h: New.
* NEWS: Announce Xilinx MicroBlaze support.
There are some required changes to opcodes/microblaze* which I'll send
to the Binutils list.
--
Michael Eager eager@eagercon.com
1960 Park Blvd., Palo Alto, CA 94306 650-325-8077
diff -urNp --exclude '*.swp' --exclude DEV-PHASE --exclude .svn --exclude CVS gdb/gdb/config/djgpp/fnchange.lst mb-gdb/gdb/config/djgpp/fnchange.lst
--- gdb/gdb/config/djgpp/fnchange.lst 2009-09-19 02:46:44.000000000 -0700
+++ mb-gdb/gdb/config/djgpp/fnchange.lst 2009-10-05 17:44:30.000000000 -0700
@@ -18,6 +18,7 @@
@V@/bfd/cpu-cr16.c @V@/bfd/cpucr16.c
@V@/bfd/cpu-cr16c.c @V@/bfd/cpucr16c.c
@V@/bfd/cpu-ia64-opc.c @V@/bfd/cpuia64-opc.c
+@V@/bfd/cpu-microblaze.c @V@/bfd/cpumb.c
@V@/bfd/cpu-m68hc11.c @V@/bfd/cm68hc11.c
@V@/bfd/cpu-m68hc12.c @V@/bfd/cm68hc12.c
@V@/bfd/efi-app-ia32.c @V@/bfd/efiia32app.c
@@ -34,6 +35,7 @@
@V@/bfd/elf32-frv.c @V@/bfd/elf32fv.c
@V@/bfd/elf32-i370.c @V@/bfd/e32i370.c
@V@/bfd/elf32-i386.c @V@/bfd/e32i86.c
+@V@/bfd/elf32-microblaze.c @V@e32mb.c
@V@/bfd/elf32-m32c.c @V@/bfd/em32c.c
@V@/bfd/elf32-m32r.c @V@/bfd/em32r.c
@V@/bfd/elf32-m68hc11.c @V@/bfd/em68hc11.c
@@ -279,6 +281,10 @@
@V@/gdb/m68kbsd-tdep.c @V@/gdb/m68bsd-tdep.c
@V@/gdb/m68knbsd-nat.c @V@/gdb/m6nbsd-nat.c
@V@/gdb/m68knbsd-tdep.c @V@/gdb/m6nbsd-tdep.c
+@V@/gdb/microblaze-rom.c @V@/gdb/mb-rom.c
+@V@/gdb/microblaze-linux-tdep.c @V@/gdb/mbl-tdep.c
+@V@/gdb/microblaze-tdep.h @V@/gdb/mb-tdep.h
+@V@/gdb/microblaze-tdep.c @V@/gdb/mb-tdep.c
@V@/gdb/mips-linux-nat.c @V@/gdb/mipslnxnat.c
@V@/gdb/mips-linux-tdep.c @V@/gdb/mipslnxtdep.c
@V@/gdb/mipsnbsd-nat.c @V@/gdb/mipsnbnat.c
@@ -511,6 +517,10 @@
@V@/opcodes/ia64-opc.c @V@/opcodes/ia64-opc.c
@V@/opcodes/iq2000-desc.c @V@/opcodes/iq2000desc.c
@V@/opcodes/iq2000-dis.c @V@/opcodes/iq2000dis.c
+@V@/opcodes/microblaze-opc.h @V@/opcodes/mb-opc.h
+@V@/opcodes/microblaze-dis.c @V@/opcodes/mb-dis.c
+@V@/opcodes/microblaze-dis.h @V@/opcodes/mb-dis.h
+@V@/opcodes/microblaze-opcm.h @V@/opcodes/mb-opcm.h
@V@/opcodes/m68hc11-dis.c @V@/opcodes/m68hc11dis.c
@V@/opcodes/m68hc11-opc.c @V@/opcodes/m68hc11opc.c
@V@/opcodes/microblaze-opc.h @V@/opcodes/mbl-opc.h
@@ -540,6 +550,9 @@
@V@/sim/frv/profile-fr500.h @V@/sim/frv/fr500-profile.h
@V@/sim/frv/profile-fr550.c @V@/sim/frv/fr550-profile.c
@V@/sim/frv/profile-fr550.h @V@/sim/frv/fr550-profile.h
+@V@/sim/microblaze @V@/sim/mb
+@V@/sim/microblaze/microblaze.h @V@/sim/mb/mb.h
+@V@/sim/microblaze/microblaze.isa @V@/sim/mb/mb.isa
@V@/sim/m68hc11/dv-m68hc11eepr.c @V@/sim/m68hc11/dv-eepr.c
@V@/sim/m68hc11/dv-m68hc11sio.c @V@/sim/m68hc11/dv-sio.c
@V@/sim/m68hc11/dv-m68hc11spi.c @V@/sim/m68hc11/dv-spi.c
diff -urNp --exclude '*.swp' --exclude DEV-PHASE --exclude .svn --exclude CVS gdb/gdb/configure.tgt mb-gdb/gdb/configure.tgt
--- gdb/gdb/configure.tgt 2009-09-27 13:46:35.000000000 -0700
+++ mb-gdb/gdb/configure.tgt 2009-10-05 10:52:47.000000000 -0700
@@ -313,6 +313,19 @@ mep-*-*)
# No sim needed. Target uses SID.
;;
+microblaze*-linux-*)
+ # Target: Xilinx MicroBlaze running Linux
+ gdb_target_obs="microblaze-tdep.o microblaze-linux-tdep.o microblaze-rom.o \
+ monitor.o dsrec.o solib.o solib-svr4.o corelow.o \
+ symfile-mem.o"
+ gdb_sim=../sim/microblaze/libsim.a
+ ;;
+microblaze*-xilinx-*)
+ # Target: Xilinx MicroBlaze running standalone
+ gdb_target_obs="microblaze-tdep.o microblaze-rom.o monitor.o dsrec.o"
+ gdb_sim=../sim/microblaze/libsim.a
+ ;;
+
mips*-sgi-irix5*)
# Target: MIPS SGI running Irix 5
gdb_target_obs="mips-tdep.o mips-irix-tdep.o solib.o solib-irix.o"
diff -urNp --exclude '*.swp' --exclude DEV-PHASE --exclude .svn --exclude CVS gdb/gdb/doc/gdb.texinfo mb-gdb/gdb/doc/gdb.texinfo
--- gdb/gdb/doc/gdb.texinfo 2009-10-04 10:37:57.000000000 -0700
+++ mb-gdb/gdb/doc/gdb.texinfo 2009-10-05 10:52:56.000000000 -0700
@@ -517,6 +517,9 @@ Tensilica, Inc.@: contributed support fo
who have worked on the Xtensa port of @value{GDBN} in the past include
Steve Tjiang, John Newlin, and Scott Foehner.
+Michael Eager and staff of Xilinx, Inc., contributed support for the
+Xilinx MicroBlaze architecture.
+
@node Sample Session
@chapter A Sample @value{GDBN} Session
@@ -16570,6 +16573,7 @@ acceptable commands.
* ARM:: ARM RDI
* M32R/D:: Renesas M32R/D
* M68K:: Motorola M68K
+* MicroBlaze:: Xilinx MicroBlaze
* MIPS Embedded:: MIPS Embedded
* OpenRISC 1000:: OpenRisc 1000
* PA:: HP PA Embedded
@@ -16821,6 +16825,44 @@ dBUG ROM monitor for Motorola ColdFire.
@end table
+@node MicroBlaze
+@subsection MicroBlaze
+@cindex Xilinx MicroBlaze
+@cindex XMD, Xilinx Microprocessor Debugger
+
+The MicroBlaze is a soft-core processor supported on various Xilinx
+FPGAs, such as Spartan or Virtex series. Boards with these processors
+usually have JTAG ports which connect to a host system running the Xilinx
+Embedded Development Kit (EDK) or Software Development Kit (SDK).
+This host system is used to download the configuration bitstream to
+the target FPGA. The Xilinx Microprocessor Debugger (XMD) program
+communicates with the target board using the JTAG interface and
+presents a @code{gdbserver} interface to the board. By default
+@code{xmd} uses port @code{1234}. (While it is possible to change
+this default port, it requires the use of undocumented @code{xmd}
+commands. Contact Xilinx support if you need to do this.)
+
+Use these GDB commands to connect to the MicroBlaze target processor.
+
+@table @code
+@item target remote :1234
+Use this command to connect to the target if you are running @value{GDBN}
+on the same system as @code{xmd}.
+
+@item target remote @var{xmd-host}:1234
+Use this command to connect to the target if it is connected to @code{xmd}
+running on a different system named @var{xmd-host}.
+
+@item load
+Use this command to download a program to the MicroBlaze target.
+
+@item set debug microblaze @var{n}
+Enable MicroBlaze-specific debugging messages if non-zero.
+
+@item show debug microblaze @var{n}
+Show MicroBlaze-specific debugging level.
+@end table
+
@node MIPS Embedded
@subsection MIPS Embedded
diff -urNp --exclude '*.swp' --exclude DEV-PHASE --exclude .svn --exclude CVS gdb/gdb/MAINTAINERS mb-gdb/gdb/MAINTAINERS
--- gdb/gdb/MAINTAINERS 2009-10-01 16:11:02.000000000 -0700
+++ mb-gdb/gdb/MAINTAINERS 2009-10-05 10:52:46.000000000 -0700
@@ -290,6 +290,10 @@ the native maintainer when resolving ABI
mep --target=mep-elf ,-Werror
Kevin Buettner kevinb@redhat.com
+ microblaze --target=microblaze-xilinx-elf ,-Werror
+ --target=microblaze-linux-gnu ,-Werror
+ Michael Eager eager@eagercon.com
+
mips --target=mips-elf ,-Werror
mn10300 --target=mn10300-elf broken
diff -urNp --exclude '*.swp' --exclude DEV-PHASE --exclude .svn --exclude CVS gdb/gdb/Makefile.in mb-gdb/gdb/Makefile.in
--- gdb/gdb/Makefile.in 2009-09-16 14:55:57.000000000 -0700
+++ mb-gdb/gdb/Makefile.in 2009-10-05 11:59:21.000000000 -0700
@@ -501,6 +501,7 @@ ALL_TARGET_OBS = \
m68kbsd-tdep.o m68klinux-tdep.o m68k-tdep.o \
m88k-tdep.o \
mep-tdep.o \
+ microblaze-tdep.o microblaze-linux-tdep.o \
mips-irix-tdep.o mips-linux-tdep.o \
mipsnbsd-tdep.o mips-tdep.o \
mn10300-linux-tdep.o mn10300-tdep.o \
@@ -750,7 +751,7 @@ config/rs6000/nm-rs6000.h top.h bsd-kvm.
annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h \
remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
-gdb_usleep.h jit.h xml-syscall.h ada-operator.inc
+gdb_usleep.h jit.h xml-syscall.h ada-operator.inc microblaze-tdep.h
# Header files that already have srcdir in them, or which are in objdir.
@@ -1434,6 +1435,7 @@ ALLDEPFILES = \
m68kbsd-nat.c m68kbsd-tdep.c \
m68klinux-nat.c m68klinux-tdep.c \
m88k-tdep.c m88kbsd-nat.c \
+ microblaze-tdep.c microblaze-linux-tdep.c \
mingw-hdep.c \
mips-linux-nat.c mips-linux-tdep.c \
mips-irix-tdep.c \
diff -urNp --exclude '*.swp' --exclude DEV-PHASE --exclude .svn --exclude CVS gdb/gdb/microblaze-linux-tdep.c mb-gdb/gdb/microblaze-linux-tdep.c
--- gdb/gdb/microblaze-linux-tdep.c 1969-12-31 16:00:00.000000000 -0800
+++ mb-gdb/gdb/microblaze-linux-tdep.c 2009-09-30 11:51:38.000000000 -0700
@@ -0,0 +1,142 @@
+/* Target-dependent code for Xilinx MicroBlaze.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it 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 this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "regcache.h"
+#include "value.h"
+#include "osabi.h"
+#include "regset.h"
+#include "solib-svr4.h"
+#include "microblaze-tdep.h"
+#include "trad-frame.h"
+#include "frame-unwind.h"
+#include "tramp-frame.h"
+
+
+static int
+microblaze_linux_memory_remove_breakpoint (struct bp_target_info *bp_tgt)
+{
+ CORE_ADDR addr = bp_tgt->placed_address;
+ const gdb_byte *bp;
+ int val;
+ int bplen;
+ gdb_byte old_contents[BREAKPOINT_MAX];
+
+ /* Determine appropriate breakpoint contents and size for this address. */
+ bp = gdbarch_breakpoint_from_pc (gdbarch, &addr, &bplen);
+ if (bp == NULL)
+ error (_("Software breakpoints not implemented for this target."));
+
+ val = target_read_memory (addr, old_contents, bplen);
+
+ /* If our breakpoint is no longer at the address, this means that the
+ program modified the code on us, so it is wrong to put back the
+ old value. */
+ if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
+ val = target_write_memory (addr, bp_tgt->shadow_contents, bplen);
+
+ return val;
+}
+
+static void
+microblaze_linux_sigtramp_cache (struct frame_info *next_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func, LONGEST offset,
+ int bias)
+{
+ CORE_ADDR base;
+ CORE_ADDR gpregs;
+ int regnum;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
+ if (bias > 0 && frame_pc_unwind (next_frame) != func)
+ /* See below, some signal trampolines increment the stack as their
+ first instruction, need to compensate for that. */
+ base -= bias;
+
+ /* Find the address of the register buffer. */
+ gpregs = base + offset;
+
+ /* Registers saved on stack. */
+ for (regnum = 0; regnum < MICROBLAZE_BTR_REGNUM; regnum++)
+ trad_frame_set_reg_addr (this_cache, regnum,
+ gpregs + regnum * MICROBLAZE_REGISTER_SIZE);
+ trad_frame_set_id (this_cache, frame_id_build (base, func));
+}
+
+
+static void
+microblaze_linux_sighandler_cache_init (const struct tramp_frame *self,
+ struct frame_info *next_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func)
+{
+ microblaze_linux_sigtramp_cache (next_frame, this_cache, func,
+ 0 /* Offset to ucontext_t. */
+ + 24 /* Offset to .reg. */,
+ 0);
+}
+
+static struct tramp_frame microblaze_linux_sighandler_tramp_frame =
+{
+ SIGTRAMP_FRAME,
+ 4,
+ {
+ { 0x31800077, -1 }, /* addik R12,R0,119. */
+ { 0xb9cc0008, -1 }, /* brki R14,8. */
+ { TRAMP_SENTINEL_INSN },
+ },
+ microblaze_linux_sighandler_cache_init
+};
+
+
+static void
+microblaze_linux_init_abi (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ set_gdbarch_memory_remove_breakpoint (gdbarch,
+ microblaze_linux_memory_remove_breakpoint);
+
+ /* Shared library handling. */
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_ilp32_fetch_link_map_offsets);
+
+ /* Trampolines. */
+ tramp_frame_prepend_unwinder (gdbarch,
+ µblaze_linux_sighandler_tramp_frame);
+}
+
+void
+_initialize_microblaze_linux_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_microblaze, 0, GDB_OSABI_LINUX,
+ microblaze_linux_init_abi);
+}
diff -urNp --exclude '*.swp' --exclude DEV-PHASE --exclude .svn --exclude CVS gdb/gdb/microblaze-rom.c mb-gdb/gdb/microblaze-rom.c
--- gdb/gdb/microblaze-rom.c 1969-12-31 16:00:00.000000000 -0800
+++ mb-gdb/gdb/microblaze-rom.c 2009-09-30 10:49:00.000000000 -0700
@@ -0,0 +1,191 @@
+/* Remote debugging interface to Xilinx MicroBlaze.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it 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 this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "monitor.h"
+#include "gdb_string.h"
+#include "serial.h"
+#include "regcache.h"
+
+static char *picobug_inits[] =
+{"\r", NULL};
+
+static struct target_ops picobug_ops;
+static struct monitor_ops picobug_cmds;
+
+/* Picobug only supports a subset of registers from MCore. In reality,
+ it doesn't support ss1, either. */
+static char *picobug_regnames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ "psr", "vbr", "epsr", "fpsr", "epc", "fpc", 0, "ss1",
+ "ss2", "ss3", "ss4", 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ "pc" };
+
+
+
+static void
+picobug_open (char *args, int from_tty)
+{
+ monitor_open (args, &picobug_cmds, from_tty);
+}
+/* We choose to write our own dumpregs routine, since the output of
+ the register dumping is rather difficult to encapsulate in a
+ regexp:
+
+picobug> rd
+ pc 2f00031e epc 2f00031e fpc 00000000
+ psr 80000101 epsr 80000101 fpsr 00000000
+ss0-ss4 bad0beef 00000000 00000000 00000000 00000000 vbr 30005c00
+ r0-r7 2f0fff4c 00000090 00000001 00000002 00000003 00000004 00000005 00000006
+ r8-r15 2f0fff64 00000000 00000000 00000000 00000000 00000000 00000000 2f00031e
+*/
+
+static int
+picobug_dumpregs (struct regcache *regcache)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ char buf[1024];
+ int resp_len;
+ char *p;
+
+ /* Send the dump register command to the monitor and
+ get the reply. */
+ monitor_printf (picobug_cmds.dump_registers);
+ resp_len = monitor_expect_prompt (buf, sizeof (buf));
+
+ p = strtok (buf, " \t\r\n");
+ while (p)
+ {
+ if (strchr (p, '-'))
+ {
+ /* got a range. either r0-r7, r8-r15 or ss0-ss4. */
+ if (strncmp (p, "r0", 2) == 0 || strncmp (p, "r8", 2) == 0)
+ {
+ int rn = (p[1] == '0' ? 0 : 8);
+ int i = 0;
+
+ /* Get the next 8 values and record them. */
+ while (i < 8)
+ {
+ p = strtok (NULL, " \t\r\n");
+ if (p)
+ monitor_supply_register (regcache, rn + i, p);
+ i++;
+ }
+ }
+ else if (strncmp (p, "ss", 2) == 0)
+ {
+ /* get the next five values, ignoring the first. */
+ int rn;
+ p = strtok (NULL, " \t\r\n");
+ for (rn = 39; rn < 43; rn++)
+ {
+ p = strtok (NULL, " \t\r\n");
+ if (p)
+ monitor_supply_register (regcache, rn, p);
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ /* Simple register type, paired. */
+ char *name = p;
+ int i;
+
+ /* Get and record value. */
+ p = strtok (NULL, " \t\r\n");
+ if (p)
+ {
+ for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
+ {
+ if (picobug_regnames[i]
+ && (strcmp (picobug_regnames[i], name) == 0))
+ break;
+ }
+
+ if (i <= gdbarch_num_regs (gdbarch))
+ monitor_supply_register (regcache, i, p);
+ }
+ }
+ p = strtok (NULL, " \t\r\n");
+ }
+
+ return 0;
+}
+
+static void
+init_picobug_cmds (void)
+{
+ picobug_cmds.flags = MO_GETMEM_NEEDS_RANGE | MO_CLR_BREAK_USES_ADDR
+ | MO_PRINT_PROGRAM_OUTPUT;
+
+ picobug_cmds.init = picobug_inits; /* Init strings */
+ picobug_cmds.cont = "g\n"; /* continue command */
+ picobug_cmds.step = "s\n"; /* single step */
+ picobug_cmds.set_break = "br %x\n"; /* set a breakpoint */
+ picobug_cmds.clr_break = "nobr %x\n"; /* clear a breakpoint */
+ picobug_cmds.clr_all_break = "nobr\n"; /* clear all breakpoints */
+ picobug_cmds.setmem.cmdb = "mm %x %x ;b\n"; /* setmem.cmdb (addr, value) */
+ picobug_cmds.setmem.cmdw = "mm %x %x ;h\n"; /* setmem.cmdw (addr, value) */
+ picobug_cmds.setmem.cmdl = "mm %x %x ;w\n"; /* setmem.cmdl (addr, value) */
+ picobug_cmds.getmem.cmdb = "md %x %x\n"; /* getmem.cmdb (start addr,
+ end addr) */
+ picobug_cmds.getmem.resp_delim = ":"; /* getmem.resp_delim */
+ picobug_cmds.setreg.cmd = "rm %s %x\n"; /* setreg.cmd (name, value) */
+ picobug_cmds.getreg.cmd = "rd %s\n"; /* getreg.cmd (name) */
+ picobug_cmds.getreg.resp_delim = ":"; /* getreg.resp_delim */
+ picobug_cmds.dump_registers = "rd\n"; /* dump_registers */
+ picobug_cmds.dumpregs = picobug_dumpregs; /* dump registers parser */
+ picobug_cmds.load = "lo\n"; /* download command */
+ picobug_cmds.prompt = "picobug> "; /* monitor command prompt */
+ picobug_cmds.line_term = "\n"; /* end-of-line terminator */
+ picobug_cmds.target = &picobug_ops; /* target operations */
+ picobug_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
+ picobug_cmds.regnames = picobug_regnames; /* registers names */
+ picobug_cmds.num_breakpoints = 20; /* number of breakpoints */
+ picobug_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
+}
+
+void
+_initialize_picobug_rom ()
+{
+ int i;
+
+ /* Initialize m32r RevC monitor target. */
+ init_picobug_cmds ();
+ init_monitor_ops (&picobug_ops);
+ picobug_ops.to_shortname = "picobug";
+ picobug_ops.to_longname = "picobug monitor";
+ picobug_ops.to_doc = "Debug via the picobug monitor.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).";
+ picobug_ops.to_open = picobug_open;
+
+ add_target (&picobug_ops);
+}
diff -urNp --exclude '*.swp' --exclude DEV-PHASE --exclude .svn --exclude CVS gdb/gdb/microblaze-tdep.c mb-gdb/gdb/microblaze-tdep.c
--- gdb/gdb/microblaze-tdep.c 1969-12-31 16:00:00.000000000 -0800
+++ mb-gdb/gdb/microblaze-tdep.c 2009-10-05 14:09:02.000000000 -0700
@@ -0,0 +1,877 @@
+/* Target-dependent code for Xilinx MicroBlaze.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it 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 this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "dis-asm.h"
+#include "frame.h"
+#include "trad-frame.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "breakpoint.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "target.h"
+#include "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "dwarf2-frame.h"
+#include "osabi.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+#include "target-descriptions.h"
+#include "opcodes/microblaze-opcm.h"
+#include "opcodes/microblaze-dis.h"
+#include "microblaze-tdep.h"
+
+/* Instruction macros used for analyzing the prologue. */
+/* This set of instruction macros need to be changed whenever the
+ prologue generated by the compiler could have more instructions or
+ different type of instructions.
+ This set also needs to be verified if it is complete. */
+#define IS_RETURN(op) (op == rtsd || op == rtid)
+#define IS_UPDATE_SP(op, rd, ra) \
+ ((op == addik || op == addi) && rd == REG_SP && ra == REG_SP)
+#define IS_SPILL_SP(op, rd, ra) \
+ ((op == swi || op == sw) && rd == REG_SP && ra == REG_SP)
+#define IS_SPILL_REG(op, rd, ra) \
+ ((op == swi || op == sw) && rd != REG_SP && ra == REG_SP)
+#define IS_ALSO_SPILL_REG(op, rd, ra, rb) \
+ ((op == swi || op == sw) && rd != REG_SP && ra == 0 && rb == REG_SP)
+#define IS_SETUP_FP(op, ra, rb) \
+ ((op == add || op == addik || op == addk) && ra == REG_SP && rb == 0)
+#define IS_SPILL_REG_FP(op, rd, ra, fpregnum) \
+ ((op == swi || op == sw) && rd != REG_SP && ra == fpregnum && ra != 0)
+#define IS_SAVE_HIDDEN_PTR(op, rd, ra, rb) \
+ ((op == add || op == addik) && ra == MICROBLAZE_FIRST_ARGREG && rb == 0)
+
+/* All registers are 32 bits. */
+#define MICROBLAZE_REGISTER_SIZE 4
+
+/* The registers of the Xilinx microblaze processor. */
+
+static const char *microblaze_register_names[] =
+{
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+ "rpc", "rmsr", "rear", "resr", "rfsr", "rbtr",
+ "rpvr0", "rpvr1", "rpvr2", "rpvr3", "rpvr4", "rpvr5", "rpvr6",
+ "rpvr7", "rpvr8", "rpvr9", "rpvr10", "rpvr11",
+ "redr", "rpid", "rzpr", "rtlbx", "rtlbsx", "rtlblo", "rtlbhi"
+};
+
+#define MICROBLAZE_NUM_REGS ARRAY_SIZE (microblaze_register_names)
+
+static int microblaze_debug = 0;
+
+#define microblaze_insn_debug(args) \
+ { if (microblaze_debug) { printf_filtered args; } }
+
+/* Return the name of register REGNUM. */
+
+static const char *
+microblaze_register_name (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum >= 0 && regnum < MICROBLAZE_NUM_REGS)
+ return microblaze_register_names[regnum];
+ return NULL;
+}
+
+static struct type *
+microblaze_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum == MICROBLAZE_SP_REGNUM)
+ return builtin_type (gdbarch)->builtin_data_ptr;
+
+ if (regnum == MICROBLAZE_PC_REGNUM)
+ return builtin_type (gdbarch)->builtin_func_ptr;
+
+ return builtin_type (gdbarch)->builtin_int;
+}
+
+
+/* Fetch the instruction at PC. */
+
+unsigned long
+microblaze_fetch_instruction (CORE_ADDR pc)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+ gdb_byte buf[4];
+
+ /* If we can't read the instruction at PC, return zero. */
+ if (target_read_memory (pc, buf, sizeof (buf)))
+ return 0;
+
+ return extract_unsigned_integer (buf, 4, byte_order);
+}
+
+
+static CORE_ADDR
+microblaze_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
+ CORE_ADDR funcaddr,
+ struct value **args, int nargs,
+ struct type *value_type,
+ CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+ struct regcache *regcache)
+{
+ error (_("push_dummy_code not implemented"));
+ return sp;
+}
+
+
+static CORE_ADDR
+microblaze_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ error (_("store_arguments not implemented"));
+ return sp;
+}
+
+static const gdb_byte *
+microblaze_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pc,
+ int *len)
+{
+ static gdb_byte break_insn[] = MICROBLAZE_BREAKPOINT;
+
+ *len = sizeof (break_insn);
+ return break_insn;
+}
+
+/* Allocate and initialize a frame cache. */
+
+static struct microblaze_frame_cache *
+microblaze_alloc_frame_cache (void)
+{
+ struct microblaze_frame_cache *cache;
+ int i;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct microblaze_frame_cache);
+
+ /* Base address. */
+ cache->base = 0;
+ cache->pc = 0;
+
+ /* Frameless until proven otherwise. */
+ cache->frameless_p = 1;
+
+ return cache;
+}
+
+/* The base of the current frame is actually in the stack pointer.
+ This happens when there is no frame pointer (microblaze ABI does not
+ require a frame pointer) or when we're stopped in the prologue or
+ epilogue itself. In these cases, microblaze_analyze_prologue will need
+ to update fi->frame before returning or analyzing the register
+ save instructions. */
+#define MICROBLAZE_MY_FRAME_IN_SP 0x1
+
+/* The base of the current frame is in a frame pointer register.
+ This register is noted in frame_extra_info->fp_regnum.
+
+ Note that the existance of an FP might also indicate that the
+ function has called alloca. */
+#define MICROBLAZE_MY_FRAME_IN_FP 0x2
+
+/* Function prologues on the Xilinx microblaze processors consist of:
+
+ - adjustments to the stack pointer (r1) (addi r1, r1, imm)
+ - making a copy of r1 into another register (a "frame" pointer)
+ (add r?, r1, r0)
+ - store word/multiples that use r1 or the frame pointer as the
+ base address (swi r?, r1, imm OR swi r?, fp, imm)
+
+ Note that microblaze really doesn't have a real frame pointer.
+ Instead, the compiler may copy the SP into a register (usually
+ r19) to act as an arg pointer. For our target-dependent purposes,
+ the frame info's "frame" member will be the beginning of the
+ frame. The SP could, in fact, point below this.
+
+ The prologue ends when an instruction fails to meet either of
+ these criteria. */
+
+/* Analyze the prologue to determine where registers are saved,
+ the end of the prologue, etc. Return the address of the first line
+ of "real" code (i.e., the end of the prologue). */
+
+CORE_ADDR
+microblaze_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
+ struct microblaze_frame_cache *cache)
+{
+ char *name;
+ CORE_ADDR func_addr, func_end, addr, stop, prologue_end_addr = 0;
+ unsigned long insn;
+ int rn, rd, ra, rb, imm;
+ enum microblaze_instr op;
+ int flags = 0;
+ int save_hidden_pointer_found = 0;
+ int non_stack_instruction_found = 0;
+
+ /* Find the start of this function. */
+ find_pc_partial_function (pc, &name, &func_addr, &func_end);
+ if (func_addr < pc)
+ pc = func_addr;
+
+ if (current_pc < pc)
+ return current_pc;
+
+ /* Initialize info about frame. */
+ cache->framesize = 0;
+ cache->fp_regnum = MICROBLAZE_SP_REGNUM;
+ cache->frameless_p = 1;
+
+ /* Start decoding the prologue. We start by checking two special cases:
+
+ 1. We're about to return
+ 2. We're at the first insn of the prologue.
+
+ If we're about to return, our frame has already been deallocated.
+ If we are stopped at the first instruction of a prologue,
+ then our frame has not yet been set up. */
+
+ /* Get the first insn from memory. */
+
+ insn = microblaze_fetch_instruction (pc);
+ op = microblaze_decode_insn (insn, &rd, &ra, &rb, &imm);
+
+ if (IS_RETURN(op))
+ return pc;
+
+ /* Start at beginning of function and analyze until we get to the
+ current pc, or the end of the function, whichever is first. */
+ stop = (current_pc < func_end ? current_pc : func_end);
+
+ microblaze_insn_debug (("MICROBLAZE: Scanning prologue: name=%s, "
+ "func_addr=0x%x, stop=0x%x\n",
+ name, (unsigned int) func_addr,
+ (unsigned int) stop));
+
+ for (addr = func_addr; addr < stop; addr += INST_WORD_SIZE)
+ {
+ insn = microblaze_fetch_instruction (addr);
+ op = microblaze_decode_insn (insn, &rd, &ra, &rb, &imm);
+ if (microblaze_debug)
+ printf_filtered ("MICROBLAZE: %08x %08lx\n", (unsigned int) pc, insn);
+
+ /* This code is very sensitive to what functions are present in the
+ prologue. It assumes that the (addi, addik, swi, sw) can be the
+ only instructions in the prologue. */
+ if (IS_UPDATE_SP(op, rd, ra))
+ {
+ microblaze_insn_debug ((
+ "MICROBLAZE: got addi r1,r1,%d; contnuing\n", imm));
+ if (cache->framesize)
+ break; /* break if framesize already computed. */
+ cache->framesize = -imm; /* stack grows towards low memory. */
+ cache->frameless_p = 0; /* Frame found. */
+ save_hidden_pointer_found = 0;
+ non_stack_instruction_found = 0;
+ continue;
+ }
+ else if (IS_SPILL_SP(op, rd, ra))
+ {
+ /* Spill stack pointer. */
+ cache->register_offsets[rd] = imm; /* SP spilled before updating. */
+
+ microblaze_insn_debug (
+ ("MICROBLAZE: swi r1 r1 %d, continuing\n", imm));
+ save_hidden_pointer_found = 0;
+ if (!cache->framesize)
+ non_stack_instruction_found = 0;
+ continue;
+ }
+ else if (IS_SPILL_REG(op, rd, ra))
+ {
+ /* Spill register. */
+ cache->register_offsets[rd] = imm - cache->framesize;
+
+ microblaze_insn_debug (
+ ("MICROBLAZE: swi %d r1 %d, continuing\n", rd, imm));
+ save_hidden_pointer_found = 0;
+ if (!cache->framesize)
+ non_stack_instruction_found = 0;
+ continue;
+ }
+ else if (IS_ALSO_SPILL_REG(op, rd, ra, rb))
+ {
+ /* Spill register. */
+ cache->register_offsets[rd] = 0 - cache->framesize;
+
+ microblaze_insn_debug (
+ ("MICROBLAZE: sw %d r0 r1, continuing\n", rd));
+ save_hidden_pointer_found = 0;
+ if (!cache->framesize)
+ non_stack_instruction_found = 0;
+ continue;
+ }
+ else if (IS_SETUP_FP(op, ra, rb))
+ {
+ /* We have a frame pointer. Note the register which is
+ acting as the frame pointer. */
+ flags |= MICROBLAZE_MY_FRAME_IN_FP;
+ flags &= ~MICROBLAZE_MY_FRAME_IN_SP;
+ cache->fp_regnum = rd;
+ microblaze_insn_debug (
+ ("MICROBLAZE: Found a frame pointer: r%d\n",
+ cache->fp_regnum));
+ save_hidden_pointer_found = 0;
+ if (!cache->framesize)
+ non_stack_instruction_found = 0;
+ continue;
+ }
+ else if (IS_SPILL_REG_FP(op, rd, ra, cache->fp_regnum))
+ {
+ cache->register_offsets[rd] = imm - cache->framesize;
+ /* reg spilled after updating. */
+
+ microblaze_insn_debug (
+ ("MICROBLAZE: swi %d %d %d, continuing\n", rd, ra, imm));
+ save_hidden_pointer_found = 0;
+ if (!cache->framesize)
+ non_stack_instruction_found = 0;
+ continue;
+ }
+ else if (IS_SAVE_HIDDEN_PTR(op, rd, ra, rb))
+ {
+ /* If the first argument is a hidden pointer to the area where the
+ return structure is to be saved, then it is saved as part of the
+ prologue. */
+
+ microblaze_insn_debug (
+ ("MICROBLAZE: add %d %d %d, continuing\n", rd, ra, rb));
+ save_hidden_pointer_found = 1;
+ if (!cache->framesize)
+ non_stack_instruction_found = 0;
+ continue;
+ }
+
+ /* As a result of the modification in the next step where we continue
+ to analyze the prologue till we reach a control flow instruction,
+ we need another variable to store when exactly a non-stack
+ instruction was encountered, which is the current definition
+ of a prologue. */
+ if (!non_stack_instruction_found)
+ prologue_end_addr = addr;
+ non_stack_instruction_found = 1;
+
+ /* When optimizations are enabled, it is not guaranteed that prologue
+ instructions are not mixed in with other instructions from the
+ program. Some programs show this behavior at -O2. This can be
+ avoided by adding -fno-schedule-insns2 switch as of now (edk 8.1)
+ In such cases, we scan the function until we see the first control
+ instruction. */
+
+ {
+ unsigned op = (unsigned)insn >> 26;
+
+ if (!(op == 0x26 || op == 0x27 || op == 0x2d || op == 0x2e || op == 0x2f))
+ /* continue if not control flow (branch, return). */
+ continue;
+ else if (op == 0x2c)
+ continue; /* continue if imm. */
+ }
+
+ /* This is not a prologue insn, so stop here. */
+ microblaze_insn_debug (
+ ("microblaze: insn is not a prologue insn -- ending scan\n"));
+ break;
+ }
+
+ microblaze_insn_debug (("microblaze: done analyzing prologue\n"));
+ microblaze_insn_debug (("microblaze: prologue end = 0x%x\n", (int) addr));
+
+ /* If the last instruction was an add rd, r5, r0 then don't count it as
+ part of the prologue. */
+ if (save_hidden_pointer_found)
+ prologue_end_addr -= INST_WORD_SIZE;
+
+ return prologue_end_addr;
+}
+
+static CORE_ADDR
+microblaze_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ gdb_byte buf[4];
+ CORE_ADDR pc;
+
+ frame_unwind_register (next_frame, MICROBLAZE_PC_REGNUM, buf);
+ pc = extract_typed_address (buf, builtin_type (gdbarch)->builtin_func_ptr);
+ /* For sentinel frame, return address is actual PC. For other frames,
+ return address is pc+8. This is a workaround because gcc does not
+ generate correct return address in CIE. */
+ if (frame_relative_level (next_frame) >= 0)
+ pc += 8;
+ return pc;
+}
+
+/* Return PC of first real instruction of the function starting at
+ START_PC. */
+
+CORE_ADDR
+microblaze_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
+{
+ struct symtab_and_line sal;
+ CORE_ADDR func_start, func_end, ostart_pc;
+ struct microblaze_frame_cache cache;
+
+ /* This is the preferred method, find the end of the prologue by
+ using the debugging information. Debugging info does not always
+ give the right answer since parameters are stored on stack after this.
+ Always analyze the prologue. */
+ if (find_pc_partial_function (start_pc, NULL, &func_start, &func_end))
+ {
+ sal = find_pc_line (func_start, 0);
+
+ if (sal.end < func_end
+ && start_pc <= sal.end)
+ start_pc = sal.end;
+ }
+
+ ostart_pc = microblaze_analyze_prologue (func_start, 0xffffffffUL, &cache);
+
+ if (ostart_pc > start_pc)
+ return ostart_pc;
+ return start_pc;
+}
+
+/* Normal frames. */
+
+struct microblaze_frame_cache *
+microblaze_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct microblaze_frame_cache *cache;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ CORE_ADDR func, pc, fp;
+ int rn;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = microblaze_alloc_frame_cache ();
+ *this_cache = cache;
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ /* Clear offsets to saved regs in frame. */
+ for (rn = 0; rn < gdbarch_num_regs (gdbarch); rn++)
+ cache->register_offsets[rn] = -1;
+
+ func = get_frame_func (next_frame);
+
+ cache->pc = get_frame_address_in_block (next_frame);
+
+ return cache;
+}
+
+static void
+microblaze_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct microblaze_frame_cache *cache =
+ microblaze_frame_cache (next_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (cache->base == 0)
+ return;
+
+ (*this_id) = frame_id_build (cache->base, cache->pc);
+}
+
+static struct value *
+microblaze_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ struct microblaze_frame_cache *cache =
+ microblaze_frame_cache (this_frame, this_cache);
+
+ if (cache->frameless_p)
+ {
+ if (regnum == MICROBLAZE_PC_REGNUM)
+ regnum = 15;
+ if (regnum == MICROBLAZE_SP_REGNUM)
+ regnum = 1;
+ return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+ }
+ else
+ return trad_frame_get_prev_register (this_frame, cache->saved_regs,
+ regnum);
+
+}
+
+static const struct frame_unwind microblaze_frame_unwind =
+{
+ NORMAL_FRAME,
+ microblaze_frame_this_id,
+ microblaze_frame_prev_register,
+ NULL,
+ default_frame_sniffer
+};
+
+static CORE_ADDR
+microblaze_frame_base_address (struct frame_info *next_frame, void **this_cache)
+{
+ struct microblaze_frame_cache *cache =
+ microblaze_frame_cache (next_frame, this_cache);
+
+ return cache->base;
+}
+
+static const struct frame_base microblaze_frame_base =
+{
+ µblaze_frame_unwind,
+ microblaze_frame_base_address,
+ microblaze_frame_base_address,
+ microblaze_frame_base_address
+};
+
+/* Extract from an array REGBUF containing the (raw) register state, a
+ function return value of TYPE, and copy that into VALBUF. */
+static void
+microblaze_extract_return_value (struct type *type, struct regcache *regcache,
+ gdb_byte *valbuf)
+{
+ gdb_byte buf[8];
+
+ /* Copy the return value (starting) in RETVAL_REGNUM to VALBUF. */
+ switch (TYPE_LENGTH (type))
+ {
+ case 1: /* return last byte in the register. */
+ regcache_cooked_read (regcache, MICROBLAZE_RETVAL_REGNUM, buf);
+ memcpy(valbuf, buf + MICROBLAZE_REGISTER_SIZE - 1, 1);
+ return;
+ case 2: /* return last 2 bytes in register. */
+ memcpy(valbuf, buf + MICROBLAZE_REGISTER_SIZE - 2, 2);
+ return;
+ case 4: /* for sizes 4 or 8, copy the required length. */
+ case 8:
+ regcache_cooked_read (regcache, MICROBLAZE_RETVAL_REGNUM, buf);
+ regcache_cooked_read (regcache, MICROBLAZE_RETVAL_REGNUM+1, buf+4);
+ memcpy (valbuf, buf, TYPE_LENGTH (type));
+ return;
+ default:
+ fatal (_("Unsupported return value size requested"));
+ }
+}
+
+/* Store the return value in VALBUF (of type TYPE) where the caller
+ expects to see it.
+
+ Integers up to four bytes are stored in r3.
+
+ Longs are stored in r3 (most significant word) and r4 (least
+ significant word).
+
+ Small structures are always returned on stack.
+*/
+
+static void
+microblaze_store_return_value (struct type *type, struct regcache *regcache,
+ const gdb_byte *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+ gdb_byte buf[8];
+
+ memset (buf, 0, sizeof(buf));
+
+ /* Integral and pointer return values. */
+
+ if (len > 4)
+ {
+ gdb_assert (len == 8);
+ memcpy (buf, valbuf, 8);
+ regcache_cooked_write (regcache, MICROBLAZE_RETVAL_REGNUM+1, buf + 4);
+ }
+ else
+ /* ??? Do we need to do any sign-extension here? */
+ memcpy (buf + 4 - len, valbuf, len);
+
+ regcache_cooked_write (regcache, MICROBLAZE_RETVAL_REGNUM, buf);
+}
+
+static enum return_value_convention
+microblaze_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ if (readbuf)
+ microblaze_extract_return_value (type, regcache, readbuf);
+ if (writebuf)
+ microblaze_store_return_value (type, regcache, writebuf);
+
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+static int
+microblaze_stabs_argument_has_addr (struct gdbarch *gdbarch, struct type *type)
+{
+ return (TYPE_LENGTH (type) == 16);
+}
+
+int
+microblaze_can_use_hardware_watchpoints (enum bptype type, int count, int ot)
+{
+ switch (type)
+ {
+ case bp_hardware_breakpoint:
+ if (count <= 2)
+ return 1;
+ break;
+ case bp_read_watchpoint:
+ case bp_hardware_watchpoint:
+ if (count <= 1)
+ return 1;
+ break;
+ default:
+ return 0;
+ }
+ return -1;
+}
+
+/* Simulate single-step calls, since microblaze does not support
+ single-stepping. */
+
+/* single_step() is called just before we want to resume the inferior,
+ if we want to single-step it but there is no hardware or kernel
+ single-step support. We find all the possible targets of the
+ coming instruction and breakpoint them.
+
+ single_step is also called just after the inferior stops. If we had
+ set up a simulated single-step, we undo our damage. */
+
+int
+microblaze_software_single_step (struct frame_info *frame)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ struct regcache *regcache = get_current_regcache ();
+
+ /* Save the address and the values of the next_pc and the target. */
+ static struct sstep_breaks
+ {
+ CORE_ADDR address;
+ bfd_boolean valid;
+ } stepbreaks[2];
+
+ CORE_ADDR pc;
+ long insn;
+ enum microblaze_instr minstr;
+ int is_unsigned_num;
+ enum microblaze_instr_type insn_type;
+ short delay_slots;
+ int imm;
+ int immfound = 0;
+
+ /* Set a breakpoint at the next instruction. */
+ /* If the current instruction is an imm, set it at the inst after. */
+ /* If the instruction has a delay slot, skip the delay slot. */
+ pc = get_frame_register_unsigned (frame, MICROBLAZE_PC_REGNUM);
+ insn = microblaze_fetch_instruction (pc);
+ minstr = get_insn_microblaze (insn, &is_unsigned_num, &insn_type,
+ &delay_slots);
+ if (insn_type == immediate_inst)
+ {
+ int rd, ra, rb;
+ immfound = 1;
+ minstr = microblaze_decode_insn (insn, &rd, &ra, &rb, &imm);
+ pc = pc + INST_WORD_SIZE;
+ insn = microblaze_fetch_instruction (pc);
+ minstr = get_insn_microblaze (insn, &is_unsigned_num, &insn_type,
+ &delay_slots);
+ }
+ stepbreaks[0].address = pc + (delay_slots * INST_WORD_SIZE) + INST_WORD_SIZE;
+ if (insn_type != return_inst)
+ stepbreaks[0].valid = 1;
+ else
+ stepbreaks[0].valid = 0;
+
+ /* Now check for branch or return instructions. */
+ if (insn_type == branch_inst || insn_type == return_inst)
+ {
+ int limm;
+ int lrd, lra, lrb;
+ ULONGEST ra, rb;
+ bfd_boolean targetvalid;
+ bfd_boolean unconditionalbranch;
+ microblaze_decode_insn(insn, &lrd, &lra, &lrb, &limm);
+ if (lra >= 0 && lra < gdbarch_num_regs (gdbarch))
+ regcache_cooked_read_unsigned (regcache, lra, &ra);
+ else
+ ra = 0;
+ if (lrb >= 0 && lrb < gdbarch_num_regs (gdbarch))
+ regcache_cooked_read_unsigned (regcache, lrb, &rb);
+ else
+ rb = 0;
+ stepbreaks[1].address =
+ microblaze_get_target_address (insn, immfound, imm, pc,
+ ra, rb, &targetvalid,
+ &unconditionalbranch);
+ if (unconditionalbranch)
+ /* This is a unconditional branch: will not come to the next address. */
+ stepbreaks[0].valid = 0;
+ if (targetvalid
+ && (stepbreaks[0].valid == 0
+ || (stepbreaks[0].address != stepbreaks[1].address))
+ && (stepbreaks[1].address != pc))
+ stepbreaks[1].valid = 1;
+ else
+ stepbreaks[1].valid = 0;
+ }
+ else
+ stepbreaks[1].valid = 0;
+
+ /* Insert the breakpoints. */
+ if (stepbreaks[0].valid)
+ insert_single_step_breakpoint (gdbarch, stepbreaks[0].address);
+ if (stepbreaks[1].valid)
+ insert_single_step_breakpoint (gdbarch, stepbreaks[1].address);
+
+ return 1;
+}
+
+static void
+microblaze_write_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+ regcache_cooked_write_unsigned (regcache, MICROBLAZE_PC_REGNUM, pc);
+}
+
+static int dwarf2_to_reg_map[78] =
+{ 0 /* r0 */, 1 /* r1 */, 2 /* r2 */, 3 /* r3 */, /* 0- 3 */
+ 4 /* r4 */, 5 /* r5 */, 6 /* r6 */, 7 /* r7 */, /* 4- 7 */
+ 8 /* r8 */, 9 /* r9 */, 10 /* r10 */, 11 /* r11 */, /* 8-11 */
+ 12 /* r12 */, 13 /* r13 */, 14 /* r14 */, 15 /* r15 */, /* 12-15 */
+ 16 /* r16 */, 17 /* r17 */, 18 /* r18 */, 19 /* r19 */, /* 16-19 */
+ 20 /* r20 */, 21 /* r21 */, 22 /* r22 */, 23 /* r23 */, /* 20-23 */
+ 24 /* r24 */, 25 /* r25 */, 26 /* r26 */, 27 /* r27 */, /* 24-25 */
+ 28 /* r28 */, 29 /* r29 */, 30 /* r30 */, 31 /* r31 */, /* 28-31 */
+ -1 /* $f0 */, -1 /* $f1 */, -1 /* $f2 */, -1 /* $f3 */, /* 32-35 */
+ -1 /* $f4 */, -1 /* $f5 */, -1 /* $f6 */, -1 /* $f7 */, /* 36-39 */
+ -1 /* $f8 */, -1 /* $f9 */, -1 /* $f10 */, -1 /* $f11 */, /* 40-43 */
+ -1 /* $f12 */, -1 /* $f13 */, -1 /* $f14 */, -1 /* $f15 */, /* 44-47 */
+ -1 /* $f16 */, -1 /* $f17 */, -1 /* $f18 */, -1 /* $f19 */, /* 48-51 */
+ -1 /* $f20 */, -1 /* $f21 */, -1 /* $f22 */, -1 /* $f23 */, /* 52-55 */
+ -1 /* $f24 */, -1 /* $f25 */, -1 /* $f26 */, -1 /* $f27 */, /* 56-59 */
+ -1 /* $f28 */, -1 /* $f29 */, -1 /* $f30 */, -1 /* $f31 */, /* 60-63 */
+ -1 /* hi */, -1 /* lo */, -1 /* accum*/, 33 /* rmsr */, /* 64-67 */
+ -1 /* $fcc1*/, -1 /* $fcc2*/, -1 /* $fcc3*/, -1 /* $fcc4*/, /* 68-71 */
+ -1 /* $fcc5*/, -1 /* $fcc6*/, -1 /* $fcc7*/, -1 /* $ap */, /* 72-75 */
+ -1 /* $rap */, -1 /* $frp */ /* 76-77 */
+};
+
+static int
+microblaze_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int reg)
+{
+ gdb_assert (reg < sizeof (dwarf2_to_reg_map));
+ return dwarf2_to_reg_map[reg];
+}
+
+static struct gdbarch *
+microblaze_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch_tdep *tdep;
+ struct gdbarch *gdbarch;
+
+ /* If there is already a candidate, use it. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != NULL)
+ return arches->gdbarch;
+
+ /* Allocate space for the new architecture. */
+ tdep = XMALLOC (struct gdbarch_tdep);
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ set_gdbarch_long_double_bit (gdbarch, 128);
+
+ set_gdbarch_num_regs (gdbarch, MICROBLAZE_NUM_REGS);
+ set_gdbarch_register_name (gdbarch, microblaze_register_name);
+ set_gdbarch_register_type (gdbarch, microblaze_register_type);
+
+ /* Register numbers of various important registers. */
+ set_gdbarch_sp_regnum (gdbarch, MICROBLAZE_SP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, MICROBLAZE_PC_REGNUM);
+
+ /* Map Dwarf2 registers to GDB registers. */
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, microblaze_dwarf2_reg_to_regnum);
+
+ /* Call dummy code. */
+ set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+ set_gdbarch_push_dummy_code (gdbarch, microblaze_push_dummy_code);
+ set_gdbarch_push_dummy_call (gdbarch, microblaze_push_dummy_call);
+
+ set_gdbarch_return_value (gdbarch, microblaze_return_value);
+ set_gdbarch_stabs_argument_has_addr
+ (gdbarch, microblaze_stabs_argument_has_addr);
+
+ set_gdbarch_skip_prologue (gdbarch, microblaze_skip_prologue);
+
+ /* Stack grows downward. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ set_gdbarch_breakpoint_from_pc (gdbarch, microblaze_breakpoint_from_pc);
+
+ set_gdbarch_frame_args_skip (gdbarch, 8);
+
+ set_gdbarch_print_insn (gdbarch, print_insn_microblaze);
+
+ set_gdbarch_software_single_step (gdbarch, microblaze_software_single_step);
+ set_gdbarch_write_pc (gdbarch, microblaze_write_pc);
+
+ set_gdbarch_unwind_pc (gdbarch, microblaze_unwind_pc);
+
+ frame_base_set_default (gdbarch, µblaze_frame_base);
+
+ /* Hook in ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch);
+
+ /* Unwind the frame. */
+ dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, µblaze_frame_unwind);
+ frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
+
+ return gdbarch;
+}
+
+int
+microblaze_frame_num_args_p (struct gdbarch *gdbarch)
+{
+ return 0;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_microblaze_tdep (void);
+
+void
+_initialize_microblaze_tdep (void)
+{
+ register_gdbarch_init (bfd_arch_microblaze, microblaze_gdbarch_init);
+
+ /* Debug this files internals. */
+ add_setshow_zinteger_cmd ("microblaze", class_maintenance,
+ µblaze_debug, _("\
+Set microblaze debugging."), _("\
+Show microblaze debugging."), _("\
+When non-zero, microblaze specific debugging is enabled."),
+ NULL,
+ NULL,
+ &setdebuglist, &showdebuglist);
+
+}
diff -urNp --exclude '*.swp' --exclude DEV-PHASE --exclude .svn --exclude CVS gdb/gdb/microblaze-tdep.h mb-gdb/gdb/microblaze-tdep.h
--- gdb/gdb/microblaze-tdep.h 1969-12-31 16:00:00.000000000 -0800
+++ mb-gdb/gdb/microblaze-tdep.h 2009-10-05 14:34:14.000000000 -0700
@@ -0,0 +1,121 @@
+/* Target-dependent code for Xilinx MicroBlaze.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it 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 this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef MICROBLAZE_TDEP_H
+#define MICROBLAZE_TDEP_H 1
+
+
+/* Microblaze architecture-specific information. */
+struct gdbarch_tdep
+{
+};
+
+struct microblaze_frame_cache
+{
+ /* Base address. */
+ CORE_ADDR base;
+ CORE_ADDR pc;
+
+ /* Do we have a frame? */
+ int frameless_p;
+
+ /* Frame size. */
+ int framesize;
+
+ /* Frame register. */
+ int fp_regnum;
+
+ /* Offsets to saved registers. */
+ int register_offsets[57]; /* Must match MICROBLAZE_NUM_REGS. */
+
+ /* Table of saved registers. */
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Register numbers. */
+enum microblaze_regnum
+{
+ MICROBLAZE_R0_REGNUM,
+ MICROBLAZE_R1_REGNUM, MICROBLAZE_SP_REGNUM = MICROBLAZE_R1_REGNUM,
+ MICROBLAZE_R2_REGNUM,
+ MICROBLAZE_R3_REGNUM, MICROBLAZE_RETVAL_REGNUM = MICROBLAZE_R3_REGNUM,
+ MICROBLAZE_R4_REGNUM,
+ MICROBLAZE_R5_REGNUM, MICROBLAZE_FIRST_ARGREG = MICROBLAZE_R5_REGNUM,
+ MICROBLAZE_R6_REGNUM,
+ MICROBLAZE_R7_REGNUM,
+ MICROBLAZE_R8_REGNUM,
+ MICROBLAZE_R9_REGNUM,
+ MICROBLAZE_R10_REGNUM, MICROBLAZE_LAST_ARGREG = MICROBLAZE_R10_REGNUM,
+ MICROBLAZE_R11_REGNUM,
+ MICROBLAZE_R12_REGNUM,
+ MICROBLAZE_R13_REGNUM,
+ MICROBLAZE_R14_REGNUM,
+ MICROBLAZE_R15_REGNUM,
+ MICROBLAZE_R16_REGNUM,
+ MICROBLAZE_R17_REGNUM,
+ MICROBLAZE_R18_REGNUM,
+ MICROBLAZE_R19_REGNUM,
+ MICROBLAZE_R20_REGNUM,
+ MICROBLAZE_R21_REGNUM,
+ MICROBLAZE_R22_REGNUM,
+ MICROBLAZE_R23_REGNUM,
+ MICROBLAZE_R24_REGNUM,
+ MICROBLAZE_R25_REGNUM,
+ MICROBLAZE_R26_REGNUM,
+ MICROBLAZE_R27_REGNUM,
+ MICROBLAZE_R28_REGNUM,
+ MICROBLAZE_R29_REGNUM,
+ MICROBLAZE_R30_REGNUM,
+ MICROBLAZE_R31_REGNUM,
+ MICROBLAZE_PC_REGNUM,
+ MICROBLAZE_MSR_REGNUM,
+ MICROBLAZE_EAR_REGNUM,
+ MICROBLAZE_ESR_REGNUM,
+ MICROBLAZE_FSR_REGNUM,
+ MICROBLAZE_BTR_REGNUM,
+ MICROBLAZE_PVR0_REGNUM,
+ MICROBLAZE_PVR1_REGNUM,
+ MICROBLAZE_PVR2_REGNUM,
+ MICROBLAZE_PVR3_REGNUM,
+ MICROBLAZE_PVR4_REGNUM,
+ MICROBLAZE_PVR5_REGNUM,
+ MICROBLAZE_PVR6_REGNUM,
+ MICROBLAZE_PVR7_REGNUM,
+ MICROBLAZE_PVR8_REGNUM,
+ MICROBLAZE_PVR9_REGNUM,
+ MICROBLAZE_PVR10_REGNUM,
+ MICROBLAZE_PVR11_REGNUM,
+ MICROBLAZE_REDR_REGNUM,
+ MICROBLAZE_RPID_REGNUM,
+ MICROBLAZE_RZPR_REGNUM,
+ MICROBLAZE_RTLBX_REGNUM,
+ MICROBLAZE_RTLBSX_REGNUM,
+ MICROBLAZE_RTLBLO_REGNUM,
+ MICROBLAZE_RTLBHI_REGNUM
+};
+
+/* MICROBLAZE_BREAKPOINT defines the breakpoint that should be used.
+ Only used for native debugging. */
+#define MICROBLAZE_BREAKPOINT {0xb9, 0xcc, 0x00, 0x60}
+
+extern CORE_ADDR microblaze_analyze_prologue (CORE_ADDR, CORE_ADDR,
+ struct microblaze_frame_cache *);
+
+
+#endif /* microblaze-tdep.h */
diff -urNp --exclude '*.swp' --exclude DEV-PHASE --exclude .svn --exclude CVS gdb/gdb/NEWS mb-gdb/gdb/NEWS
--- gdb/gdb/NEWS 2009-10-04 10:39:30.000000000 -0700
+++ mb-gdb/gdb/NEWS 2009-10-05 10:52:47.000000000 -0700
@@ -482,6 +482,11 @@ Lattice Mico32 lm32-*
x86 DICOS i[34567]86-*-dicos*
x86_64 DICOS x86_64-*-dicos*
S+core 3 score-*-*
+Xilinx MicroBlaze microblaze-*-*
+
+* New Simulators
+
+Xilinx MicroBlaze microblaze
* The GDB remote stub, gdbserver, now supports x86 Windows CE
(mingw32ce) debugging.
diff -urNp --exclude '*.swp' --exclude DEV-PHASE --exclude .svn --exclude CVS gdb/opcodes/microblaze-dis.c mb-gdb/opcodes/microblaze-dis.c
--- gdb/opcodes/microblaze-dis.c 2009-09-25 12:59:51.000000000 -0700
+++ mb-gdb/opcodes/microblaze-dis.c 2009-10-05 14:18:58.000000000 -0700
@@ -24,9 +24,10 @@
#define STATIC_TABLE
#define DEFINE_TABLE
-#include "microblaze-opc.h"
#include "dis-asm.h"
#include <strings.h>
+#include "microblaze-opc.h"
+#include "microblaze-dis.h"
#define get_field_rd(instr) get_field (instr, RD_MASK, RD_LOW)
#define get_field_r1(instr) get_field (instr, RA_MASK, RA_LOW)
@@ -35,11 +36,6 @@
#define get_int_field_r1(instr) ((instr & RA_MASK) >> RA_LOW)
-enum microblaze_instr get_insn_microblaze (long, bfd_boolean *,
- enum microblaze_instr_type *, short *);
-unsigned long microblaze_get_target_address (long, bfd_boolean, int, long, long,
- long, bfd_boolean *, bfd_boolean *);
-enum microblaze_instr microblaze_decode_insn (long insn, int *rd, int *ra, int *rb, int *imm);
static char *
get_field (long instr, long mask, unsigned short low)
diff -urNp --exclude '*.swp' --exclude DEV-PHASE --exclude .svn --exclude CVS gdb/opcodes/microblaze-dis.h mb-gdb/opcodes/microblaze-dis.h
--- gdb/opcodes/microblaze-dis.h 1969-12-31 16:00:00.000000000 -0800
+++ mb-gdb/opcodes/microblaze-dis.h 2009-10-05 14:11:15.000000000 -0700
@@ -0,0 +1,34 @@
+/* Disassemble Xilinx microblaze instructions.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ This file is part of the GNU opcodes library.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ It is distributed in the hope that it 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 this file; see the file COPYING. If not, write to the
+ Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#ifndef MICROBLAZE_DIS_H
+#define MICROBLAZE_DIS_H 1
+
+extern enum microblaze_instr microblaze_decode_insn (long, int *, int *,
+ int *, int *);
+extern unsigned long microblaze_get_target_address (long, bfd_boolean, int,
+ long, long, long, bfd_boolean *, bfd_boolean *);
+
+extern enum microblaze_instr get_insn_microblaze (long, bfd_boolean *,
+ enum microblaze_instr_type *,
+ short *);
+
+#endif /* microblaze-dis.h */