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


i moved the sim header to the sim patch and pushed that first, then the gdb one.  
i don't like having commits that are not bisectable, nor having to squash large 
ones to avoid.

see attached patches for what went in.

thanks for the port!
-mike
From f46e4eb78ba55e8bf8dedd98d7fe354729181710 Mon Sep 17 00:00:00 2001
From: James Bowman <james.bowman@ftdichip.com>
Date: Mon, 23 Mar 2015 19:20:59 +0000
Subject: [PATCH 1/2] sim: ft32: new port

FT32 is a new high performance 32-bit RISC core developed by FTDI for
embedded applications.
---
 include/gdb/ChangeLog                |     4 +
 include/gdb/sim-ft32.h               |    35 +
 sim/ChangeLog                        |     5 +
 sim/configure                        |     9 +
 sim/configure.tgt                    |     4 +
 sim/ft32/ChangeLog                   |     8 +
 sim/ft32/Makefile.in                 |    48 +
 sim/ft32/aclocal.m4                  |   129 +
 sim/ft32/config.in                   |   163 +
 sim/ft32/configure                   | 15740 +++++++++++++++++++++++++++++++++
 sim/ft32/configure.ac                |    15 +
 sim/ft32/ft32-sim.h                  |    43 +
 sim/ft32/interp.c                    |   913 ++
 sim/ft32/sim-main.h                  |    58 +
 sim/testsuite/ChangeLog              |     4 +
 sim/testsuite/configure              |     4 +
 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 +
 20 files changed, 18127 insertions(+)
 create mode 100644 include/gdb/sim-ft32.h
 create mode 100644 sim/ft32/ChangeLog
 create mode 100644 sim/ft32/Makefile.in
 create mode 100644 sim/ft32/aclocal.m4
 create mode 100644 sim/ft32/config.in
 create mode 100755 sim/ft32/configure
 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/include/gdb/ChangeLog b/include/gdb/ChangeLog
index 88bd15c..d36d6b8 100644
--- a/include/gdb/ChangeLog
+++ b/include/gdb/ChangeLog
@@ -1,3 +1,7 @@
+2015-03-28  James Bowman  <james.bowman@ftdichip.com>
+
+	* sim-ft32.h: New file.
+
 2015-05-15  Mike Frysinger  <vapier@gentoo.org>
 
 	* remote-sim.h (struct host_callback_struct): Define.
diff --git a/include/gdb/sim-ft32.h b/include/gdb/sim-ft32.h
new file mode 100644
index 0000000..73c4f63
--- /dev/null
+++ b/include/gdb/sim-ft32.h
@@ -0,0 +1,35 @@
+/* This file defines the interface between the FT32 simulator and GDB.
+
+   Copyright (C) 2005-2015 Free Software Foundation, Inc.
+   Contributed by FTDI.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* Register numbers of various important registers.  */
+enum ft32_regnum
+{
+  FT32_FP_REGNUM,               /* Address of executing stack frame.  */
+  FT32_SP_REGNUM,               /* Address of top of stack.  */
+  FT32_R0_REGNUM,
+  FT32_R1_REGNUM,
+  FT32_CC_REGNUM = 31,
+  FT32_PC_REGNUM = 32           /* Program counter.  */
+};
+
+/* Number of machine registers.  */
+#define FT32_NUM_REGS 33        /* 32 real registers + PC */
+
diff --git a/sim/ChangeLog b/sim/ChangeLog
index 37ee409..8b7fcb3 100644
--- a/sim/ChangeLog
+++ b/sim/ChangeLog
@@ -1,3 +1,8 @@
+2015-03-28  James Bowman  <james.bowman@ftdichip.com>
+
+	* configure.tgt: Add FT32 entry.
+	* configure: Regenerate.
+
 2015-03-16  Mike Frysinger  <vapier@gentoo.org>
 
 	* .gitignore: Delete tconfig.h.
diff --git a/sim/configure b/sim/configure
index 36d356e..740042a 100755
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/ChangeLog b/sim/ft32/ChangeLog
new file mode 100644
index 0000000..1479658
--- /dev/null
+++ b/sim/ft32/ChangeLog
@@ -0,0 +1,8 @@
+2015-03-28  James Bowman  <james.bowman@ftdichip.com>
+
+	* Makefile.in: New file, FT32 sim Makefile.
+	* configure.ac: 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.
+	* aclocal.m4, config.in, configure: Regenerate.
diff --git a/sim/ft32/Makefile.in b/sim/ft32/Makefile.in
new file mode 100644
index 0000000..f16039a
--- /dev/null
+++ b/sim/ft32/Makefile.in
@@ -0,0 +1,48 @@
+#    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-reg.o	\
+	sim-resume.o	\
+	sim-signal.o	\
+	sim-stop.o	\
+	sim-trace.o	\
+	sim-utils.o	\
+	$(SIM_EXTRA_OBJS)
+
+## COMMON_POST_CONFIG_FRAG
diff --git a/sim/ft32/aclocal.m4 b/sim/ft32/aclocal.m4
new file mode 100644
index 0000000..517bc73
diff --git a/sim/ft32/config.in b/sim/ft32/config.in
new file mode 100644
index 0000000..6003e58
diff --git a/sim/ft32/configure b/sim/ft32/configure
new file mode 100755
index 0000000..1d18263
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..1d664ba
--- /dev/null
+++ b/sim/ft32/ft32-sim.h
@@ -0,0 +1,43 @@
+/* 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>
+
+#include "gdb/sim-ft32.h"
+
+#define FT32_HARD_FP 29
+#define FT32_HARD_CC 30
+#define FT32_HARD_SP 31
+
+struct ft32_cpu_state {
+  uint32_t regs[32];
+  uint32_t pc;
+  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..931ad2b
--- /dev/null
+++ b/sim/ft32/interp.c
@@ -0,0 +1,913 @@
+/* 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-options.h"
+
+#include "opcode/ft32.h"
+
+/*
+ * FT32 is a Harvard architecture: RAM and code occupy
+ * different address spaces.
+ *
+ * sim and gdb model FT32 memory by adding 0x800000 to RAM
+ * addresses. This means that sim/gdb can treat all addresses
+ * similarly.
+ *
+ * The address space looks like:
+ *
+ *    00000   start of code memory
+ *    3ffff   end of code memory
+ *   800000   start of RAM
+ *   80ffff   end of RAM
+ */
+
+#define RAM_BIAS  0x800000  /* Bias added to RAM addresses.  */
+
+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;
+    }
+}
+
+/*
+ * Align EA according to its size DW.
+ * The FT32 ignores the low bit of a 16-bit addresss,
+ * and the low two bits of a 32-bit address.
+ */
+static uint32_t ft32_align (uint32_t dw, uint32_t ea)
+{
+  switch (dw)
+    {
+    case 1:
+      ea &= ~1;
+      break;
+    case 2:
+      ea &= ~3;
+      break;
+    default:
+      break;
+    }
+  return ea;
+}
+
+/* Read an item from memory address EA, sized DW.  */
+static uint32_t
+ft32_read_item (SIM_DESC sd, int dw, uint32_t ea)
+{
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+  address_word cia = CIA_GET (cpu);
+  uint8_t byte[4];
+  uint32_t r;
+
+  ea = ft32_align (dw, ea);
+
+  switch (dw) {
+    case 0:
+      return sim_core_read_aligned_1 (cpu, cia, read_map, ea);
+    case 1:
+      return sim_core_read_aligned_2 (cpu, cia, read_map, ea);
+    case 2:
+      return sim_core_read_aligned_4 (cpu, cia, read_map, ea);
+    default:
+      abort ();
+  }
+}
+
+/* Write item V to memory address EA, sized DW.  */
+static void
+ft32_write_item (SIM_DESC sd, int dw, uint32_t ea, uint32_t v)
+{
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+  address_word cia = CIA_GET (cpu);
+  uint8_t byte[4];
+
+  ea = ft32_align (dw, ea);
+
+  switch (dw) {
+    case 0:
+      sim_core_write_aligned_1 (cpu, cia, write_map, ea, v);
+      break;
+    case 1:
+      sim_core_write_aligned_2 (cpu, cia, write_map, ea, v);
+      break;
+    case 2:
+      sim_core_write_aligned_4 (cpu, cia, write_map, ea, v);
+      break;
+    default:
+      abort ();
+  }
+}
+
+#define ILLEGAL() \
+  sim_engine_halt (sd, cpu, NULL, insnpc, sim_signalled, SIM_SIGILL)
+
+static uint32_t cpu_mem_read (SIM_DESC sd, uint32_t dw, uint32_t ea)
+{
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+  uint32_t insnpc = cpu->state.pc;
+  uint32_t r;
+  uint8_t byte[4];
+
+  ea &= 0x1ffff;
+  if (ea & ~0xffff)
+    {
+      /* Simulate some IO devices */
+      switch (ea)
+	{
+	case 0x1fff4:
+	  /* Read the simulator cycle timer.  */
+	  return cpu->state.cycles / 100;
+	default:
+	  sim_io_eprintf (sd, "Illegal IO read address %08x, pc %#x\n",
+			  ea, insnpc);
+	  ILLEGAL ();
+	}
+    }
+  return ft32_read_item (sd, dw, RAM_BIAS + ea);
+}
+
+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 &= 0x1ffff;
+  if (ea & 0x10000)
+    {
+      /* Simulate some IO devices */
+      switch (ea)
+	{
+	case 0x10000:
+	  /* Console output */
+	  putchar (d & 0xff);
+	  break;
+	case 0x1fc80:
+	  /* Unlock the PM write port */
+	  cpu->state.pm_unlock = (d == 0x1337f7d1);
+	  break;
+	case 0x1fc84:
+	  /* Set the PM write address register */
+	  cpu->state.pm_addr = d;
+	  break;
+	case 0x1fc88:
+	  /* Write to PM */
+	  ft32_write_item (sd, dw, cpu->state.pm_addr, d);
+	  break;
+	case 0x1fffc:
+	  /* Normal exit.  */
+	  sim_engine_halt (sd, cpu, NULL, cpu->state.pc, sim_exited, cpu->state.regs[0]);
+	  break;
+	case 0x1fff8:
+	  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
+    ft32_write_item (sd, dw, RAM_BIAS + ea, d);
+}
+
+#define GET_BYTE(ea)    cpu_mem_read (sd, 0, (ea))
+#define PUT_BYTE(ea, d) cpu_mem_write (sd, 0, (ea), (d))
+
+/* LSBS (n) is a mask of the least significant N bits.  */
+#define LSBS(n) ((1U << (n)) - 1)
+
+static void ft32_push (SIM_DESC sd, uint32_t v)
+{
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+  cpu->state.regs[FT32_HARD_SP] -= 4;
+  cpu->state.regs[FT32_HARD_SP] &= 0xffff;
+  cpu_mem_write (sd, 2, cpu->state.regs[FT32_HARD_SP], 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[FT32_HARD_SP]);
+  cpu->state.regs[FT32_HARD_SP] += 4;
+  cpu->state.regs[FT32_HARD_SP] &= 0xffff;
+  return r;
+}
+
+/* Extract the low SIZ bits of N as an unsigned number.  */
+static int nunsigned (int siz, int n)
+{
+  return n & LSBS (siz);
+}
+
+/* Extract the low SIZ bits of N as a signed number.  */
+static int nsigned (int siz, int n)
+{
+  int shift = (sizeof (int) * 8) - siz;
+  return (n << shift) >> shift;
+}
+
+/* Signed division N / D, matching hw behavior for (MIN_INT, -1).  */
+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);
+}
+
+/* Signed modulus N % D, matching hw behavior for (MIN_INT, -1).  */
+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);
+}
+
+/* Circular rotate right N by B bits.  */
+static uint32_t ror (uint32_t n, uint32_t b)
+{
+  b &= 31;
+  return (n >> b) | (n << (32 - b));
+}
+
+/* Implement the BINS machine instruction.
+   See FT32 Programmer's Reference for details.  */
+static uint32_t bins (uint32_t d, uint32_t f, uint32_t len, uint32_t pos)
+{
+  uint32_t bitmask = LSBS (len) << pos;
+  return (d & ~bitmask) | ((f << pos) & bitmask);
+}
+
+/* Implement the FLIP machine instruction.
+   See FT32 Programmer's Reference for details.  */
+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);
+  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 = ft32_read_item (sd, 2, cpu->state.pc);
+  cpu->state.cycles += 1;
+
+  /* Handle "call 8" (which is FT32's "break" equivalent) here.  */
+  if (inst == 0x00340002)
+    {
+      sim_engine_halt (sd, cpu, NULL,
+		       cpu->state.pc,
+		       sim_stopped, SIM_SIGTRAP);
+      goto escape;
+    }
+
+  dw   =              (inst >> FT32_FLD_DW_BIT) & LSBS (FT32_FLD_DW_SIZ);
+  cb   =              (inst >> FT32_FLD_CB_BIT) & LSBS (FT32_FLD_CB_SIZ);
+  r_d  =              (inst >> FT32_FLD_R_D_BIT) & LSBS (FT32_FLD_R_D_SIZ);
+  cr   =              (inst >> FT32_FLD_CR_BIT) & LSBS (FT32_FLD_CR_SIZ);
+  cv   =              (inst >> FT32_FLD_CV_BIT) & LSBS (FT32_FLD_CV_SIZ);
+  bt   =              (inst >> FT32_FLD_BT_BIT) & LSBS (FT32_FLD_BT_SIZ);
+  r_1  =              (inst >> FT32_FLD_R_1_BIT) & LSBS (FT32_FLD_R_1_SIZ);
+  rimm =              (inst >> FT32_FLD_RIMM_BIT) & LSBS (FT32_FLD_RIMM_SIZ);
+  r_2  =              (inst >> FT32_FLD_R_2_BIT) & LSBS (FT32_FLD_R_2_SIZ);
+  k20  = nsigned (20, (inst >> FT32_FLD_K20_BIT) & LSBS (FT32_FLD_K20_SIZ));
+  pa   =              (inst >> FT32_FLD_PA_BIT) & LSBS (FT32_FLD_PA_SIZ);
+  aa   =              (inst >> FT32_FLD_AA_BIT) & LSBS (FT32_FLD_AA_SIZ);
+  k16  =              (inst >> FT32_FLD_K16_BIT) & LSBS (FT32_FLD_K16_SIZ);
+  k8   = nsigned (8,  (inst >> FT32_FLD_K8_BIT) & LSBS (FT32_FLD_K8_SIZ));
+  al   =              (inst >> FT32_FLD_AL_BIT) & LSBS (FT32_FLD_AL_SIZ);
+
+  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 take = (cr == 3) || ((1 & (cpu->state.regs[28 + cr] >> cb)) == cv);
+	if (take)
+	  {
+	    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 ();
+	  }
+	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.regs[r_d] = ft32_read_item (sd, dw, pa << 2);
+      cpu->state.cycles += 1;
+      break;
+
+    case FT32_PAT_LPMI:
+      cpu->state.regs[r_d] = ft32_read_item (sd, dw, cpu->state.regs[r_1] + k8);
+      cpu->state.cycles += 1;
+      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.regs[r_d] = cpu_mem_read (sd, dw, aa);
+      cpu->state.cycles += 1;
+      break;
+
+    case FT32_PAT_LDI:
+      cpu->state.regs[r_d] = cpu_mem_read (sd, dw, cpu->state.regs[r_1] + k8);
+      cpu->state.cycles += 1;
+      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;
+	cpu->state.cycles += 1;
+      }
+      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;
+	cpu->state.cycles += 1;
+      }
+      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[FT32_HARD_SP];
+      cpu->state.regs[FT32_HARD_SP] -= k16;
+      cpu->state.regs[FT32_HARD_SP] &= 0xffff;
+      break;
+
+    case FT32_PAT_UNLINK:
+      cpu->state.regs[FT32_HARD_SP] = cpu->state.regs[r_d];
+      cpu->state.regs[FT32_HARD_SP] &= 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:
+	  {
+	    /* strcmp instruction.  */
+	    uint32_t a = r_1v;
+	    uint32_t b = rimmv;
+	    uint32_t i = 0;
+	    while ((GET_BYTE (a + i) != 0) &&
+		   (GET_BYTE (a + i) == GET_BYTE (b + i)))
+	      i++;
+	    cpu->state.regs[r_d] = GET_BYTE (a + i) - GET_BYTE (b + i);
+	  }
+	  break;
+
+	case 0x5:
+	  {
+	    /* memcpy instruction.  */
+	    uint32_t src = r_1v;
+	    uint32_t dst = cpu->state.regs[r_d];
+	    uint32_t i;
+	    for (i = 0; i < rimmv; i++)
+	      PUT_BYTE (dst + i, GET_BYTE (src + i));
+	  }
+	  break;
+	case 0x6:
+	  {
+	    /* strlen instruction.  */
+	    uint32_t src = r_1v;
+	    uint32_t i;
+	    for (i = 0; GET_BYTE (src + i) != 0; i++)
+	      ;
+	    cpu->state.regs[r_d] = i;
+	  }
+	  break;
+	case 0x7:
+	  {
+	    /* memset instruction.  */
+	    uint32_t dst = cpu->state.regs[r_d];
+	    uint32_t i;
+	    for (i = 0; i < rimmv; i++)
+	      PUT_BYTE (dst + i, r_1v);
+	  }
+	  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:
+	  {
+	    /* stpcpy instruction.  */
+	    uint32_t src = r_1v;
+	    uint32_t dst = cpu->state.regs[r_d];
+	    uint32_t i;
+	    for (i = 0; GET_BYTE (src + i) != 0; i++)
+	      PUT_BYTE (dst + i, GET_BYTE (src + i));
+	    PUT_BYTE (dst + i, 0);
+	    cpu->state.regs[r_d] = dst + i;
+	  }
+	  break;
+	case 0xe:
+	  {
+	    /* streamout instruction.  */
+	    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 ();
+	}
+      break;
+
+    default:
+      sim_io_eprintf (sd, "Unhandled pattern %d at %08x\n", upper, insnpc);
+      ILLEGAL ();
+    }
+  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);
+
+  return sim_core_write_buffer (sd, cpu, write_map, buffer, addr, size);
+}
+
+int
+sim_read (SIM_DESC sd,
+	  SIM_ADDR addr,
+	  unsigned char *buffer,
+	  int size)
+{
+  sim_cpu *cpu = STATE_CPU (sd, 0);
+
+  return sim_core_read_buffer (sd, cpu, read_map, buffer, addr, size);
+}
+
+static uint32_t *
+ft32_lookup_register (SIM_CPU *cpu, int nr)
+{
+  /* Handle the register number translation here.
+   * Sim registers are 0-31.
+   * Other tools (gcc, gdb) use:
+   * 0 - fp
+   * 1 - sp
+   * 2 - r0
+   * 31 - cc
+   */
+
+  if ((nr < 0) || (nr > 32))
+    {
+      sim_io_eprintf (CPU_STATE (cpu), "unknown register %i\n", nr);
+      abort ();
+    }
+
+  switch (nr)
+    {
+    case FT32_FP_REGNUM:
+      return &cpu->state.regs[FT32_HARD_FP];
+    case FT32_SP_REGNUM:
+      return &cpu->state.regs[FT32_HARD_SP];
+    case FT32_CC_REGNUM:
+      return &cpu->state.regs[FT32_HARD_CC];
+    case FT32_PC_REGNUM:
+      return &cpu->state.pc;
+    default:
+      return &cpu->state.regs[nr - 2];
+    }
+}
+
+static int
+ft32_reg_store (SIM_CPU *cpu,
+		int rn,
+		unsigned char *memory,
+		int length)
+{
+  if (0 <= rn && rn <= 32)
+    {
+      if (length == 4)
+	*ft32_lookup_register (cpu, rn) = ft32_extract_unsigned_integer (memory, 4);
+
+      return 4;
+    }
+  else
+    return 0;
+}
+
+static int
+ft32_reg_fetch (SIM_CPU *cpu,
+		int rn,
+		unsigned char *memory,
+		int length)
+{
+  if (0 <= rn && rn <= 32)
+    {
+      if (length == 4)
+	ft32_store_unsigned_integer (memory, 4, *ft32_lookup_register (cpu, rn));
+
+      return 4;
+    }
+  else
+    return 0;
+}
+
+static sim_cia
+ft32_pc_get (SIM_CPU *cpu)
+{
+  return 32;
+}
+
+static void
+ft32_pc_set (SIM_CPU *cpu, sim_cia newpc)
+{
+  cpu->state.pc = newpc;
+}
+
+/* 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;
+  size_t i;
+  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;
+    }
+
+  /* getopt will print the error message so we just have to exit if this fails.
+     FIXME: Hmmm...  in the case of gdb we need getopt to call
+     print_filtered.  */
+  if (sim_parse_args (sd, argv) != 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,0x40000");
+      sim_do_command (sd, "memory region 0x800000,0x10000");
+    }
+
+  /* Check for/establish the 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;
+    }
+
+  /* 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;
+    }
+
+  /* CPU specific initialization.  */
+  for (i = 0; i < MAX_NR_PROCESSORS; ++i)
+    {
+      SIM_CPU *cpu = STATE_CPU (sd, i);
+
+      CPU_REG_FETCH (cpu) = ft32_reg_fetch;
+      CPU_REG_STORE (cpu) = ft32_reg_store;
+      CPU_PC_FETCH (cpu) = ft32_pc_get;
+      CPU_PC_STORE (cpu) = ft32_pc_set;
+    }
+
+  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[FT32_HARD_SP] = 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..6cb7c7e
--- /dev/null
+++ b/sim/ft32/sim-main.h
@@ -0,0 +1,58 @@
+/* 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"
+
+typedef struct _sim_cpu SIM_CPU;
+
+#include "ft32-sim.h"
+
+struct _sim_cpu {
+
+  /* The following are internal simulator state variables: */
+#define CIA_GET(CPU) ((CPU)->state.pc + 0)
+#define CIA_SET(CPU,CIA) ((CPU)->state.pc = (CIA))
+
+  struct ft32_cpu_state state;
+
+  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/ChangeLog b/sim/testsuite/ChangeLog
index be7ad56..7580586 100644
--- a/sim/testsuite/ChangeLog
+++ b/sim/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2015-03-28  James Bowman  <james.bowman@ftdichip.com>
+
+	* configure: Regenerate.
+
 2014-03-10  Mike Frysinger  <vapier@gentoo.org>
 
 	* configure: Regenerate.
