On 03 Feb 2015 04:06, James Bowman wrote:
> FT32 is a new high performance 32-bit RISC core developed by FTDI for embedded applications.
ah, we def don't have enough CPUs in the market as is ;)
> Support for FT32 has already been added to binutils. This patch adds gdb and sim support.
where's the testsuite man ? :) it should be trivial to start one with .s
files -- just look at sim/testsuite/sim/. otherwise there's no way to keep
regressions from slipping in.
> 2014-02-03 James Bowman <james.bowman@ftdichip.com>
>
> * gdb/Makefile.in, gdb/configure.tgt: FT32 target added
> * sim/configure.tgt: FT32 target added
> * sim/configure: Regenerated
> * sim/ft32/configure: Regenerated
> * gdb/ft32-tdep.c,h: Support FT32
> * sim/ft32/*: FT32 simulator
notes:
- the date reflects commit time, not original creation
- ChangeLog entries are split up across dirs
- line items are indented with tabs
- the notes should be full sentences; i.e. you should have a period at the end
on to the code ... a few more notes:
- i wrote this feedback over a few "sessions", so there might be incomplete
thoughts as i paused to do other things
- feel free to ask questions about new things or things that aren't clear
- as you make the adjustments below, make sure to periodically save & build &
run & test ... the sim can be really easy to run into the weeds and trying to
figure out what exactly you got wrong hard to trackback
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
>
> - glibc-tdep.c \
> + ft32-tdep.c \
> + glibc-tdep.c \
looks like you broke the indentation for glibc-tdep.c
> --- /dev/null
> +++ b/gdb/ft32-tdep.c
>
> Copyright (C) 2009-2014 Free Software Foundation, Inc.
it is 2015 now. should fix in all your files.
> +#include <string.h>
do you really need to include this ? other tdeps don't seem to.
> +// #include "record-full.h"
dead code -> delete ?
looks like you've got a couple of dead lines in your patch. please go through
the whole thing and clean this up.
> +/* Use an invalid address value as 'not available' marker. */
> +enum { REG_UNAVAIL = (CORE_ADDR) -1 };
space after the -
> + int established; // Has the new frame been LINKed
use /* comments */ everywhere. seems to come up a few times -- please fix
globally.
we've got bfd_boolean for bool fields too rather than open code it with an int
> +static const unsigned char *
> +ft32_breakpoint_from_pc (struct gdbarch *gdbarch,
> + CORE_ADDR *pcptr, int *lenptr)
indentation is slightly broken
> +{
> + static gdb_byte breakpoint[] = { 0x02, 0x00, 0x34, 0x00 };
const ?
> +char *ft32_register_names[] =
static const char * const ft32_register_names[] ?
> +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;
only one space after the return
> #define IS_PUSH(inst) (((inst) & 0xfff00000) == 0x84000000)
i think usually we put insn constants/etc... into the corresponding
include/opcode/ header rather than pasting them inline. this makes sharing
between opcodes, gdb, sim, etc... much easier.
> +static CORE_ADDR
> +ft32_analyze_prologue (CORE_ADDR start_addr, CORE_ADDR end_addr,
> + struct ft32_frame_cache *cache,
> + struct gdbarch *gdbarch)
indentation is slightly off
> if (start_addr >= end_addr)
> {
> return end_addr;
> }
pretty sure you can (and should) omit braces in cases like this
> + if (IS_PUSH(inst))
space needed between func and args:
if (IS_PUSH (inst))
a quick scan shows this comes up multiple times -- please fix globally
> 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];
should use a tab here since you hit 8 spaces. this comes up a couple of times
-- please fix globally.
> + }
> + // printf("(Framesize=%lld,cache->saved_regs[FT32_PC_REGNUM]=%ld)\n", cache->framesize, cache->saved_regs[FT32_PC_REGNUM]);
> + return next_addr;
> +
> +}
there should be a blank line above the return, not below it ;)
> + plg_end = ft32_analyze_prologue (func_addr,
> + func_end, &cache, gdbarch);
indentation is off
> + /* Don't use line number debug info for assembly source
> + files. */
this doesn't need to be wrapped
> + /* No useable line symbol. Use result of prologue parsing
> + method. */
neither does this
> +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);
indentation is off
> +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);
same here
> + if (regnum < FT32_NUM_REGS && cache->saved_regs[regnum] != REG_UNAVAIL)
> + {
> + return frame_unwind_got_memory (this_frame, regnum,
> + 0x800000 | cache->saved_regs[regnum]);
> + }
drop the braces
> +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);
indentation is broken
> +#if 0
drop all the #if 0 code. this comes up a few times -- please fix globally.
> +static int
> +ft32_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
> + CORE_ADDR addr)
> +{
> + return -1;
> +#if 0
> ... 400 more lines ...
> +#endif
> +}
err, what now ?
> --- /dev/null
> +++ b/gdb/ft32-tdep.h
>
> +/* 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 */
this probably should be in include/gdb/sim-ft32.h instead so you can share it
also, define FT32_NUM_REGS in terms of FT32_PC_REGNUM ?
> +#endif /* ft32-tdep.h */
the style is to list the macro (FT32_TDEP_H), not the file
> --- /dev/null
> +++ b/sim/ft32/Makefile.in
>
> +dtbdir = @datadir@/gdb-`sed q ${srcdir}/../../gdb/version.in`/dtb
unused -> delete
> +SIM_OBJS = interp.o sim-load.o sim-io.o sim-config.o sim-utils.o \
> +sim-options.o sim-module.o sim-core.o sim-endian.o sim-trace.o \
> +sim-engine.o sim-fpu.o sim-bits.o sim-profile.o sim-events.o \
> +sim-memopt.o
please one-line & sort this list:
SIM_OBJS = \
bar.o \
foo.o
you also want to use $(SIM_NEW_COMMON_OBJS) at the start and $(SIM_EXTRA_OBJS)
at the end
missing:
SIM_RUN_OBJS = nrun.o
> +SIM_EXTRA_LIBS = -lm -lz -ldl
you don't seem to use any of these libs -> delete
> +SIM_EXTRA_CLEAN = ft32-clean
> +# SIM_EXTRA_INSTALL = install-dtb
> +# SIM_CFLAGS = -DDTB="\"$(dtbdir)/ft32-gdb.dtb\""
unused -> delete
> +all: interp.o
> +
> +interp.o: interp.c
> +
> +ft32-clean:
don't need any of this -> delete
> --- /dev/null
> +++ b/sim/ft32/configure.ac
>
> +AC_CHECK_TOOL(DTC, dtc)
unused -> delete
> +SIM_AC_OPTION_INLINE()
drop the parens
since you're a new port, you should start with SIM_AC_OPTION_WARNINGS enabled.
obviously that also means cleaning up all the warnings generated in the ft32/
subdir once you do :).
> +AC_CHECK_HEADERS(unistd.h)
unused -> delete
> --- /dev/null
> +++ b/sim/ft32/interp.c
>
> + Contributed by FTDI (support@ftdichip.com)
use <support@ftdichip.com> instead of (support@ftdichip.com)
> +This file is part of GDB, the GNU debugger.
this isn't part of gdb ;). please fix the indentation in this comment block.
these comments apply to all your sim files it looks like.
> +#include <sys/times.h>
> +#include <sys/param.h>
you've got a lot of weird system header includes in your files. please check
each one to see if they're actually used.
> +#include <netinet/in.h> /* for byte ordering macros */
i really hope you're not using macros (like hton/ntoh) from this header :).
that's not how the sim handles endianness. a quick glance shows you're not, so
just delete the header and be done.
> +typedef int word;
> +typedef unsigned int uword;
at least uword is not used, and word looks hardly used. i guess you should punt
both and tweak the little code relying on them.
> +extern const ft32_opc_info_t ft32_opc_info[128];
> +
> +host_callback * callback;
> +
> +FILE *tracefile;
> +
> +static char *myname;
> +static SIM_OPEN_KIND sim_kind;
> +static int issue_messages = 0;
> +
> +struct {
> + uint32_t regs[32];
> + uint32_t pc;
> + uint8_t pm[262144];
> + uint8_t ram[65536];
> + uint64_t num_i;
> + uint64_t cycles;
> + uint64_t next_tick_cycle;
> + enum sim_stop reason;
> + int pm_unlock;
> + uint32_t pm_addr;
> + int exception;
> +} cpu;
there should be no global state. read-only constants are OK, but that's not
what these are.
> +unsigned long
> +ft32_extract_unsigned_integer (addr, len)
should be static
> + unsigned char * addr;
> + int len;
we want these old style prototypes to die ... please convert globally
> +{
> + unsigned long retval;
> + unsigned char * p;
> + unsigned char * startaddr = (unsigned char *)addr;
> + unsigned char * endaddr = startaddr + len;
there should be no space after the * as part of the decl:
unsigned char *p;
but there should be a space after the cast:
... = (unsigned char *) addr;
> + if (len > (int) sizeof (unsigned long))
> + printf ("That operation is not available on integers of more than %ld bytes.",
> + sizeof (unsigned long));
general rule: a sim should never write directly to stdout/stderr (i.e. use
printf or fprintf). look at common/sim-io.h for the funcs you should instead.
> +void
> +ft32_store_unsigned_integer (addr, len, val)
same feedback for this func as above
> +void
> +sim_size (int s)
> +{
> +}
once you convert to nrun.c (see earlier comments), you can drop this
> +static void
> +set_initial_gprs ()
funcs that take no args must use (void) in C and not ().
> +{
> + int i;
> + long space;
> +}
pointless func ? delete it.
> +static void
> +interrupt ()
> +{
> + // cpu.asregs.exception = SIGINT;
> +}
pointless func ? delete it.
> +uint32_t cpu_pm_read(SIM_DESC sd, int dw, uint32_t ea)
static, and space before the (
> +{
> + sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
> + address_word cia = CIA_GET (scpu);
> + uint32_t r;
> +
> + if ((ea & ~0x3ffff) != 0)
> + {
> + fprintf(stderr, "Illegal PM address %08x, pc %#x\n", ea, cpu.pc);
> + exit(0);
> + }
i'm not sure what this mask is trying to accomplish ... are you attemting to
enforce some kind of address space ? when you initialized the sim, you should
have allocated the memory then, and let the sim itself take care of valid
addresses.
> +void
> +sim_resume (sd, step, siggnal)
you should use sim-resume.o instead
then you'll need a sim_engine_run like so:
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 (cpu);
if (sim_events_tick (sd))
sim_events_process (sd);
}
}
then declare a step_once func and put all the cpu-specific logc in there
> +int
> +sim_write (sd, addr, buffer, size)
>
> +int
> +sim_read (sd, addr, buffer, size)
i think once you switch to nrun.c, you won't need these anymore
> +int
> +sim_store_register (sd, rn, memory, length)
>
> +int
> +sim_fetch_register (sd, rn, memory, length)
you should create a helper func that does the rn<->pointer lookup so that you
can use it here. e.g. something like:
static unsigned_word
ft32_lookup_register (SIM_DESC sd, int nr)
{
SIM_CPU *cpu = STATE_CPU (sd, 0);
switch (nr)
{
case 0: return cpu->registers[0];
...
default: return NULL;
}
}
then the store/fetch funcs become much simpler
ideally you'd switch to sim-reg.o in your Makefile's SIM_OBJS ... that'll
provide these entry points. that would require also enabling sim-model.o
& SIM_AC_OPTION_DEFAULT_MODEL support, but i don't think that'd be too hard.
if you look at bfin/machs.c and start at "sim_machs", i think you should be
able to track it down easily enough.
> +int
> +sim_trace (sd)
once you switch to nrun.c, you can delete this
> +void
> +sim_stop_reason (sd, reason, sigrc)
add sim-reason.o to your SIM_OBJS to get this for free
> +int
> +sim_stop (sd)
add sim-stop.o to your SIM_OBJS to get this for free
> +void
> +sim_info (sd, verbose)
once you switch to nrun.c/SIM_NEW_COMMON_OBJS, you get this for free
> +SIM_DESC
> +sim_open (kind, cb, abfd, argv)
before this func, you should add:
/* 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 sd = sim_state_alloc (kind, cb);
> + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
i don't think you need this assert
after this alloc, you should do:
/* 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;
}
you'll have to add sim-cpu.o to your SIM_OMJS
> + if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
> + return 0;
you should call free_state in the error path here
after this section, you should call:
if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
/* getopt will print the error message so we just have to exit if this fails.
FIXME: Hmmm... in the case of gdb we need getopt to call
print_filtered. */
if (sim_parse_args (sd, argv) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
> + sim_do_command(sd," memory region 0x00000000,0x4000000") ;
> + sim_do_command(sd," memory region 0xE0000000,0x10000") ;
instead, do:
/* Allocate external memory if none specified by user.
Use address 4 here in case the user wanted address 0 unmapped. */
if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0)
{
sim_do_command(sd, "memory region 0x00000000,0x4000000");
sim_do_command(sd, "memory region 0xE0000000,0x10000");
}
notice the style fixes too
then you'll want to do:
/* Check for/establish the a reference program image. */
if (sim_analyze_program (sd,
(STATE_PROG_ARGV (sd) != NULL
? *STATE_PROG_ARGV (sd)
: NULL), abfd) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
> + myname = argv[0];
won't be needed after you drop sim_load (see below)
> + callback = cb;
you shouldn't need this -- the call to sim_state_alloc above already assigned
the callback
> + if (kind == SIM_OPEN_STANDALONE)
> + issue_messages = 1;
this variable looks pointless in this whole codebase -> delete
> + set_initial_gprs (); /* Reset the GPR registers. */
you should move this to just before the return, and walk all cpus:
/* CPU specific initialization. */
for (i = 0; i < MAX_NR_PROCESSORS; ++i)
{
SIM_CPU *cpu = STATE_CPU (sd, i);
set_initial_gprs (sd, cpu);
}
> + if (sim_config (sd) != SIM_RC_OK)
> + {
> + sim_module_uninstall (sd);
call your new free_state() helper instead
> + if (sim_post_argv_init (sd) != SIM_RC_OK)
> + {
> + /* Uninstall the modules to avoid memory leaks,
> + file descriptor leaks, etc. */
> + sim_module_uninstall (sd);
delete the comment & call your new free_state() helper instead
> +void
> +sim_close (sd, quitting)
> + SIM_DESC sd;
> + int quitting;
> +{
> + /* nothing to do */
> +}
you should do:
sim_module_uninstall (sd);
> +static void
> +load_dtb (SIM_DESC sd, const char *filename)
unused -> delete
> +SIM_RC
> +sim_load (sd, prog, abfd, from_tty)
add sim-hload.o to your SIM_OBJS and you get this for free
> +SIM_RC
> +sim_create_inferior (sd, prog_bfd, argv, env)
> +{
> + sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
SIM_CPU *cpu = STATE_CPU (sd, 0);
> + /* Set the initial register set. */
> + l = issue_messages;
> + issue_messages = 0;
> + set_initial_gprs ();
> + issue_messages = l;
you shouldn't need to do this. you already handled this in sim_open.
> + // printf("start address %#lx\n", bfd_get_start_address (prog_bfd));
> + cpu.pc = bfd_get_start_address (prog_bfd);
> + cpu.regs[31] = 0x00000;
> + cpu.num_i = 0;
> + cpu.cycles = 0;
> + cpu.next_tick_cycle = 100000;
you should instead do:
/* Set the PC. */
if (abfd != NULL)
addr = bfd_get_start_address (abfd);
else
addr = 0;
sim_pc_set (cpu, addr);
if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
{
freeargv (STATE_PROG_ARGV (sd));
STATE_PROG_ARGV (sd) = dupargv (argv);
}
> +void
> +sim_kill (sd)
you shouldn't need this -> delete
looks like i should clean up the tree too
> +void
> +sim_do_command (sd, cmd)
once you switch to nrun.c/SIM_NEW_COMMON_OBJS, you get this for free
> +void
> +sim_set_callbacks (ptr)
once you switch to nrun.c, you can delete this
> --- /dev/null
> +++ b/sim/ft32/sim-main.h
>
> +#define SIM_HAVE_BIENDIAN
once you switch to nrun.c, you can delete this
> + /* The following are internal simulator state variables: */
> +#define CIA_GET(CPU) ((CPU)->registers[PCIDX] + 0)
> +#define CIA_SET(CPU,CIA) ((CPU)->registers[PCIDX] = (CIA))
you should define these to CPU_PC_SET/CPU_PC_GET instead. we should probably
make that the default too so ports don't have to do it.
> +/* 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. */
gnu style says to put two spaces after periods
that said, i have a hard time believing the speed thing here when your current
store/fetch register functions are doing byte level memory accesses
> + unsigned_word registers[19];
per above, you should probably create dedicated fields for each register. this
would also make it easier to debug assuming you have named registers like $pc
and $fp and $sp.
> --- /dev/null
> +++ b/sim/ft32/sysdep.h
looks like you copied & pasted this from another port. fairly certain you don't
need or want any of it. just delete the file entirely.
-mike
@@ -647,6 +647,7 @@ ALL_TARGET_OBS = \
dicos-tdep.o \
fbsd-tdep.o \
frv-linux-tdep.o frv-tdep.o \
+ ft32-tdep.o \
h8300-tdep.o \
hppabsd-tdep.o hppanbsd-tdep.o hppaobsd-tdep.o \
hppa-hpux-tdep.o hppa-linux-tdep.o hppa-tdep.o \
@@ -943,7 +944,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 \
@@ -1646,7 +1647,8 @@ ALLDEPFILES = \
fbsd-nat.c \
fbsd-tdep.c \
fork-child.c \
- glibc-tdep.c \
+ ft32-tdep.c \
+ glibc-tdep.c \
go32-nat.c h8300-tdep.c \
hppa-tdep.c hppa-hpux-tdep.c hppa-hpux-nat.c \
hppa-linux-tdep.c hppa-linux-nat.c \
@@ -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"
new file mode 100644
@@ -0,0 +1,1007 @@
+/* Target-dependent code for FT32.
+
+ Copyright (C) 2009-2014 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 <string.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 "record-full.h"
+
+#include "gdb_assert.h"
+
+#include "ft32-tdep.h"
+
+/* Local functions. */
+
+extern void _initialize_ft32_tdep (void);
+
+/* Use an invalid address value 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;
+ int 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 gdb_byte breakpoint[] = { 0x02, 0x00, 0x34, 0x00 };
+
+ *lenptr = sizeof (breakpoint);
+ return breakpoint;
+}
+
+/* FT32 register names. */
+
+char *ft32_register_names[] =
+{
+ "fp", "sp",
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "cc",
+ "pc"
+};
+
+/* Implement the "register_name" gdbarch method. */
+
+static const char *
+ft32_register_name (struct gdbarch *gdbarch, int reg_nr)
+{
+ if (reg_nr < 0)
+ return NULL;
+ if (reg_nr >= FT32_NUM_REGS)
+ return NULL;
+ return ft32_register_names[reg_nr];
+}
+
+/* Implement the "register_type" gdbarch method. */
+
+static struct type *
+ft32_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+ if (reg_nr == FT32_PC_REGNUM)
+ return builtin_type (gdbarch)->builtin_func_ptr;
+ else if (reg_nr == FT32_SP_REGNUM || reg_nr == FT32_FP_REGNUM)
+ return builtin_type (gdbarch)->builtin_data_ptr;
+ else
+ return builtin_type (gdbarch)->builtin_int32;
+}
+
+/* Write into appropriate registers a function return value
+ of type TYPE, given in virtual format. */
+
+static void
+ft32_store_return_value (struct type *type, struct regcache *regcache,
+ const void *valbuf)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ CORE_ADDR regval;
+ int len = TYPE_LENGTH (type);
+
+ /* Things always get returned in RET1_REGNUM, RET2_REGNUM. */
+ regval = extract_unsigned_integer (valbuf, len > 4 ? 4 : len, byte_order);
+ regcache_cooked_write_unsigned (regcache, FT32_R0_REGNUM, regval);
+ if (len > 4)
+ {
+ regval = extract_unsigned_integer ((gdb_byte *) valbuf + 4,
+ len - 4, byte_order);
+ regcache_cooked_write_unsigned (regcache, FT32_R1_REGNUM, regval);
+ }
+}
+
+/* Decode the instructions within the given address range. Decide
+ when we must have reached the end of the function prologue. If a
+ frame_info pointer is provided, fill in its saved_regs etc.
+
+ Returns the address of the first instruction after the prologue. */
+
+#define IS_PUSH(inst) (((inst) & 0xfff00000) == 0x84000000)
+#define PUSH_REG(inst) (FT32_R0_REGNUM + (((inst) >> 15) & 0x1f))
+#define IS_LINK(inst) (((inst) & 0xffff0000) == 0x95d00000)
+#define LINK_SIZE(inst) ((inst) & 0xffff)
+
+static CORE_ADDR
+ft32_analyze_prologue (CORE_ADDR start_addr, CORE_ADDR end_addr,
+ struct ft32_frame_cache *cache,
+ struct gdbarch *gdbarch)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ CORE_ADDR next_addr;
+ ULONGEST inst, inst2;
+ LONGEST offset;
+ int regnum;
+
+ // printf("(%#lx-%#lx)", start_addr, end_addr);
+ 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;
+ }
+ }
+ // printf("(Framesize=%lld,cache->saved_regs[FT32_PC_REGNUM]=%ld)\n", cache->framesize, cache->saved_regs[FT32_PC_REGNUM]);
+ return next_addr;
+
+}
+
+/* Find the end of function prologue. */
+
+static CORE_ADDR
+ft32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ CORE_ADDR func_addr = 0, func_end = 0;
+ const char *func_name;
+
+ /* See if we can determine the end of the prologue via the symbol table.
+ If so, then return either PC, or the PC after the prologue, whichever
+ is greater. */
+ if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
+ {
+ CORE_ADDR post_prologue_pc
+ = skip_prologue_using_sal (gdbarch, func_addr);
+ if (post_prologue_pc != 0)
+ return max (pc, post_prologue_pc);
+ else
+ {
+ /* Can't determine prologue from the symbol table, need to examine
+ instructions. */
+ struct symtab_and_line sal;
+ struct symbol *sym;
+ struct ft32_frame_cache cache;
+ CORE_ADDR plg_end;
+
+ memset (&cache, 0, sizeof cache);
+
+ plg_end = ft32_analyze_prologue (func_addr,
+ func_end, &cache, gdbarch);
+ /* Found a function. */
+ sym = lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL);
+ /* Don't use line number debug info for assembly source
+ files. */
+ if (sym && SYMBOL_LANGUAGE (sym) != language_asm)
+ {
+ sal = find_pc_line (func_addr, 0);
+ if (sal.end && sal.end < func_end)
+ {
+ /* Found a line number, use it as end of
+ prologue. */
+ return sal.end;
+ }
+ }
+ /* No useable line symbol. Use result of prologue parsing
+ method. */
+ return plg_end;
+ }
+ }
+
+ /* No function symbol -- just return the PC. */
+ return (CORE_ADDR) pc;
+}
+
+/* Implement the "read_pc" gdbarch method. */
+
+static CORE_ADDR
+ft32_read_pc (struct regcache *regcache)
+{
+ ULONGEST pc;
+
+ regcache_cooked_read_unsigned (regcache, FT32_PC_REGNUM, &pc);
+ return pc;
+}
+
+/* Implement the "write_pc" gdbarch method. */
+
+static void
+ft32_write_pc (struct regcache *regcache, CORE_ADDR val)
+{
+ regcache_cooked_write_unsigned (regcache, FT32_PC_REGNUM, val);
+}
+
+/* Implement the "unwind_sp" gdbarch method. */
+
+static CORE_ADDR
+ft32_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, FT32_SP_REGNUM);
+}
+
+/* Given a return value in `regbuf' with a type `valtype',
+ extract and copy its value into `valbuf'. */
+
+static void
+ft32_extract_return_value (struct type *type, struct regcache *regcache,
+ void *dst)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ bfd_byte *valbuf = dst;
+ int len = TYPE_LENGTH (type);
+ ULONGEST tmp;
+
+ /* By using store_unsigned_integer we avoid having to do
+ anything special for small big-endian values. */
+ regcache_cooked_read_unsigned (regcache, FT32_R0_REGNUM, &tmp);
+ store_unsigned_integer (valbuf, (len > 4 ? len - 4 : len), byte_order, tmp);
+
+ /* Ignore return values more than 8 bytes in size because the ft32
+ returns anything more than 8 bytes in the stack. */
+ if (len > 4)
+ {
+ regcache_cooked_read_unsigned (regcache, FT32_R1_REGNUM, &tmp);
+ store_unsigned_integer (valbuf + len - 4, 4, byte_order, tmp);
+ }
+}
+
+/* Implement the "return_value" gdbarch method. */
+
+static enum return_value_convention
+ft32_return_value (struct gdbarch *gdbarch, struct value *function,
+ struct type *valtype, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ if (TYPE_LENGTH (valtype) > 8)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ else
+ {
+ if (readbuf != NULL)
+ ft32_extract_return_value (valtype, regcache, readbuf);
+ if (writebuf != NULL)
+ ft32_store_return_value (valtype, regcache, writebuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+}
+
+/* Allocate and initialize a ft32_frame_cache object. */
+
+static struct ft32_frame_cache *
+ft32_alloc_frame_cache (void)
+{
+ struct ft32_frame_cache *cache;
+ int i;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct ft32_frame_cache);
+
+ cache->base = 0;
+ cache->saved_sp = 0;
+ cache->pc = 0;
+ cache->framesize = 0;
+ for (i = 0; i < FT32_NUM_REGS; ++i)
+ cache->saved_regs[i] = REG_UNAVAIL;
+
+ return cache;
+}
+
+/* Populate a ft32_frame_cache object for this_frame. */
+
+static struct ft32_frame_cache *
+ft32_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct ft32_frame_cache *cache;
+ CORE_ADDR current_pc;
+ int i;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = ft32_alloc_frame_cache ();
+ *this_cache = cache;
+
+ cache->base = get_frame_register_unsigned (this_frame, FT32_FP_REGNUM);
+ if (cache->base == 0)
+ return cache;
+
+ cache->pc = get_frame_func (this_frame);
+ current_pc = get_frame_pc (this_frame);
+ if (cache->pc)
+ {
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ ft32_analyze_prologue (cache->pc, current_pc, cache, gdbarch);
+ if (!cache->established)
+ cache->base = get_frame_register_unsigned (this_frame, FT32_SP_REGNUM);
+ }
+
+ cache->saved_sp = cache->base - 4;
+
+ for (i = 0; i < FT32_NUM_REGS; ++i)
+ if (cache->saved_regs[i] != REG_UNAVAIL)
+ cache->saved_regs[i] = cache->base + cache->saved_regs[i];
+
+ return cache;
+}
+
+/* Implement the "unwind_pc" gdbarch method. */
+
+static CORE_ADDR
+ft32_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, FT32_PC_REGNUM);
+}
+
+/* Given a GDB frame, determine the address of the calling function's
+ frame. This will be used to create a new GDB frame struct. */
+
+static void
+ft32_frame_this_id (struct frame_info *this_frame,
+ void **this_prologue_cache, struct frame_id *this_id)
+{
+ struct ft32_frame_cache *cache = ft32_frame_cache (this_frame,
+ this_prologue_cache);
+
+ /* This marks the outermost frame. */
+ if (cache->base == 0)
+ return;
+
+ *this_id = frame_id_build (cache->saved_sp, cache->pc);
+}
+
+/* Get the value of register regnum in the previous stack frame. */
+
+static struct value *
+ft32_frame_prev_register (struct frame_info *this_frame,
+ void **this_prologue_cache, int regnum)
+{
+ struct ft32_frame_cache *cache = ft32_frame_cache (this_frame,
+ this_prologue_cache);
+
+ gdb_assert (regnum >= 0);
+
+ if (regnum == FT32_SP_REGNUM && cache->saved_sp)
+ return frame_unwind_got_constant (this_frame, regnum, cache->saved_sp);
+
+ if (regnum < FT32_NUM_REGS && cache->saved_regs[regnum] != REG_UNAVAIL)
+ {
+ return frame_unwind_got_memory (this_frame, regnum,
+ 0x800000 | cache->saved_regs[regnum]);
+ }
+
+ return frame_unwind_got_register (this_frame, regnum, regnum);
+}
+
+static const struct frame_unwind ft32_frame_unwind =
+{
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ ft32_frame_this_id,
+ ft32_frame_prev_register,
+ NULL,
+ default_frame_sniffer
+};
+
+/* Return the base address of this_frame. */
+
+static CORE_ADDR
+ft32_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+ struct ft32_frame_cache *cache = ft32_frame_cache (this_frame,
+ this_cache);
+
+ return cache->base;
+}
+
+static const struct frame_base ft32_frame_base =
+{
+ &ft32_frame_unwind,
+ ft32_frame_base_address,
+ ft32_frame_base_address,
+ ft32_frame_base_address
+};
+
+static struct frame_id
+ft32_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ CORE_ADDR sp = get_frame_register_unsigned (this_frame, FT32_SP_REGNUM);
+
+ return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+#if 0
+/* Read an unsigned integer from the inferior, and adjust
+ endianess. */
+static ULONGEST
+ft32_process_readu (CORE_ADDR addr, char *buf,
+ int length, enum bfd_endian byte_order)
+{
+ if (target_read_memory (addr, buf, length))
+ {
+ if (record_debug)
+ printf_unfiltered (_("Process record: error reading memory at "
+ "addr 0x%s len = %d.\n"),
+ paddress (target_gdbarch (), addr), length);
+ return -1;
+ }
+
+ return extract_unsigned_integer (buf, length, byte_order);
+}
+#endif
+
+/* Parse the current instruction and record the values of the registers and
+ memory that will be changed in current instruction to "record_arch_list".
+ Return -1 if something wrong. */
+
+static int
+ft32_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
+ CORE_ADDR addr)
+{
+ return -1;
+#if 0
+ gdb_byte buf[4];
+ uint16_t inst;
+ uint32_t tmpu32;
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog, "Process record: ft32_process_record "
+ "addr = 0x%s\n",
+ paddress (target_gdbarch (), addr));
+
+ inst = (uint16_t) ft32_process_readu (addr, buf, 2, byte_order);
+
+ /* Decode instruction. */
+ if (inst & (1 << 15))
+ {
+ if (inst & (1 << 14))
+ {
+ /* This is a Form 3 instruction. */
+ int opcode = (inst >> 10 & 0xf);
+
+ switch (opcode)
+ {
+ case 0x00: /* beq */
+ case 0x01: /* bne */
+ case 0x02: /* blt */
+ case 0x03: /* bgt */
+ case 0x04: /* bltu */
+ case 0x05: /* bgtu */
+ case 0x06: /* bge */
+ case 0x07: /* ble */
+ case 0x08: /* bgeu */
+ case 0x09: /* bleu */
+ /* Do nothing. */
+ break;
+ default:
+ {
+ /* Do nothing. */
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* This is a Form 2 instruction. */
+ int opcode = (inst >> 12 & 0x3);
+ switch (opcode)
+ {
+ case 0x00: /* inc */
+ case 0x01: /* dec */
+ case 0x02: /* gsr */
+ {
+ int reg = (inst >> 8) & 0xf;
+ if (record_full_arch_list_add_reg (regcache, reg))
+ return -1;
+ }
+ break;
+ case 0x03: /* ssr */
+ {
+ /* Do nothing until GDB learns about ft32's special
+ registers. */
+ }
+ break;
+ default:
+ /* Do nothing. */
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* This is a Form 1 instruction. */
+ int opcode = inst >> 8;
+
+ switch (opcode)
+ {
+ case 0x00: /* nop */
+ /* Do nothing. */
+ break;
+ case 0x01: /* ldi.l (immediate) */
+ case 0x02: /* mov (register-to-register) */
+ {
+ int reg = (inst >> 4) & 0xf;
+ if (record_full_arch_list_add_reg (regcache, reg))
+ return -1;
+ }
+ break;
+ case 0x03: /* jsra */
+ {
+ regcache_raw_read (regcache,
+ FT32_SP_REGNUM, (gdb_byte *) & tmpu32);
+ tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+ 4, byte_order);
+ if (record_full_arch_list_add_reg (regcache, FT32_FP_REGNUM)
+ || (record_full_arch_list_add_reg (regcache,
+ FT32_SP_REGNUM))
+ || record_full_arch_list_add_mem (tmpu32 - 12, 12))
+ return -1;
+ }
+ break;
+ case 0x04: /* ret */
+ {
+ if (record_full_arch_list_add_reg (regcache, FT32_FP_REGNUM)
+ || (record_full_arch_list_add_reg (regcache,
+ FT32_SP_REGNUM)))
+ return -1;
+ }
+ break;
+ case 0x05: /* add.l */
+ {
+ int reg = (inst >> 4) & 0xf;
+ if (record_full_arch_list_add_reg (regcache, reg))
+ return -1;
+ }
+ break;
+ case 0x06: /* push */
+ {
+ int reg = (inst >> 4) & 0xf;
+ regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
+ tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+ 4, byte_order);
+ if (record_full_arch_list_add_reg (regcache, reg)
+ || record_full_arch_list_add_mem (tmpu32 - 4, 4))
+ return -1;
+ }
+ break;
+ case 0x07: /* pop */
+ {
+ int a = (inst >> 4) & 0xf;
+ int b = inst & 0xf;
+ if (record_full_arch_list_add_reg (regcache, a)
+ || record_full_arch_list_add_reg (regcache, b))
+ return -1;
+ }
+ break;
+ case 0x08: /* lda.l */
+ {
+ int reg = (inst >> 4) & 0xf;
+ if (record_full_arch_list_add_reg (regcache, reg))
+ return -1;
+ }
+ break;
+ case 0x09: /* sta.l */
+ {
+ tmpu32 = (uint32_t) ft32_process_readu (addr+2, buf,
+ 4, byte_order);
+ if (record_full_arch_list_add_mem (tmpu32, 4))
+ return -1;
+ }
+ break;
+ case 0x0a: /* ld.l (register indirect) */
+ {
+ int reg = (inst >> 4) & 0xf;
+ if (record_full_arch_list_add_reg (regcache, reg))
+ return -1;
+ }
+ break;
+ case 0x0b: /* st.l */
+ {
+ int reg = (inst >> 4) & 0xf;
+ regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
+ tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+ 4, byte_order);
+ if (record_full_arch_list_add_mem (tmpu32, 4))
+ return -1;
+ }
+ break;
+ case 0x0c: /* ldo.l */
+ {
+ int reg = (inst >> 4) & 0xf;
+ if (record_full_arch_list_add_reg (regcache, reg))
+ return -1;
+ }
+ break;
+ case 0x0d: /* sto.l */
+ {
+ int reg = (inst >> 4) & 0xf;
+ uint32_t offset = (uint32_t) ft32_process_readu (addr+2, buf, 4,
+ byte_order);
+ regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
+ tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+ 4, byte_order);
+ tmpu32 += offset;
+ if (record_full_arch_list_add_mem (tmpu32, 4))
+ return -1;
+ }
+ break;
+ case 0x0e: /* cmp */
+ {
+ if (record_full_arch_list_add_reg (regcache, FT32_CC_REGNUM))
+ return -1;
+ }
+ break;
+ case 0x0f:
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ {
+ /* Do nothing. */
+ break;
+ }
+ case 0x19: /* jsr */
+ {
+ regcache_raw_read (regcache,
+ FT32_SP_REGNUM, (gdb_byte *) & tmpu32);
+ tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+ 4, byte_order);
+ if (record_full_arch_list_add_reg (regcache, FT32_FP_REGNUM)
+ || (record_full_arch_list_add_reg (regcache,
+ FT32_SP_REGNUM))
+ || record_full_arch_list_add_mem (tmpu32 - 12, 12))
+ return -1;
+ }
+ break;
+ case 0x1a: /* jmpa */
+ {
+ /* Do nothing. */
+ }
+ break;
+ case 0x1b: /* ldi.b (immediate) */
+ case 0x1c: /* ld.b (register indirect) */
+ case 0x1d: /* lda.b */
+ {
+ int reg = (inst >> 4) & 0xf;
+ if (record_full_arch_list_add_reg (regcache, reg))
+ return -1;
+ }
+ break;
+ case 0x1e: /* st.b */
+ {
+ int reg = (inst >> 4) & 0xf;
+ regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
+ tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+ 4, byte_order);
+ if (record_full_arch_list_add_mem (tmpu32, 1))
+ return -1;
+ }
+ break;
+ case 0x1f: /* sta.b */
+ {
+ tmpu32 = ft32_process_readu (addr+2, (char *) buf,
+ 4, byte_order);
+ if (record_full_arch_list_add_mem (tmpu32, 1))
+ return -1;
+ }
+ break;
+ case 0x20: /* ldi.s (immediate) */
+ case 0x21: /* ld.s (register indirect) */
+ case 0x22: /* lda.s */
+ {
+ int reg = (inst >> 4) & 0xf;
+ if (record_full_arch_list_add_reg (regcache, reg))
+ return -1;
+ }
+ break;
+ case 0x23: /* st.s */
+ {
+ int reg = (inst >> 4) & 0xf;
+ regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
+ tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+ 4, byte_order);
+ if (record_full_arch_list_add_mem (tmpu32, 2))
+ return -1;
+ }
+ break;
+ case 0x24: /* sta.s */
+ {
+ tmpu32 = ft32_process_readu (addr+2, (char *) buf,
+ 4, byte_order);
+ if (record_full_arch_list_add_mem (tmpu32, 2))
+ return -1;
+ }
+ break;
+ case 0x25: /* jmp */
+ {
+ /* Do nothing. */
+ }
+ break;
+ case 0x26: /* and */
+ case 0x27: /* lshr */
+ case 0x28: /* ashl */
+ case 0x29: /* sub.l */
+ case 0x2a: /* neg */
+ case 0x2b: /* or */
+ case 0x2c: /* not */
+ case 0x2d: /* ashr */
+ case 0x2e: /* xor */
+ case 0x2f: /* mul.l */
+ {
+ int reg = (inst >> 4) & 0xf;
+ if (record_full_arch_list_add_reg (regcache, reg))
+ return -1;
+ }
+ break;
+ case 0x30: /* swi */
+ {
+ /* We currently implement support for libgloss'
+ system calls. */
+
+ int inum = ft32_process_readu (addr+2, (char *) buf,
+ 4, byte_order);
+
+ switch (inum)
+ {
+ case 0x1: /* SYS_exit */
+ {
+ /* Do nothing. */
+ }
+ break;
+ case 0x2: /* SYS_open */
+ {
+ if (record_full_arch_list_add_reg (regcache, RET1_REGNUM))
+ return -1;
+ }
+ break;
+ case 0x4: /* SYS_read */
+ {
+ uint32_t length, ptr;
+
+ /* Read buffer pointer is in $r1. */
+ regcache_raw_read (regcache, 3, (gdb_byte *) & ptr);
+ ptr = extract_unsigned_integer ((gdb_byte *) & ptr,
+ 4, byte_order);
+
+ /* String length is at 0x12($fp). */
+ regcache_raw_read (regcache,
+ FT32_FP_REGNUM, (gdb_byte *) & tmpu32);
+ tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+ 4, byte_order);
+ length = ft32_process_readu (tmpu32+20, (char *) buf,
+ 4, byte_order);
+
+ if (record_full_arch_list_add_mem (ptr, length))
+ return -1;
+ }
+ break;
+ case 0x5: /* SYS_write */
+ {
+ if (record_full_arch_list_add_reg (regcache, RET1_REGNUM))
+ return -1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case 0x31: /* div.l */
+ case 0x32: /* udiv.l */
+ case 0x33: /* mod.l */
+ case 0x34: /* umod.l */
+ {
+ int reg = (inst >> 4) & 0xf;
+ if (record_full_arch_list_add_reg (regcache, reg))
+ return -1;
+ }
+ break;
+ case 0x35: /* brk */
+ /* Do nothing. */
+ break;
+ case 0x36: /* ldo.b */
+ {
+ int reg = (inst >> 4) & 0xf;
+ if (record_full_arch_list_add_reg (regcache, reg))
+ return -1;
+ }
+ break;
+ case 0x37: /* sto.b */
+ {
+ int reg = (inst >> 4) & 0xf;
+ uint32_t offset = (uint32_t) ft32_process_readu (addr+2, buf, 4,
+ byte_order);
+ regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
+ tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+ 4, byte_order);
+ tmpu32 += offset;
+ if (record_full_arch_list_add_mem (tmpu32, 1))
+ return -1;
+ }
+ break;
+ case 0x38: /* ldo.s */
+ {
+ int reg = (inst >> 4) & 0xf;
+ if (record_full_arch_list_add_reg (regcache, reg))
+ return -1;
+ }
+ break;
+ case 0x39: /* sto.s */
+ {
+ int reg = (inst >> 4) & 0xf;
+ uint32_t offset = (uint32_t) ft32_process_readu (addr+2, buf, 4,
+ byte_order);
+ regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
+ tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
+ 4, byte_order);
+ tmpu32 += offset;
+ if (record_full_arch_list_add_mem (tmpu32, 2))
+ return -1;
+ }
+ break;
+ default:
+ /* Do nothing. */
+ break;
+ }
+ }
+
+ if (record_full_arch_list_add_reg (regcache, FT32_PC_REGNUM))
+ return -1;
+ if (record_full_arch_list_add_end ())
+ return -1;
+ return 0;
+#endif
+}
+
+/* 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);
+
+ /* Support reverse debugging. */
+ set_gdbarch_process_record (gdbarch, ft32_process_record);
+
+ return gdbarch;
+}
+
+/* Register this machine's init routine. */
+
+void
+_initialize_ft32_tdep (void)
+{
+ register_gdbarch_init (bfd_arch_ft32, ft32_gdbarch_init);
+}
new file mode 100644
@@ -0,0 +1,42 @@
+/* Target-dependent code for the FT32.
+
+ Copyright (C) 2002-2013 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 MOXIE. */
+};
+
+/* 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 */
+
+#endif /* ft32-tdep.h */
@@ -111,6 +111,9 @@ case "${target}" in
powerpc*-*-*)
SIM_ARCH(ppc)
;;
+ ft32-*-*)
+ SIM_ARCH(ft32)
+ ;;
v850*-*-*)
SIM_ARCH(v850)
sim_igen=yes
new file mode 100644
@@ -0,0 +1,38 @@
+# Makefile template for Configure for the ft32 sim library.
+# Copyright (C) 2008-2013 Free Software Foundation, Inc.
+# Written by Anthony Green
+#
+# 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
+
+dtbdir = @datadir@/gdb-`sed q ${srcdir}/../../gdb/version.in`/dtb
+
+SIM_OBJS = interp.o sim-load.o sim-io.o sim-config.o sim-utils.o \
+sim-options.o sim-module.o sim-core.o sim-endian.o sim-trace.o \
+sim-engine.o sim-fpu.o sim-bits.o sim-profile.o sim-events.o \
+sim-memopt.o
+
+SIM_EXTRA_LIBS = -lm -lz -ldl
+SIM_EXTRA_CLEAN = ft32-clean
+# SIM_EXTRA_INSTALL = install-dtb
+# SIM_CFLAGS = -DDTB="\"$(dtbdir)/ft32-gdb.dtb\""
+
+## COMMON_POST_CONFIG_FRAG
+
+all: interp.o
+
+interp.o: interp.c
+
+ft32-clean:
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,18 @@
+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
+
+AC_CHECK_TOOL(DTC, dtc)
+
+SIM_AC_OPTION_ENDIAN(LITTLE_ENDIAN)
+SIM_AC_OPTION_ALIGNMENT(STRICT_ALIGNMENT)
+SIM_AC_OPTION_HOSTENDIAN
+SIM_AC_OPTION_ENVIRONMENT
+SIM_AC_OPTION_INLINE()
+
+AC_CHECK_HEADERS(unistd.h)
+
+SIM_AC_OUTPUT
new file mode 100644
@@ -0,0 +1,1014 @@
+/* Simulator for the FT32 processor
+ Copyright (C) 2008-2013 Free Software Foundation, Inc.
+ Contributed by FTDI (support@ftdichip.com)
+
+This file is part of GDB, the GNU debugger.
+
+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 "sysdep.h"
+#include <sys/times.h>
+#include <sys/param.h>
+#include <netinet/in.h> /* for byte ordering macros */
+#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"
+
+extern const ft32_opc_info_t ft32_opc_info[128];
+
+typedef int word;
+typedef unsigned int uword;
+
+host_callback * callback;
+
+FILE *tracefile;
+
+static char *myname;
+static SIM_OPEN_KIND sim_kind;
+static int issue_messages = 0;
+
+struct {
+ uint32_t regs[32];
+ uint32_t pc;
+ uint8_t pm[262144];
+ uint8_t ram[65536];
+ uint64_t num_i;
+ uint64_t cycles;
+ uint64_t next_tick_cycle;
+ enum sim_stop reason;
+ int pm_unlock;
+ uint32_t pm_addr;
+ int exception;
+} cpu;
+
+unsigned long
+ft32_extract_unsigned_integer (addr, len)
+ unsigned char * addr;
+ int len;
+{
+ unsigned long retval;
+ unsigned char * p;
+ unsigned char * startaddr = (unsigned char *)addr;
+ unsigned char * endaddr = startaddr + len;
+
+ if (len > (int) sizeof (unsigned long))
+ printf ("That operation is not available on integers of more than %ld bytes.",
+ sizeof (unsigned long));
+
+ /* 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;
+}
+
+void
+ft32_store_unsigned_integer (addr, len, val)
+ 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;
+ }
+}
+
+void
+sim_size (int s)
+{
+}
+
+static void
+set_initial_gprs ()
+{
+ int i;
+ long space;
+}
+
+static void
+interrupt ()
+{
+ // cpu.asregs.exception = SIGINT;
+}
+
+/* Write a 4 byte value to memory. */
+
+static void INLINE
+wlat (sim_cpu *scpu, word pc, word x, word v)
+{
+ address_word cia = CIA_GET (scpu);
+
+ sim_core_write_aligned_4 (scpu, cia, write_map, x, v);
+}
+
+static int tracing = 0;
+
+uint32_t cpu_pm_read(SIM_DESC sd, int dw, uint32_t ea)
+{
+ sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
+ address_word cia = CIA_GET (scpu);
+ uint32_t r;
+
+ if ((ea & ~0x3ffff) != 0)
+ {
+ fprintf(stderr, "Illegal PM address %08x, pc %#x\n", ea, cpu.pc);
+ exit(0);
+ }
+
+ switch (dw)
+ {
+ case 1:
+ ea &= ~1;
+ break;
+ case 2:
+ ea &= ~3;
+ break;
+ default:
+ break;
+ }
+ r = sim_core_read_aligned_1 (scpu, cia, read_map, ea);
+ if (1 <= dw)
+ {
+ r += (sim_core_read_aligned_1 (scpu, cia, read_map, ea+1) << 8);
+ if (2 <= dw)
+ {
+ r += (sim_core_read_aligned_1 (scpu, cia, read_map, ea+2) << 16);
+ r += (sim_core_read_aligned_1 (scpu, cia, read_map, ea+3) << 24);
+ }
+ }
+ return r;
+}
+
+static uint32_t safe_addr(uint32_t dw, uint32_t ea)
+{
+ if ((ea & ~0x1ffff) != 0)
+ {
+ fprintf(stderr, "Illegal RAM address %08x, pc %#x\n", ea, cpu.pc);
+ exit(0);
+ }
+ ea &= 0x1ffff;
+ switch (dw)
+ {
+ case 1:
+ // if ((ea & 1) == 0);
+ ea &= ~1;
+ break;
+ case 2:
+ // ASSERT((ea & 3) == 0);
+ ea &= ~3;
+ break;
+ default:
+ break;
+ }
+ return ea;
+}
+
+static uint32_t cpu_mem_read(uint32_t dw, uint32_t ea)
+{
+ uint32_t r;
+
+ ea = safe_addr(dw, ea);
+ if ((ea & ~0xffff))
+ {
+ switch (ea)
+ {
+ case 0x10000:
+ case 0x10020:
+ return getchar();
+ case 0x10024:
+ return 1;
+ case 0x1fff4:
+ // printf("cycles = %lld, us = %u\n", cpu.cycles, (uint32_t)(cpu.cycles / 100));
+ return (uint32_t)(cpu.cycles / 100);
+ default:
+ fprintf(stderr, "Illegal IO read address %08x, pc %#x\n", ea, cpu.pc);
+ exit(0);
+ }
+ }
+ r = cpu.ram[ea];
+ if (1 <= dw)
+ {
+ r += (cpu.ram[ea + 1] << 8);
+ if (2 <= dw)
+ {
+ r += cpu.ram[ea + 2] << 16;
+ r += cpu.ram[ea + 3] << 24;
+ }
+ }
+ return r;
+}
+
+static void cpu_mem_write(SIM_DESC sd, uint32_t dw, uint32_t ea, uint32_t d)
+{
+ ea = safe_addr(dw, ea);
+ if (ea & 0x10000)
+ {
+ if (tracefile)
+ fprintf(tracefile, "IO write %c %08x to %0x\n", "bsl"[dw], d, ea);
+ switch (ea)
+ {
+ case 0x10000:
+ putchar(d & 0xff);
+ break;
+ case 0x1fc80:
+ cpu.pm_unlock = (d == 0x1337f7d1);
+ break;
+ case 0x1fc84:
+ cpu.pm_addr = d;
+ break;
+ case 0x1fc88:
+ {
+ sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
+ address_word cia = CIA_GET (scpu);
+ sim_core_write_aligned_1 (scpu, cia, read_map, cpu.pm_addr + 0, d & 0xff);
+ sim_core_write_aligned_1 (scpu, cia, read_map, cpu.pm_addr + 1, (d >> 8) & 0xff);
+ sim_core_write_aligned_1 (scpu, cia, read_map, cpu.pm_addr + 2, (d >> 16) & 0xff);
+ sim_core_write_aligned_1 (scpu, cia, read_map, cpu.pm_addr + 3, (d >> 24) & 0xff);
+ }
+ break;
+ case 0x10024:
+ case 0x1fffc:
+ break;
+ case 0x1fff8:
+ printf("DEBUG "); // fall-though...
+ case 0x19470:
+ {
+ uint32_t d16 = (d & 0xffff) | ((d & 0xffff) << 16);
+ uint32_t d8 = (d16 & 0x00ff00ff) | ((d16 & 0x00ff00ff) << 8);
+ switch (dw)
+ {
+ case 0: d = d8; break;
+ case 1: d = d16; break;
+ }
+ printf("%08x\n", d);
+ }
+ break;
+ default:
+ fprintf(stderr, "Unknown IO write %08x to to %08x\n", d, ea);
+ }
+ }
+ else
+ {
+ cpu.ram[ea] = d & 0xff;
+ if (1 <= dw)
+ {
+ cpu.ram[ea + 1] = (d >> 8) & 0xff;
+ if (2 <= dw)
+ {
+ cpu.ram[ea + 2] = (d >> 16) & 0xff;
+ cpu.ram[ea + 3] = (d >> 24) & 0xff;
+ }
+ }
+ }
+}
+
+static void ft32_push(SIM_DESC sd, uint32_t v)
+{
+ cpu.regs[31] -= 4;
+ cpu.regs[31] &= 0xffff;
+ cpu_mem_write(sd, 2, cpu.regs[31], v);
+}
+
+static uint32_t ft32_pop()
+{
+ uint32_t r = cpu_mem_read(2, cpu.regs[31]);
+ cpu.regs[31] += 4;
+ cpu.regs[31] &= 0xffff;
+ return r;
+}
+
+static int nunsigned(int siz, int bits)
+{
+ int mask = (1L << siz) - 1;
+ return bits & mask;
+}
+
+static int nsigned(int siz, int bits)
+{
+ int shift = (sizeof(int) * 8) - siz;
+ return (bits << shift) >> shift;
+}
+
+static uint32_t ft32sdiv(uint32_t n, uint32_t d)
+{
+ if (n == 0x80000000UL && d == 0xffffffffUL)
+ return 0x80000000UL;
+ else
+ return (uint32_t)((int)n / (int)d);
+}
+
+static uint32_t ft32smod(uint32_t n, uint32_t d)
+{
+ if (n == 0x80000000UL && d == 0xffffffffUL)
+ return 0;
+ else
+ return (uint32_t)((int)n % (int)d);
+}
+
+static uint32_t ror(uint32_t n, uint32_t b)
+{
+ b &= 31;
+ return (n >> b) | (n << (32 - b));
+}
+
+static uint32_t bins(uint32_t d, uint32_t f, uint32_t len, uint32_t pos)
+{
+ uint32_t mask = ((1 << len) - 1) << pos;
+ return (d & ~mask) | ((f << pos) & mask);
+}
+
+static uint32_t flip(uint32_t x, uint32_t b)
+{
+ if (b & 1)
+ x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
+ if (b & 2)
+ x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
+ if (b & 4)
+ x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
+ if (b & 8)
+ x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
+ if (b & 16)
+ x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16;
+ return x;
+}
+
+void
+sim_resume (sd, step, siggnal)
+ SIM_DESC sd;
+ int step, siggnal;
+{
+ void (* sigsave)();
+ sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
+ address_word cia = CIA_GET (scpu);
+
+ sigsave = signal (SIGINT, interrupt);
+ cpu.reason = sim_stopped;
+
+ do
+ {
+ if (cpu.cycles >= cpu.next_tick_cycle)
+ {
+ cpu.next_tick_cycle += 100000;
+ ft32_push(sd, cpu.pc);
+ cpu.pc = 12; // interrupt 1
+ }
+ uint32_t inst = cpu_pm_read(sd, 2, cpu.pc);
+ cpu.cycles += 1;
+ // printf("inst at %04x: %08x\n", cpu.pc, inst);
+
+ // Handle "call 8" (which is FT32's "break" equivalent) here
+ if (inst == 0x00340002)
+ {
+ cpu.reason = sim_stopped;
+ goto escape;
+ }
+ uint32_t dw = (inst >> FT32_FLD_DW_BIT) & ((1U << FT32_FLD_DW_SIZ) - 1);
+ uint32_t cb = (inst >> FT32_FLD_CB_BIT) & ((1U << FT32_FLD_CB_SIZ) - 1);
+ uint32_t r_d = (inst >> FT32_FLD_R_D_BIT) & ((1U << FT32_FLD_R_D_SIZ) - 1);
+ uint32_t cr = (inst >> FT32_FLD_CR_BIT) & ((1U << FT32_FLD_CR_SIZ) - 1);
+ uint32_t cv = (inst >> FT32_FLD_CV_BIT) & ((1U << FT32_FLD_CV_SIZ) - 1);
+ uint32_t bt = (inst >> FT32_FLD_BT_BIT) & ((1U << FT32_FLD_BT_SIZ) - 1);
+ uint32_t r_1 = (inst >> FT32_FLD_R_1_BIT) & ((1U << FT32_FLD_R_1_SIZ) - 1);
+ uint32_t rimm = (inst >> FT32_FLD_RIMM_BIT) & ((1U << FT32_FLD_RIMM_SIZ) - 1);
+ uint32_t r_2 = (inst >> FT32_FLD_R_2_BIT) & ((1U << FT32_FLD_R_2_SIZ) - 1);
+ uint32_t k20 = nsigned(20, (inst >> FT32_FLD_K20_BIT) & ((1U << FT32_FLD_K20_SIZ) - 1));
+ uint32_t pa = (inst >> FT32_FLD_PA_BIT) & ((1U << FT32_FLD_PA_SIZ) - 1);
+ uint32_t aa = (inst >> FT32_FLD_AA_BIT) & ((1U << FT32_FLD_AA_SIZ) - 1);
+ uint32_t k16 = (inst >> FT32_FLD_K16_BIT) & ((1U << FT32_FLD_K16_SIZ) - 1);
+ uint32_t k8 = nsigned(8, (inst >> FT32_FLD_K8_BIT) & ((1U << FT32_FLD_K8_SIZ) - 1));
+ uint32_t al = (inst >> FT32_FLD_AL_BIT) & ((1U << FT32_FLD_AL_SIZ) - 1);
+
+ uint32_t r_1v = cpu.regs[r_1];
+ uint32_t rimmv = (rimm & 0x400) ? nsigned(10, rimm) : cpu.regs[rimm & 0x1f];
+
+ uint32_t bit_pos = rimmv & 31;
+ uint32_t bit_len = 0xf & (rimmv >> 5);
+ if (bit_len == 0)
+ bit_len = 16;
+
+ uint32_t upper = (inst >> 27);
+
+ uint32_t insnpc = cpu.pc;
+ cpu.pc += 4;
+ switch (upper)
+ {
+ case FT32_PAT_TOC:
+ case FT32_PAT_TOCI:
+ {
+ int takeit = (cr == 3) || ((1 & (cpu.regs[28 + cr] >> cb)) == cv);
+ if (takeit)
+ {
+ cpu.cycles += 1;
+ if (bt)
+ {
+ /* this is a call */
+ if (tracefile)
+ fprintf(tracefile, "r0=%08x r1=%08x r2=%08x r3=%08x\n", cpu.regs[0], cpu.regs[1], cpu.regs[2], cpu.regs[3]);
+ ft32_push(sd, cpu.pc);
+ }
+ if (upper == FT32_PAT_TOC)
+ {
+ cpu.pc = pa << 2;
+ }
+ else
+ {
+ if (tracefile)
+ fprintf(tracefile, "indirect r%d to %#x\n", r_2, cpu.regs[r_2]);
+ cpu.pc = cpu.regs[r_2];
+ }
+ if (cpu.pc == 0x8)
+ {
+ fprintf(stderr, "PC is 8!\n");
+ 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:
+ printf("Unhandled alu %#x\n", al);
+ goto escape;
+ }
+ if (upper == FT32_PAT_ALUOP)
+ {
+ cpu.regs[r_d] = result;
+ }
+ else
+ {
+ uint32_t dwmask;
+ int dwsiz;
+ switch (dw)
+ {
+ case 0: dwsiz = 7; dwmask = 0xffU; break;
+ case 1: dwsiz = 15; dwmask = 0xffffU; break;
+ case 2: dwsiz = 31; dwmask = 0xffffffffU; break;
+ }
+
+ int zero = (0 == (result & dwmask));
+ int sign = 1 & (result >> dwsiz);
+ int ahi = 1 & (r_1v >> dwsiz);
+ int bhi = 1 & (rimmv >> dwsiz);
+ int overflow = (sign != ahi) & (ahi == !bhi);
+ int carry;
+ int bit = (dwsiz + 1);
+ uint64_t ra = r_1v & dwmask;
+ uint64_t 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;
+ }
+ int above = (!carry & !zero);
+ int greater = (sign == overflow) & !zero;
+ int greatereq = (sign == overflow);
+
+ cpu.regs[r_d] = (
+ (above << 6) |
+ (greater << 5) |
+ (greatereq << 4) |
+ (sign << 3) |
+ (overflow << 2) |
+ (carry << 1) |
+ (zero << 0));
+ }
+ if (0)
+ fprintf(tracefile, "%06x: result=%08x, \n", cpu.pc, result);
+ }
+ break;
+
+ case FT32_PAT_LDK:
+ cpu.regs[r_d] = k20;
+ break;
+
+ case FT32_PAT_LPM:
+ cpu.cycles += 1;
+ cpu.regs[r_d] = cpu_pm_read(sd, dw, pa << 2);
+ break;
+
+ case FT32_PAT_LPMI:
+ cpu.cycles += 1;
+ cpu.regs[r_d] = cpu_pm_read(sd, dw, cpu.regs[r_1] + k8);
+ if (tracefile)
+ fprintf(tracefile, "lpmi %x %08x\n", cpu.regs[r_1] + k8, cpu.regs[r_d]);
+ break;
+
+ case FT32_PAT_STA:
+ cpu_mem_write(sd, dw, aa, cpu.regs[r_d]);
+ if (aa == 0x1fffc)
+ {
+ cpu.reason = sim_exited;
+ goto escape;
+ }
+ break;
+
+ case FT32_PAT_STI:
+ if (tracefile)
+ fprintf(tracefile, "STI %#x <= %08x\n", cpu.regs[r_d] + k8, cpu.regs[r_1]);
+ cpu_mem_write(sd, dw, cpu.regs[r_d] + k8, cpu.regs[r_1]);
+ break;
+
+ case FT32_PAT_LDA:
+ cpu.cycles += 1;
+ cpu.regs[r_d] = cpu_mem_read(dw, aa);
+ break;
+
+ case FT32_PAT_LDI:
+ cpu.cycles += 1;
+ cpu.regs[r_d] = cpu_mem_read(dw, cpu.regs[r_1] + k8);
+ if (tracefile)
+ fprintf(tracefile, "LDI %#x <= %08x\n", cpu.regs[r_d], cpu.regs[r_1] + k8);
+ break;
+
+ case FT32_PAT_PUSH:
+ ft32_push(sd, r_1v);
+ break;
+
+ case FT32_PAT_LINK:
+ ft32_push(sd, cpu.regs[r_d]);
+ cpu.regs[r_d] = cpu.regs[31];
+ cpu.regs[31] -= k16;
+ cpu.regs[31] &= 0xffff;
+ break;
+
+ case FT32_PAT_UNLINK:
+ cpu.regs[31] = cpu.regs[r_d];
+ cpu.regs[31] &= 0xffff;
+ cpu.regs[r_d] = ft32_pop();
+ break;
+
+ case FT32_PAT_POP:
+ cpu.cycles += 1;
+ cpu.regs[r_d] = ft32_pop();
+ break;
+
+ case FT32_PAT_RETURN:
+ cpu.pc = ft32_pop();
+ break;
+
+ case FT32_PAT_FFUOP:
+ if (tracefile)
+ fprintf(tracefile, "ffu %#x\n", al);
+ switch (al)
+ {
+ case 0x0: cpu.regs[r_d] = r_1v / rimmv; break;
+ case 0x1: cpu.regs[r_d] = r_1v % rimmv; break;
+ case 0x2: cpu.regs[r_d] = ft32sdiv(r_1v, rimmv); break;
+ case 0x3: cpu.regs[r_d] = ft32smod(r_1v, rimmv); break;
+
+ case 0x4: cpu.regs[r_d] = strcmp(cpu.ram + r_1v, cpu.ram + rimmv); break;
+ case 0x5: memcpy(cpu.ram + cpu.regs[r_d], cpu.ram + r_1v, rimmv); break;
+ case 0x6: cpu.regs[r_d] = strlen(cpu.ram + r_1v); break;
+ case 0x7: memset(cpu.ram + cpu.regs[r_d], r_1v, rimmv); break;
+ case 0x8: cpu.regs[r_d] = r_1v * rimmv; break;
+ case 0x9: cpu.regs[r_d] = ((uint64_t)r_1v * (uint64_t)rimmv) >> 32; break;
+ case 0xe:
+ {
+ // streamout
+ uint32_t i;
+ uint32_t src = cpu.regs[r_1];
+ for (i = 0; i < rimmv; i += (1 << dw))
+ {
+ cpu_mem_write(sd, dw, cpu.regs[r_d], cpu_mem_read(dw, src));
+ src += (1 << dw);
+ }
+ }
+ break;
+ default:
+ printf("Unhandled ffu %#x\n", al);
+ goto escape;
+ }
+ break;
+
+ default:
+ goto escape;
+ }
+ cpu.num_i++;
+ if (tracefile)
+ fprintf(tracefile, "@%lld pc=%#x inst=%08x r%d=%08x\n", cpu.num_i, insnpc, inst, r_d, cpu.regs[r_d]);
+ }
+ while (!step);
+escape:
+ cpu.exception = step ? SIGTRAP : 0;
+ if (cpu.reason == sim_exited)
+ {
+ cpu.exception = cpu.regs[0];
+ printf("[FT32 sim ending:%llu instructions executed. Exit code %d]\n", cpu.num_i, (int)cpu.exception);
+ }
+
+ signal (SIGINT, sigsave);
+}
+
+int
+sim_write (sd, addr, buffer, size)
+ SIM_DESC sd;
+ SIM_ADDR addr;
+ const unsigned char * buffer;
+ int size;
+{
+ sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
+ // printf("sim_write(%#x, %#x)\n", addr, size);
+
+ if (addr < 0x800000)
+ {
+ sim_core_write_buffer (sd, scpu, write_map, buffer, addr, size);
+ }
+ else
+ {
+ int i;
+
+ addr -= 0x800000;
+ for (i = 0; i < size; i++)
+ cpu_mem_write(sd, 0, addr + i, buffer[i]);
+ }
+ return size;
+}
+
+int
+sim_read (sd, addr, buffer, size)
+ SIM_DESC sd;
+ SIM_ADDR addr;
+ unsigned char * buffer;
+ int size;
+{
+ sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
+
+ // printf("[sim_read %#x, %d]\n", addr, size);
+ if (addr < 0x800000)
+ {
+ sim_core_read_buffer (sd, scpu, read_map, buffer, addr, size);
+ }
+ else
+ {
+ int i;
+
+ addr -= 0x800000;
+ for (i = 0; i < size; i++)
+ buffer[i] = cpu_mem_read(0, addr + i);
+ }
+
+ return size;
+}
+
+#define NUM_FT32_REGS 32
+int
+sim_store_register (sd, rn, memory, length)
+ SIM_DESC sd;
+ int rn;
+ unsigned char * memory;
+ int length;
+{
+ if (0 <= rn && rn <= 32)
+ {
+ if (length == 4)
+ {
+ long ival;
+
+ /* misalignment safe */
+ ival = ft32_extract_unsigned_integer (memory, 4);
+ if (rn == 32)
+ cpu.pc = ival;
+ else
+ cpu.regs[rn] = ival;
+ }
+
+ return 4;
+ }
+ else
+ return 0;
+}
+
+int
+sim_fetch_register (sd, rn, memory, length)
+ SIM_DESC sd;
+ int rn;
+ unsigned char * memory;
+ int length;
+{
+ if (0 <= rn && rn <= 32)
+ {
+ if (length == 4)
+ {
+ long ival;
+ // Handle the register number translation here.
+ // Sim registers are, duh, 0-31.
+ // Other tools (gcc, gdb) uses:
+ // 0 - fp
+ // 1 - sp
+ // 2 - r0
+ // 31 - cc
+ switch (rn)
+ {
+ case 0:
+ ival = cpu.regs[29];
+ break;
+ case 1:
+ ival = cpu.regs[31];
+ break;
+ case 31:
+ ival = cpu.regs[30];
+ break;
+ case 32:
+ ival = cpu.pc;
+ break;
+ default:
+ ival = cpu.regs[rn - 2];
+ }
+ // printf("[sim_fetch_register(%d)=%08x]", rn, ival);
+
+ /* misalignment-safe */
+ ft32_store_unsigned_integer (memory, 4, ival);
+ }
+
+ return 4;
+ }
+ else
+ return 0;
+}
+
+
+int
+sim_trace (sd)
+ SIM_DESC sd;
+{
+ if (tracefile == 0)
+ tracefile = fopen("trace.csv", "wb");
+ tracefile = stdout;
+
+ tracing = 1;
+
+ sim_resume (sd, 0, 0);
+
+ // fclose(tracefile);
+
+ tracing = 0;
+
+ return 1;
+}
+
+void
+sim_stop_reason (sd, reason, sigrc)
+ SIM_DESC sd;
+ enum sim_stop * reason;
+ int * sigrc;
+{
+ *reason = cpu.reason;
+ *sigrc = cpu.exception;
+}
+
+
+int
+sim_stop (sd)
+ SIM_DESC sd;
+{
+ // cpu.asregs.exception = SIGINT;
+ return 1;
+}
+
+
+void
+sim_info (sd, verbose)
+ SIM_DESC sd;
+ int verbose;
+{
+ // callback->printf_filtered (callback, "\n\n# instructions executed %llu\n", cpu.asregs.insts);
+}
+
+
+SIM_DESC
+sim_open (kind, cb, abfd, argv)
+ SIM_OPEN_KIND kind;
+ host_callback * cb;
+ struct bfd * abfd;
+ char ** argv;
+{
+ SIM_DESC sd = sim_state_alloc (kind, cb);
+ SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+
+ if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
+ return 0;
+
+ sim_do_command(sd," memory region 0x00000000,0x4000000") ;
+ sim_do_command(sd," memory region 0xE0000000,0x10000") ;
+
+ myname = argv[0];
+ callback = cb;
+
+ if (kind == SIM_OPEN_STANDALONE)
+ issue_messages = 1;
+
+ set_initial_gprs (); /* Reset the GPR registers. */
+
+ /* Configure/verify the target byte order and other runtime
+ configuration options. */
+ if (sim_config (sd) != SIM_RC_OK)
+ {
+ sim_module_uninstall (sd);
+ return 0;
+ }
+
+ if (sim_post_argv_init (sd) != SIM_RC_OK)
+ {
+ /* Uninstall the modules to avoid memory leaks,
+ file descriptor leaks, etc. */
+ sim_module_uninstall (sd);
+ return 0;
+ }
+
+ return sd;
+}
+
+void
+sim_close (sd, quitting)
+ SIM_DESC sd;
+ int quitting;
+{
+ /* nothing to do */
+}
+
+
+/* Load the device tree blob. */
+
+static void
+load_dtb (SIM_DESC sd, const char *filename)
+{
+ int size = 0;
+ FILE *f = fopen (filename, "rb");
+ char *buf;
+ sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
+ if (f == NULL)
+ {
+ printf ("WARNING: ``%s'' could not be opened.\n", filename);
+ return;
+ }
+ fseek (f, 0, SEEK_END);
+ size = ftell(f);
+ fseek (f, 0, SEEK_SET);
+ buf = alloca (size);
+ if (size != fread (buf, 1, size, f))
+ {
+ printf ("ERROR: error reading ``%s''.\n", filename);
+ return;
+ }
+ sim_core_write_buffer (sd, scpu, write_map, buf, 0xE0000000, size);
+ // cpu.asregs.sregs[9] = 0xE0000000;
+ fclose (f);
+}
+
+SIM_RC
+sim_load (sd, prog, abfd, from_tty)
+ SIM_DESC sd;
+ const char * prog;
+ bfd * abfd;
+ int from_tty;
+{
+ /* Do the right thing for ELF executables; this turns out to be
+ just about the right thing for any object format that:
+ - we crack using BFD routines
+ - follows the traditional UNIX text/data/bss layout
+ - calls the bss section ".bss". */
+
+ extern bfd * sim_load_file (); /* ??? Don't know where this should live. */
+ bfd * prog_bfd;
+
+ {
+ bfd * handle;
+ handle = bfd_openr (prog, 0); /* could be "ft32" */
+
+ if (!handle)
+ {
+ printf("``%s'' could not be opened.\n", prog);
+ return SIM_RC_FAIL;
+ }
+
+ /* Makes sure that we have an object file, also cleans gets the
+ section headers in place. */
+ if (!bfd_check_format (handle, bfd_object))
+ {
+ /* wasn't an object file */
+ bfd_close (handle);
+ printf ("``%s'' is not appropriate object file.\n", prog);
+ return SIM_RC_FAIL;
+ }
+
+ /* Clean up after ourselves. */
+ bfd_close (handle);
+ }
+
+ memset(cpu.ram, 0, 65536);
+ /* from sh -- dac */
+ prog_bfd = sim_load_file (sd, myname, callback, prog, abfd,
+ sim_kind == SIM_OPEN_DEBUG,
+ 0, sim_write);
+ if (prog_bfd == NULL)
+ return SIM_RC_FAIL;
+
+ if (abfd == NULL)
+ bfd_close (prog_bfd);
+
+ return SIM_RC_OK;
+}
+
+SIM_RC
+sim_create_inferior (sd, prog_bfd, argv, env)
+ SIM_DESC sd;
+ struct bfd * prog_bfd;
+ char ** argv;
+ char ** env;
+{
+ char ** avp;
+ int l, argc, i, tp;
+ sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
+
+ /* Set the initial register set. */
+ l = issue_messages;
+ issue_messages = 0;
+ set_initial_gprs ();
+ issue_messages = l;
+
+ // printf("start address %#lx\n", bfd_get_start_address (prog_bfd));
+ cpu.pc = bfd_get_start_address (prog_bfd);
+ cpu.regs[31] = 0x00000;
+ cpu.num_i = 0;
+ cpu.cycles = 0;
+ cpu.next_tick_cycle = 100000;
+
+ return SIM_RC_OK;
+}
+
+void
+sim_kill (sd)
+ SIM_DESC sd;
+{
+ if (tracefile)
+ fclose(tracefile);
+}
+
+void
+sim_do_command (sd, cmd)
+ SIM_DESC sd;
+ const char * cmd;
+{
+ if (sim_args_command (sd, cmd) != SIM_RC_OK)
+ sim_io_printf (sd,
+ "Error: \"%s\" is not a valid ft32 simulator command.\n",
+ cmd);
+}
+
+void
+sim_set_callbacks (ptr)
+ host_callback * ptr;
+{
+ callback = ptr;
+}
new file mode 100644
@@ -0,0 +1,61 @@
+/* Moxie Simulator definition.
+ Copyright (C) 2009-2013 Free Software Foundation, Inc.
+ Contributed by Anthony Green <green@moxielogic.com>
+
+This file is part of GDB, the GNU debugger.
+
+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
+
+#define SIM_HAVE_BIENDIAN
+
+#include "sim-basics.h"
+
+typedef address_word sim_cia;
+
+#include "sim-base.h"
+#include "bfd.h"
+
+#define PCIDX 17
+
+struct _sim_cpu {
+
+ /* The following are internal simulator state variables: */
+#define CIA_GET(CPU) ((CPU)->registers[PCIDX] + 0)
+#define CIA_SET(CPU,CIA) ((CPU)->registers[PCIDX] = (CIA))
+
+/* To keep this default simulator simple, and fast, we use a direct
+ vector of registers. The internal simulator engine then uses
+ manifests to access the correct slot. */
+
+ unsigned_word registers[19];
+
+ 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,94 @@
+/* System includes and definitions used by the FT32 simulator.
+ Copyright (C) 2008-2013 Free Software Foundation, Inc.
+ Contributed by FTDI <support@ftdichip.com>
+
+This file is part of GDB, the GNU debugger.
+
+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 __SYSDEP_H
+#define __SYSDEP_H
+
+#ifndef hosts_std_host_H
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/file.h>
+#include "ansidecl.h"
+
+#ifndef O_ACCMODE
+#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
+#endif
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+/*#include <string.h>*/
+#else
+extern char * mktemp ();
+#ifndef memset
+extern PTR memset ();
+#endif
+
+#ifndef DONTDECLARE_MALLOC
+extern PTR malloc ();
+extern PTR realloc ();
+#endif
+
+#ifndef __GNUC__
+extern PTR memcpy ();
+#else
+/* char * memcpy (); */
+#endif
+
+#ifdef __STDC__
+extern void free ();
+#else
+extern int free();
+#endif
+
+#ifndef strchr
+extern char * strchr();
+#endif
+extern char * getenv();
+extern PTR memchr();
+extern char * strrchr();
+
+extern char * strrchr();
+extern char * ctime();
+extern long atol();
+extern char * getenv();
+#endif /* STDC_HEADERS */
+
+#ifndef BYTES_IN_PRINTF_INT
+#define BYTES_IN_PRINTF_INT 4
+#endif
+
+#include "fopen-same.h"
+#define hosts_std_host_H
+#endif
+
+#ifdef STDC_HEADERS
+#include <stddef.h>
+#endif /* STDC_HEADERS */
+
+#endif /* __SYSDEP_H */