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


Just pinging on this.

Attached is the FT32 patchset, updated for the current tree.
Also new in this patchset is a testsuite for the FT32 simulator.

--
James Bowman
FTDI Open Source Liaison

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:

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

	* Mainfile.in: Add FT32 entries.
	* configure.tgt: Add FT32 entry.
	* ft32-tdep.c,h: New file, FT32 target-dependent code.

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

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

sim/:
2015-03-10  James Bowman  <james.bowman@ftdichip.com>

	* configure.tgt: Add FT32 entry.

sim/ft32/:
2015-03-10  James Bowman  <james.bowman@ftdichip.com>

	* Makefile.in: New file, FT32 sim Makefile.
	* configure.ac: New file, FT32 sim config.
	* config.in: New file, FT32 sim config.
	* ft32-sim.h: New file, FT32 sim CPU object.
	* interp.c: New file, FT32 simulator.
	* sim-main.h: New file, FT32 simulator wrapper.

sim/testsuite/sim/ft32/
2015-03-10  James Bowman  <james.bowman@ftdichip.com>

	* ChangeLog: New file, FT32 sim testsuite changelog.
	* allinsn.exp: New file, FT32 sim testsuite.
	* basic.s: New file, FT32 sim testsuite basic test.
	* testutils.inc: New file, FT32 sim testsuite utility macros.


From: James Bowman <james.bowman@ftdichip.com>
Date: Tue, 10 Mar 2015 09:29:36 -0700
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                    |    4 +
 sim/ft32/Makefile.in                 |   49 ++
 sim/ft32/config.in                   |  154 ++++++
 sim/ft32/configure.ac                |   15 +
 sim/ft32/ft32-sim.h                  |   39 ++
 sim/ft32/interp.c                    |  831 ++++++++++++++++++++++++++++++++
 sim/ft32/sim-main.h                  |   63 +++
 sim/testsuite/sim/ft32/ChangeLog     |    3 +
 sim/testsuite/sim/ft32/allinsn.exp   |   15 +
 sim/testsuite/sim/ft32/basic.s       |  862 ++++++++++++++++++++++++++++++++++
 sim/testsuite/sim/ft32/testutils.inc |   65 +++
 16 files changed, 2716 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/config.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
 create mode 100644 sim/testsuite/sim/ft32/ChangeLog
 create mode 100644 sim/testsuite/sim/ft32/allinsn.exp
 create mode 100644 sim/testsuite/sim/ft32/basic.s
 create mode 100644 sim/testsuite/sim/ft32/testutils.inc

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8c2a4de..bc9eb79 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -651,6 +651,7 @@ ALL_TARGET_OBS = \
 	dicos-tdep.o \
 	fbsd-tdep.o \
 	frv-linux-tdep.o frv-tdep.o \
+	ft32-tdep.o \
 	h8300-tdep.o \
 	hppabsd-tdep.o hppanbsd-tdep.o hppaobsd-tdep.o \
 	hppa-hpux-tdep.o hppa-linux-tdep.o hppa-tdep.o \
@@ -948,7 +949,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 \
@@ -1652,6 +1653,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..a18db8f
--- /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..026b81f 100644
--- a/sim/configure.tgt
+++ b/sim/configure.tgt
@@ -111,6 +111,10 @@ case "${target}" in
    powerpc*-*-*)
        SIM_ARCH(ppc)
        ;;
+   ft32-*-*)
+       SIM_ARCH(ft32)
+       sim_testsuite=yes
+       ;;
    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/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..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..1603b5c
--- /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
diff --git a/sim/testsuite/sim/ft32/ChangeLog b/sim/testsuite/sim/ft32/ChangeLog
new file mode 100644
index 0000000..592fdd5
--- /dev/null
+++ b/sim/testsuite/sim/ft32/ChangeLog
@@ -0,0 +1,3 @@
+2015-02-23  James Bowman  <james.bowman@ftdichip.com>
+
+	* basic.s, allinsn.exp, testutils.inc: New files.
diff --git a/sim/testsuite/sim/ft32/allinsn.exp b/sim/testsuite/sim/ft32/allinsn.exp
new file mode 100644
index 0000000..730b422
--- /dev/null
+++ b/sim/testsuite/sim/ft32/allinsn.exp
@@ -0,0 +1,15 @@
+# ft32 simulator testsuite
+
+if [istarget ft32-*] {
+    # all machines
+    set all_machs "ft32"
+
+    foreach src [lsort [glob -nocomplain $srcdir/$subdir/*.s]] {
+	# If we're only testing specific files and this isn't one of them,
+	# skip it.
+	if ![runtest_file_p $runtests $src] {
+	    continue
+	}
+	run_sim_test $src $all_machs
+    }
+}
diff --git a/sim/testsuite/sim/ft32/basic.s b/sim/testsuite/sim/ft32/basic.s
new file mode 100644
index 0000000..8b9e9c8
--- /dev/null
+++ b/sim/testsuite/sim/ft32/basic.s
@@ -0,0 +1,862 @@
+# check that basic insns work.
+# mach: ft32
+
+.include "testutils.inc"
+
+	start
+
+        ldk     $r4,10
+        add     $r4,$r4,23
+        EXPECT  $r4,33
+
+# lda, sta
+        .data
+tmp:    .long     0
+        .text
+
+        xor.l     $r0,$r0,$r0
+        EXPECT    $r0,0x00000000
+        xor.l     $r0,$r0,$r0
+        add.l     $r0,$r0,1
+        EXPECT    $r0,0x00000001
+ 
+        ldk.l     $r0,0x4567
+        EXPECT    $r0,0x00004567
+
+        lpm.l     $r0,k_12345678
+        EXPECT    $r0,0x12345678
+
+        sta.l     tmp,$r0
+        lda.l     $r1,tmp
+        EXPECT    $r1,0x12345678
+
+        lda.b     $r1,tmp
+        EXPECT    $r1,0x00000078
+
+        lda.b     $r1,tmp+1
+        EXPECT    $r1,0x00000056
+
+        lda.b     $r1,tmp+2
+        EXPECT    $r1,0x00000034
+
+        lda.b     $r1,tmp+3
+        EXPECT    $r1,0x00000012
+
+        sta.b     tmp+1,$r0
+        lda.l     $r1,tmp+0
+        EXPECT    $r1,0x12347878
+
+# immediate
+        ldk.l     $r1,12
+        add.l     $r1,$r1,4
+        EXPECT    $r1,0x00000010
+        add.l     $r1,$r1,0x1ff
+        EXPECT    $r1,0x0000020f
+        add.l     $r1,$r1,-0x200
+        EXPECT    $r1,0x0000000f
+      
+# addk
+        xor.l     $r1,$r0,$r0
+        add.l     $r2,$r1,127
+        EXPECT    $r2,0x0000007f
+
+        add.l     $r2,$r2,127
+        EXPECT    $r2,0x000000fe
+
+        add.l     $r2,$r2,-127
+        EXPECT    $r2,0x0000007f
+
+        add.l     $r2,$r2,-128
+        EXPECT    $r2,0xffffffff
+
+        add.l     $r2,$r2,1
+        EXPECT    $r2,0x00000000
+
+# mul
+        ldk.l     $r1,100
+        ldk.l     $r2,77
+        mul.l     $r3,$r1,$r2
+        EXPECT    $r3,0x00001e14
+
+        # 0x12345678 ** 2 = 0x14b66dc1df4d840L
+        mul.l     $r3,$r0,$r0
+        EXPECT    $r3,0x1df4d840
+        muluh.l   $r3,$r0,$r0
+        EXPECT    $r3,0x014b66dc
+
+# push and pop
+        push.l    $r0
+        EXPECT    $sp,0x0000fffc
+        ldi.l     $r3,$sp,0
+        EXPECT    $r3,0x12345678
+
+        pop.l     $r4
+        EXPECT    $sp,0x00000000
+        EXPECT    $r4,0x12345678
+
+        ldk.l     $r1,0x1111
+        push.l    $r1
+        ldk.l     $r1,0x2222
+        push.l    $r1
+        ldk.l     $r1,0x3333
+        push.l    $r1
+        ldk.l     $r1,0x4444
+        push.l    $r1
+        EXPECT    $sp,0x0000fff0
+        pop.l     $r1
+        EXPECT    $r1,0x00004444
+        pop.l     $r1
+        EXPECT    $r1,0x00003333
+        pop.l     $r1
+        EXPECT    $r1,0x00002222
+        pop.l     $r1
+        EXPECT    $r1,0x00001111
+
+# push and pop with $sp changes
+        ldk.l     $r1,0xa111
+        push.l    $r1
+        sub.l     $sp,$sp,4
+        ldk.l     $r1,0xa222
+        push.l    $r1
+        add.l     $sp,$sp,-36
+        add.l     $sp,$sp,36
+        pop.l     $r1
+        EXPECT    $r1,0x0000a222
+        add.l     $sp,$sp,4
+        pop.l     $r1
+        EXPECT    $r1,0x0000a111
+
+# sti
+        ldk.l     $r2,80
+        EXPECT    $r2,0x00000050
+        sti.l     $r2,0,$r0
+        lda.l     $r1,80
+        EXPECT    $r1,0x12345678
+
+        ldk.l     $r3,0xF0
+        sti.b     $r2,0,$r3
+        lda.l     $r1,80
+        EXPECT    $r1,0x123456f0
+
+        add.l     $r2,$r2,1
+        sti.l     $r2,0,$r0
+        sti.b     $r2,0,$r3
+        lda.l     $r1,80
+        EXPECT    $r1,0x1234f078
+
+        add.l     $r2,$r2,1
+        sti.l     $r2,0,$r0
+        sti.b     $r2,0,$r3
+        lda.l     $r1,80
+        EXPECT    $r1,0x12f05678
+
+        add.l     $r2,$r2,1
+        sti.l     $r2,0,$r0
+        sti.b     $r2,0,$r3
+        lda.l     $r1,80
+        EXPECT    $r1,0xf0345678
+
+        ldk.l     $r2,80
+        sti.l     $r2,0,$r0
+        ldk.s     $r3,0xbeef
+        sti.s     $r2,0,$r3
+        lda.l     $r1,80
+        EXPECT    $r1,0x1234beef
+        add.l     $r2,$r2,2
+        sti.s     $r2,0,$r3
+        lda.l     $r1,80
+        EXPECT    $r1,0xbeefbeef
+
+# lpmi
+
+        ldk.l     $r1,k_12345678
+        lpmi.l    $r2,$r1,0
+        EXPECT    $r2,0x12345678
+
+        lpmi.b    $r2,$r1,0
+        EXPECT    $r2,0x00000078
+
+        add.l     $r1,$r1,1
+        lpmi.b    $r2,$r1,0
+        EXPECT    $r2,0x00000056
+
+        add.l     $r1,$r1,1
+        lpmi.b    $r2,$r1,0
+        EXPECT    $r2,0x00000034
+
+        add.l     $r1,$r1,1
+        lpmi.b    $r2,$r1,0
+        EXPECT    $r2,0x00000012
+
+        lpmi.l    $r2,$r1,4
+        EXPECT    $r2,0xabcdef01
+
+        lpmi.l    $r2,$r1,-4
+        EXPECT    $r2,0x10111213
+
+        lpmi.b    $r2,$r1,-4
+        EXPECT    $r2,0x00000010
+
+        ldk.l     $r1,k_12345678
+        lpmi.s    $r2,$r1,0
+        EXPECT    $r2,0x00005678
+        lpmi.s    $r2,$r1,2
+        EXPECT    $r2,0x00001234
+        lpmi.b    $r2,$r1,6
+        EXPECT    $r2,0x000000cd
+        lpmi.b    $r2,$r1,7
+        EXPECT    $r2,0x000000ab
+        lpmi.b    $r2,$r1,-1
+        EXPECT    $r2,0x00000010
+        lpmi.s    $r2,$r1,-2
+        EXPECT    $r2,0x00001011
+
+        ldk.l     $r1,k_12345678-127
+        lpmi.b    $r2,$r1,127
+        EXPECT    $r2,0x00000078
+
+        ldk.l     $r1,k_12345678+128
+        lpmi.b    $r2,$r1,-128
+        EXPECT    $r2,0x00000078
+
+# shifts
+
+        lpm.l     $r0,k_12345678
+        ldk.l     $r2,4
+        ashl.l    $r1,$r0,$r2
+        EXPECT    $r1,0x23456780
+        lshr.l    $r1,$r0,$r2
+        EXPECT    $r1,0x01234567
+        ashr.l    $r1,$r0,$r2
+        EXPECT    $r1,0x01234567
+
+        lpm.l     $r0,k_abcdef01
+        ashl.l    $r1,$r0,$r2
+        EXPECT    $r1,0xbcdef010
+        lshr.l    $r1,$r0,$r2
+        EXPECT    $r1,0x0abcdef0
+        ashr.l    $r1,$r0,$r2
+        EXPECT    $r1,0xfabcdef0
+
+# rotate right
+      
+        lpm.l     $r0,k_12345678
+        ror.l     $r1,$r0,0
+        EXPECT    $r1,0x12345678
+        ror.l     $r1,$r0,12
+        EXPECT    $r1,0x67812345
+        ror.l     $r1,$r0,-4
+        EXPECT    $r1,0x23456781
+
+# jmpx
+        ldk       $r28,0xaaaaa
+        jmpx      0,$r28,1,failcase
+        jmpx      1,$r28,0,failcase
+        jmpx      2,$r28,1,failcase
+        jmpx      3,$r28,0,failcase
+        jmpx      4,$r28,1,failcase
+        jmpx      5,$r28,0,failcase
+        jmpx      6,$r28,1,failcase
+        jmpx      7,$r28,0,failcase
+        jmpx      8,$r28,1,failcase
+        jmpx      9,$r28,0,failcase
+        jmpx      10,$r28,1,failcase
+        jmpx      11,$r28,0,failcase
+        jmpx      12,$r28,1,failcase
+        jmpx      13,$r28,0,failcase
+        jmpx      14,$r28,1,failcase
+        jmpx      15,$r28,0,failcase
+        jmpx      16,$r28,1,failcase
+        jmpx      17,$r28,0,failcase
+        jmpx      18,$r28,1,failcase
+        jmpx      19,$r28,0,failcase
+
+        move      $r29,$r28
+        ldk       $r28,0
+        jmpx      0,$r29,1,failcase
+        jmpx      1,$r29,0,failcase
+        jmpx      2,$r29,1,failcase
+        jmpx      3,$r29,0,failcase
+        jmpx      4,$r29,1,failcase
+        jmpx      5,$r29,0,failcase
+        jmpx      6,$r29,1,failcase
+        jmpx      7,$r29,0,failcase
+        jmpx      8,$r29,1,failcase
+        jmpx      9,$r29,0,failcase
+        jmpx      10,$r29,1,failcase
+        jmpx      11,$r29,0,failcase
+        jmpx      12,$r29,1,failcase
+        jmpx      13,$r29,0,failcase
+        jmpx      14,$r29,1,failcase
+        jmpx      15,$r29,0,failcase
+        jmpx      16,$r29,1,failcase
+        jmpx      17,$r29,0,failcase
+        jmpx      18,$r29,1,failcase
+        jmpx      19,$r29,0,failcase
+
+        move      $r30,$r29
+        ldk       $r29,0
+        jmpx      0,$r30,1,failcase
+        jmpx      1,$r30,0,failcase
+        jmpx      2,$r30,1,failcase
+        jmpx      3,$r30,0,failcase
+        jmpx      4,$r30,1,failcase
+        jmpx      5,$r30,0,failcase
+        jmpx      6,$r30,1,failcase
+        jmpx      7,$r30,0,failcase
+        jmpx      8,$r30,1,failcase
+        jmpx      9,$r30,0,failcase
+        jmpx      10,$r30,1,failcase
+        jmpx      11,$r30,0,failcase
+        jmpx      12,$r30,1,failcase
+        jmpx      13,$r30,0,failcase
+        jmpx      14,$r30,1,failcase
+        jmpx      15,$r30,0,failcase
+        jmpx      16,$r30,1,failcase
+        jmpx      17,$r30,0,failcase
+        jmpx      18,$r30,1,failcase
+        jmpx      19,$r30,0,failcase
+
+# callx
+        ldk       $r30,0xaaaaa
+        callx     0,$r30,0,skip1
+        jmp       failcase
+        callx     1,$r30,1,skip1
+        jmp       failcase
+        callx     2,$r30,0,skip1
+        jmp       failcase
+        callx     3,$r30,1,skip1
+        jmp       failcase
+
+        callx     0,$r30,1,skip1
+        ldk       $r30,0x123
+        EXPECT    $r30,0x123
+
+#define BIT(N,M)  ((((N) & 15) << 5) | (M))
+# bextu
+        bextu.l   $r1,$r0,(0<<5)|0
+        EXPECT    $r1,0x00005678
+        bextu.l   $r1,$r0,(4<<5)|0
+        EXPECT    $r1,0x00000008
+        bextu.l   $r1,$r0,(4<<5)|4
+        EXPECT    $r1,0x00000007
+        bextu.l   $r1,$r0,(4<<5)|28
+        EXPECT    $r1,0x00000001
+        bextu.l   $r1,$r0,(8<<5)|16
+        EXPECT    $r1,0x00000034
+        ldk.l     $r2,-1
+        bextu.l   $r1,$r2,(6<<5)|(3)
+        EXPECT    $r1,0x0000003f
+
+# bexts
+        bexts.l   $r1,$r0,(8<<5)|0
+        EXPECT    $r1,0x00000078
+        bexts.l   $r1,$r0,(0<<5)|16
+        EXPECT    $r1,0x00001234
+        bexts.l   $r1,$r0,(4<<5)|0
+        EXPECT    $r1,0xfffffff8
+        # extract the '5' digit in widths 4-1
+        bexts.l   $r1,$r0,(4<<5)|12
+        EXPECT    $r1,0x00000005
+        bexts.l   $r1,$r0,(3<<5)|12
+        EXPECT    $r1,0xfffffffd
+        bexts.l   $r1,$r0,(2<<5)|12
+        EXPECT    $r1,0x00000001
+        bexts.l   $r1,$r0,(1<<5)|12
+        EXPECT    $r1,0xffffffff
+
+# btst
+        # low four bits should be 0,0,0,1
+        btst.l    $r0,(1<<5)|0
+        jmpc      nz,failcase
+        btst.l    $r0,(1<<5)|1
+        jmpc      nz,failcase
+        btst.l    $r0,(1<<5)|2
+        jmpc      nz,failcase
+        btst.l    $r0,(1<<5)|3
+        jmpc      z,failcase
+
+        # the 6 bit field starting at position 24 is positive
+        btst.l    $r0,(6<<5)|24
+        jmpc      s,failcase
+        # the 5 bit field starting at position 24 is negative
+        btst.l    $r0,(5<<5)|24
+        jmpc      ns,failcase
+
+        EXPECT    $r0,0x12345678
+
+# bins
+        bins.l    $r1,$r0,(8 << 5) | (0)
+        EXPECT    $r1,0x12345600
+
+        bins.l    $r1,$r0,(0 << 5) | (8)
+        EXPECT    $r1,0x12000078
+
+        ldk.l     $r1,(0xff << 10) | (8 << 5) | (8)
+        bins.l    $r1,$r0,$r1
+        EXPECT    $r1,0x1234ff78
+
+        call      litr1
+        .long     (0x8dd1 << 10) | (0 << 5) | (0)
+        bins.l    $r1,$r0,$r1
+        EXPECT    $r1,0x12348dd1
+
+        call      litr1
+        .long     (0x8dd1 << 10) | (0 << 5) | (16)
+        bins.l    $r1,$r0,$r1
+        EXPECT    $r1,0x8dd15678
+
+        ldk.l     $r1,(0xde << 10) | (8 << 5) | (0)
+        bins.l    $r1,$r0,$r1
+        EXPECT    $r1,0x123456de
+
+# ldl
+        ldk.l     $r0,0
+        ldl.l     $r3,$r0,0
+        EXPECT    $r3,0x00000000
+        ldk.l     $r0,-1
+        ldl.l     $r3,$r0,-1
+        EXPECT    $r3,0xffffffff
+        ldk.l     $r0,(0x12345678 >> 10)
+        ldl.l     $r3,$r0,(0x12345678 & 0x3ff)
+        EXPECT    $r3,0x12345678
+        ldk.l     $r0,(0xe2345678 >> 10)
+        ldl.l     $r3,$r0,(0xe2345678 & 0x3ff)
+        EXPECT    $r3,0xe2345678
+
+# flip
+        ldk.l     $r0,0x0000001
+        flip.l    $r1,$r0,0
+        EXPECT    $r1,0x00000001
+
+        lpm.l     $r0,k_12345678
+        flip.l    $r1,$r0,0
+        EXPECT    $r1,0x12345678
+        flip.l    $r1,$r0,24
+        EXPECT    $r1,0x78563412
+        flip.l    $r1,$r0,31
+        EXPECT    $r1,0x1e6a2c48
+
+# stack push pop
+
+        EXPECT    $sp,0x00000000
+        ldk.l     $r6,0x6666
+        push.l    $r6
+        or.l      $r0,$r0,$r0      # xxx
+        EXPECT    $sp,0x0000fffc
+        ldi.l     $r1,$sp,0
+        EXPECT    $r1,0x00006666
+        pop.l     $r1
+        EXPECT    $r1,0x00006666
+        EXPECT    $sp,0x00000000
+
+# call/return
+        call      fowia
+        push.l    $r1
+        call      fowia
+        pop.l     $r2
+        sub.l     $r1,$r1,$r2
+        EXPECT    $r1,0x00000008
+
+# add,carry
+
+        ldk.l     $r0,0
+        ldk.l     $r1,0
+        call      add64
+        EXPECT    $r1,0x00000000
+        EXPECT    $r0,0x00000000
+
+        lpm.l     $r0,k_abcdef01
+        lpm.l     $r1,k_abcdef01
+        call      add64
+        EXPECT    $r1,0x00000001
+        EXPECT    $r0,0x579bde02
+
+        ldk.l     $r0,4
+        ldk.l     $r1,-5
+        call      add64
+        EXPECT    $r1,0x00000000
+        EXPECT    $r0,0xffffffff
+
+        ldk.l     $r0,5
+        ldk.l     $r1,-5
+        call      add64
+        EXPECT    $r1,0x00000001
+        EXPECT    $r0,0x00000000
+
+        lpm.l     $r0,k_12345678
+        ldk.l     $r1,-1
+        call      add64
+        EXPECT    $r1,0x00000001
+        EXPECT    $r0,0x12345677
+
+        ldk.l     $r0,-1
+        ldk.l     $r1,-1
+        call      add64
+        EXPECT    $r1,0x00000001
+        EXPECT    $r0,0xfffffffe
+
+# inline literal
+        call      lit
+        .long     0xdecafbad
+        EXPECT    $r0,0xdecafbad
+
+        ldk.l     $r1,0xee
+        call      lit
+        ldk.l     $r1,0xfe
+        EXPECT    $r1,0x000000ee
+
+        call      lit
+        .long     0x01020304
+        EXPECT    $r0,0x01020304
+
+        call      lit
+        .long     lit
+        calli     $r0
+        .long     0xffaa55aa
+        EXPECT    $r0,0xffaa55aa
+
+# comparisons
+        ldk.l     $r0,-100
+        ldk.l     $r1,100
+        cmp.l     $r0,$r1
+
+        ldk.l     $r2,0
+        jmpc      lt,.c1
+        ldk.l     $r2,1
+.c1:
+        EXPECT    $r2,0x00000000
+
+        ldk.l     $r2,0
+        jmpc      gt,.c2
+        ldk.l     $r2,1
+.c2:
+        EXPECT    $r2,0x00000001
+
+        ldk.l     $r2,0
+        jmpc      a,.c3
+        ldk.l     $r2,1
+.c3:
+        EXPECT    $r2,0x00000000
+
+        ldk.l     $r2,0
+        jmpc      b,.c4
+        ldk.l     $r2,1
+.c4:
+        EXPECT    $r2,0x00000001
+
+        ldk.l     $r2,0
+        jmpc      be,.c5
+        ldk.l     $r2,1
+.c5:
+        EXPECT    $r2,0x00000001
+
+# 8-bit comparisons
+        ldk.l     $r0,0x8fe
+        ldk.l     $r1,0x708
+        cmp.b     $r0,$r1
+
+        ldk.l     $r2,0
+        jmpc      lt,.8c1
+        ldk.l     $r2,1
+.8c1:
+        EXPECT    $r2,0x00000000
+
+        ldk.l     $r2,0
+        jmpc      gt,.8c2
+        ldk.l     $r2,1
+.8c2:
+        EXPECT    $r2,0x00000001
+
+        ldk.l     $r2,0
+        jmpc      a,.8c3
+        ldk.l     $r2,1
+.8c3:
+        EXPECT    $r2,0x00000000
+
+        ldk.l     $r2,0
+        jmpc      b,.8c4
+        ldk.l     $r2,1
+.8c4:
+        EXPECT    $r2,0x00000001
+
+        ldk.l     $r2,0
+        jmpc      be,.8c5
+        ldk.l     $r2,1
+.8c5:
+        EXPECT    $r2,0x00000001
+
+        ldk.l     $r0,0x8aa
+        ldk.l     $r1,0x7aa
+        cmp.b     $r0,$r1
+
+        ldk.l     $r2,0
+        jmpc      z,.8c6
+        ldk.l     $r2,1
+.8c6:
+        EXPECT    $r2,0x00000000
+
+        ldk.b     $r0,1
+        ldk.b     $r2,0xe0
+        cmp.b     $r2,0x1c0
+        jmpc      a,.8c7
+        ldk.b     $r0,0
+.8c7:
+        EXPECT    $r0,0x00000001
+
+# conditional call
+        cmp.l     $r0,$r0
+        callc     z,lit
+        .long     0xccddeeff
+        callc     nz,zr0
+        EXPECT    $r0,0xccddeeff
+
+# modify return address
+        ldk.l     $r0,0x66
+        call      skip1
+        ldk.l     $r0,0xAA
+        EXPECT    $r0,0x00000066
+
+        ldk.l     $r0,0x77
+        call      skip2
+        ldk.l     $r0,0xBB
+        EXPECT    $r0,0x00000077
+
+# simple recursive function
+        ldk.l     $r0,1
+        call      factorial
+        EXPECT    $r0,0x00000001
+        ldk.l     $r0,2
+        call      factorial
+        EXPECT    $r0,0x00000002
+        ldk.l     $r0,3
+        call      factorial
+        EXPECT    $r0,0x00000006
+        ldk.l     $r0,4
+        call      factorial
+        EXPECT    $r0,0x00000018
+        ldk.l     $r0,5
+        call      factorial
+        EXPECT    $r0,0x00000078
+        ldk.l     $r0,6
+        call      factorial
+        EXPECT    $r0,0x000002d0
+        ldk.l     $r0,7
+        call      factorial
+        EXPECT    $r0,0x000013b0
+        ldk.l     $r0,12
+        call      factorial
+        EXPECT    $r0,0x1c8cfc00
+
+# read sp after a call
+        call      nullfunc
+        EXPECT    $sp,0x00000000 
+
+# CALLI->RETURN
+        ldk.l     $r4,nullfunc
+        calli     $r4
+        EXPECT    $sp,0x00000000 
+
+# Link/unlink
+        ldk.l     $r14,0x17566
+
+        link      $r14,48
+        EXPECT    $r14,0x0000fffc
+        sub.l     $sp,$sp,200
+        unlink    $r14
+        EXPECT    $r14,0x00017566
+
+# LINK->UNLINK
+        link      $r14,48
+        unlink    $r14
+        EXPECT    $r14,0x00017566
+
+# LINK->JUMPI
+        ldk.l     $r3,.here
+        link      $r14,48
+        jmpi      $r3
+        jmp       failcase
+.here:
+        unlink    $r14
+        EXPECT    $r14,0x00017566
+
+# LINK->RETURN
+# (This is a nonsense combination, but can still exericse it by
+# using a negative parameter for the link.  "link $r14,-4" leaves
+# $sp exactly unchanged.)
+        ldk.l     $r0,.returnhere
+        push.l    $r0
+        link      $r14,0xfffc
+        return
+.returnhere:
+        EXPECT    $sp,0x00000000 
+
+# LPMI->CALLI
+        ldk.l     $r0,k_abcdef01
+        ldk.l     $r1,increment
+        lpmi.l    $r0,$r0,0
+        calli     $r1
+        EXPECT    $r0,0xabcdef02
+
+# STRLen
+        lpm.l     $r4,str3
+        sta.l     tmp,$r4
+        ldk.l     $r0,tmp
+        strlen.b  $r1,$r0
+        EXPECT    $r1,0x00000003
+        strlen.s  $r1,$r0
+        EXPECT    $r1,0x00000003
+        strlen.l  $r1,$r0
+        EXPECT    $r1,0x00000003
+
+        ldk.l     $r4,0
+        sta.b     4,$r4
+        strlen.l  $r1,$r0
+        EXPECT    $r1,0x00000000
+
+        ldk.l     $r4,-1
+        sta.l     4,$r4
+        lpm.l     $r4,str3
+        sta.l     8,$r4
+        strlen.l  $r1,$r0
+        EXPECT    $r1,0x00000007
+
+# MEMSet
+        ldk.l     $r0,4
+        ldk.l     $r1,0xaa
+        memset.s  $r0,$r1,8
+        ldk.l     $r1,0x55
+        memset.b  $r0,$r1,5
+        lda.l     $r0,4
+        EXPECT    $r0,0x55555555
+        lda.l     $r0,8
+        EXPECT    $r0,0xaaaaaa55
+
+# first cycle after mispredict
+        ldk.l     $r0,3
+        cmp.l     $r0,$r0
+        jmpc      nz,failcase
+        add.l     $r0,$r0,7
+        EXPECT    $r0,0x0000000a 
+        jmpc      nz,failcase
+        push.l    $r0
+        EXPECT    $sp,0x0000fffc 
+        pop.l     $r0
+
+# $sp access after stall
+        lpm.l     $r13,0
+        push.l    $r0
+        EXPECT    $sp,0x0000fffc
+        pop.l     $r0
+
+        push.l    $r0
+        add.l     $sp,$sp,-484
+        EXPECT    $sp,0x0000fe18
+        EXPECT    $sp,0x0000fe18
+        EXPECT    $sp,0x0000fe18
+        add.l     $sp,$sp,484
+        EXPECT    $sp,0x0000fffc
+        pop.l     $r0
+
+# atomic exchange
+        lpm.l     $r0,k_12345678
+        lpm.l     $r1,k_abcdef01
+        sta.l     100,$r1
+        exa.l     $r0,100
+        EXPECT    $r0,0xabcdef01
+        lda.l     $r0,100
+        EXPECT    $r0,0x12345678
+
+        lpm.l     $r0,k_12345678
+        lpm.l     $r1,k_abcdef01
+        sta.l     144,$r1
+        ldk.l     $r7,20
+        exi.l     $r0,$r7,124
+        EXPECT    $r0,0xabcdef01
+        lda.l     $r0,144
+        EXPECT    $r0,0x12345678
+
+        lpm.l     $r0,k_12345678
+        lpm.l     $r1,k_abcdef01
+        push      $r1
+        exi.l     $r0,$sp,0
+        EXPECT    $r0,0xabcdef01
+        pop.l     $r0
+        EXPECT    $r0,0x12345678
+
+# final stack check
+        EXPECT    $sp,0x00000000
+
+        PASS
+
+# --------------------------------------------------
+
+skip1:          # skip the instruction after the call
+        pop.l     $r1
+        add.l     $r1,$r1,4
+        push.l    $r1
+        return
+
+skipparent:     # skip the instruction after the caller's call
+        ldi.l     $r1,$sp,4
+        add.l     $r1,$r1,4
+        sti.l     $sp,4,$r1
+        return
+skip2:
+        call      skipparent
+        return
+
+add64:
+        addcc.l   $r0,$r1
+        add.l     $r0,$r0,$r1
+        ldk.l     $r1,0
+        jmpc      nc,.done
+        ldk.l     $r1,1
+.done:
+        return
+
+fowia:  # find out where I'm at
+        ldi.l     $r1,$sp,0
+        return
+
+lit:    # load literal to $r0
+        pop.l     $r14
+        lpmi.l    $r0,$r14,0
+        add.l     $r14,$r14,4
+        jmpi      $r14
+zr0:
+        ldk.l     $r0,0
+        return
+litr1:
+        ldi.l     $r1,$sp,0
+        add.l     $r1,$r1,4
+        sti.l     $sp,0,$r1
+        lpmi.l    $r1,$r1,-4
+        return
+
+factorial:
+        ldk.l     $r1,1
+        cmp.l     $r0,$r1
+        jmpc      z,.factdone
+        push.l    $r0
+        add.l     $r0,$r0,-1
+        call      factorial
+        pop.l     $r1
+        mul.l     $r0,$r0,$r1
+.factdone:
+        return
+
+nullfunc:
+        return
+
+increment:
+        add.l     $r0,$r0,1
+        return
+
+        .long   0x10111213
+k_12345678:
+        .long   0x12345678
+k_abcdef01:
+        .long   0xabcdef01
+str3:
+        .string   "abc"
diff --git a/sim/testsuite/sim/ft32/testutils.inc b/sim/testsuite/sim/ft32/testutils.inc
new file mode 100644
index 0000000..af0997b
--- /dev/null
+++ b/sim/testsuite/sim/ft32/testutils.inc
@@ -0,0 +1,65 @@
+
+# Write ch to the standard output
+        .macro outch  ch
+        ldk   $r0,\ch
+        sta   0x10000,$r0
+        .endm
+
+# End the test with return code c
+        .macro  exit c
+        ldk   $r0,\c
+        sta   0x1fffc,$r0
+        .endm
+
+# All assembler tests should start with this macro "start"
+	.macro start
+	.text
+
+        jmp     __start
+        jmp     __start
+        reti
+
+        .data
+ccsave: .long   0
+        .text
+
+# Fiddling to load $cc from the following word in program memory
+loadcc:
+        exi     $r29,$sp,0
+        lpmi    $cc,$r29,0
+        add     $r29,$r29,4
+        exi     $r29,$sp,0
+        return
+
+failcase:
+        outch 'f'
+        outch 'a'
+        outch 'i'
+        outch 'l'
+        outch '\n'
+        exit  1
+
+__start:
+
+	.endm
+
+# At the end of the test, the code should reach this macro PASS
+        .macro PASS
+        outch 'p'
+        outch 'a'
+        outch 's'
+        outch 's'
+        outch '\n'
+        exit  0
+        .endm
+
+# Confirm that reg has value, and fail immediately if not
+# Preserves all registers
+        .macro EXPECT reg,value
+        sta   ccsave,$cc
+        call  loadcc
+        .long \value
+        cmp   \reg,$cc
+        jmpc  nz,failcase
+        lda   $cc,ccsave
+        .endm
-- 
1.7.9.5


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