diff --git a/sim/testsuite/configure b/sim/testsuite/configure
index f90bd47..1dcaa41 100755
diff --git a/sim/testsuite/sim/ft32/ChangeLog b/sim/testsuite/sim/ft32/ChangeLog
new file mode 100644
index 0000000..a0cfa18
--- /dev/null
+++ b/sim/testsuite/sim/ft32/ChangeLog
@@ -0,0 +1,3 @@
+2015-02-28  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..c92f295
--- /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..c07811f
--- /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
-- 
2.3.3

From 49d45b20c01da11b7493a5c28bdced7558999d6d Mon Sep 17 00:00:00 2001
From: James Bowman <james.bowman@ftdichip.com>
Date: Mon, 23 Mar 2015 19:15:32 +0000
Subject: [PATCH 2/2] gdb: ft32: new port

FT32 is a new high performance 32-bit RISC core developed by FTDI for
embedded applications.
---
 gdb/ChangeLog     |   9 +
 gdb/Makefile.in   |   5 +-
 gdb/configure.tgt |   5 +
 gdb/ft32-tdep.c   | 549 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/ft32-tdep.h   |  28 +++
 5 files changed, 595 insertions(+), 1 deletion(-)
 create mode 100644 gdb/ft32-tdep.c
 create mode 100644 gdb/ft32-tdep.h

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 6c6b94e..fe6811e 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,12 @@
+2015-03-28  James Bowman  <james.bowman@ftdichip.com>
+
+	* Makefile.in (ALL_TARGET_OBS): Add ft32-tdep.o.
+	(HFILES_NO_SRCDIR): Add ft32-tdep.h.
+	(ALLDEPFILES): Add ft32-tdep.c.
+	* configure.tgt: Add FT32 entry.
+	* ft32-tdep.c: New file, FT32 target-dependent code.
+	* ft32-tdep.h: New file, FT32 target-dependent code.
+
 2015-03-27  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
 	Revert:
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ae50041..907997b 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -651,6 +651,7 @@ ALL_TARGET_OBS = \
 	dicos-tdep.o \
 	fbsd-tdep.o \
 	frv-linux-tdep.o frv-tdep.o \
