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, FT32] gdb and sim support


FT32 is a new high performance 32-bit RISC core developed by FTDI for embedded applications.

Support for FT32 has already been added to binutils. This patch adds gdb and sim support.

Please can someone review it, and if appropriate commit it, as I do not have write access to the tree.

The FSF have acknowledged receipt of FTDI's copyright assignment papers.

Thanks very much. ChangeLog entry:

2014-02-03  James Bowman  <james.bowman@ftdichip.com>

        * gdb/Makefile.in, gdb/configure.tgt: FT32 target added
        * sim/configure.tgt: FT32 target added
        * sim/configure: Regenerated
        * sim/ft32/configure: Regenerated
        * gdb/ft32-tdep.c,h: Support FT32
        * sim/ft32/*: FT32 simulator

--
James Bowman
FTDI Open Source Liaison

From: James Bowman <james.bowman@ftdichip.com>
Date: Mon, 2 Feb 2015 19:43:24 -0800
Subject: [PATCH] FT32 support

---
 gdb/Makefile.in       |    6 +-
 gdb/configure.tgt     |    5 +
 gdb/ft32-tdep.c       | 1007 ++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/ft32-tdep.h       |   42 ++
 sim/configure.tgt     |    3 +
 sim/ft32/Makefile.in  |   38 ++
 sim/ft32/config.in    |  154 ++++++++
 sim/ft32/configure.ac |   18 +
 sim/ft32/interp.c     | 1014 +++++++++++++++++++++++++++++++++++++++++++++++++
 sim/ft32/sim-main.h   |   61 +++
 sim/ft32/sysdep.h     |   94 +++++
 11 files changed, 2440 insertions(+), 2 deletions(-)
 create mode 100644 gdb/ft32-tdep.c
 create mode 100644 gdb/ft32-tdep.h
 create mode 100644 sim/ft32/Makefile.in
 create mode 100644 sim/ft32/config.in
 create mode 100644 sim/ft32/configure.ac
 create mode 100644 sim/ft32/interp.c
 create mode 100644 sim/ft32/sim-main.h
 create mode 100644 sim/ft32/sysdep.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8addef4..d922eb2 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -647,6 +647,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-hpux-tdep.o hppa-linux-tdep.o hppa-tdep.o \
@@ -943,7 +944,7 @@ psymtab.h psympriv.h progspace.h bfin-tdep.h ia64-hpux-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 \
@@ -1646,7 +1647,8 @@ ALLDEPFILES = \
 	fbsd-nat.c \
 	fbsd-tdep.c \
 	fork-child.c \
-	glibc-tdep.c \
+	ft32-tdep.c \
+        glibc-tdep.c \
 	go32-nat.c h8300-tdep.c \
 	hppa-tdep.c hppa-hpux-tdep.c hppa-hpux-nat.c \
 	hppa-linux-tdep.c hppa-linux-nat.c \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 7fdd34e..26274bd 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -621,6 +621,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..f183661
--- /dev/null
+++ b/gdb/ft32-tdep.c
@@ -0,0 +1,1007 @@
+/* Target-dependent code for FT32.
+
+   Copyright (C) 2009-2014 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 <string.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 "record-full.h"
+
+#include "gdb_assert.h"
+
+#include "ft32-tdep.h"
+
+/* Local functions.  */
+
+extern void _initialize_ft32_tdep (void);
+
+/* Use an invalid address value as 'not available' marker.  */
+enum { REG_UNAVAIL = (CORE_ADDR) -1 };
+
+struct ft32_frame_cache
+{
+  /* Base address.  */
+  CORE_ADDR base;
+  CORE_ADDR pc;
+  LONGEST framesize;
+  CORE_ADDR saved_regs[FT32_NUM_REGS];
+  CORE_ADDR saved_sp;
+  int established;  // Has the new frame been LINKed
+};
+
+/* 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 gdb_byte breakpoint[] = { 0x02, 0x00, 0x34, 0x00 };
+
+  *lenptr = sizeof (breakpoint);
+  return breakpoint;
+}
+
+/* FT32 register names.  */
+
+char *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 void *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 ((gdb_byte *) 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;
+
+  // printf("(%#lx-%#lx)", start_addr, end_addr);
+  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;
+        }
+    }
+  // printf("(Framesize=%lld,cache->saved_regs[FT32_PC_REGNUM]=%ld)\n", cache->framesize, cache->saved_regs[FT32_PC_REGNUM]);
+  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 && 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 (CORE_ADDR) 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,
+			   void *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);
+
+  cache->base = 0;
+  cache->saved_sp = 0;
+  cache->pc = 0;
+  cache->framesize = 0;
+  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,
+                                      0x800000 | 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));
+}
+
+#if 0
+/* Read an unsigned integer from the inferior, and adjust
+   endianess.  */
+static ULONGEST
+ft32_process_readu (CORE_ADDR addr, char *buf,
+		     int length, enum bfd_endian byte_order)
+{
+  if (target_read_memory (addr, buf, length))
+    {
+      if (record_debug)
+	printf_unfiltered (_("Process record: error reading memory at "
+			     "addr 0x%s len = %d.\n"),
+			   paddress (target_gdbarch (), addr), length);
+      return -1;
+    }
+
+  return extract_unsigned_integer (buf, length, byte_order);
+}
+#endif
+
+/* Parse the current instruction and record the values of the registers and
+   memory that will be changed in current instruction to "record_arch_list".
+   Return -1 if something wrong.  */
+
+static int
+ft32_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
+		      CORE_ADDR addr)
+{
+  return -1;
+#if 0
+  gdb_byte buf[4];
+  uint16_t inst;
+  uint32_t tmpu32;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+  if (record_debug > 1)
+    fprintf_unfiltered (gdb_stdlog, "Process record: ft32_process_record "
+			            "addr = 0x%s\n",
+			paddress (target_gdbarch (), addr));
+
+  inst = (uint16_t) ft32_process_readu (addr, buf, 2, byte_order);
+
+  /* Decode instruction.  */
+  if (inst & (1 << 15))
+    {
+      if (inst & (1 << 14))
+	{
+	  /* This is a Form 3 instruction.  */
+	  int opcode = (inst >> 10 & 0xf);
+
+	  switch (opcode)
+	    {
+	    case 0x00: /* beq */
+	    case 0x01: /* bne */
+	    case 0x02: /* blt */
+	    case 0x03: /* bgt */
+	    case 0x04: /* bltu */
+	    case 0x05: /* bgtu */
+	    case 0x06: /* bge */
+	    case 0x07: /* ble */
+	    case 0x08: /* bgeu */
+	    case 0x09: /* bleu */
+	      /* Do nothing.  */
+	      break;
+	    default:
+	      {
+		/* Do nothing.  */
+		break;
+	      }
+	    }
+	}
+      else
+	{
+	  /* This is a Form 2 instruction.  */
+	  int opcode = (inst >> 12 & 0x3);
+	  switch (opcode)
+	    {
+	    case 0x00: /* inc */
+	    case 0x01: /* dec */
+	    case 0x02: /* gsr */
+	      {
+		int reg = (inst >> 8) & 0xf;
+		if (record_full_arch_list_add_reg (regcache, reg))
+		  return -1;
+	      }
+	      break;
+	    case 0x03: /* ssr */
+	      {
+		/* Do nothing until GDB learns about ft32's special
+		   registers.  */
+	      }
+	      break;
+	    default:
+	      /* Do nothing.  */
+	      break;
+	    }
+	}
+    }
+  else
+    {
+      /* This is a Form 1 instruction.  */
+      int opcode = inst >> 8;
+
+      switch (opcode)
+	{
+	case 0x00: /* nop */
+	  /* Do nothing.  */
+	  break;
+	case 0x01: /* ldi.l (immediate) */
+	case 0x02: /* mov (register-to-register) */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    if (record_full_arch_list_add_reg (regcache, reg))
+	      return -1;
+	  }
+	  break;
+	case 0x03: /* jsra */
+	  {
+	    regcache_raw_read (regcache,
+			       FT32_SP_REGNUM, (gdb_byte *) & tmpu32);
+	    tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+					       4, byte_order);
+	    if (record_full_arch_list_add_reg (regcache, FT32_FP_REGNUM)
+		|| (record_full_arch_list_add_reg (regcache,
+						   FT32_SP_REGNUM))
+		|| record_full_arch_list_add_mem (tmpu32 - 12, 12))
+	      return -1;
+	  }
+	  break;
+	case 0x04: /* ret */
+	  {
+	    if (record_full_arch_list_add_reg (regcache, FT32_FP_REGNUM)
+		|| (record_full_arch_list_add_reg (regcache,
+						   FT32_SP_REGNUM)))
+	      return -1;
+	  }
+	  break;
+	case 0x05: /* add.l */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    if (record_full_arch_list_add_reg (regcache, reg))
+	      return -1;
+	  }
+	  break;
+	case 0x06: /* push */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
+	    tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+					       4, byte_order);
+	    if (record_full_arch_list_add_reg (regcache, reg)
+		|| record_full_arch_list_add_mem (tmpu32 - 4, 4))
+	      return -1;
+	  }
+	  break;
+	case 0x07: /* pop */
+	  {
+	    int a = (inst >> 4) & 0xf;
+	    int b = inst & 0xf;
+	    if (record_full_arch_list_add_reg (regcache, a)
+		|| record_full_arch_list_add_reg (regcache, b))
+	      return -1;
+	  }
+	  break;
+	case 0x08: /* lda.l */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    if (record_full_arch_list_add_reg (regcache, reg))
+	      return -1;
+	  }
+	  break;
+	case 0x09: /* sta.l */
+	  {
+	    tmpu32 = (uint32_t) ft32_process_readu (addr+2, buf,
+						     4, byte_order);
+	    if (record_full_arch_list_add_mem (tmpu32, 4))
+	      return -1;
+	  }
+	  break;
+	case 0x0a: /* ld.l (register indirect) */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    if (record_full_arch_list_add_reg (regcache, reg))
+	      return -1;
+	  }
+	  break;
+	case 0x0b: /* st.l */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
+	    tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+					       4, byte_order);
+	    if (record_full_arch_list_add_mem (tmpu32, 4))
+	      return -1;
+	  }
+	  break;
+	case 0x0c: /* ldo.l */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    if (record_full_arch_list_add_reg (regcache, reg))
+	      return -1;
+	  }
+	  break;
+	case 0x0d: /* sto.l */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    uint32_t offset = (uint32_t) ft32_process_readu (addr+2, buf, 4,
+							      byte_order);
+	    regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
+	    tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+					       4, byte_order);
+	    tmpu32 += offset;
+	    if (record_full_arch_list_add_mem (tmpu32, 4))
+	      return -1;
+	  }
+	  break;
+	case 0x0e: /* cmp */
+	  {
+	    if (record_full_arch_list_add_reg (regcache, FT32_CC_REGNUM))
+	      return -1;
+	  }
+	  break;
+	case 0x0f:
+	case 0x10:
+	case 0x11:
+	case 0x12:
+	case 0x13:
+	case 0x14:
+	case 0x15:
+	case 0x16:
+	case 0x17:
+	case 0x18:
+	  {
+	    /* Do nothing.  */
+	    break;
+	  }
+	case 0x19: /* jsr */
+	  {
+	    regcache_raw_read (regcache,
+			       FT32_SP_REGNUM, (gdb_byte *) & tmpu32);
+	    tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+					       4, byte_order);
+	    if (record_full_arch_list_add_reg (regcache, FT32_FP_REGNUM)
+		|| (record_full_arch_list_add_reg (regcache,
+						   FT32_SP_REGNUM))
+		|| record_full_arch_list_add_mem (tmpu32 - 12, 12))
+	      return -1;
+	  }
+	  break;
+	case 0x1a: /* jmpa */
+	  {
+	    /* Do nothing.  */
+	  }
+	  break;
+	case 0x1b: /* ldi.b (immediate) */
+	case 0x1c: /* ld.b (register indirect) */
+	case 0x1d: /* lda.b */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    if (record_full_arch_list_add_reg (regcache, reg))
+	      return -1;
+	  }
+	  break;
+	case 0x1e: /* st.b */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
+	    tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+					       4, byte_order);
+	    if (record_full_arch_list_add_mem (tmpu32, 1))
+	      return -1;
+	  }
+	  break;
+	case 0x1f: /* sta.b */
+	  {
+	    tmpu32 = ft32_process_readu (addr+2, (char *) buf,
+					  4, byte_order);
+	    if (record_full_arch_list_add_mem (tmpu32, 1))
+	      return -1;
+	  }
+	  break;
+	case 0x20: /* ldi.s (immediate) */
+	case 0x21: /* ld.s (register indirect) */
+	case 0x22: /* lda.s */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    if (record_full_arch_list_add_reg (regcache, reg))
+	      return -1;
+	  }
+	  break;
+	case 0x23: /* st.s */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
+	    tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+					       4, byte_order);
+	    if (record_full_arch_list_add_mem (tmpu32, 2))
+	      return -1;
+	  }
+	  break;
+	case 0x24: /* sta.s */
+	  {
+	    tmpu32 = ft32_process_readu (addr+2, (char *) buf,
+					  4, byte_order);
+	    if (record_full_arch_list_add_mem (tmpu32, 2))
+	      return -1;
+	  }
+	  break;
+	case 0x25: /* jmp */
+	  {
+	    /* Do nothing.  */
+	  }
+	  break;
+	case 0x26: /* and */
+	case 0x27: /* lshr */
+	case 0x28: /* ashl */
+	case 0x29: /* sub.l */
+	case 0x2a: /* neg */
+	case 0x2b: /* or */
+	case 0x2c: /* not */
+	case 0x2d: /* ashr */
+	case 0x2e: /* xor */
+	case 0x2f: /* mul.l */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    if (record_full_arch_list_add_reg (regcache, reg))
+	      return -1;
+	  }
+	  break;
+	case 0x30: /* swi */
+	  {
+	    /* We currently implement support for libgloss'
+	       system calls.  */
+
+	    int inum = ft32_process_readu (addr+2, (char *) buf,
+					    4, byte_order);
+
+	    switch (inum)
+	      {
+	      case 0x1: /* SYS_exit */
+		{
+		  /* Do nothing.  */
+		}
+		break;
+	      case 0x2: /* SYS_open */
+		{
+		  if (record_full_arch_list_add_reg (regcache, RET1_REGNUM))
+		    return -1;
+		}
+		break;
+	      case 0x4: /* SYS_read */
+		{
+		  uint32_t length, ptr;
+
+		  /* Read buffer pointer is in $r1.  */
+		  regcache_raw_read (regcache, 3, (gdb_byte *) & ptr);
+		  ptr = extract_unsigned_integer ((gdb_byte *) & ptr,
+						  4, byte_order);
+
+		  /* String length is at 0x12($fp).  */
+		  regcache_raw_read (regcache,
+				     FT32_FP_REGNUM, (gdb_byte *) & tmpu32);
+		  tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+						     4, byte_order);
+		  length = ft32_process_readu (tmpu32+20, (char *) buf,
+						4, byte_order);
+
+		  if (record_full_arch_list_add_mem (ptr, length))
+		    return -1;
+		}
+		break;
+	      case 0x5: /* SYS_write */
+		{
+		  if (record_full_arch_list_add_reg (regcache, RET1_REGNUM))
+		    return -1;
+		}
+		break;
+	      default:
+		break;
+	      }
+	  }
+	  break;
+	case 0x31: /* div.l */
+	case 0x32: /* udiv.l */
+	case 0x33: /* mod.l */
+	case 0x34: /* umod.l */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    if (record_full_arch_list_add_reg (regcache, reg))
+	      return -1;
+	  }
+	  break;
+	case 0x35: /* brk */
+	  /* Do nothing.  */
+	  break;
+	case 0x36: /* ldo.b */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    if (record_full_arch_list_add_reg (regcache, reg))
+	      return -1;
+	  }
+	  break;
+	case 0x37: /* sto.b */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    uint32_t offset = (uint32_t) ft32_process_readu (addr+2, buf, 4,
+							      byte_order);
+	    regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
+	    tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+					       4, byte_order);
+	    tmpu32 += offset;
+	    if (record_full_arch_list_add_mem (tmpu32, 1))
+	      return -1;
+	  }
+	  break;
+	case 0x38: /* ldo.s */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    if (record_full_arch_list_add_reg (regcache, reg))
+	      return -1;
+	  }
+	  break;
+	case 0x39: /* sto.s */
+	  {
+	    int reg = (inst >> 4) & 0xf;
+	    uint32_t offset = (uint32_t) ft32_process_readu (addr+2, buf, 4,
+							      byte_order);
+	    regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
+	    tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+					       4, byte_order);
+	    tmpu32 += offset;
+	    if (record_full_arch_list_add_mem (tmpu32, 2))
+	      return -1;
+	  }
+	  break;
+	default:
+	  /* Do nothing.  */
+	  break;
+	}
+    }
+
+  if (record_full_arch_list_add_reg (regcache, FT32_PC_REGNUM))
+    return -1;
+  if (record_full_arch_list_add_end ())
+    return -1;
+  return 0;
+#endif
+}
+
+/* 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);
+
+  /* Support reverse debugging.  */
+  set_gdbarch_process_record (gdbarch, ft32_process_record);
+
+  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..f561392
--- /dev/null
+++ b/gdb/ft32-tdep.h
@@ -0,0 +1,42 @@
+/* Target-dependent code for the FT32.
+
+   Copyright (C) 2002-2013 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 MOXIE.  */
+};
+
+/* 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_PC_REGNUM = 32		/* Program counter.  */
+};
+
+/* Number of machine registers.  */
+#define FT32_NUM_REGS 33          /* 32 real registers + PC */
+
+#endif /* ft32-tdep.h */
diff --git a/sim/configure.tgt b/sim/configure.tgt
index d112e72..443418e 100644
--- a/sim/configure.tgt
+++ b/sim/configure.tgt
@@ -111,6 +111,9 @@ case "${target}" in
    powerpc*-*-*)
        SIM_ARCH(ppc)
        ;;
