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]

RE: [PATCH, FT32] gdb and sim support


Thanks for the review. All is reworked here. There were so many items,
I will skip the things that I just fixed.  So now a list of notes/queries
on the remainder.

The reworked ChangeLog and patchset are below.

> > 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
> 
> notes:
>  - ChangeLog entries are split up across dirs

Do you mean I should not split? Organize in some other way?

> where's the testsuite man ? :)  it should be trivial to start one with .s
> files  -- just look at sim/testsuite/sim/.  otherwise there's no way to keep
> regressions from slipping in.

Good idea. We are currently running the gcc testsuite on the simulator
as our regression test.  Would it be OK if I defer, and add a sim
testsuite after this submit?

> > +/* Use an invalid address value as 'not available' marker.  */
> > +enum { REG_UNAVAIL = (CORE_ADDR) -1 };

This is actually the value -1 being cast. I have rewritten the line to
make this clearer.

> > #define IS_PUSH(inst)   (((inst) & 0xfff00000) == 0x84000000)
> 
> i think usually we put insn constants/etc... into the corresponding 
> include/opcode/ header rather than pasting them inline.  this makes sharing 
> between opcodes, gdb, sim, etc... much easier.

Sounds good. I have submitted the relevant patch to binutils.  When it
comes through I will make the corresponding change in gdb.

> since you're a new port, you should start with SIM_AC_OPTION_WARNINGS enabled.  
> obviously that also means cleaning up all the warnings generated in the ft32/ 
> subdir once you do :).

Done - it now compiles without warnings. It would be nice to be able to
build it with warnings as errors.

> > --- /dev/null
> > +++ b/sim/ft32/interp.c
> 
> ideally you'd switch to sim-reg.o in your Makefile's SIM_OBJS ... that'll 
> provide these entry points.  that would require also enabling sim-model.o 
> & SIM_AC_OPTION_DEFAULT_MODEL support, but i don't think that'd be too hard.
> if you look at bfin/machs.c and start at "sim_machs", i think you should be 
> able to track it down easily enough.

This change is causing me some trouble.  OK to defer it until after the
main submit?

--

ChangeLog entry:

2015-02-23  James Bowman  <james.bowman@ftdichip.com>

	* gdb/Makefile.in, gdb/configure.tgt: FT32 target added.
	* include/gdb/sim-ft32.h: FT32 sim/gdb interface 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

From: James Bowman <james.bowman@ftdichip.com>
Date: Mon, 23 Feb 2015 18:31:18 +0800
Subject: [PATCH] FT32 Support

---
 gdb/Makefile.in        |    4 +-
 gdb/configure.tgt      |    5 +
 gdb/ft32-tdep.c        |  546 +++++++++++++++++++++++++++++++
 gdb/ft32-tdep.h        |   28 ++
 include/gdb/sim-ft32.h |   34 ++
 sim/configure.tgt      |    3 +
 sim/ft32/Makefile.in   |   49 +++
 sim/ft32/configure.ac  |   15 +
 sim/ft32/ft32-sim.h    |   39 +++
 sim/ft32/interp.c      |  831 ++++++++++++++++++++++++++++++++++++++++++++++++
 sim/ft32/sim-main.h    |   63 ++++
 11 files changed, 1616 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
 create mode 100644 sim/ft32/Makefile.in
 create mode 100644 sim/ft32/configure.ac
 create mode 100644 sim/ft32/ft32-sim.h
 create mode 100644 sim/ft32/interp.c
 create mode 100644 sim/ft32/sim-main.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 16e2f1c..62cae68 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 \
@@ -945,7 +946,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 \
@@ -1649,6 +1650,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 hppa-hpux-tdep.c hppa-hpux-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..f040f3b
--- /dev/null
+++ b/gdb/ft32-tdep.c
@@ -0,0 +1,546 @@
+/* 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"
+
+/* 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.  */
+  CORE_ADDR base;
+  CORE_ADDR pc;
+  LONGEST framesize;
+  CORE_ADDR saved_regs[FT32_NUM_REGS];
+  CORE_ADDR saved_sp;
+  bfd_boolean 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 const gdb_byte breakpoint[] = { 0x02, 0x00, 0x34, 0x00 };
+
+  *lenptr = sizeof (breakpoint);
+  return breakpoint;
+}
+
+/* FT32 register names.  */
+
+static const 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;
+
+  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 && 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));
+}
+
+/* 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..6602df3
--- /dev/null
+++ b/include/gdb/sim-ft32.h
@@ -0,0 +1,34 @@
+/* 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_PC_REGNUM = 32           /* Program counter.  */
+};
+
+/* Number of machine registers.  */
+#define FT32_NUM_REGS 33        /* 32 real registers + PC */
+
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..322a6c9
--- /dev/null
+++ b/sim/ft32/Makefile.in
@@ -0,0 +1,49 @@
+#    Makefile template for Configure for the ft32 sim library.
+#    Copyright (C) 2008-2015 Free Software Foundation, Inc.
+#    Written by FTDI
+#
+# 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
+
+
+SIM_OBJS = \
+  $(SIM_NEW_COMMON_OBJS) \
+  interp.o	\
+  sim-bits.o	\
+  sim-config.o	\
+  sim-core.o	\
+  sim-cpu.o	\
+  sim-endian.o	\
+  sim-engine.o	\
+  sim-events.o	\
+  sim-fpu.o	\
+  sim-hload.o	\
+  sim-io.o	\
+  sim-load.o	\
+  sim-memopt.o	\
+  sim-module.o	\
+  sim-options.o	\
+  sim-profile.o	\
+  sim-reason.o	\
+  sim-resume.o	\
+  sim-signal.o	\
+  sim-stop.o	\
+  sim-trace.o	\
+  sim-utils.o	\
+  $(SIM_EXTRA_OBJS)
+
+SIM_RUN_OBJS = nrun.o
+
+## COMMON_POST_CONFIG_FRAG
diff --git a/sim/ft32/configure.ac b/sim/ft32/configure.ac
new file mode 100644
index 0000000..2107f74
--- /dev/null
+++ b/sim/ft32/configure.ac
@@ -0,0 +1,15 @@
+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
+
+SIM_AC_OPTION_ENDIAN(LITTLE_ENDIAN)
+SIM_AC_OPTION_ALIGNMENT(STRICT_ALIGNMENT)
+SIM_AC_OPTION_HOSTENDIAN
+SIM_AC_OPTION_ENVIRONMENT
+SIM_AC_OPTION_INLINE
+SIM_AC_OPTION_WARNINGS
+
+SIM_AC_OUTPUT
diff --git a/sim/ft32/ft32-sim.h b/sim/ft32/ft32-sim.h
new file mode 100644
index 0000000..d39fe7f
--- /dev/null
+++ b/sim/ft32/ft32-sim.h
@@ -0,0 +1,39 @@
+/* Simulator for the FT32 processor
+
+   Copyright (C) 2008-2015 Free Software Foundation, Inc.
+   Contributed by FTDI <support@ftdichip.com>
+
+   This file is part of simulators.
+
+   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_SIM_H_
+#define _FT32_SIM_H_
+
+#include <stdint.h>
+
+struct ft32_cpu_state {
+  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;
+  int pm_unlock;
+  uint32_t pm_addr;
+  int exception;
+};
+
+#endif  /* _FT32_SIM_H_ */
diff --git a/sim/ft32/interp.c b/sim/ft32/interp.c
new file mode 100644
index 0000000..040c6c7
--- /dev/null
+++ b/sim/ft32/interp.c
@@ -0,0 +1,831 @@
+/* Simulator for the FT32 processor
+
+   Copyright (C) 2008-2015 Free Software Foundation, Inc.
+   Contributed by FTDI <support@ftdichip.com>
+
+   This file is part of simulators.
+
+   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 <stdint.h>
+
+#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"
+
+static unsigned long
+ft32_extract_unsigned_integer (unsigned char *addr, int len)
+{
+  unsigned long retval;
+  unsigned char *p;
+  unsigned char *startaddr = (unsigned char *) addr;
+  unsigned char *endaddr = startaddr + len;
+
+  /* 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;
+}
+
+static void
+ft32_store_unsigned_integer (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;
+    }
+}
+
+static int tracing = 0;
+
+static uint32_t
+cpu_pm_read (SIM_DESC sd, int dw, uint32_t ea)
+{
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+  address_word cia = CIA_GET (cpu);
+  uint32_t r;
+
+  switch (dw)
+  {
+    case 1:
+      ea &= ~1;
+      break;
+    case 2:
+      ea &= ~3;
+      break;
+    default:
+      break;
+  }
+  r = sim_core_read_aligned_1 (cpu, cia, read_map, ea);
+  if (1 <= dw)
+    {
+      r += (sim_core_read_aligned_1 (cpu, cia, read_map, ea+1) << 8);
+      if (2 <= dw)
+	{
+	  r += (sim_core_read_aligned_1 (cpu, cia, read_map, ea+2) << 16);
+	  r += (sim_core_read_aligned_1 (cpu, cia, read_map, ea+3) << 24);
+	}
+    }
+  return r;
+}
+
+static uint32_t safe_addr (uint32_t dw, uint32_t ea)
+{
+  ea &= 0x1ffff;
+  switch (dw)
+  {
+    case 1:
+      ea &= ~1;
+      break;
+    case 2:
+      ea &= ~3;
+      break;
+    default:
+      break;
+  }
+  return ea;
+}
+
+static uint32_t cpu_mem_read (SIM_DESC sd, uint32_t dw, uint32_t ea)
+{
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+  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:
+	return (uint32_t)(cpu->state.cycles / 100);
+      default:
+	sim_io_eprintf (sd, "Illegal IO read address %08x, pc %#x\n", ea, cpu->state.pc);
+	exit (0);
+      }
+    }
+  r = cpu->state.ram[ea];
+  if (1 <= dw)
+    {
+      r += (cpu->state.ram[ea + 1] << 8);
+      if (2 <= dw)
+	{
+	  r += cpu->state.ram[ea + 2] << 16;
+	  r += cpu->state.ram[ea + 3] << 24;
+	}
+    }
+  return r;
+}
+
+static void cpu_mem_write (SIM_DESC sd, uint32_t dw, uint32_t ea, uint32_t d)
+{
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+  ea = safe_addr (dw, ea);
+  if (ea & 0x10000)
+    {
+      switch (ea)
+      {
+      case 0x10000:
+	putchar (d & 0xff);
+	break;
+      case 0x1fc80:
+	cpu->state.pm_unlock = (d == 0x1337f7d1);
+	break;
+      case 0x1fc84:
+	cpu->state.pm_addr = d;
+	break;
+      case 0x1fc88:
+	{
+	  address_word cia = CIA_GET (cpu);
+	  sim_core_write_aligned_1 (cpu, cia, read_map, cpu->state.pm_addr + 0, d & 0xff);
+	  sim_core_write_aligned_1 (cpu, cia, read_map, cpu->state.pm_addr + 1, (d >> 8) & 0xff);
+	  sim_core_write_aligned_1 (cpu, cia, read_map, cpu->state.pm_addr + 2, (d >> 16) & 0xff);
+	  sim_core_write_aligned_1 (cpu, cia, read_map, cpu->state.pm_addr + 3, (d >> 24) & 0xff);
+	}
+	break;
+      case 0x10024:
+	break;
+      case 0x1fffc:
+	/* Normal exit */
+	sim_engine_halt (sd, cpu, NULL, cpu->state.pc, sim_exited, cpu->state.regs[0]);
+	break;
+      case 0x1fff8:
+      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;
+	  }
+	  sim_io_printf (sd, "Debug write %08x\n", d);
+	}
+	break;
+      default:
+	sim_io_eprintf (sd, "Unknown IO write %08x to to %08x\n", d, ea);
+      }
+    }
+  else
+    {
+      cpu->state.ram[ea] = d & 0xff;
+      if (1 <= dw)
+	{
+	  cpu->state.ram[ea + 1] = (d >> 8) & 0xff;
+	  if (2 <= dw)
+	    {
+	      cpu->state.ram[ea + 2] = (d >> 16) & 0xff;
+	      cpu->state.ram[ea + 3] = (d >> 24) & 0xff;
+	    }
+	}
+    }
+}
+
+static void ft32_push (SIM_DESC sd, uint32_t v)
+{
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+  cpu->state.regs[31] -= 4;
+  cpu->state.regs[31] &= 0xffff;
+  cpu_mem_write (sd, 2, cpu->state.regs[31], v);
+}
+
+static uint32_t ft32_pop (SIM_DESC sd)
+{
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+  uint32_t r = cpu_mem_read (sd, 2, cpu->state.regs[31]);
+  cpu->state.regs[31] += 4;
+  cpu->state.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;
+}
+
+static
+void step_once (SIM_DESC sd)
+{
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+  address_word cia = CIA_GET (cpu);
+  const char *ram_char = (const char *)cpu->state.ram;
+
+#define ILLEGAL_INSTRUCTION() \
+  sim_engine_halt (sd, cpu, NULL, insnpc, sim_signalled, SIM_SIGILL)
+
+    {
+      uint32_t inst;
+      uint32_t dw;
+      uint32_t cb;
+      uint32_t r_d;
+      uint32_t cr;
+      uint32_t cv;
+      uint32_t bt;
+      uint32_t r_1;
+      uint32_t rimm;
+      uint32_t r_2;
+      uint32_t k20;
+      uint32_t pa;
+      uint32_t aa;
+      uint32_t k16;
+      uint32_t k8;
+      uint32_t al;
+      uint32_t r_1v;
+      uint32_t rimmv;
+      uint32_t bit_pos;
+      uint32_t bit_len;
+      uint32_t upper;
+      uint32_t insnpc;
+
+      if (cpu->state.cycles >= cpu->state.next_tick_cycle)
+	{
+	  cpu->state.next_tick_cycle += 100000;
+	  ft32_push (sd, cpu->state.pc);
+	  cpu->state.pc = 12;  /* interrupt 1 */
+	}
+      inst = cpu_pm_read (sd, 2, cpu->state.pc);
+      cpu->state.cycles += 1;
+
+      /* Handle "call 8" (which is FT32's "break" equivalent) here */
+      if (inst == 0x00340002)
+	{
+	  goto escape;
+	}
+      dw   =              (inst >> FT32_FLD_DW_BIT) & ((1U << FT32_FLD_DW_SIZ) - 1);
+      cb   =              (inst >> FT32_FLD_CB_BIT) & ((1U << FT32_FLD_CB_SIZ) - 1);
+      r_d  =              (inst >> FT32_FLD_R_D_BIT) & ((1U << FT32_FLD_R_D_SIZ) - 1);
+      cr   =              (inst >> FT32_FLD_CR_BIT) & ((1U << FT32_FLD_CR_SIZ) - 1);
+      cv   =              (inst >> FT32_FLD_CV_BIT) & ((1U << FT32_FLD_CV_SIZ) - 1);
+      bt   =              (inst >> FT32_FLD_BT_BIT) & ((1U << FT32_FLD_BT_SIZ) - 1);
+      r_1 =               (inst >> FT32_FLD_R_1_BIT) & ((1U << FT32_FLD_R_1_SIZ) - 1);
+      rimm =              (inst >> FT32_FLD_RIMM_BIT) & ((1U << FT32_FLD_RIMM_SIZ) - 1);
+      r_2  =              (inst >> FT32_FLD_R_2_BIT) & ((1U << FT32_FLD_R_2_SIZ) - 1);
+      k20  = nsigned (20, (inst >> FT32_FLD_K20_BIT) & ((1U << FT32_FLD_K20_SIZ) - 1));
+      pa   =              (inst >> FT32_FLD_PA_BIT) & ((1U << FT32_FLD_PA_SIZ) - 1);
+      aa   =              (inst >> FT32_FLD_AA_BIT) & ((1U << FT32_FLD_AA_SIZ) - 1);
+      k16  =              (inst >> FT32_FLD_K16_BIT) & ((1U << FT32_FLD_K16_SIZ) - 1);
+      k8   = nsigned (8,  (inst >> FT32_FLD_K8_BIT) & ((1U << FT32_FLD_K8_SIZ) - 1));
+      al   =              (inst >> FT32_FLD_AL_BIT) & ((1U << FT32_FLD_AL_SIZ) - 1);
+
+      r_1v = cpu->state.regs[r_1];
+      rimmv = (rimm & 0x400) ? nsigned (10, rimm) : cpu->state.regs[rimm & 0x1f];
+
+      bit_pos = rimmv & 31;
+      bit_len = 0xf & (rimmv >> 5);
+      if (bit_len == 0)
+	bit_len = 16;
+
+      upper = (inst >> 27);
+
+      insnpc = cpu->state.pc;
+      cpu->state.pc += 4;
+      switch (upper)
+      {
+	case FT32_PAT_TOC:
+	case FT32_PAT_TOCI:
+	  {
+	    int takeit = (cr == 3) || ((1 & (cpu->state.regs[28 + cr] >> cb)) == cv);
+	    if (takeit)
+	      {
+		cpu->state.cycles += 1;
+		if (bt)
+		  ft32_push (sd, cpu->state.pc); /* this is a call */
+		if (upper == FT32_PAT_TOC)
+		  cpu->state.pc = pa << 2;
+		else
+		  cpu->state.pc = cpu->state.regs[r_2];
+		if (cpu->state.pc == 0x8)
+		  {
+		    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:
+		sim_io_eprintf (sd, "Unhandled alu %#x\n", al);
+		ILLEGAL_INSTRUCTION ();
+	    }
+	    if (upper == FT32_PAT_ALUOP)
+	      {
+		cpu->state.regs[r_d] = result;
+	      }
+	      else
+	      {
+		uint32_t dwmask = 0;
+		int dwsiz = 0;
+		int zero;
+		int sign;
+		int ahi;
+		int bhi;
+		int overflow;
+		int carry;
+		int bit;
+		uint64_t ra;
+		uint64_t rb;
+		int above;
+		int greater;
+		int greatereq;
+
+		switch (dw)
+		{
+		  case 0: dwsiz = 7;  dwmask = 0xffU; break;
+		  case 1: dwsiz = 15; dwmask = 0xffffU; break;
+		  case 2: dwsiz = 31; dwmask = 0xffffffffU; break;
+		}
+
+		zero = (0 == (result & dwmask));
+		sign = 1 & (result >> dwsiz);
+		ahi = 1 & (r_1v >> dwsiz);
+		bhi = 1 & (rimmv >> dwsiz);
+		overflow = (sign != ahi) & (ahi == !bhi);
+		bit = (dwsiz + 1);
+		ra = r_1v & dwmask;
+		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;
+		}
+		above = (!carry & !zero);
+		greater = (sign == overflow) & !zero;
+		greatereq = (sign == overflow);
+
+		cpu->state.regs[r_d] = (
+		  (above << 6) |
+		  (greater << 5) |
+		  (greatereq << 4) |
+		  (sign << 3) |
+		  (overflow << 2) |
+		  (carry << 1) |
+		  (zero << 0));
+	      }
+	  }
+	  break;
+
+	case FT32_PAT_LDK:
+	  cpu->state.regs[r_d] = k20;
+	  break;
+
+	case FT32_PAT_LPM:
+	  cpu->state.cycles += 1;
+	  cpu->state.regs[r_d] = cpu_pm_read (sd, dw, pa << 2);
+	  break;
+
+	case FT32_PAT_LPMI:
+	  cpu->state.cycles += 1;
+	  cpu->state.regs[r_d] = cpu_pm_read (sd, dw, cpu->state.regs[r_1] + k8);
+	  break;
+
+	case FT32_PAT_STA:
+	  cpu_mem_write (sd, dw, aa, cpu->state.regs[r_d]);
+	  break;
+
+	case FT32_PAT_STI:
+	  cpu_mem_write (sd, dw, cpu->state.regs[r_d] + k8, cpu->state.regs[r_1]);
+	  break;
+
+	case FT32_PAT_LDA:
+	  cpu->state.cycles += 1;
+	  cpu->state.regs[r_d] = cpu_mem_read (sd, dw, aa);
+	  break;
+
+	case FT32_PAT_LDI:
+	  cpu->state.cycles += 1;
+	  cpu->state.regs[r_d] = cpu_mem_read (sd, dw, cpu->state.regs[r_1] + k8);
+	  break;
+
+	case FT32_PAT_EXA:
+	  {
+	    uint32_t tmp;
+	    tmp = cpu_mem_read (sd, dw, aa);
+	    cpu_mem_write (sd, dw, aa, cpu->state.regs[r_d]);
+	    cpu->state.regs[r_d] = tmp;
+	  }
+	  break;
+
+	case FT32_PAT_EXI:
+	  {
+	    uint32_t tmp;
+	    tmp = cpu_mem_read (sd, dw, cpu->state.regs[r_1] + k8);
+	    cpu_mem_write (sd, dw, cpu->state.regs[r_1] + k8, cpu->state.regs[r_d]);
+	    cpu->state.regs[r_d] = tmp;
+	  }
+	  break;
+
+	case FT32_PAT_PUSH:
+	  ft32_push (sd, r_1v);
+	  break;
+
+	case FT32_PAT_LINK:
+	  ft32_push (sd, cpu->state.regs[r_d]);
+	  cpu->state.regs[r_d] = cpu->state.regs[31];
+	  cpu->state.regs[31] -= k16;
+	  cpu->state.regs[31] &= 0xffff;
+	  break;
+
+	case FT32_PAT_UNLINK:
+	  cpu->state.regs[31] = cpu->state.regs[r_d];
+	  cpu->state.regs[31] &= 0xffff;
+	  cpu->state.regs[r_d] = ft32_pop (sd);
+	  break;
+
+	case FT32_PAT_POP:
+	  cpu->state.cycles += 1;
+	  cpu->state.regs[r_d] = ft32_pop (sd);
+	  break;
+
+	case FT32_PAT_RETURN:
+	  cpu->state.pc = ft32_pop (sd);
+	  break;
+
+	case FT32_PAT_FFUOP:
+	  switch (al)
+	  {
+	  case 0x0: cpu->state.regs[r_d] = r_1v / rimmv; break;
+	  case 0x1: cpu->state.regs[r_d] = r_1v % rimmv; break;
+	  case 0x2: cpu->state.regs[r_d] = ft32sdiv (r_1v, rimmv); break;
+	  case 0x3: cpu->state.regs[r_d] = ft32smod (r_1v, rimmv); break;
+
+	  case 0x4: cpu->state.regs[r_d] = strcmp (ram_char + r_1v, ram_char + rimmv); break;
+	  case 0x5: memcpy ((char*)(cpu->state.ram) + cpu->state.regs[r_d], ram_char + r_1v, rimmv); break;
+	  case 0x6: cpu->state.regs[r_d] = strlen (ram_char + r_1v); break;
+	  case 0x7: memset ((char *)(cpu->state.ram) + cpu->state.regs[r_d], r_1v, rimmv); break;
+	  case 0x8: cpu->state.regs[r_d] = r_1v * rimmv; break;
+	  case 0x9: cpu->state.regs[r_d] = ((uint64_t)r_1v * (uint64_t)rimmv) >> 32; break;
+	  case 0xa: {
+	    const char *s = stpcpy ((char*)(cpu->state.ram) + cpu->state.regs[r_d], ram_char + r_1v);
+	    cpu->state.regs[r_d] = (uint32_t)(s - (const char*)(cpu->state.ram + cpu->state.regs[r_d]));
+	    break;
+	  }
+	  case 0xe:
+	    {
+	      uint32_t i;
+	      uint32_t src = cpu->state.regs[r_1];
+	      for (i = 0; i < rimmv; i += (1 << dw))
+		{
+		  cpu_mem_write (sd, dw, cpu->state.regs[r_d], cpu_mem_read (sd, dw, src));
+		  src += (1 << dw);
+		}
+	    }
+	    break;
+	  default:
+	    sim_io_eprintf (sd, "Unhandled ffu %#x at %08x\n", al, insnpc);
+	    ILLEGAL_INSTRUCTION ();
+	  }
+	  break;
+
+	default:
+	  sim_io_eprintf (sd, "Unhandled pattern %d at %08x\n", upper, insnpc);
+	  ILLEGAL_INSTRUCTION ();
+      }
+      cpu->state.num_i++;
+    }
+escape:
+  ;
+}
+
+void
+sim_engine_run (SIM_DESC sd,
+		int next_cpu_nr,  /* ignore  */
+		int nr_cpus,      /* ignore  */
+		int siggnal)      /* ignore  */
+{
+  sim_cpu *cpu;
+
+  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+
+  cpu = STATE_CPU (sd, 0);
+
+  while (1)
+    {
+      step_once (sd);
+      if (sim_events_tick (sd))
+	sim_events_process (sd);
+    }
+}
+
+int
+sim_write (SIM_DESC sd,
+	   SIM_ADDR addr,
+	   const unsigned char *buffer,
+	   int size)
+{
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+
+  if (addr < 0x800000)
+    {
+      sim_core_write_buffer (sd, cpu, 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 (SIM_DESC sd,
+	  SIM_ADDR addr,
+	  unsigned char *buffer,
+	  int size)
+{
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+
+  if (addr < 0x800000)
+    {
+      sim_core_read_buffer (sd, cpu, read_map, buffer, addr, size);
+    }
+    else
+    {
+      int i;
+
+      addr -= 0x800000;
+      for (i = 0; i < size; i++)
+	buffer[i] = cpu_mem_read (sd, 0, addr + i);
+    }
+
+  return size;
+}
+
+static uint32_t*
+ft32_lookup_register (SIM_DESC sd, int nr)
+{
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+
+  /* 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 (nr)
+  {
+  case 0:
+    return &cpu->state.regs[29];
+    break;
+  case 1:
+    return &cpu->state.regs[31];
+    break;
+  case 31:
+    return &cpu->state.regs[30];
+    break;
+  case 32:
+    return &cpu->state.pc;
+    break;
+  default:
+    return &cpu->state.regs[nr - 2];
+  }
+}
+
+int
+sim_store_register (SIM_DESC sd,
+		    int rn,
+		    unsigned char *memory,
+		    int length)
+{
+  if (0 <= rn && rn <= 32)
+    {
+      if (length == 4)
+	*ft32_lookup_register (sd, rn) = ft32_extract_unsigned_integer (memory, 4);
+
+      return 4;
+    }
+  else
+    return 0;
+}
+
+int
+sim_fetch_register (SIM_DESC sd,
+		    int rn,
+		    unsigned char *memory,
+		    int length)
+{
+  if (0 <= rn && rn <= 32)
+    {
+      if (length == 4)
+	ft32_store_unsigned_integer (memory, 4, *ft32_lookup_register (sd, rn));
+
+      return 4;
+    }
+  else
+    return 0;
+}
+
+/* Cover function of sim_state_free to free the cpu buffers as well.  */
+
+static void
+free_state (SIM_DESC sd)
+{
+  if (STATE_MODULES (sd) != NULL)
+    sim_module_uninstall (sd);
+  sim_cpu_free_all (sd);
+  sim_state_free (sd);
+}
+
+SIM_DESC
+sim_open (SIM_OPEN_KIND kind,
+	  host_callback *cb,
+	  struct bfd *abfd,
+	  char **argv)
+{
+  char c;
+  SIM_DESC sd = sim_state_alloc (kind, cb);
+
+  /* The cpu data is kept in a separately allocated chunk of memory.  */
+  if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  /* Allocate external memory if none specified by user.
+     Use address 4 here in case the user wanted address 0 unmapped.  */
+  if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0)
+    {
+      sim_do_command (sd, "memory region 0x00000000,0x4000000");
+      sim_do_command (sd, "memory region 0xE0000000,0x10000");
+    }
+
+  /* Check for/establish the a reference program image.  */
+  if (sim_analyze_program (sd,
+			   (STATE_PROG_ARGV (sd) != NULL
+			    ? *STATE_PROG_ARGV (sd)
+			    : NULL), abfd) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  sd->base.prog_argv = argv + 1;
+
+  /* Configure/verify the target byte order and other runtime
+     configuration options.  */
+  if (sim_config (sd) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  if (sim_post_argv_init (sd) != SIM_RC_OK)
+    {
+      free_state (sd);
+      return 0;
+    }
+
+  return sd;
+}
+
+void
+sim_close (SIM_DESC sd,
+	   int quitting)
+{
+  sim_module_uninstall (sd);
+}
+
+SIM_RC
+sim_create_inferior (SIM_DESC sd,
+		     struct bfd *abfd,
+		     char **argv,
+		     char **env)
+{
+  uint32_t addr;
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+
+  /* Set the PC.  */
+  if (abfd != NULL)
+    addr = bfd_get_start_address (abfd);
+  else
+    addr = 0;
+
+  if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
+    {
+      freeargv (STATE_PROG_ARGV (sd));
+      STATE_PROG_ARGV (sd) = dupargv (argv);
+    }
+  cpu->state.regs[31] = addr;
+  cpu->state.num_i = 0;
+  cpu->state.cycles = 0;
+  cpu->state.next_tick_cycle = 100000;
+
+  return SIM_RC_OK;
+}
diff --git a/sim/ft32/sim-main.h b/sim/ft32/sim-main.h
new file mode 100644
index 0000000..7b011e0
--- /dev/null
+++ b/sim/ft32/sim-main.h
@@ -0,0 +1,63 @@
+/* Simulator for FTDI FT32 processor.
+
+   Copyright (C) 2009-2015 Free Software Foundation, Inc.
+   Contributed by FTDI <support@ftdichip.com>
+
+   This file is part of simulators.
+   
+   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
+
+#include "sim-basics.h"
+
+typedef address_word sim_cia;
+
+#include "sim-base.h"
+#include "bfd.h"
+
+#define PCIDX 17
+
+#include "ft32-sim.h"
+
+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. */
+
+  struct ft32_cpu_state state;
+  unsigned_word registers[33];
+
+  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
-- 
1.7.9.5


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