+	ft32-tdep.o \
 	h8300-tdep.o \
 	hppabsd-tdep.o hppanbsd-tdep.o hppaobsd-tdep.o \
 	hppa-linux-tdep.o hppa-tdep.o \
@@ -949,7 +950,8 @@ psymtab.h psympriv.h progspace.h bfin-tdep.h \
 amd64-darwin-tdep.h charset-list.h \
 config/djgpp/langinfo.h config/djgpp/nl_types.h darwin-nat.h \
 dicos-tdep.h filesystem.h gcore.h gdb_wchar.h hppabsd-tdep.h \
-i386-darwin-tdep.h x86-nat.h linux-record.h moxie-tdep.h nios2-tdep.h \
+i386-darwin-tdep.h i386-nat.h linux-record.h moxie-tdep.h nios2-tdep.h \
+ft32-tdep.h \
 osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent.h \
 python/python-internal.h python/python.h ravenscar-thread.h record.h \
 record-full.h solib-aix.h \
@@ -1655,6 +1657,7 @@ ALLDEPFILES = \
 	fbsd-nat.c \
 	fbsd-tdep.c \
 	fork-child.c \
+	ft32-tdep.c \
 	glibc-tdep.c \
 	go32-nat.c h8300-tdep.c \
 	hppa-tdep.c \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index c97ebdd..8feda7c 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -615,6 +615,11 @@ xstormy16-*-*)
 	# No simulator libraries are needed -- target uses SID.
 	;;
 
