[FT32] gdb and sim support

Message ID CA9BBF0458F83C4F9051448B941B57D117234ACB@glaexch1
State Committed
Headers

Commit Message

James Bowman March 23, 2015, 7:15 p.m. UTC
  > Oy! I didn't realize that the definitions were duplicated. Yes, indeed,
> let's make sure the sim and gdb both use the same defines.

OK, all done. I have updated the patch for your review. sim-ft32.h is
still part of gdb, and the sim uses its definitions for the register
read interface.

--
James Bowman
FTDI Open Source Liaison


gdb/:
2015-03-23  James Bowman  <james.bowman@ftdichip.com>

	* Makefile.in (ALL_TARGET_OBS): Add ft32-tdep.o.
	(HFILES_NO_SRCDIR): Add ft32-tdep.h.
	(ALLDEPFILES): Add ft32-tdep.c.
	* configure.tgt: Add FT32 entry.
	* ft32-tdep.c: New file, FT32 target-dependent code.
	* ft32-tdep.h: New file, FT32 target-dependent code.

include/gdb/:
2015-03-23  James Bowman  <james.bowman@ftdichip.com>

	* sim-ft32.h: New file, FT32 simulator/GDB interface.


From: James Bowman <james.bowman@ftdichip.com>
Date: Mon, 23 Mar 2015 12:11:47 -0700
Subject: [PATCH] FT32 Support

---
 gdb/Makefile.in        |    5 +-
 gdb/configure.tgt      |    5 +
 gdb/ft32-tdep.c        |  549 ++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/ft32-tdep.h        |   28 +++
 include/gdb/sim-ft32.h |   35 +++
 5 files changed, 621 insertions(+), 1 deletion(-)
 create mode 100644 gdb/ft32-tdep.c
 create mode 100644 gdb/ft32-tdep.h
 create mode 100644 include/gdb/sim-ft32.h
  

Comments

Joel Brobecker March 23, 2015, 11:04 p.m. UTC | #1
On Mon, Mar 23, 2015 at 07:15:32PM +0000, James Bowman wrote:
> 
> > Oy! I didn't realize that the definitions were duplicated. Yes, indeed,
> > let's make sure the sim and gdb both use the same defines.
> 
> OK, all done. I have updated the patch for your review. sim-ft32.h is
> still part of gdb, and the sim uses its definitions for the register
> read interface.

OK - If prefer to do it this way, then you will need to merge
the GDB and sim part into the same patch. This is because you can't
commit the GDB part without the sim (because of the configure bit
that pulls in libsim.a), and you can't commit the sim part first,
because it depends on sim-ft32.h which is brought in by the GDB
part. That's why I thought it would make better sense for this file
to be part of the sim patch, but if both patches get approved, and
you merge them before pushing them, then I'm happy.

> gdb/:
> 2015-03-23  James Bowman  <james.bowman@ftdichip.com>
> 
> 	* Makefile.in (ALL_TARGET_OBS): Add ft32-tdep.o.
> 	(HFILES_NO_SRCDIR): Add ft32-tdep.h.
> 	(ALLDEPFILES): Add ft32-tdep.c.
> 	* configure.tgt: Add FT32 entry.
> 	* ft32-tdep.c: New file, FT32 target-dependent code.
> 	* ft32-tdep.h: New file, FT32 target-dependent code.
> 
> include/gdb/:
> 2015-03-23  James Bowman  <james.bowman@ftdichip.com>
> 
> 	* sim-ft32.h: New file, FT32 simulator/GDB interface.

This part of the submission is pre-approved, with a couple of
very minor comments below.

When you do push to sourceware.org, would you mind sending a copy
of the patch that actually got pushed? (standard protocol for all
patches, for our records on this mailing-list)

(if you need write-after-approval access to the repository, please
send me an email privately)

Thank you,
  

Patch

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index dbace2d..c844d38 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -651,6 +651,7 @@  ALL_TARGET_OBS = \
 	dicos-tdep.o \
 	fbsd-tdep.o \
 	frv-linux-tdep.o frv-tdep.o \
+	ft32-tdep.o \
 	h8300-tdep.o \
 	hppabsd-tdep.o hppanbsd-tdep.o hppaobsd-tdep.o \
 	hppa-linux-tdep.o hppa-tdep.o \
@@ -949,7 +950,8 @@  psymtab.h psympriv.h progspace.h bfin-tdep.h \
 amd64-darwin-tdep.h charset-list.h \
 config/djgpp/langinfo.h config/djgpp/nl_types.h darwin-nat.h \
 dicos-tdep.h filesystem.h gcore.h gdb_wchar.h hppabsd-tdep.h \
-i386-darwin-tdep.h x86-nat.h linux-record.h moxie-tdep.h nios2-tdep.h \
+i386-darwin-tdep.h i386-nat.h linux-record.h moxie-tdep.h nios2-tdep.h \
+ft32-tdep.h \
 osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent.h \
 python/python-internal.h python/python.h ravenscar-thread.h record.h \
 record-full.h solib-aix.h \
@@ -1655,6 +1657,7 @@  ALLDEPFILES = \
 	fbsd-nat.c \
 	fbsd-tdep.c \
 	fork-child.c \
+	ft32-tdep.c \
 	glibc-tdep.c \
 	go32-nat.c h8300-tdep.c \
 	hppa-tdep.c \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index c97ebdd..8feda7c 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -615,6 +615,11 @@  xstormy16-*-*)
 	# No simulator libraries are needed -- target uses SID.
 	;;
 
+ft32-*-elf)
+	gdb_target_obs="ft32-tdep.o"
+	gdb_sim=../sim/ft32/libsim.a
+	;;
+
 v850*-*-elf | v850*-*-rtems*)
 	# Target: NEC V850 processor
 	gdb_target_obs="v850-tdep.o"