+   ft32-*-*)
+       SIM_ARCH(ft32)
+       ;;
    v850*-*-*)
        SIM_ARCH(v850)
        sim_igen=yes
diff --git a/sim/ft32/Makefile.in b/sim/ft32/Makefile.in
new file mode 100644
index 0000000..d0de231
--- /dev/null
+++ b/sim/ft32/Makefile.in
@@ -0,0 +1,38 @@
+#    Makefile template for Configure for the ft32 sim library.
+#    Copyright (C) 2008-2013 Free Software Foundation, Inc.
+#    Written by Anthony Green
+#
+# 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/>.
+
+## COMMON_PRE_CONFIG_FRAG
+
+dtbdir = @datadir@/gdb-`sed q ${srcdir}/../../gdb/version.in`/dtb
+
+SIM_OBJS = interp.o sim-load.o sim-io.o sim-config.o sim-utils.o	\
+sim-options.o sim-module.o sim-core.o sim-endian.o sim-trace.o	\
+sim-engine.o sim-fpu.o sim-bits.o sim-profile.o sim-events.o \
+sim-memopt.o
+
+SIM_EXTRA_LIBS = -lm -lz -ldl
+SIM_EXTRA_CLEAN = ft32-clean
+# SIM_EXTRA_INSTALL = install-dtb
+# SIM_CFLAGS = -DDTB="\"$(dtbdir)/ft32-gdb.dtb\""
+
+## COMMON_POST_CONFIG_FRAG
+
+all: interp.o
+
+interp.o: interp.c
+
+ft32-clean:
diff --git a/sim/ft32/config.in b/sim/ft32/config.in
new file mode 100644
index 0000000..8de933c
--- /dev/null
+++ b/sim/ft32/config.in
@@ -0,0 +1,154 @@
+/* config.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Define to 1 if translation of program messages to the user's native
+   language is requested. */
+#undef ENABLE_NLS
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <errno.h> header file. */
+#undef HAVE_ERRNO_H
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the <fpu_control.h> header file. */
+#undef HAVE_FPU_CONTROL_H
+
+/* Define to 1 if you have the `getrusage' function. */
+#undef HAVE_GETRUSAGE
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the `time' function. */
+#undef HAVE_TIME
+
+/* Define to 1 if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the <zlib.h> header file. */
+#undef HAVE_ZLIB_H
+
+/* Define to 1 if you have the `__setfpucw' function. */
+#undef HAVE___SETFPUCW
+
+/* Name of this package. */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Additional package description */
+#undef PKGVERSION
+
+/* Bug reporting address */
+#undef REPORT_BUGS_TO
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
diff --git a/sim/ft32/configure.ac b/sim/ft32/configure.ac
new file mode 100644
index 0000000..4695c16
--- /dev/null
+++ b/sim/ft32/configure.ac
@@ -0,0 +1,18 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.64)dnl
+AC_INIT(Makefile.in)
+sinclude(../common/acinclude.m4)
+
+SIM_AC_COMMON
+
+AC_CHECK_TOOL(DTC, dtc)
+
+SIM_AC_OPTION_ENDIAN(LITTLE_ENDIAN)
+SIM_AC_OPTION_ALIGNMENT(STRICT_ALIGNMENT)
+SIM_AC_OPTION_HOSTENDIAN
+SIM_AC_OPTION_ENVIRONMENT
+SIM_AC_OPTION_INLINE()
+
+AC_CHECK_HEADERS(unistd.h)
+
+SIM_AC_OUTPUT
diff --git a/sim/ft32/interp.c b/sim/ft32/interp.c
new file mode 100644
index 0000000..493706b
--- /dev/null
+++ b/sim/ft32/interp.c
@@ -0,0 +1,1014 @@
+/* Simulator for the FT32 processor
+   Copyright (C) 2008-2013 Free Software Foundation, Inc.
+   Contributed by FTDI (support@ftdichip.com)
+
+This file is part of GDB, the GNU debugger.
+
+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 "config.h"
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include "sysdep.h"
+#include <sys/times.h>
+#include <sys/param.h>
+#include <netinet/in.h>	/* for byte ordering macros */
+#include "bfd.h"
+#include "gdb/callback.h"
+#include "libiberty.h"
+#include "gdb/remote-sim.h"
+
+#include "sim-main.h"
+#include "sim-base.h"
+
+#include "opcode/ft32.h"
+
+extern const ft32_opc_info_t ft32_opc_info[128];
+
+typedef int word;
+typedef unsigned int uword;
+
+host_callback *       callback;
+
+FILE *tracefile;
+
+static char *myname;
+static SIM_OPEN_KIND sim_kind;
+static int issue_messages = 0;
+
+struct {
+  uint32_t regs[32];
+  uint32_t pc;
+  uint8_t pm[262144];
+  uint8_t ram[65536];
+  uint64_t num_i;
+  uint64_t cycles;
+  uint64_t next_tick_cycle;
+  enum sim_stop reason;
+  int pm_unlock;
+  uint32_t pm_addr;
+  int exception;
+} cpu;
+
+unsigned long
+ft32_extract_unsigned_integer (addr, len)
+     unsigned char * addr;
+     int len;
+{
+  unsigned long retval;
+  unsigned char * p;
+  unsigned char * startaddr = (unsigned char *)addr;
+  unsigned char * endaddr = startaddr + len;
+
+  if (len > (int) sizeof (unsigned long))
+    printf ("That operation is not available on integers of more than %ld bytes.",
+	    sizeof (unsigned long));
+
+  /* Start at the most significant end of the integer, and work towards
+     the least significant.  */
+  retval = 0;
+
+  for (p = endaddr; p > startaddr;)
+    retval = (retval << 8) | * -- p;
+
+  return retval;
+}
+
+void
+ft32_store_unsigned_integer (addr, len, val)
+     unsigned char * addr;
+     int len;
+     unsigned long val;
+{
+  unsigned char * p;
+  unsigned char * startaddr = (unsigned char *)addr;
+  unsigned char * endaddr = startaddr + len;
+
+  for (p = startaddr; p < endaddr; p++)
+    {
+      *p = val & 0xff;
+      val >>= 8;
+    }
+}
+
+void
+sim_size (int s)
+{
+}
+
+static void
+set_initial_gprs ()
+{
+  int i;
+  long space;
+}
+
+static void
+interrupt ()
+{
+  // cpu.asregs.exception = SIGINT;
+}
+
+/* Write a 4 byte value to memory.  */
+
+static void INLINE
+wlat (sim_cpu *scpu, word pc, word x, word v)
+{
+  address_word cia = CIA_GET (scpu);
+
+  sim_core_write_aligned_4 (scpu, cia, write_map, x, v);
+}
+
+static int tracing = 0;
+
+uint32_t cpu_pm_read(SIM_DESC sd, int dw, uint32_t ea)
+{
+  sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
+  address_word cia = CIA_GET (scpu);
+  uint32_t r;
+
+  if ((ea & ~0x3ffff) != 0)
+    {
+      fprintf(stderr, "Illegal PM address %08x, pc %#x\n", ea, cpu.pc);
+      exit(0);
+    }
+
+  switch (dw)
+  {
+    case 1:
+      ea &= ~1;
+      break;
+    case 2:
+      ea &= ~3;
+      break;
+    default:
+      break;
+  }
+  r = sim_core_read_aligned_1 (scpu, cia, read_map, ea);
+  if (1 <= dw)
+    {
+      r += (sim_core_read_aligned_1 (scpu, cia, read_map, ea+1) << 8);
+      if (2 <= dw)
+        {
+          r += (sim_core_read_aligned_1 (scpu, cia, read_map, ea+2) << 16);
+          r += (sim_core_read_aligned_1 (scpu, cia, read_map, ea+3) << 24);
+        }
+    }
+  return r;
+}
+
+static uint32_t safe_addr(uint32_t dw, uint32_t ea)
+{
+  if ((ea & ~0x1ffff) != 0)
+    {
+      fprintf(stderr, "Illegal RAM address %08x, pc %#x\n", ea, cpu.pc);
+      exit(0);
+    }
+  ea &= 0x1ffff;
+  switch (dw)
+  {
+    case 1:
+      // if ((ea & 1) == 0);
+      ea &= ~1;
+      break;
+    case 2:
+      // ASSERT((ea & 3) == 0);
+      ea &= ~3;
+      break;
+    default:
+      break;
+  }
+  return ea;
+}
+
+static uint32_t cpu_mem_read(uint32_t dw, uint32_t ea)
+{
+  uint32_t r;
+
+  ea = safe_addr(dw, ea);
+  if ((ea & ~0xffff))
+    {
+      switch (ea)
+      {
+      case 0x10000:
+      case 0x10020:
+        return getchar();
+      case 0x10024:
+        return 1;
+      case 0x1fff4:
+        // printf("cycles = %lld, us = %u\n", cpu.cycles, (uint32_t)(cpu.cycles / 100));
+        return (uint32_t)(cpu.cycles / 100);
+      default:
+        fprintf(stderr, "Illegal IO read address %08x, pc %#x\n", ea, cpu.pc);
+        exit(0);
+      }
+    }
+  r = cpu.ram[ea];
+  if (1 <= dw)
+    {
+      r += (cpu.ram[ea + 1] << 8);
+      if (2 <= dw)
+        {
+          r += cpu.ram[ea + 2] << 16;
+          r += cpu.ram[ea + 3] << 24;
+        }
+    }
+  return r;
+}
+
+static void cpu_mem_write(SIM_DESC sd, uint32_t dw, uint32_t ea, uint32_t d)
+{
+  ea = safe_addr(dw, ea);
+  if (ea & 0x10000)
+    {
+      if (tracefile)
+        fprintf(tracefile, "IO write %c %08x to %0x\n", "bsl"[dw], d, ea);
+      switch (ea)
+      {
+      case 0x10000:
+        putchar(d & 0xff);
+        break;
+      case 0x1fc80:
+        cpu.pm_unlock = (d == 0x1337f7d1);
+        break;
+      case 0x1fc84:
+        cpu.pm_addr = d;
+        break;
+      case 0x1fc88:
+        {
+          sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
+          address_word cia = CIA_GET (scpu);
+          sim_core_write_aligned_1 (scpu, cia, read_map, cpu.pm_addr + 0, d & 0xff);
+          sim_core_write_aligned_1 (scpu, cia, read_map, cpu.pm_addr + 1, (d >> 8) & 0xff);
+          sim_core_write_aligned_1 (scpu, cia, read_map, cpu.pm_addr + 2, (d >> 16) & 0xff);
+          sim_core_write_aligned_1 (scpu, cia, read_map, cpu.pm_addr + 3, (d >> 24) & 0xff);
+        }
+        break;
+      case 0x10024:
+      case 0x1fffc:
+        break;
+      case 0x1fff8:
+        printf("DEBUG "); // fall-though...
+      case 0x19470:
+        {
+          uint32_t d16 = (d & 0xffff) | ((d & 0xffff) << 16);
+          uint32_t d8 = (d16 & 0x00ff00ff) | ((d16 & 0x00ff00ff) << 8);
+          switch (dw)
+          {
+          case 0: d = d8; break;
+          case 1: d = d16; break;
+          }
+          printf("%08x\n", d);
+        }
+        break;
+      default:
+        fprintf(stderr, "Unknown IO write %08x to to %08x\n", d, ea);
+      }
+    }
+  else
+    {
+      cpu.ram[ea] = d & 0xff;
+      if (1 <= dw)
+        {
+          cpu.ram[ea + 1] = (d >> 8) & 0xff;
+          if (2 <= dw)
+            {
+              cpu.ram[ea + 2] = (d >> 16) & 0xff;
+              cpu.ram[ea + 3] = (d >> 24) & 0xff;
+            }
+        }
+    }
+}
+
+static void ft32_push(SIM_DESC sd, uint32_t v)
+{
+  cpu.regs[31] -= 4;
+  cpu.regs[31] &= 0xffff;
+  cpu_mem_write(sd, 2, cpu.regs[31], v);
+}
+
+static uint32_t ft32_pop()
+{
+  uint32_t r = cpu_mem_read(2, cpu.regs[31]);
+  cpu.regs[31] += 4;
+  cpu.regs[31] &= 0xffff;
+  return r;
+}
+
+static int nunsigned(int siz, int bits)
+{
+  int mask = (1L << siz) - 1;
+  return bits & mask;
+}
+
+static int nsigned(int siz, int bits)
+{
+  int shift = (sizeof(int) * 8) - siz;
+  return (bits << shift) >> shift;
+}
+
+static uint32_t ft32sdiv(uint32_t n, uint32_t d)
+{
+  if (n == 0x80000000UL && d == 0xffffffffUL)
+    return 0x80000000UL;
+  else
+    return (uint32_t)((int)n / (int)d);
+}
+
+static uint32_t ft32smod(uint32_t n, uint32_t d)
+{
+  if (n == 0x80000000UL && d == 0xffffffffUL)
+    return 0;
+  else
+    return (uint32_t)((int)n % (int)d);
+}
+
+static uint32_t ror(uint32_t n, uint32_t b)
+{
+  b &= 31;
+  return (n >> b) | (n << (32 - b));
+}
+
+static uint32_t bins(uint32_t d, uint32_t f, uint32_t len, uint32_t pos)
+{
+  uint32_t mask = ((1 << len) - 1) << pos;
+  return (d & ~mask) | ((f << pos) & mask);
+}
+
+static uint32_t flip(uint32_t x, uint32_t b)
+{
+  if (b & 1)
+    x = (x & 0x55555555) <<  1 | (x & 0xAAAAAAAA) >>  1;
+  if (b & 2)
+    x = (x & 0x33333333) <<  2 | (x & 0xCCCCCCCC) >>  2;
+  if (b & 4)
+    x = (x & 0x0F0F0F0F) <<  4 | (x & 0xF0F0F0F0) >>  4;
+  if (b & 8)
+    x = (x & 0x00FF00FF) <<  8 | (x & 0xFF00FF00) >>  8;
+  if (b & 16)
+    x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16;
+  return x;
+}
+
+void
+sim_resume (sd, step, siggnal)
+     SIM_DESC sd;
+     int step, siggnal;
+{
+  void (* sigsave)();
+  sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
+  address_word cia = CIA_GET (scpu);
+
+  sigsave = signal (SIGINT, interrupt);
+  cpu.reason = sim_stopped;
+
+  do
+    {
+      if (cpu.cycles >= cpu.next_tick_cycle)
+        {
+          cpu.next_tick_cycle += 100000;
+          ft32_push(sd, cpu.pc);
+          cpu.pc = 12;  // interrupt 1
+        }
+      uint32_t inst = cpu_pm_read(sd, 2, cpu.pc);
+      cpu.cycles += 1;
+      // printf("inst at %04x: %08x\n", cpu.pc, inst);
+
+      // Handle "call 8" (which is FT32's "break" equivalent) here
+      if (inst == 0x00340002)
+        {
+          cpu.reason = sim_stopped;
+          goto escape;
+        }
+      uint32_t dw   =             (inst >> FT32_FLD_DW_BIT) & ((1U << FT32_FLD_DW_SIZ) - 1);
+      uint32_t cb   =             (inst >> FT32_FLD_CB_BIT) & ((1U << FT32_FLD_CB_SIZ) - 1);
+      uint32_t r_d  =             (inst >> FT32_FLD_R_D_BIT) & ((1U << FT32_FLD_R_D_SIZ) - 1);
+      uint32_t cr   =             (inst >> FT32_FLD_CR_BIT) & ((1U << FT32_FLD_CR_SIZ) - 1);
+      uint32_t cv   =             (inst >> FT32_FLD_CV_BIT) & ((1U << FT32_FLD_CV_SIZ) - 1);
+      uint32_t bt   =             (inst >> FT32_FLD_BT_BIT) & ((1U << FT32_FLD_BT_SIZ) - 1);
+      uint32_t r_1 =              (inst >> FT32_FLD_R_1_BIT) & ((1U << FT32_FLD_R_1_SIZ) - 1);
+      uint32_t rimm =             (inst >> FT32_FLD_RIMM_BIT) & ((1U << FT32_FLD_RIMM_SIZ) - 1);
+      uint32_t r_2  =             (inst >> FT32_FLD_R_2_BIT) & ((1U << FT32_FLD_R_2_SIZ) - 1);
+      uint32_t k20  = nsigned(20, (inst >> FT32_FLD_K20_BIT) & ((1U << FT32_FLD_K20_SIZ) - 1));
+      uint32_t pa   =             (inst >> FT32_FLD_PA_BIT) & ((1U << FT32_FLD_PA_SIZ) - 1);
+      uint32_t aa   =             (inst >> FT32_FLD_AA_BIT) & ((1U << FT32_FLD_AA_SIZ) - 1);
+      uint32_t k16  =             (inst >> FT32_FLD_K16_BIT) & ((1U << FT32_FLD_K16_SIZ) - 1);
+      uint32_t k8   = nsigned(8,  (inst >> FT32_FLD_K8_BIT) & ((1U << FT32_FLD_K8_SIZ) - 1));
+      uint32_t al   =             (inst >> FT32_FLD_AL_BIT) & ((1U << FT32_FLD_AL_SIZ) - 1);
+
+      uint32_t r_1v = cpu.regs[r_1];
+      uint32_t rimmv = (rimm & 0x400) ? nsigned(10, rimm) : cpu.regs[rimm & 0x1f];
+
+      uint32_t bit_pos = rimmv & 31;
+      uint32_t bit_len = 0xf & (rimmv >> 5);
+      if (bit_len == 0)
+        bit_len = 16;
+
+      uint32_t upper = (inst >> 27);
+
+      uint32_t insnpc = cpu.pc;
+      cpu.pc += 4;
+      switch (upper)
+      {
+        case FT32_PAT_TOC:
+        case FT32_PAT_TOCI:
+          {
+            int takeit = (cr == 3) || ((1 & (cpu.regs[28 + cr] >> cb)) == cv);
+            if (takeit)
+              {
+                cpu.cycles += 1;
+                if (bt)
+                  {
+                    /* this is a call */
+                    if (tracefile)
+                      fprintf(tracefile, "r0=%08x r1=%08x r2=%08x r3=%08x\n", cpu.regs[0], cpu.regs[1], cpu.regs[2], cpu.regs[3]);
+                    ft32_push(sd, cpu.pc);
+                  }
+                if (upper == FT32_PAT_TOC)
+                  {
+                    cpu.pc = pa << 2;
+                  }
+                else
+                  {
+                    if (tracefile)
+                      fprintf(tracefile, "indirect r%d to %#x\n", r_2, cpu.regs[r_2]);
+                    cpu.pc = cpu.regs[r_2];
+                  }
+                if (cpu.pc == 0x8)
+                  {
+                    fprintf(stderr, "PC is 8!\n");
+                    goto escape;
+                  }
+              }
+          }
+          break;
+
+        case FT32_PAT_ALUOP:
+        case FT32_PAT_CMPOP:
+          {
+            uint32_t result;
+            switch (al)
+            {
+              case 0x0: result = r_1v + rimmv; break;
+              case 0x1: result = ror(r_1v, rimmv); break;
+              case 0x2: result = r_1v - rimmv; break;
+              case 0x3: result = (r_1v << 10) | (1023 & rimmv); break;
+              case 0x4: result = r_1v & rimmv; break;
+              case 0x5: result = r_1v | rimmv; break;
+              case 0x6: result = r_1v ^ rimmv; break;
+              case 0x7: result = ~(r_1v ^ rimmv); break;
+              case 0x8: result = r_1v << rimmv; break;
+              case 0x9: result = r_1v >> rimmv; break;
+              case 0xa: result = (int32_t)r_1v >> rimmv; break;
+              case 0xb: result = bins(r_1v, rimmv >> 10, bit_len, bit_pos); break;
+              case 0xc: result = nsigned(bit_len, r_1v >> bit_pos); break;
+              case 0xd: result = nunsigned(bit_len, r_1v >> bit_pos); break;
+              case 0xe: result = flip(r_1v, rimmv); break;
+              default:
+                printf("Unhandled alu %#x\n", al);
+                goto escape;
+            }
+            if (upper == FT32_PAT_ALUOP)
+              {
+                cpu.regs[r_d] = result;
+              }
+              else
+              {
+                uint32_t dwmask;
+                int dwsiz;
+                switch (dw)
+                {
+                  case 0: dwsiz = 7;  dwmask = 0xffU; break;
+                  case 1: dwsiz = 15; dwmask = 0xffffU; break;
+                  case 2: dwsiz = 31; dwmask = 0xffffffffU; break;
+                }
+
+                int zero = (0 == (result & dwmask));
+                int sign = 1 & (result >> dwsiz);
+                int ahi = 1 & (r_1v >> dwsiz);
+                int bhi = 1 & (rimmv >> dwsiz);
+                int overflow = (sign != ahi) & (ahi == !bhi);
+                int carry;
+                int bit = (dwsiz + 1);
+                uint64_t ra = r_1v & dwmask;
+                uint64_t rb = rimmv & dwmask;
+                switch (al)
+                {
+                  case 0x0: carry = 1 & ((ra + rb) >> bit); break;
+                  case 0x2: carry = 1 & ((ra - rb) >> bit); break;
+                  default:  carry = 0; break;
+                }
+                int above = (!carry & !zero);
+                int greater = (sign == overflow) & !zero;
+                int greatereq = (sign == overflow);
+
+                cpu.regs[r_d] = (
+                  (above << 6) |
+                  (greater << 5) |
+                  (greatereq << 4) |
+                  (sign << 3) |
+                  (overflow << 2) |
+                  (carry << 1) |
+                  (zero << 0));
+              }
+            if (0)
+              fprintf(tracefile, "%06x: result=%08x, \n", cpu.pc, result);
+          }
+          break;
+
+        case FT32_PAT_LDK:
+          cpu.regs[r_d] = k20;
+          break;
+
+        case FT32_PAT_LPM:
+          cpu.cycles += 1;
+          cpu.regs[r_d] = cpu_pm_read(sd, dw, pa << 2);
+          break;
+
+        case FT32_PAT_LPMI:
+          cpu.cycles += 1;
+          cpu.regs[r_d] = cpu_pm_read(sd, dw, cpu.regs[r_1] + k8);
+          if (tracefile)
+            fprintf(tracefile, "lpmi %x %08x\n", cpu.regs[r_1] + k8, cpu.regs[r_d]);
+          break;
+
+        case FT32_PAT_STA:
+          cpu_mem_write(sd, dw, aa, cpu.regs[r_d]);
+          if (aa == 0x1fffc)
+            {
+              cpu.reason = sim_exited;
+              goto escape;
+            }
+          break;
+
+        case FT32_PAT_STI:
+          if (tracefile)
+            fprintf(tracefile, "STI %#x <= %08x\n", cpu.regs[r_d] + k8, cpu.regs[r_1]);
+          cpu_mem_write(sd, dw, cpu.regs[r_d] + k8, cpu.regs[r_1]);
+          break;
+
+        case FT32_PAT_LDA:
+          cpu.cycles += 1;
+          cpu.regs[r_d] = cpu_mem_read(dw, aa);
+          break;
+
+        case FT32_PAT_LDI:
+          cpu.cycles += 1;
+          cpu.regs[r_d] = cpu_mem_read(dw, cpu.regs[r_1] + k8);
+          if (tracefile)
+            fprintf(tracefile, "LDI %#x <= %08x\n", cpu.regs[r_d], cpu.regs[r_1] + k8);
+          break;
+
+        case FT32_PAT_PUSH:
+          ft32_push(sd, r_1v);
+          break;
+
+        case FT32_PAT_LINK:
+          ft32_push(sd, cpu.regs[r_d]);
+          cpu.regs[r_d] = cpu.regs[31];
+          cpu.regs[31] -= k16;
+          cpu.regs[31] &= 0xffff;
+          break;
+
+        case FT32_PAT_UNLINK:
+          cpu.regs[31] = cpu.regs[r_d];
+          cpu.regs[31] &= 0xffff;
+          cpu.regs[r_d] = ft32_pop();
+          break;
+
+        case FT32_PAT_POP:
+          cpu.cycles += 1;
+          cpu.regs[r_d] = ft32_pop();
+          break;
+
+        case FT32_PAT_RETURN:
+          cpu.pc = ft32_pop();
+          break;
+
+        case FT32_PAT_FFUOP:
+          if (tracefile)
+            fprintf(tracefile, "ffu %#x\n", al);
+          switch (al)
+          {
+          case 0x0: cpu.regs[r_d] = r_1v / rimmv; break;
+          case 0x1: cpu.regs[r_d] = r_1v % rimmv; break;
+          case 0x2: cpu.regs[r_d] = ft32sdiv(r_1v, rimmv); break;
+          case 0x3: cpu.regs[r_d] = ft32smod(r_1v, rimmv); break;
+
+          case 0x4: cpu.regs[r_d] = strcmp(cpu.ram + r_1v, cpu.ram + rimmv); break;
+          case 0x5: memcpy(cpu.ram + cpu.regs[r_d], cpu.ram + r_1v, rimmv); break;
+          case 0x6: cpu.regs[r_d] = strlen(cpu.ram + r_1v); break;
+          case 0x7: memset(cpu.ram + cpu.regs[r_d], r_1v, rimmv); break;
+          case 0x8: cpu.regs[r_d] = r_1v * rimmv; break;
+          case 0x9: cpu.regs[r_d] = ((uint64_t)r_1v * (uint64_t)rimmv) >> 32; break;
+          case 0xe:
+            {
+              // streamout
+              uint32_t i;
+              uint32_t src = cpu.regs[r_1];
+              for (i = 0; i < rimmv; i += (1 << dw))
+                {
+                  cpu_mem_write(sd, dw, cpu.regs[r_d], cpu_mem_read(dw, src));
+                  src += (1 << dw);
+                }
+            }
+            break;
+          default:
+            printf("Unhandled ffu %#x\n", al);
+            goto escape;
+          }
+          break;
+
+        default:
+          goto escape;
+      }
+      cpu.num_i++;
+      if (tracefile)
+        fprintf(tracefile, "@%lld pc=%#x inst=%08x r%d=%08x\n", cpu.num_i, insnpc, inst, r_d, cpu.regs[r_d]);
+    }
+    while (!step);
+escape:
+  cpu.exception = step ? SIGTRAP : 0;
+  if (cpu.reason == sim_exited)
+    {
+      cpu.exception = cpu.regs[0];
+      printf("[FT32 sim ending:%llu instructions executed. Exit code %d]\n", cpu.num_i, (int)cpu.exception);
+    }
+
+  signal (SIGINT, sigsave);
+}
+
+int
+sim_write (sd, addr, buffer, size)
+     SIM_DESC sd;
+     SIM_ADDR addr;
+     const unsigned char * buffer;
+     int size;
+{
+  sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
+  // printf("sim_write(%#x, %#x)\n", addr, size);
+
+  if (addr < 0x800000)
+    {
+      sim_core_write_buffer (sd, scpu, write_map, buffer, addr, size);
+    }
+    else
+    {
+      int i;
+
+      addr -= 0x800000;
+      for (i = 0; i < size; i++)
+        cpu_mem_write(sd, 0, addr + i, buffer[i]);
+    }
+  return size;
+}
+
+int
+sim_read (sd, addr, buffer, size)
+     SIM_DESC sd;
+     SIM_ADDR addr;
+     unsigned char * buffer;
+     int size;
+{
+  sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
+
+  // printf("[sim_read %#x, %d]\n", addr, size);
+  if (addr < 0x800000)
+    {
+      sim_core_read_buffer (sd, scpu, read_map, buffer, addr, size);
+    }
+    else
+    {
+      int i;
+
+      addr -= 0x800000;
+      for (i = 0; i < size; i++)
+        buffer[i] = cpu_mem_read(0, addr + i);
+    }
+
+  return size;
+}
+
+#define NUM_FT32_REGS 32
+int
+sim_store_register (sd, rn, memory, length)
+     SIM_DESC sd;
+     int rn;
+     unsigned char * memory;
+     int length;
+{
+  if (0 <= rn && rn <= 32)
+    {
+      if (length == 4)
+	{
+	  long ival;
+
+	  /* misalignment safe */
+	  ival = ft32_extract_unsigned_integer (memory, 4);
+	  if (rn == 32)
+            cpu.pc = ival;
+          else
+            cpu.regs[rn] = ival;
+	}
+
+      return 4;
+    }
+  else
+    return 0;
+}
+
+int
+sim_fetch_register (sd, rn, memory, length)
+     SIM_DESC sd;
+     int rn;
+     unsigned char * memory;
+     int length;
+{
+  if (0 <= rn && rn <= 32)
+    {
+      if (length == 4)
+	{
+	  long ival;
+          // Handle the register number translation here.
+          // Sim registers are, duh, 0-31.
+          // Other tools (gcc, gdb) uses:
+          // 0 - fp
+          // 1 - sp
+          // 2 - r0
+          // 31 - cc
+          switch (rn)
+          {
+          case 0:
+            ival = cpu.regs[29];
+            break;
+          case 1:
+            ival = cpu.regs[31];
+            break;
+          case 31:
+            ival = cpu.regs[30];
+            break;
+          case 32:
+            ival = cpu.pc;
+            break;
+          default:
+            ival = cpu.regs[rn - 2];
+          }
+          // printf("[sim_fetch_register(%d)=%08x]", rn, ival);
+
+	  /* misalignment-safe */
+	  ft32_store_unsigned_integer (memory, 4, ival);
+	}
+
+      return 4;
+    }
+  else
+    return 0;
+}
+
+
+int
+sim_trace (sd)
+     SIM_DESC sd;
+{
+  if (tracefile == 0)
+    tracefile = fopen("trace.csv", "wb");
+  tracefile = stdout;
+
+  tracing = 1;
+
+  sim_resume (sd, 0, 0);
+
+  // fclose(tracefile);
+
+  tracing = 0;
+
+  return 1;
+}
+
+void
+sim_stop_reason (sd, reason, sigrc)
+     SIM_DESC sd;
+     enum sim_stop * reason;
+     int * sigrc;
+{
+  *reason = cpu.reason;
+  *sigrc = cpu.exception;
+}
+
+
+int
+sim_stop (sd)
+     SIM_DESC sd;
+{
+  // cpu.asregs.exception = SIGINT;
+  return 1;
+}
+
+
+void
+sim_info (sd, verbose)
+     SIM_DESC sd;
+     int verbose;
+{
+  // callback->printf_filtered (callback, "\n\n# instructions executed  %llu\n", cpu.asregs.insts);
+}
+
+
+SIM_DESC
+sim_open (kind, cb, abfd, argv)
+     SIM_OPEN_KIND kind;
+     host_callback * cb;
+     struct bfd * abfd;
+     char ** argv;
+{
+  SIM_DESC sd = sim_state_alloc (kind, cb);
+  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+
+  if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
+    return 0;
+
+  sim_do_command(sd," memory region 0x00000000,0x4000000") ;
+  sim_do_command(sd," memory region 0xE0000000,0x10000") ;
+
+  myname = argv[0];
+  callback = cb;
+
+  if (kind == SIM_OPEN_STANDALONE)
+    issue_messages = 1;
+
+  set_initial_gprs ();	/* Reset the GPR registers.  */
+
+  /* Configure/verify the target byte order and other runtime
+     configuration options.  */
+  if (sim_config (sd) != SIM_RC_OK)
+    {
+      sim_module_uninstall (sd);
+      return 0;
+    }
+
+  if (sim_post_argv_init (sd) != SIM_RC_OK)
+    {
+      /* Uninstall the modules to avoid memory leaks,
+	 file descriptor leaks, etc.  */
+      sim_module_uninstall (sd);
+      return 0;
+    }
+
+  return sd;
+}
+
+void
+sim_close (sd, quitting)
+     SIM_DESC sd;
+     int quitting;
+{
+  /* nothing to do */
+}
+
+
+/* Load the device tree blob.  */
+
+static void
+load_dtb (SIM_DESC sd, const char *filename)
+{
+  int size = 0;
+  FILE *f = fopen (filename, "rb");
+  char *buf;
+  sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
+ if (f == NULL)
+    {
+      printf ("WARNING: ``%s'' could not be opened.\n", filename);
+      return;
+    }
+  fseek (f, 0, SEEK_END);
+  size = ftell(f);
+  fseek (f, 0, SEEK_SET);
+  buf = alloca (size);
+  if (size != fread (buf, 1, size, f))
+    {
+      printf ("ERROR: error reading ``%s''.\n", filename);
+      return;
+    }
+  sim_core_write_buffer (sd, scpu, write_map, buf, 0xE0000000, size);
+  // cpu.asregs.sregs[9] = 0xE0000000;
+  fclose (f);
+}
+
+SIM_RC
+sim_load (sd, prog, abfd, from_tty)
+     SIM_DESC sd;
+     const char * prog;
+     bfd * abfd;
+     int from_tty;
+{
+  /* Do the right thing for ELF executables; this turns out to be
+     just about the right thing for any object format that:
+       - we crack using BFD routines
+       - follows the traditional UNIX text/data/bss layout
+       - calls the bss section ".bss".   */
+
+  extern bfd * sim_load_file (); /* ??? Don't know where this should live.  */
+  bfd * prog_bfd;
+
+  {
+    bfd * handle;
+    handle = bfd_openr (prog, 0);	/* could be "ft32" */
+
+    if (!handle)
+      {
+	printf("``%s'' could not be opened.\n", prog);
+	return SIM_RC_FAIL;
+      }
+
+    /* Makes sure that we have an object file, also cleans gets the
+       section headers in place.  */
+    if (!bfd_check_format (handle, bfd_object))
+      {
+	/* wasn't an object file */
+	bfd_close (handle);
+	printf ("``%s'' is not appropriate object file.\n", prog);
+	return SIM_RC_FAIL;
+      }
+
+    /* Clean up after ourselves.  */
+    bfd_close (handle);
+  }
+
+  memset(cpu.ram, 0, 65536);
+  /* from sh -- dac */
+  prog_bfd = sim_load_file (sd, myname, callback, prog, abfd,
+                            sim_kind == SIM_OPEN_DEBUG,
+                            0, sim_write);
+  if (prog_bfd == NULL)
+    return SIM_RC_FAIL;
+
+  if (abfd == NULL)
+    bfd_close (prog_bfd);
+
+  return SIM_RC_OK;
+}
+
+SIM_RC
+sim_create_inferior (sd, prog_bfd, argv, env)
+     SIM_DESC sd;
+     struct bfd * prog_bfd;
+     char ** argv;
+     char ** env;
+{
+  char ** avp;
+  int l, argc, i, tp;
+  sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
+
+  /* Set the initial register set.  */
+  l = issue_messages;
+  issue_messages = 0;
+  set_initial_gprs ();
+  issue_messages = l;
+
+  // printf("start address %#lx\n", bfd_get_start_address (prog_bfd));
+  cpu.pc = bfd_get_start_address (prog_bfd);
+  cpu.regs[31] = 0x00000;
+  cpu.num_i = 0;
+  cpu.cycles = 0;
+  cpu.next_tick_cycle = 100000;
+
+  return SIM_RC_OK;
+}
+
+void
+sim_kill (sd)
+     SIM_DESC sd;
+{
+  if (tracefile)
+    fclose(tracefile);
+}
+
+void
+sim_do_command (sd, cmd)
+     SIM_DESC sd;
+     const char * cmd;
+{
+  if (sim_args_command (sd, cmd) != SIM_RC_OK)
+    sim_io_printf (sd,
+		   "Error: \"%s\" is not a valid ft32 simulator command.\n",
+		   cmd);
+}
+
+void
+sim_set_callbacks (ptr)
+     host_callback * ptr;
+{
+  callback = ptr;
+}
diff --git a/sim/ft32/sim-main.h b/sim/ft32/sim-main.h
new file mode 100644
index 0000000..89f0f72
--- /dev/null
+++ b/sim/ft32/sim-main.h
@@ -0,0 +1,61 @@
+/* Moxie Simulator definition.
+   Copyright (C) 2009-2013 Free Software Foundation, Inc.
+   Contributed by Anthony Green <green@moxielogic.com>
+
+This file is part of GDB, the GNU debugger.
+
+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 SIM_MAIN_H
+#define SIM_MAIN_H
+
+#define SIM_HAVE_BIENDIAN
+
+#include "sim-basics.h"
+
+typedef address_word sim_cia;
+
+#include "sim-base.h"
+#include "bfd.h"
+
+#define PCIDX 17
+
+struct _sim_cpu {
+
+  /* The following are internal simulator state variables: */
+#define CIA_GET(CPU) ((CPU)->registers[PCIDX] + 0)
+#define CIA_SET(CPU,CIA) ((CPU)->registers[PCIDX] = (CIA))
+
+/* To keep this default simulator simple, and fast, we use a direct
+   vector of registers. The internal simulator engine then uses
+   manifests to access the correct slot. */
+
+  unsigned_word registers[19];
+
+  sim_cpu_base base;
+};
+
+struct sim_state {
+
+  sim_cpu cpu[MAX_NR_PROCESSORS];
+#if (WITH_SMP)
+#define STATE_CPU(sd,n) (&(sd)->cpu[n])
+#else
+#define STATE_CPU(sd,n) (&(sd)->cpu[0])
+#endif
+
+  sim_state_base base;
+};
+
+#endif
diff --git a/sim/ft32/sysdep.h b/sim/ft32/sysdep.h
new file mode 100644
index 0000000..d82b70b
--- /dev/null
+++ b/sim/ft32/sysdep.h
@@ -0,0 +1,94 @@
+/* System includes and definitions used by the FT32 simulator.
+   Copyright (C) 2008-2013 Free Software Foundation, Inc.
+   Contributed by FTDI <support@ftdichip.com>
+
+This file is part of GDB, the GNU debugger.
+
+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 __SYSDEP_H
+#define __SYSDEP_H
+
+#ifndef	hosts_std_host_H
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/file.h>
+#include "ansidecl.h"
+
+#ifndef	O_ACCMODE
+#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
+#endif
+#ifndef	SEEK_SET
+#define SEEK_SET 0
+#endif
+#ifndef	SEEK_CUR
+#define SEEK_CUR 1
+#endif
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+/*#include <string.h>*/
+#else
+extern char * mktemp ();
+#ifndef memset
+extern PTR    memset ();
+#endif
+
+#ifndef	DONTDECLARE_MALLOC
+extern PTR   malloc ();
+extern PTR   realloc ();
+#endif
+
+#ifndef	__GNUC__
+extern PTR   memcpy ();
+#else
+/* char * memcpy (); */
+#endif
+
+#ifdef __STDC__
+extern void free ();
+#else
+extern int free();
+#endif
+
+#ifndef strchr
+extern char * strchr();
+#endif
+extern char * getenv();
+extern PTR    memchr();
+extern char * strrchr();
+
+extern char * strrchr();
+extern char * ctime();
+extern long   atol();
+extern char * getenv();
+#endif /* STDC_HEADERS */
+
+#ifndef	BYTES_IN_PRINTF_INT
+#define BYTES_IN_PRINTF_INT 4
+#endif
+
+#include "fopen-same.h"
+#define hosts_std_host_H
+#endif
+
+#ifdef	STDC_HEADERS
+#include <stddef.h>
+#endif /* STDC_HEADERS */
+
+#endif /* __SYSDEP_H */
-- 
1.7.9.5


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