+ft32-*-elf)
+	gdb_target_obs="ft32-tdep.o"
+	gdb_sim=../sim/ft32/libsim.a
+	;;
+
 v850*-*-elf | v850*-*-rtems*)
 	# Target: NEC V850 processor
 	gdb_target_obs="v850-tdep.o"
diff --git a/gdb/ft32-tdep.c b/gdb/ft32-tdep.c
new file mode 100644
index 0000000..41a7191
--- /dev/null
+++ b/gdb/ft32-tdep.c
@@ -0,0 +1,549 @@
+/* Target-dependent code for FT32.
+
+   Copyright (C) 2009-2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "value.h"
+#include "inferior.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "osabi.h"
+#include "language.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "trad-frame.h"
+#include "dis-asm.h"
+#include "record.h"
+
+#include "gdb_assert.h"
+
+#include "ft32-tdep.h"
+#include "gdb/sim-ft32.h"
+
+#define RAM_BIAS  0x800000  /* Bias added to RAM addresses.  */
+
+/* Local functions.  */
+
+extern void _initialize_ft32_tdep (void);
+
+/* Use an invalid address -1 as 'not available' marker.  */
+enum { REG_UNAVAIL = (CORE_ADDR) (-1) };
+
+struct ft32_frame_cache
+{
+  /* Base address of the frame */
+  CORE_ADDR base;
+  /* Function this frame belongs to */
+  CORE_ADDR pc;
+  /* Total size of this frame */
+  LONGEST framesize;
+  /* Saved registers in this frame */
+  CORE_ADDR saved_regs[FT32_NUM_REGS];
+  /* Saved SP in this frame */
+  CORE_ADDR saved_sp;
+  /* Has the new frame been LINKed.  */
+  bfd_boolean established;
+};
+
+/* Implement the "frame_align" gdbarch method.  */
+
+static CORE_ADDR
+ft32_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+  /* Align to the size of an instruction (so that they can safely be
+     pushed onto the stack.  */
+  return sp & ~1;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const unsigned char *
+ft32_breakpoint_from_pc (struct gdbarch *gdbarch,
+			 CORE_ADDR *pcptr, int *lenptr)
+{
+  static const gdb_byte breakpoint[] = { 0x02, 0x00, 0x34, 0x00 };
+
+  *lenptr = sizeof (breakpoint);
+  return breakpoint;
+}
+
+/* FT32 register names.  */
+
+static const char *const ft32_register_names[] =
+{
+    "fp", "sp",
+    "r0", "r1", "r2", "r3",  "r4", "r5", "r6", "r7",
+    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+    "r16", "r17", "r18", "r19",  "r20", "r21", "r22", "r23",
+    "r24", "r25", "r26", "r27", "r28", "cc",
+    "pc"
+};
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+ft32_register_name (struct gdbarch *gdbarch, int reg_nr)
+{
+  if (reg_nr < 0)
+    return NULL;
+  if (reg_nr >= FT32_NUM_REGS)
+    return NULL;
+  return ft32_register_names[reg_nr];
+}
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+ft32_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  if (reg_nr == FT32_PC_REGNUM)
+    return builtin_type (gdbarch)->builtin_func_ptr;
+  else if (reg_nr == FT32_SP_REGNUM || reg_nr == FT32_FP_REGNUM)
+    return builtin_type (gdbarch)->builtin_data_ptr;
+  else
+    return builtin_type (gdbarch)->builtin_int32;
+}
+
+/* Write into appropriate registers a function return value
+   of type TYPE, given in virtual format.  */
+
+static void
+ft32_store_return_value (struct type *type, struct regcache *regcache,
+			 const gdb_byte *valbuf)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR regval;
+  int len = TYPE_LENGTH (type);
+
+  /* Things always get returned in RET1_REGNUM, RET2_REGNUM.  */
+  regval = extract_unsigned_integer (valbuf, len > 4 ? 4 : len, byte_order);
+  regcache_cooked_write_unsigned (regcache, FT32_R0_REGNUM, regval);
+  if (len > 4)
+    {
+      regval = extract_unsigned_integer (valbuf + 4,
+					 len - 4, byte_order);
+      regcache_cooked_write_unsigned (regcache, FT32_R1_REGNUM, regval);
+    }
+}
+
+/* Decode the instructions within the given address range.  Decide
+   when we must have reached the end of the function prologue.  If a
+   frame_info pointer is provided, fill in its saved_regs etc.
+
+   Returns the address of the first instruction after the prologue.  */
+
+#define IS_PUSH(inst)   (((inst) & 0xfff00000) == 0x84000000)
+#define PUSH_REG(inst)  (FT32_R0_REGNUM + (((inst) >> 15) & 0x1f))
+#define IS_LINK(inst)   (((inst) & 0xffff0000) == 0x95d00000)
+#define LINK_SIZE(inst) ((inst) & 0xffff)
+
+static CORE_ADDR
+ft32_analyze_prologue (CORE_ADDR start_addr, CORE_ADDR end_addr,
+		       struct ft32_frame_cache *cache,
+		       struct gdbarch *gdbarch)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR next_addr;
+  ULONGEST inst, inst2;
+  LONGEST offset;
+  int regnum;
+
+  cache->saved_regs[FT32_PC_REGNUM] = 0;
+  cache->framesize = 0;
+
+  if (start_addr >= end_addr)
+      return end_addr;
+
+  cache->established = 0;
+  for (next_addr = start_addr; next_addr < end_addr; )
+    {
+      inst = read_memory_unsigned_integer (next_addr, 4, byte_order);
+
+      if (IS_PUSH (inst))
+	{
+	  regnum = PUSH_REG (inst);
+	  cache->framesize += 4;
+	  cache->saved_regs[regnum] = cache->framesize;
+	  next_addr += 4;
+	}
+      else
+	break;
+    }
+  for (regnum = FT32_R0_REGNUM; regnum < FT32_PC_REGNUM; regnum++)
+    {
+      if (cache->saved_regs[regnum] != REG_UNAVAIL)
+	cache->saved_regs[regnum] = cache->framesize - cache->saved_regs[regnum];
+    }
+  cache->saved_regs[FT32_PC_REGNUM] = cache->framesize;
+
+  /* It is a LINK?  */
+  if (next_addr < end_addr)
+    {
+      inst = read_memory_unsigned_integer (next_addr, 4, byte_order);
+      if (IS_LINK (inst))
+	{
+	  cache->established = 1;
+	  for (regnum = FT32_R0_REGNUM; regnum < FT32_PC_REGNUM; regnum++)
+	    {
+	      if (cache->saved_regs[regnum] != REG_UNAVAIL)
+		cache->saved_regs[regnum] += 4;
+	    }
+	  cache->saved_regs[FT32_PC_REGNUM] = cache->framesize + 4;
+	  cache->saved_regs[FT32_FP_REGNUM] = 0;
+	  cache->framesize += LINK_SIZE (inst);
+	  next_addr += 4;
+	}
+    }
+
+  return next_addr;
+}
+
+/* Find the end of function prologue.  */
+
+static CORE_ADDR
+ft32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR func_addr = 0, func_end = 0;
+  const char *func_name;
+
+  /* See if we can determine the end of the prologue via the symbol table.
+     If so, then return either PC, or the PC after the prologue, whichever
+     is greater.  */
+  if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
+    {
+      CORE_ADDR post_prologue_pc
+	= skip_prologue_using_sal (gdbarch, func_addr);
+      if (post_prologue_pc != 0)
+	return max (pc, post_prologue_pc);
+      else
+	{
+	  /* Can't determine prologue from the symbol table, need to examine
+	     instructions.  */
+	  struct symtab_and_line sal;
+	  struct symbol *sym;
+	  struct ft32_frame_cache cache;
+	  CORE_ADDR plg_end;
+
+	  memset (&cache, 0, sizeof cache);
+
+	  plg_end = ft32_analyze_prologue (func_addr,
+					   func_end, &cache, gdbarch);
+	  /* Found a function.  */
+	  sym = lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL);
+	  /* Don't use line number debug info for assembly source files.  */
+	  if ((sym != NULL) && SYMBOL_LANGUAGE (sym) != language_asm)
+	    {
+	      sal = find_pc_line (func_addr, 0);
+	      if (sal.end && sal.end < func_end)
+		{
+		  /* Found a line number, use it as end of prologue.  */
+		  return sal.end;
+		}
+	    }
+	  /* No useable line symbol.  Use result of prologue parsing method.  */
+	  return plg_end;
+	}
+    }
+
+  /* No function symbol -- just return the PC.  */
+  return pc;
+}
+
+/* Implement the "read_pc" gdbarch method.  */
+
+static CORE_ADDR
+ft32_read_pc (struct regcache *regcache)
+{
+  ULONGEST pc;
+
+  regcache_cooked_read_unsigned (regcache, FT32_PC_REGNUM, &pc);
+  return pc;
+}
+
+/* Implement the "write_pc" gdbarch method.  */
+
+static void
+ft32_write_pc (struct regcache *regcache, CORE_ADDR val)
+{
+  regcache_cooked_write_unsigned (regcache, FT32_PC_REGNUM, val);
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+ft32_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, FT32_SP_REGNUM);
+}
+
+/* Given a return value in `regbuf' with a type `valtype',
+   extract and copy its value into `valbuf'.  */
+
+static void
+ft32_extract_return_value (struct type *type, struct regcache *regcache,
+			   gdb_byte *dst)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  bfd_byte *valbuf = dst;
+  int len = TYPE_LENGTH (type);
+  ULONGEST tmp;
+
+  /* By using store_unsigned_integer we avoid having to do
+     anything special for small big-endian values.  */
+  regcache_cooked_read_unsigned (regcache, FT32_R0_REGNUM, &tmp);
+  store_unsigned_integer (valbuf, (len > 4 ? len - 4 : len), byte_order, tmp);
+
+  /* Ignore return values more than 8 bytes in size because the ft32
+     returns anything more than 8 bytes in the stack.  */
+  if (len > 4)
+    {
+      regcache_cooked_read_unsigned (regcache, FT32_R1_REGNUM, &tmp);
+      store_unsigned_integer (valbuf + len - 4, 4, byte_order, tmp);
+    }
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+ft32_return_value (struct gdbarch *gdbarch, struct value *function,
+		   struct type *valtype, struct regcache *regcache,
+		   gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+  if (TYPE_LENGTH (valtype) > 8)
+    return RETURN_VALUE_STRUCT_CONVENTION;
+  else
+    {
+      if (readbuf != NULL)
+	ft32_extract_return_value (valtype, regcache, readbuf);
+      if (writebuf != NULL)
+	ft32_store_return_value (valtype, regcache, writebuf);
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+}
+
+/* Allocate and initialize a ft32_frame_cache object.  */
+
+static struct ft32_frame_cache *
+ft32_alloc_frame_cache (void)
+{
+  struct ft32_frame_cache *cache;
+  int i;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct ft32_frame_cache);
+
+  for (i = 0; i < FT32_NUM_REGS; ++i)
+    cache->saved_regs[i] = REG_UNAVAIL;
+
+  return cache;
+}
+
+/* Populate a ft32_frame_cache object for this_frame.  */
+
+static struct ft32_frame_cache *
+ft32_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  struct ft32_frame_cache *cache;
+  CORE_ADDR current_pc;
+  int i;
+
+  if (*this_cache)
+    return *this_cache;
+
+  cache = ft32_alloc_frame_cache ();
+  *this_cache = cache;
+
+  cache->base = get_frame_register_unsigned (this_frame, FT32_FP_REGNUM);
+  if (cache->base == 0)
+    return cache;
+
+  cache->pc = get_frame_func (this_frame);
+  current_pc = get_frame_pc (this_frame);
+  if (cache->pc)
+    {
+      struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
+      ft32_analyze_prologue (cache->pc, current_pc, cache, gdbarch);
+      if (!cache->established)
+	cache->base = get_frame_register_unsigned (this_frame, FT32_SP_REGNUM);
+    }
+
+  cache->saved_sp = cache->base - 4;
+
+  for (i = 0; i < FT32_NUM_REGS; ++i)
+    if (cache->saved_regs[i] != REG_UNAVAIL)
+      cache->saved_regs[i] = cache->base + cache->saved_regs[i];
+
+  return cache;
+}
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+ft32_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, FT32_PC_REGNUM);
+}
+
+/* Given a GDB frame, determine the address of the calling function's
+   frame.  This will be used to create a new GDB frame struct.  */
+
+static void
+ft32_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  struct ft32_frame_cache *cache = ft32_frame_cache (this_frame,
+						     this_prologue_cache);
+
+  /* This marks the outermost frame.  */
+  if (cache->base == 0)
+    return;
+
+  *this_id = frame_id_build (cache->saved_sp, cache->pc);
+}
+
+/* Get the value of register regnum in the previous stack frame.  */
+
+static struct value *
+ft32_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct ft32_frame_cache *cache = ft32_frame_cache (this_frame,
+						     this_prologue_cache);
+
+  gdb_assert (regnum >= 0);
+
+  if (regnum == FT32_SP_REGNUM && cache->saved_sp)
+    return frame_unwind_got_constant (this_frame, regnum, cache->saved_sp);
+
+  if (regnum < FT32_NUM_REGS && cache->saved_regs[regnum] != REG_UNAVAIL)
+      return frame_unwind_got_memory (this_frame, regnum,
+				      RAM_BIAS | cache->saved_regs[regnum]);
+
+  return frame_unwind_got_register (this_frame, regnum, regnum);
+}
+
+static const struct frame_unwind ft32_frame_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  ft32_frame_this_id,
+  ft32_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Return the base address of this_frame.  */
+
+static CORE_ADDR
+ft32_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+  struct ft32_frame_cache *cache = ft32_frame_cache (this_frame,
+						     this_cache);
+
+  return cache->base;
+}
+
+static const struct frame_base ft32_frame_base =
+{
+  &ft32_frame_unwind,
+  ft32_frame_base_address,
+  ft32_frame_base_address,
+  ft32_frame_base_address
+};
+
+static struct frame_id
+ft32_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp = get_frame_register_unsigned (this_frame, FT32_SP_REGNUM);
+
+  return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+/* Allocate and initialize the ft32 gdbarch object.  */
+
+static struct gdbarch *
+ft32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+
+  /* If there is already a candidate, use it.  */
+  arches = gdbarch_list_lookup_by_info (arches, &info);
+  if (arches != NULL)
+    return arches->gdbarch;
+
+  /* Allocate space for the new architecture.  */
+  tdep = XNEW (struct gdbarch_tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_read_pc (gdbarch, ft32_read_pc);
+  set_gdbarch_write_pc (gdbarch, ft32_write_pc);
+  set_gdbarch_unwind_sp (gdbarch, ft32_unwind_sp);
+
+  set_gdbarch_num_regs (gdbarch, FT32_NUM_REGS);
+  set_gdbarch_sp_regnum (gdbarch, FT32_SP_REGNUM);
+  set_gdbarch_pc_regnum (gdbarch, FT32_PC_REGNUM);
+  set_gdbarch_register_name (gdbarch, ft32_register_name);
+  set_gdbarch_register_type (gdbarch, ft32_register_type);
+
+  set_gdbarch_return_value (gdbarch, ft32_return_value);
+
+  set_gdbarch_skip_prologue (gdbarch, ft32_skip_prologue);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_breakpoint_from_pc (gdbarch, ft32_breakpoint_from_pc);
+  set_gdbarch_frame_align (gdbarch, ft32_frame_align);
+
+  frame_base_set_default (gdbarch, &ft32_frame_base);
+
+  /* Methods for saving / extracting a dummy frame's ID.  The ID's
+     stack address must match the SP value returned by
+     PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos.  */
+  set_gdbarch_dummy_id (gdbarch, ft32_dummy_id);
+
+  set_gdbarch_unwind_pc (gdbarch, ft32_unwind_pc);
+
+  set_gdbarch_print_insn (gdbarch, print_insn_ft32);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  /* Hook in the default unwinders.  */
+  frame_unwind_append_unwinder (gdbarch, &ft32_frame_unwind);
+
+  /* Support simple overlay manager.  */
+  set_gdbarch_overlay_update (gdbarch, simple_overlay_update);
+
+  return gdbarch;
+}
+
+/* Register this machine's init routine.  */
+
+void
+_initialize_ft32_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_ft32, ft32_gdbarch_init);
+}
diff --git a/gdb/ft32-tdep.h b/gdb/ft32-tdep.h
new file mode 100644
index 0000000..5c52480
--- /dev/null
+++ b/gdb/ft32-tdep.h
@@ -0,0 +1,28 @@
+/* Target-dependent code for the FT32.
+
+   Copyright (C) 2002-2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef FT32_TDEP_H
+#define FT32_TDEP_H
+
+struct gdbarch_tdep
+{
+  /* gdbarch target dependent data here.  Currently unused for FT32.  */
+};
+
+#endif /* FT32_TDEP_H */
-- 
2.3.3

Attachment: signature.asc
Description: Digital signature


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