@@ -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
new file mode 100644
@@ -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
new file mode 100644
@@ -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
new file mode 100644
@@ -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
new file mode 100644
@@ -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_ */
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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
new file mode 100644
@@ -0,0 +1,3 @@
+2015-02-23 James Bowman <james.bowman@ftdichip.com>
+
+ * basic.s, allinsn.exp, testutils.inc: New files.
new file mode 100644
@@ -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
+ }
+}
new file mode 100644
@@ -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"
new file mode 100644
@@ -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