diff --git a/gdb/ft32-tdep.c b/gdb/ft32-tdep.c
new file mode 100644
index 0000000..41a7191
--- /dev/null
+++ b/gdb/ft32-tdep.c
@@ -0,0 +1,549 @@ 
+/* Target-dependent code for FT32.
+
+   Copyright (C) 2009-2015 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 "frame-unwind.h"
+#include "frame-base.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "value.h"
+#include "inferior.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "osabi.h"
+#include "language.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "trad-frame.h"
+#include "dis-asm.h"
+#include "record.h"
+
+#include "gdb_assert.h"
+
+#include "ft32-tdep.h"
+#include "gdb/sim-ft32.h"
+
+#define RAM_BIAS  0x800000  /* Bias added to RAM addresses.  */
+
+/* Local functions.  */
+
+extern void _initialize_ft32_tdep (void);
+
+/* Use an invalid address -1 as 'not available' marker.  */
+enum { REG_UNAVAIL = (CORE_ADDR) (-1) };
+
+struct ft32_frame_cache
+{
+  /* Base address of the frame */
+  CORE_ADDR base;
+  /* Function this frame belongs to */
+  CORE_ADDR pc;
+  /* Total size of this frame */
+  LONGEST framesize;
+  /* Saved registers in this frame */
+  CORE_ADDR saved_regs[FT32_NUM_REGS];
+  /* Saved SP in this frame */
+  CORE_ADDR saved_sp;
+  /* Has the new frame been LINKed.  */
+  bfd_boolean established;
+};
+
+/* Implement the "frame_align" gdbarch method.  */
+
+static CORE_ADDR
+ft32_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+  /* Align to the size of an instruction (so that they can safely be
+     pushed onto the stack.  */
+  return sp & ~1;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const unsigned char *
+ft32_breakpoint_from_pc (struct gdbarch *gdbarch,
+			 CORE_ADDR *pcptr, int *lenptr)
+{
+  static const gdb_byte breakpoint[] = { 0x02, 0x00, 0x34, 0x00 };
+
+  *lenptr = sizeof (breakpoint);
+  return breakpoint;
+}
+
+/* FT32 register names.  */
+
+static const char *const ft32_register_names[] =
+{
+    "fp", "sp",
+    "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", "cc",
+    "pc"
+};
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+ft32_register_name (struct gdbarch *gdbarch, int reg_nr)
+{
+  if (reg_nr < 0)
+    return NULL;
+  if (reg_nr >= FT32_NUM_REGS)
+    return NULL;
+  return ft32_register_names[reg_nr];
+}
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+ft32_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  if (reg_nr == FT32_PC_REGNUM)
+    return builtin_type (gdbarch)->builtin_func_ptr;
+  else if (reg_nr == FT32_SP_REGNUM || reg_nr == FT32_FP_REGNUM)
+    return builtin_type (gdbarch)->builtin_data_ptr;
+  else
+    return builtin_type (gdbarch)->builtin_int32;
+}
+
+/* Write into appropriate registers a function return value
+   of type TYPE, given in virtual format.  */
+
+static void
+ft32_store_return_value (struct type *type, struct regcache *regcache,
+			 const gdb_byte *valbuf)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR regval;
+  int len = TYPE_LENGTH (type);
+
+  /* Things always get returned in RET1_REGNUM, RET2_REGNUM.  */
+  regval = extract_unsigned_integer (valbuf, len > 4 ? 4 : len, byte_order);
+  regcache_cooked_write_unsigned (regcache, FT32_R0_REGNUM, regval);
+  if (len > 4)
+    {
+      regval = extract_unsigned_integer (valbuf + 4,
+					 len - 4, byte_order);
+      regcache_cooked_write_unsigned (regcache, FT32_R1_REGNUM, regval);
+    }
+}
+
+/* Decode the instructions within the given address range.  Decide
+   when we must have reached the end of the function prologue.  If a
+   frame_info pointer is provided, fill in its saved_regs etc.
+
+   Returns the address of the first instruction after the prologue.  */
+
+#define IS_PUSH(inst)   (((inst) & 0xfff00000) == 0x84000000)
+#define PUSH_REG(inst)  (FT32_R0_REGNUM + (((inst) >> 15) & 0x1f))
+#define IS_LINK(inst)   (((inst) & 0xffff0000) == 0x95d00000)
+#define LINK_SIZE(inst) ((inst) & 0xffff)
+
+static CORE_ADDR
+ft32_analyze_prologue (CORE_ADDR start_addr, CORE_ADDR end_addr,
+		       struct ft32_frame_cache *cache,
+		       struct gdbarch *gdbarch)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR next_addr;
+  ULONGEST inst, inst2;
+  LONGEST offset;
+  int regnum;
+
+  cache->saved_regs[FT32_PC_REGNUM] = 0;
+  cache->framesize = 0;
+
+  if (start_addr >= end_addr)
+      return end_addr;
+
+  cache->established = 0;
+  for (next_addr = start_addr; next_addr < end_addr; )
+    {
+      inst = read_memory_unsigned_integer (next_addr, 4, byte_order);
+
+      if (IS_PUSH (inst))
+	{
+	  regnum = PUSH_REG (inst);
+	  cache->framesize += 4;
+	  cache->saved_regs[regnum] = cache->framesize;
+	  next_addr += 4;
+	}
+      else
+	break;
+    }
+  for (regnum = FT32_R0_REGNUM; regnum < FT32_PC_REGNUM; regnum++)
+    {
+      if (cache->saved_regs[regnum] != REG_UNAVAIL)
+	cache->saved_regs[regnum] = cache->framesize - cache->saved_regs[regnum];
+    }
+  cache->saved_regs[FT32_PC_REGNUM] = cache->framesize;
+
+  /* It is a LINK?  */
+  if (next_addr < end_addr)
+    {
+      inst = read_memory_unsigned_integer (next_addr, 4, byte_order);
+      if (IS_LINK (inst))
+	{
+	  cache->established = 1;
+	  for (regnum = FT32_R0_REGNUM; regnum < FT32_PC_REGNUM; regnum++)
+	    {
+	      if (cache->saved_regs[regnum] != REG_UNAVAIL)
+		cache->saved_regs[regnum] += 4;
+	    }
+	  cache->saved_regs[FT32_PC_REGNUM] = cache->framesize + 4;
+	  cache->saved_regs[FT32_FP_REGNUM] = 0;
+	  cache->framesize += LINK_SIZE (inst);
+	  next_addr += 4;
+	}
+    }
+
+  return next_addr;
+}
+
+/* Find the end of function prologue.  */
+
+static CORE_ADDR
+ft32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR func_addr = 0, func_end = 0;
+  const char *func_name;
+
+  /* See if we can determine the end of the prologue via the symbol table.
+     If so, then return either PC, or the PC after the prologue, whichever
+     is greater.  */
+  if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
+    {
+      CORE_ADDR post_prologue_pc
+	= skip_prologue_using_sal (gdbarch, func_addr);
+      if (post_prologue_pc != 0)
+	return max (pc, post_prologue_pc);
+      else
+	{
+	  /* Can't determine prologue from the symbol table, need to examine
+	     instructions.  */
+	  struct symtab_and_line sal;
+	  struct symbol *sym;
+	  struct ft32_frame_cache cache;
+	  CORE_ADDR plg_end;
+
+	  memset (&cache, 0, sizeof cache);
+
+	  plg_end = ft32_analyze_prologue (func_addr,
+					   func_end, &cache, gdbarch);
+	  /* Found a function.  */
+	  sym = lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL);
+	  /* Don't use line number debug info for assembly source files.  */
+	  if ((sym != NULL) && SYMBOL_LANGUAGE (sym) != language_asm)
+	    {
+	      sal = find_pc_line (func_addr, 0);
+	      if (sal.end && sal.end < func_end)
+		{
+		  /* Found a line number, use it as end of prologue.  */
+		  return sal.end;
+		}
+	    }
+	  /* No useable line symbol.  Use result of prologue parsing method.  */
+	  return plg_end;
+	}
+    }
+
+  /* No function symbol -- just return the PC.  */
+  return pc;
+}
+
+/* Implement the "read_pc" gdbarch method.  */
+
+static CORE_ADDR
+ft32_read_pc (struct regcache *regcache)
+{
+  ULONGEST pc;
+
+  regcache_cooked_read_unsigned (regcache, FT32_PC_REGNUM, &pc);
+  return pc;
+}
+
+/* Implement the "write_pc" gdbarch method.  */
+
+static void
+ft32_write_pc (struct regcache *regcache, CORE_ADDR val)
+{
+  regcache_cooked_write_unsigned (regcache, FT32_PC_REGNUM, val);
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+ft32_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, FT32_SP_REGNUM);
+}
+
+/* Given a return value in `regbuf' with a type `valtype',
+   extract and copy its value into `valbuf'.  */
+
+static void
+ft32_extract_return_value (struct type *type, struct regcache *regcache,
+			   gdb_byte *dst)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  bfd_byte *valbuf = dst;
+  int len = TYPE_LENGTH (type);
+  ULONGEST tmp;
+
+  /* By using store_unsigned_integer we avoid having to do
+     anything special for small big-endian values.  */
+  regcache_cooked_read_unsigned (regcache, FT32_R0_REGNUM, &tmp);
+  store_unsigned_integer (valbuf, (len > 4 ? len - 4 : len), byte_order, tmp);
+
+  /* Ignore return values more than 8 bytes in size because the ft32
+     returns anything more than 8 bytes in the stack.  */
+  if (len > 4)
+    {
+      regcache_cooked_read_unsigned (regcache, FT32_R1_REGNUM, &tmp);
+      store_unsigned_integer (valbuf + len - 4, 4, byte_order, tmp);
+    }
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+ft32_return_value (struct gdbarch *gdbarch, struct value *function,
+		   struct type *valtype, struct regcache *regcache,
+		   gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+  if (TYPE_LENGTH (valtype) > 8)
+    return RETURN_VALUE_STRUCT_CONVENTION;
+  else
+    {
+      if (readbuf != NULL)
+	ft32_extract_return_value (valtype, regcache, readbuf);
+      if (writebuf != NULL)
+	ft32_store_return_value (valtype, regcache, writebuf);
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+}
+
+/* Allocate and initialize a ft32_frame_cache object.  */
+
+static struct ft32_frame_cache *
+ft32_alloc_frame_cache (void)
+{
+  struct ft32_frame_cache *cache;
+  int i;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct ft32_frame_cache);
+
+  for (i = 0; i < FT32_NUM_REGS; ++i)
+    cache->saved_regs[i] = REG_UNAVAIL;
+
+  return cache;
+}
+
+/* Populate a ft32_frame_cache object for this_frame.  */
+
+static struct ft32_frame_cache *
+ft32_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  struct ft32_frame_cache *cache;
+  CORE_ADDR current_pc;
+  int i;
+
+  if (*this_cache)
+    return *this_cache;
+
+  cache = ft32_alloc_frame_cache ();
+  *this_cache = cache;
+
+  cache->base = get_frame_register_unsigned (this_frame, FT32_FP_REGNUM);
+  if (cache->base == 0)
+    return cache;
+
+  cache->pc = get_frame_func (this_frame);
+  current_pc = get_frame_pc (this_frame);
+  if (cache->pc)
+    {
+      struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
+      ft32_analyze_prologue (cache->pc, current_pc, cache, gdbarch);
+      if (!cache->established)
+	cache->base = get_frame_register_unsigned (this_frame, FT32_SP_REGNUM);
+    }
+
+  cache->saved_sp = cache->base - 4;
+
+  for (i = 0; i < FT32_NUM_REGS; ++i)
+    if (cache->saved_regs[i] != REG_UNAVAIL)
+      cache->saved_regs[i] = cache->base + cache->saved_regs[i];
+
+  return cache;
+}
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+ft32_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, FT32_PC_REGNUM);
+}
+
+/* Given a GDB frame, determine the address of the calling function's
+   frame.  This will be used to create a new GDB frame struct.  */
+
+static void
+ft32_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  struct ft32_frame_cache *cache = ft32_frame_cache (this_frame,
+						     this_prologue_cache);
+
+  /* This marks the outermost frame.  */
+  if (cache->base == 0)
+    return;
+
+  *this_id = frame_id_build (cache->saved_sp, cache->pc);
+}
+
+/* Get the value of register regnum in the previous stack frame.  */
+
+static struct value *
+ft32_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct ft32_frame_cache *cache = ft32_frame_cache (this_frame,
+						     this_prologue_cache);
+
+  gdb_assert (regnum >= 0);
+
+  if (regnum == FT32_SP_REGNUM && cache->saved_sp)
+    return frame_unwind_got_constant (this_frame, regnum, cache->saved_sp);
+
+  if (regnum < FT32_NUM_REGS && cache->saved_regs[regnum] != REG_UNAVAIL)
+      return frame_unwind_got_memory (this_frame, regnum,
+				      RAM_BIAS | cache->saved_regs[regnum]);
+
+  return frame_unwind_got_register (this_frame, regnum, regnum);
+}
+
+static const struct frame_unwind ft32_frame_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  ft32_frame_this_id,
+  ft32_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Return the base address of this_frame.  */
+
+static CORE_ADDR
+ft32_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+  struct ft32_frame_cache *cache = ft32_frame_cache (this_frame,
+						     this_cache);
+
+  return cache->base;
+}
+
+static const struct frame_base ft32_frame_base =
+{
+  &ft32_frame_unwind,
+  ft32_frame_base_address,
+  ft32_frame_base_address,
+  ft32_frame_base_address
+};
+
+static struct frame_id
+ft32_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp = get_frame_register_unsigned (this_frame, FT32_SP_REGNUM);
+
+  return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+/* Allocate and initialize the ft32 gdbarch object.  */
+
+static struct gdbarch *
+ft32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+
+  /* 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 = XNEW (struct gdbarch_tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_read_pc (gdbarch, ft32_read_pc);
+  set_gdbarch_write_pc (gdbarch, ft32_write_pc);
+  set_gdbarch_unwind_sp (gdbarch, ft32_unwind_sp);
+
+  set_gdbarch_num_regs (gdbarch, FT32_NUM_REGS);
+  set_gdbarch_sp_regnum (gdbarch, FT32_SP_REGNUM);
+  set_gdbarch_pc_regnum (gdbarch, FT32_PC_REGNUM);
+  set_gdbarch_register_name (gdbarch, ft32_register_name);
+  set_gdbarch_register_type (gdbarch, ft32_register_type);
+
+  set_gdbarch_return_value (gdbarch, ft32_return_value);
+
+  set_gdbarch_skip_prologue (gdbarch, ft32_skip_prologue);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_breakpoint_from_pc (gdbarch, ft32_breakpoint_from_pc);
+  set_gdbarch_frame_align (gdbarch, ft32_frame_align);
+
+  frame_base_set_default (gdbarch, &ft32_frame_base);
+
+  /* Methods for saving / extracting a dummy frame's ID.  The ID's
+     stack address must match the SP value returned by
+     PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos.  */
+  set_gdbarch_dummy_id (gdbarch, ft32_dummy_id);
+
+  set_gdbarch_unwind_pc (gdbarch, ft32_unwind_pc);
+
+  set_gdbarch_print_insn (gdbarch, print_insn_ft32);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  /* Hook in the default unwinders.  */
+  frame_unwind_append_unwinder (gdbarch, &ft32_frame_unwind);
+
+  /* Support simple overlay manager.  */
+  set_gdbarch_overlay_update (gdbarch, simple_overlay_update);
+
+  return gdbarch;
+}
+
+/* Register this machine's init routine.  */
+
+void
+_initialize_ft32_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_ft32, ft32_gdbarch_init);
+}
diff --git a/gdb/ft32-tdep.h b/gdb/ft32-tdep.h
new file mode 100644
index 0000000..5c52480
--- /dev/null
+++ b/gdb/ft32-tdep.h
@@ -0,0 +1,28 @@ 
+/* Target-dependent code for the FT32.
+
+   Copyright (C) 2002-2015 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 FT32_TDEP_H
+#define FT32_TDEP_H
+
+struct gdbarch_tdep
+{
+  /* gdbarch target dependent data here.  Currently unused for FT32.  */
+};
+
+#endif /* FT32_TDEP_H */
diff --git a/include/gdb/sim-ft32.h b/include/gdb/sim-ft32.h
new file mode 100644
index 0000000..73c4f63
--- /dev/null
+++ b/include/gdb/sim-ft32.h
@@ -0,0 +1,35 @@ 
+/* This file defines the interface between the FT32 simulator and GDB.
+
+   Copyright (C) 2005-2015 Free Software Foundation, Inc.
+   Contributed by FTDI.
+
+   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/>.  */
+
+
+/* Register numbers of various important registers.  */
+enum ft32_regnum
+{
+  FT32_FP_REGNUM,               /* Address of executing stack frame.  */
+  FT32_SP_REGNUM,               /* Address of top of stack.  */
+  FT32_R0_REGNUM,
+  FT32_R1_REGNUM,
+  FT32_CC_REGNUM = 31,
+  FT32_PC_REGNUM = 32           /* Program counter.  */
+};
+
+/* Number of machine registers.  */
+#define FT32_NUM_REGS 33        /* 32 real registers + PC */
+