This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Add support for Xilinx MicroBlaze


Hi --

Attached is a revised patch which adds support for the
Xilinx MicroBlaze.  I believe that I've addressed all
of the previous comments.

This patch requires a small patch to binutils/opcodes
which is being submitted shortly.

The simulator for Xilinx MicroBlaze has been approved
by the maintainers and will be checked in.

2009-09-23 Michael Eager <eager@eagercon.com>

  * 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.
  * microblaze-linux-tdep.c: New.
  * microblaze-rom.c: New.
  * microblaze-tdep.c: New.
  * microblaze-tdep.h: New.
  * NEWS: Announce Xilinx MicroBlaze support.


-- 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/configure.tgt mb-gdb/gdb/configure.tgt
--- gdb/gdb/configure.tgt	2009-08-06 03:28:38.000000000 -0700
+++ mb-gdb/gdb/configure.tgt	2009-09-21 12:12:32.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-09-06 10:14:43.000000000 -0700
+++ mb-gdb/gdb/doc/gdb.texinfo	2009-09-23 11:02:38.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
 
@@ -16427,6 +16430,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
@@ -16678,6 +16682,38 @@ 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 XMD-HOST:1234
+Use this command to connect to the target if it is connected to @code{xmd}
+running on a different system named @code{XMD-HOST}.
+
+@item load
+Use this command to download a program to the MicroBlaze target.
+@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-08-06 03:28:37.000000000 -0700
+++ mb-gdb/gdb/MAINTAINERS	2009-09-06 12:26:05.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-08-27 09:08:34.000000000 -0700
+++ mb-gdb/gdb/Makefile.in	2009-08-27 12:20:01.000000000 -0700
@@ -498,6 +498,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 \
@@ -1390,6 +1391,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-21 12:23:33.000000000 -0700
@@ -0,0 +1,139 @@
+/* Target-dependent code for Xilinx MicroBlaze.
+   Copyright 2009 Free Software Foundation, Inc.
+
+   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 2 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, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#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 * 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,
+				&microblaze_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-21 12:23:30.000000000 -0700
@@ -0,0 +1,190 @@
+/* Remote debugging interface to Xilinx MicroBlaze.
+   Copyright 2009 Free Software Foundation, Inc.
+
+   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 2 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, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#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" };
+
+
+
+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-09-23 10:27:08.000000000 -0700
@@ -0,0 +1,895 @@
+/* Target-dependent code for Xilinx MicroBlaze.
+   Copyright 2009 Free Software Foundation, Inc.
+
+   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 2 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, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#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"
+
+
+/* FIXME - this shouldn't be here */
+#include "../opcodes/microblaze-opcm.h"
+
+#include "microblaze-tdep.h"
+
+extern enum microblaze_instr get_insn_microblaze (long, bfd_boolean *,
+		enum microblaze_instr_type *, short *);
+extern unsigned long microblaze_get_target_address (long, bfd_boolean, int, long, long,
+					     long, bfd_boolean *, bfd_boolean *);
+
+
+/* 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)
+
+#define mb_error(msg) internal_error (__FILE__, __LINE__, _(msg))
+
+extern enum microblaze_instr microblaze_decode_insn (long, int *, int *,
+						     int *, int *);
+
+static int microblaze_debug = 0;
+
+static void
+microblaze_dump_insn (char *commnt, CORE_ADDR pc, int insn)
+{
+  if (microblaze_debug)
+    {
+      printf_filtered ("MICROBLAZE:  %s %08x %08x ",
+		       commnt, (unsigned int) pc, (unsigned int) insn);
+      /* print_insn_microblaze (pc, &tm_print_insn_info); */
+      printf_filtered ("\n");
+    }
+}
+#define microblaze_insn_debug(args) \
+	{ if (microblaze_debug) printf_filtered args; }
+#define mb_warn(msg) \
+	 if (microblaze_debug) printf ("mb_warning: %s:%d %s\n", __FILE__, __LINE__, _(msg))
+
+
+/* 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)
+{
+  gdb_byte buf[4];
+  unsigned long insn;
+  int i;
+
+  /* If we can't read the instruction at PC, return zero.  */
+  if (target_read_memory (pc, buf, sizeof (buf)))
+    return 0;
+
+  insn = 0;
+  for (i = 0; i < sizeof (buf); i++)
+    insn = (insn << 8) | buf[i];
+  return insn;
+}
+
+
+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)
+{
+  mb_warn ("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)
+{
+  mb_warn ("store_arguments not implemented");
+  return sp;
+}
+
+/* Return a pointer to a string of bytes that encode a breakpoint
+   instruction, store the length of the string in *LEN. */
+
+static const gdb_byte *
+microblaze_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pc, int *len)
+{
+  static gdb_byte break_insn[] = 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;
+}
+
+/* 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;
+  bfd_boolean save_hidden_pointer_found = FALSE;
+  bfd_boolean non_stack_instruction_found = FALSE;
+
+  /* printf("microblaze_analyze_prologue (pc = 0x%8.8x, "
+	    "current_pc = 0x%8.8x, cache = 0x%8.8x)\n",
+	    (int) pc, (int) current_pc, (int) cache);	*/
+
+  /* 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);
+      microblaze_dump_insn ("got 2: ", addr, 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 = -1 * imm; /* stack grows towards low memory */
+	  cache->frameless_p = 0; /* Frame found. */
+	  save_hidden_pointer_found = FALSE;
+	  non_stack_instruction_found = FALSE;
+	  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 = FALSE;
+	  if (!cache->framesize)
+	    non_stack_instruction_found = FALSE;
+	  continue;
+	}
+      else if (IS_SPILL_REG(op, rd, ra))
+	{
+	  /* Spill register */
+	  cache->register_offsets[rd] = imm - cache->framesize;
+		/* reg spilled after updating */
+
+	  microblaze_insn_debug (
+		("MICROBLAZE: swi %d r1 %d, continuing\n", rd, imm));
+	  save_hidden_pointer_found = FALSE;
+	  if (!cache->framesize)
+	    non_stack_instruction_found = FALSE;
+	  continue;
+	}
+      else if (IS_ALSO_SPILL_REG(op, rd, ra, rb))
+	{
+	  /* Spill register */
+	  cache->register_offsets[rd] = 0 - cache->framesize;
+		/* reg spilled after updating */
+
+	  microblaze_insn_debug (
+		("MICROBLAZE: sw %d r0 r1, continuing\n", rd));
+	  save_hidden_pointer_found = FALSE;
+	  if (!cache->framesize)
+	    non_stack_instruction_found = FALSE;
+	  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 |= MY_FRAME_IN_FP;
+	  flags &= ~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 = FALSE;
+	  if (!cache->framesize)
+	    non_stack_instruction_found = FALSE;
+	  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 = FALSE;
+	  if (!cache->framesize)
+	    non_stack_instruction_found = FALSE;
+	  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 = TRUE;
+	  if (!cache->framesize)
+	    non_stack_instruction_found = FALSE;
+	  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 = TRUE;
+
+      /* 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);
+
+  /* FIXME:  Rework this code and add comments. */
+  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 =
+{
+  &microblaze_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 + REGISTER_SIZE - 1, 1);
+	return;
+      case 2:	/* return last 2 bytes in register */
+	memcpy(valbuf, buf + 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:
+	printf_filtered("Fatal error: unsupported return value size "
+			"requested (%s @ %d)\n", __FILE__, __LINE__);
+    }
+}
+
+/* Store the return value in VALBUF (of type TYPE) where the caller
+   expects to see it.
+
+   Integers are stored in r3.
+
+   Values less than 32 bits (short, boolean) are stored in r2, right
+   justified and sign or zero extended.		FIXME
+
+   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);		/* FIXME */
+}
+
+int
+microblaze_can_use_hardware_watchpoints (enum bptype type, int len, int ot)
+{
+    int count = 0;
+
+    switch (type)
+      {
+	case bp_hardware_breakpoint:
+	  count = 2;
+	  break;
+	case bp_read_watchpoint:
+	  count = 1;
+	  break;
+	case bp_hardware_watchpoint:
+	  count = 1;
+	  break;
+	default:
+	  count = 0;
+      }
+    return count;
+}
+
+/* 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;
+  bfd_boolean isunsignednum;
+  enum microblaze_instr_type insn_type;
+  short delay_slots;
+  int imm;
+  bfd_boolean immfound = FALSE;
+
+  /* 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, &isunsignednum, &insn_type,
+				&delay_slots);
+  if (insn_type == immediate_inst)
+    {
+      int rd, ra, rb;
+      immfound = TRUE;
+      minstr = microblaze_decode_insn (insn, &rd, &ra, &rb, &imm);
+      pc = pc + INST_WORD_SIZE;
+      insn = microblaze_fetch_instruction (pc);
+      minstr = get_insn_microblaze (insn, &isunsignednum, &insn_type,
+				    &delay_slots);
+    }
+  stepbreaks[0].address = pc + (delay_slots * INST_WORD_SIZE) + INST_WORD_SIZE;
+  if (insn_type != return_inst)
+    {
+      stepbreaks[0].valid = TRUE;
+    }
+  else
+    {
+      stepbreaks[0].valid = FALSE;
+    }
+
+  /* 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 = FALSE;
+      if (targetvalid
+	  && (stepbreaks[0].valid == FALSE
+	      || (stepbreaks[0].address != stepbreaks[1].address))
+	  && (stepbreaks[1].address != pc))
+	{
+	  stepbreaks[1].valid = TRUE;
+	}
+      else
+	{
+	  stepbreaks[1].valid = FALSE;
+	}
+    }
+  else
+    {
+       stepbreaks[1].valid = FALSE;
+    }
+
+  /* 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)
+{
+  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_long_double_format (gdbarch, &floatformat_microblaze_quad); */
+
+  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); /* $sp */
+  set_gdbarch_pc_regnum (gdbarch, MICROBLAZE_PC_REGNUM); /* $pc */
+
+  /* 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, &microblaze_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, &microblaze_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,
+			    &microblaze_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-09-21 14:05:50.000000000 -0700
@@ -0,0 +1,197 @@
+/* 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 2 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, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#ifndef MICROBLAZE_TDEP_H
+#define MICROBLAZE_TDEP_H 1
+
+#undef MICROBLAZE_DEBUG
+#ifdef MICROBLAZE_DEBUG
+int microblaze_debug = 1;
+#endif
+
+/* 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_R6_REGNUM,
+  MICROBLAZE_R7_REGNUM,
+  MICROBLAZE_R8_REGNUM,
+  MICROBLAZE_R9_REGNUM,
+  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
+};
+
+#define RWSDP_REGNUM 13
+#define LINK_REGNUM 15
+#define PR_REGNUM 15
+#define FIRST_ARGREG 5
+#define LAST_ARGREG 10
+#define RETVAL_REGNUM 3
+
+/* All registers are 32 bits.  */
+#define REGISTER_SIZE 4
+
+/* 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 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 MY_FRAME_IN_FP 0x2
+
+/* This flag is set to indicate that this frame is the top-most
+   frame. This tells frame chain not to bother trying to unwind
+   beyond this frame.  */
+#define NO_MORE_FRAMES 0x4
+
+
+/* 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)
+/* 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 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 MY_FRAME_IN_FP 0x2
+
+/* This flag is set to indicate that this frame is the top-most
+   frame. This tells frame chain not to bother trying to unwind
+   beyond this frame.  */
+#define NO_MORE_FRAMES 0x4
+#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 == FIRST_ARGREG && rb == 0)
+
+/* BREAKPOINT defines the breakpoint that should be used.  */
+#ifdef __MICROBLAZE_UCLINUX__
+#define BREAKPOINT {0xb9, 0xcc, 0x00, 0x60}
+#else
+#define BREAKPOINT {0x98, 0x0c, 0x00, 0x00}
+#endif
+
+#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-09-06 10:14:42.000000000 -0700
+++ mb-gdb/gdb/NEWS	2009-09-23 10:41:55.000000000 -0700
@@ -442,6 +442,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.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]