From: James Bowman <james.bowman@ftdichip.com>
To: Joel Brobecker <brobecker@adacore.com>
Cc: Mike Frysinger <vapier@gentoo.org>,
"gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
Subject: RE: [PATCH, FT32] gdb and sim support
Date: Thu, 19 Mar 2015 15:21:00 -0000 [thread overview]
Message-ID: <CA9BBF0458F83C4F9051448B941B57D117232A0A@glaexch1> (raw)
In-Reply-To: <20150317173615.GC7494@adacore.com>
Hi Joel,
Thanks. This is the gdb part of the submission.
--
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 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-19 James Bowman <james.bowman@ftdichip.com>
* Mainfile.in: Add FT32 entries.
* configure.tgt: Add FT32 entry.
* ft32-tdep.c: New file, FT32 target-dependent code.
* ft32-tdep.h: New file, FT32 target-dependent code.
include/gdb/:
2015-03-19 James Bowman <james.bowman@ftdichip.com>
* sim-ft32.h: New file, FT32 simulator/GDB interface.
From: James Bowman <james.bowman@ftdichip.com>
Date: Thu, 19 Mar 2015 08:19:49 -0700
Subject: [PATCH] FT32 Support
---
gdb/Makefile.in | 24 ++-
gdb/configure.tgt | 19 +-
gdb/ft32-tdep.c | 548 ++++++++++++++++++++++++++++++++++++++++++++++++
gdb/ft32-tdep.h | 28 +++
include/gdb/sim-ft32.h | 34 +++
5 files changed, 635 insertions(+), 18 deletions(-)
create mode 100644 gdb/ft32-tdep.c
create mode 100644 gdb/ft32-tdep.h
create mode 100644 include/gdb/sim-ft32.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8c2a4de..177fbc4 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 \
@@ -1339,9 +1340,9 @@ init.c: $(INIT_FILES)
done | \
while read f; do \
case " $$fs " in \
- *" $$f "* ) ;; \
- * ) echo $$f ; fs="$$fs $$f";; \
- esac; \
+ *" $$f "* ) ;; \
+ * ) echo $$f ; fs="$$fs $$f";; \
+ esac; \
done >> init.l-tmp
@echo '/* Do not modify this file. */' >>init.c-tmp
@echo '/* It is created automatically by the Makefile. */'>>init.c-tmp
@@ -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 \
@@ -1870,13 +1872,13 @@ po/$(PACKAGE).pot: force
$(FLEX) -o$@ $< && \
rm -f $@.new && \
sed -e '/extern.*malloc/d' \
- -e '/extern.*realloc/d' \
- -e '/extern.*free/d' \
- -e '/include.*malloc.h/d' \
- -e 's/\([^x]\)malloc/\1xmalloc/g' \
- -e 's/\([^x]\)realloc/\1xrealloc/g' \
- -e 's/\([ \t;,(]\)free\([ \t]*[&(),]\)/\1xfree\2/g' \
- -e 's/\([ \t;,(]\)free$$/\1xfree/g' \
+ -e '/extern.*realloc/d' \
+ -e '/extern.*free/d' \
+ -e '/include.*malloc.h/d' \
+ -e 's/\([^x]\)malloc/\1xmalloc/g' \
+ -e 's/\([^x]\)realloc/\1xrealloc/g' \
+ -e 's/\([ \t;,(]\)free\([ \t]*[&(),]\)/\1xfree\2/g' \
+ -e 's/\([ \t;,(]\)free$$/\1xfree/g' \
-e 's/yy_flex_xrealloc/yyxrealloc/g' \
< $@ > $@.new && \
rm -f $@ && \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 7fdd34e..324fc9c 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -410,7 +410,7 @@ nios2*-*-*)
powerpc*-*-freebsd*)
# Target: FreeBSD/powerpc
gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppc64-tdep.o \
- ppcfbsd-tdep.o fbsd-tdep.o solib-svr4.o \
+ ppcfbsd-tdep.o fbsd-tdep.o solib-svr4.o \
ravenscar-thread.o ppc-ravenscar-thread.o"
;;
@@ -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"
@@ -644,7 +649,7 @@ x86_64-*-darwin*)
# Target: Darwin/x86-64
gdb_target_obs="amd64-tdep.o i386-tdep.o i387-tdep.o \
i386-darwin-tdep.o amd64-darwin-tdep.o \
- solib-darwin.o"
+ solib-darwin.o"
;;
x86_64-*-dicos*)
@@ -666,12 +671,12 @@ x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu)
bsd-uthread.o fbsd-tdep.o solib-svr4.o"
;;
x86_64-*-mingw* | x86_64-*-cygwin*)
- # Target: MingW/amd64
+ # Target: MingW/amd64
gdb_target_obs="amd64-tdep.o amd64-windows-tdep.o \
- i386-tdep.o i386-cygwin-tdep.o i387-tdep.o \
- windows-tdep.o"
+ i386-tdep.o i386-cygwin-tdep.o i387-tdep.o \
+ windows-tdep.o"
build_gdbserver=yes
- ;;
+ ;;
x86_64-*-netbsd* | x86_64-*-knetbsd*-gnu)
# Target: NetBSD/amd64
gdb_target_obs="amd64-tdep.o amd64nbsd-tdep.o i386-tdep.o i387-tdep.o \
@@ -716,7 +721,7 @@ m68*-*-openbsd* | m88*-*-openbsd* | vax-*-openbsd*) ;;
*-*-symbianelf*)
gdb_osabi=GDB_OSABI_SYMBIAN ;;
powerpc-*-aix* | rs6000-*-* | powerpc64-*-aix*)
- gdb_osabi=GDB_OSABI_AIX ;;
+ gdb_osabi=GDB_OSABI_AIX ;;
esac
# Check whether this target supports gcore.
diff --git a/gdb/ft32-tdep.c b/gdb/ft32-tdep.c
new file mode 100644
index 0000000..6aac8be
--- /dev/null
+++ b/gdb/ft32-tdep.c
@@ -0,0 +1,548 @@
+/* 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. */
+ 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 * 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 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 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,
+ RAM_BIAS | cache->saved_regs[regnum]);
+
+ return frame_unwind_got_register (this_frame, regnum, regnum);
+}
+
+static const struct frame_unwind ft32_frame_unwind =
+{
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ ft32_frame_this_id,
+ ft32_frame_prev_register,
+ NULL,
+ default_frame_sniffer
+};
+
+/* Return the base address of this_frame. */
+
+static CORE_ADDR
+ft32_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+ struct ft32_frame_cache *cache = ft32_frame_cache (this_frame,
+ this_cache);
+
+ return cache->base;
+}
+
+static const struct frame_base ft32_frame_base =
+{
+ &ft32_frame_unwind,
+ ft32_frame_base_address,
+ ft32_frame_base_address,
+ ft32_frame_base_address
+};
+
+static struct frame_id
+ft32_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ CORE_ADDR sp = get_frame_register_unsigned (this_frame, FT32_SP_REGNUM);
+
+ return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+/* Allocate and initialize the ft32 gdbarch object. */
+
+static struct gdbarch *
+ft32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+
+ /* If there is already a candidate, use it. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != NULL)
+ return arches->gdbarch;
+
+ /* Allocate space for the new architecture. */
+ tdep = XNEW (struct gdbarch_tdep);
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ set_gdbarch_read_pc (gdbarch, ft32_read_pc);
+ set_gdbarch_write_pc (gdbarch, ft32_write_pc);
+ set_gdbarch_unwind_sp (gdbarch, ft32_unwind_sp);
+
+ set_gdbarch_num_regs (gdbarch, FT32_NUM_REGS);
+ set_gdbarch_sp_regnum (gdbarch, FT32_SP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, FT32_PC_REGNUM);
+ set_gdbarch_register_name (gdbarch, ft32_register_name);
+ set_gdbarch_register_type (gdbarch, ft32_register_type);
+
+ set_gdbarch_return_value (gdbarch, ft32_return_value);
+
+ set_gdbarch_skip_prologue (gdbarch, ft32_skip_prologue);
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ set_gdbarch_breakpoint_from_pc (gdbarch, ft32_breakpoint_from_pc);
+ set_gdbarch_frame_align (gdbarch, ft32_frame_align);
+
+ frame_base_set_default (gdbarch, &ft32_frame_base);
+
+ /* Methods for saving / extracting a dummy frame's ID. The ID's
+ stack address must match the SP value returned by
+ PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos. */
+ set_gdbarch_dummy_id (gdbarch, ft32_dummy_id);
+
+ set_gdbarch_unwind_pc (gdbarch, ft32_unwind_pc);
+
+ set_gdbarch_print_insn (gdbarch, print_insn_ft32);
+
+ /* Hook in ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch);
+
+ /* Hook in the default unwinders. */
+ frame_unwind_append_unwinder (gdbarch, &ft32_frame_unwind);
+
+ /* Support simple overlay manager. */
+ set_gdbarch_overlay_update (gdbarch, simple_overlay_update);
+
+ return gdbarch;
+}
+
+/* Register this machine's init routine. */
+
+void
+_initialize_ft32_tdep (void)
+{
+ register_gdbarch_init (bfd_arch_ft32, ft32_gdbarch_init);
+}
diff --git a/gdb/ft32-tdep.h b/gdb/ft32-tdep.h
new file mode 100644
index 0000000..5c52480
--- /dev/null
+++ b/gdb/ft32-tdep.h
@@ -0,0 +1,28 @@
+/* Target-dependent code for the FT32.
+
+ Copyright (C) 2002-2015 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef FT32_TDEP_H
+#define FT32_TDEP_H
+
+struct gdbarch_tdep
+{
+ /* gdbarch target dependent data here. Currently unused for FT32. */
+};
+
+#endif /* FT32_TDEP_H */
diff --git a/include/gdb/sim-ft32.h b/include/gdb/sim-ft32.h
new file mode 100644
index 0000000..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 */
+
--
1.7.9.5
From gdb-patches-return-120924-listarch-gdb-patches=sources.redhat.com@sourceware.org Thu Mar 19 15:26:14 2015
Return-Path: <gdb-patches-return-120924-listarch-gdb-patches=sources.redhat.com@sourceware.org>
Delivered-To: listarch-gdb-patches@sources.redhat.com
Received: (qmail 32808 invoked by alias); 19 Mar 2015 15:26:14 -0000
Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm
Precedence: bulk
List-Id: <gdb-patches.sourceware.org>
List-Subscribe: <mailto:gdb-patches-subscribe@sourceware.org>
List-Archive: <http://sourceware.org/ml/gdb-patches/>
List-Post: <mailto:gdb-patches@sourceware.org>
List-Help: <mailto:gdb-patches-help@sourceware.org>, <http://sourceware.org/ml/#faqs>
Sender: gdb-patches-owner@sourceware.org
Delivered-To: mailing list gdb-patches@sourceware.org
Received: (qmail 32799 invoked by uid 89); 19 Mar 2015 15:26:13 -0000
Authentication-Results: sourceware.org; auth=none
X-Virus-Found: No
X-Spam-SWARE-Status: No, score=3.3 required=5.0 tests=AWL,BAYES_50,RCVD_IN_DNSWL_NONE,URIBL_BLACK autolearn=no version=3.3.2
X-HELO: smtp-out4.electric.net
Received: from smtp-out4.electric.net (HELO smtp-out4.electric.net) (192.162.216.184) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Thu, 19 Mar 2015 15:26:08 +0000
Received: from 1YYcKh-0007NB-Vh by out4d.electric.net with emc1-ok (Exim 4.84) (envelope-from <james.bowman@ftdichip.com>) id 1YYcKi-0007Pz-W8; Thu, 19 Mar 2015 08:26:04 -0700
Received: by emcmailer; Thu, 19 Mar 2015 08:26:04 -0700
Received: from [82.0.240.193] (helo=GLAEXCH3.ftdi.local) by out4d.electric.net with esmtps (TLSv1:AES128-SHA:128) (Exim 4.84) (envelope-from <james.bowman@ftdichip.com>) id 1YYcKh-0007NB-Vh; Thu, 19 Mar 2015 08:26:03 -0700
Received: from GLAEXCH1.ftdi.local ([172.16.0.121]) by glaexch3 ([172.16.0.161]) with mapi id 14.01.0438.000; Thu, 19 Mar 2015 15:26:03 +0000
From: James Bowman <james.bowman@ftdichip.com>
To: Mike Frysinger <vapier@gentoo.org>
CC: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
Subject: RE: [PATCH, FT32] gdb and sim support
Date: Thu, 19 Mar 2015 15:26:00 -0000
Message-ID: <CA9BBF0458F83C4F9051448B941B57D117234A18@glaexch1>
References: <CA9BBF0458F83C4F9051448B941B57D11714C9E3@glaexch1> <ORIGINAL-RELEASE-1424557036-20150219070610.GI544@vapier> <CA9BBF0458F83C4F9051448B941B57D1171BC0CB@glaexch1> <20150224045154.GE13523@vapier> <CA9BBF0458F83C4F9051448B941B57D11722A513@glaexch1>,<20150316082548.GC12926@vapier>
In-Reply-To: <20150316082548.GC12926@vapier>
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
MIME-Version: 1.0
X-Outbound-IP: 82.0.240.193
X-Env-From: james.bowman@ftdichip.com
X-PolicySMART: 3094660
X-SW-Source: 2015-03/txt/msg00588.txt.bz2
Content-length: 54559
Thanks,
Have reworked the simulator, and the revised patches are attached below.
everything done except for a couple of queries:
> > +SIM_RUN_OBJS = nrun.o
>
> i flipped the default in the latest tree so you can delete this now
Deleting this line gives:
run.o: In function `main':
... /ft32/../common/run.c:116: undefined reference to `sim_set_callbacks'
... /ft32/../common/run.c:163: undefined reference to `sim_size'
... /ft32/../common/run.c:271: undefined reference to `sim_trace'
> > + sd->base.prog_argv = argv + 1;
>
> why do you need to do this ?
Because if this is omitted, no command line arguments are processed.
Thanks again, J.
--
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 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:
sim/:
2015-03-19 James Bowman <james.bowman@ftdichip.com>
* configure.tgt: Add FT32 entry.
sim/ft32/:
2015-03-19 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-19 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: Thu, 19 Mar 2015 08:22:36 -0700
Subject: [PATCH] FT32 Support
---
sim/configure.tgt | 4 +
sim/ft32/Makefile.in | 50 ++
sim/ft32/config.in | 154 ++++++
sim/ft32/configure.ac | 15 +
sim/ft32/ft32-sim.h | 41 ++
sim/ft32/interp.c | 865 ++++++++++++++++++++++++++++++++++
sim/ft32/sim-main.h | 62 +++
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 +++
11 files changed, 2136 insertions(+)
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/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..b44a5c2
--- /dev/null
+++ b/sim/ft32/Makefile.in
@@ -0,0 +1,50 @@
+# 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)
+
+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..e98206e
--- /dev/null
+++ b/sim/ft32/ft32-sim.h
@@ -0,0 +1,41 @@
+/* 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>
+
+#define FT32_FP_REGNUM 29
+#define FT32_CC_REGNUM 30
+#define FT32_SP_REGNUM 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..71d2464
--- /dev/null
+++ b/sim/ft32/interp.c
@@ -0,0 +1,865 @@
+/* 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"
+
+#define RAM_BIAS 0x800000 /* Bias added to RAM addresses. */
+
+/* Forward declarations. */
+int ft32_reg_store (SIM_CPU *cpu, int rn, unsigned char *memory, int length);
+int ft32_reg_fetch (SIM_CPU *cpu, int rn, unsigned char *memory, int length);
+
+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. */
+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);
+ uint8_t byte[4];
+ uint32_t r;
+
+ ea = ft32_align (dw, ea);
+ sim_core_read_buffer (sd, cpu, read_map, byte, ea, 1 << dw);
+ r = byte[0];
+ if (1 <= dw)
+ {
+ r += (byte[1] << 8);
+ if (2 <= dw)
+ {
+ r += byte[2] << 16;
+ r += byte[3] << 24;
+ }
+ }
+ return r;
+}
+
+/* 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);
+ uint8_t byte[4];
+
+ ea = ft32_align (dw, ea);
+
+ byte[0] = v & 0xff;
+ byte[1] = (v >> 8) & 0xff;
+ byte[2] = (v >> 16) & 0xff;
+ byte[3] = (v >> 24) & 0xff;
+ sim_core_write_buffer (sd, cpu, write_map, byte, ea, 1 << dw);
+}
+
+#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))
+ {
+ 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)
+ {
+ 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:
+ ft32_write_item (sd, dw, cpu->state.pm_addr, d);
+ 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:
+ 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_SP_REGNUM] -= 4;
+ cpu->state.regs[FT32_SP_REGNUM] &= 0xffff;
+ cpu_mem_write (sd, 2, cpu->state.regs[FT32_SP_REGNUM], 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_SP_REGNUM]);
+ cpu->state.regs[FT32_SP_REGNUM] += 4;
+ cpu->state.regs[FT32_SP_REGNUM] &= 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)
+ 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.cycles += 1;
+ cpu->state.regs[r_d] = ft32_read_item (sd, dw, pa << 2);
+ break;
+
+ case FT32_PAT_LPMI:
+ cpu->state.cycles += 1;
+ cpu->state.regs[r_d] = ft32_read_item (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[FT32_SP_REGNUM];
+ cpu->state.regs[FT32_SP_REGNUM] -= k16;
+ cpu->state.regs[FT32_SP_REGNUM] &= 0xffff;
+ break;
+
+ case FT32_PAT_UNLINK:
+ cpu->state.regs[FT32_SP_REGNUM] = cpu->state.regs[r_d];
+ cpu->state.regs[FT32_SP_REGNUM] &= 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 *current_cpu, int nr)
+{
+ sim_cpu *cpu = current_cpu;
+
+ /* 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 > 31))
+ abort ();
+
+ switch (nr)
+ {
+ case 0:
+ return &cpu->state.regs[FT32_FP_REGNUM];
+ break;
+ case 1:
+ return &cpu->state.regs[FT32_SP_REGNUM];
+ break;
+ case 31:
+ return &cpu->state.regs[FT32_CC_REGNUM];
+ break;
+ case 32:
+ return &cpu->state.pc;
+ break;
+ default:
+ return &cpu->state.regs[nr - 2];
+ }
+}
+
+int
+ft32_reg_store (SIM_CPU *current_cpu,
+ int rn,
+ unsigned char *memory,
+ int length)
+{
+ if (0 <= rn && rn <= 32)
+ {
+ if (length == 4)
+ *ft32_lookup_register (current_cpu, rn) = ft32_extract_unsigned_integer (memory, 4);
+
+ return 4;
+ }
+ else
+ return 0;
+}
+
+int
+ft32_reg_fetch (SIM_CPU *current_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 (current_cpu, 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;
+ 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;
+ }
+
+ /* 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;
+ }
+
+ 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;
+ }
+
+ /* 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;
+ }
+
+ 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_SP_REGNUM] = 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..2dd0bdc
--- /dev/null
+++ b/sim/ft32/sim-main.h
@@ -0,0 +1,62 @@
+/* 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))
+
+/* 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;
+
+ 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..5bba2a5
--- /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
--
1.7.9.5
next prev parent reply other threads:[~2015-03-19 15:21 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-02-03 4:06 James Bowman
2015-02-10 6:27 ` James Bowman
2015-02-17 10:21 ` Mike Frysinger
2015-02-19 7:06 ` Mike Frysinger
[not found] ` <ORIGINAL-RELEASE-1424557036-20150219070610.GI544@vapier>
2015-02-23 10:40 ` James Bowman
2015-02-24 4:52 ` Mike Frysinger
2015-03-10 16:56 ` James Bowman
2015-03-16 8:25 ` Mike Frysinger
[not found] ` <CA9BBF0458F83C4F9051448B941B57D117234A18@glaexch1>
2015-03-19 18:52 ` Mike Frysinger
2015-03-20 2:57 ` James Bowman
2015-03-20 5:18 ` Mike Frysinger
2015-03-20 5:19 ` Mike Frysinger
2015-03-23 19:21 ` James Bowman
2015-03-26 7:10 ` Mike Frysinger
2015-03-26 19:05 ` James Bowman
2015-03-16 16:38 ` Mike Frysinger
2015-03-17 17:36 ` Joel Brobecker
2015-03-19 15:21 ` James Bowman [this message]
2015-03-19 18:54 ` Mike Frysinger
2015-03-20 3:01 ` James Bowman
2015-03-20 3:47 ` Mike Frysinger
2015-03-20 12:46 ` Joel Brobecker
2015-03-20 15:47 ` Mike Frysinger
2015-03-20 15:50 ` Joel Brobecker
2015-03-22 22:33 ` Mike Frysinger
2015-03-23 12:36 ` Joel Brobecker
2015-03-23 19:15 ` James Bowman
2015-03-23 23:04 ` Joel Brobecker
2015-03-28 6:21 ` Mike Frysinger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CA9BBF0458F83C4F9051448B941B57D117232A0A@glaexch1 \
--to=james.bowman@ftdichip.com \
--cc=brobecker@adacore.com \
--cc=gdb-patches@sourceware.org \
--cc=vapier@gentoo.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox