From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 4519 invoked by alias); 3 Feb 2015 04:06:54 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 4510 invoked by uid 89); 3 Feb 2015 04:06:53 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=2.6 required=5.0 tests=AWL,BAYES_50,KAM_STOCKGEN,RCVD_IN_DNSWL_NONE autolearn=no version=3.3.2 X-HELO: smtp-out4.electric.net Received: from smtp-out4.electric.net (HELO smtp-out4.electric.net) (192.162.216.181) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Tue, 03 Feb 2015 04:06:47 +0000 Received: from 1YIUl8-0005vB-U6 by out4c.electric.net with emc1-ok (Exim 4.84) (envelope-from ) id 1YIUl8-0005yN-Vk for gdb-patches@sourceware.org; Mon, 02 Feb 2015 20:06:42 -0800 Received: by emcmailer; Mon, 02 Feb 2015 20:06:42 -0800 Received: from [82.0.240.193] (helo=GLAEXCH3.ftdi.local) by out4c.electric.net with esmtps (TLSv1:AES128-SHA:128) (Exim 4.84) (envelope-from ) id 1YIUl8-0005vB-U6 for gdb-patches@sourceware.org; Mon, 02 Feb 2015 20:06:42 -0800 Received: from GLAEXCH1.ftdi.local ([172.16.0.121]) by glaexch3 ([172.16.0.161]) with mapi id 14.01.0438.000; Tue, 3 Feb 2015 04:06:35 +0000 From: James Bowman To: "gdb-patches@sourceware.org" Subject: [PATCH, FT32] gdb and sim support Date: Tue, 03 Feb 2015 04:06:00 -0000 Message-ID: Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Outbound-IP: 82.0.240.193 X-Env-From: james.bowman@ftdichip.com X-PolicySMART: 3094660 X-SW-Source: 2015-02/txt/msg00045.txt.bz2 FT32 is a new high performance 32-bit RISC core developed by FTDI for embed= ded applications. Support for FT32 has already been added to binutils. This patch adds gdb an= d sim support. Please can someone review it, and if appropriate commit it, as I do not hav= e write access to the tree. The FSF have acknowledged receipt of FTDI's copyright assignment papers. Thanks very much. ChangeLog entry: 2014-02-03 James Bowman * 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 -- James Bowman FTDI Open Source Liaison From: James Bowman Date: Mon, 2 Feb 2015 19:43:24 -0800 Subject: [PATCH] FT32 support --- gdb/Makefile.in | 6 +- gdb/configure.tgt | 5 + gdb/ft32-tdep.c | 1007 +++++++++++++++++++++++++++++++++++++++++++++= +++ gdb/ft32-tdep.h | 42 ++ sim/configure.tgt | 3 + sim/ft32/Makefile.in | 38 ++ sim/ft32/config.in | 154 ++++++++ sim/ft32/configure.ac | 18 + sim/ft32/interp.c | 1014 +++++++++++++++++++++++++++++++++++++++++++++= ++++ sim/ft32/sim-main.h | 61 +++ sim/ft32/sysdep.h | 94 +++++ 11 files changed, 2440 insertions(+), 2 deletions(-) create mode 100644 gdb/ft32-tdep.c create mode 100644 gdb/ft32-tdep.h create mode 100644 sim/ft32/Makefile.in create mode 100644 sim/ft32/config.in create mode 100644 sim/ft32/configure.ac create mode 100644 sim/ft32/interp.c create mode 100644 sim/ft32/sim-main.h create mode 100644 sim/ft32/sysdep.h diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 8addef4..d922eb2 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -647,6 +647,7 @@ ALL_TARGET_OBS =3D \ 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 ft3= 2-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 =3D \ 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 \ diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 7fdd34e..26274bd 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -621,6 +621,11 @@ xstormy16-*-*) # No simulator libraries are needed -- target uses SID. ;; =20 +ft32-*-elf) + gdb_target_obs=3D"ft32-tdep.o" + gdb_sim=3D../sim/ft32/libsim.a + ;; + v850*-*-elf | v850*-*-rtems*) # Target: NEC V850 processor gdb_target_obs=3D"v850-tdep.o" diff --git a/gdb/ft32-tdep.c b/gdb/ft32-tdep.c new file mode 100644 index 0000000..f183661 --- /dev/null +++ b/gdb/ft32-tdep.c @@ -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 . = */ + +#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 +#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 =3D (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[] =3D { 0x02, 0x00, 0x34, 0x00 }; + + *lenptr =3D sizeof (breakpoint); + return breakpoint; +} + +/* FT32 register names. */ + +char *ft32_register_names[] =3D +{ + "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 >=3D 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 =3D=3D FT32_PC_REGNUM) + return builtin_type (gdbarch)->builtin_func_ptr; + else if (reg_nr =3D=3D FT32_SP_REGNUM || reg_nr =3D=3D 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 =3D get_regcache_arch (regcache); + enum bfd_endian byte_order =3D gdbarch_byte_order (gdbarch); + CORE_ADDR regval; + int len =3D TYPE_LENGTH (type); + + /* Things always get returned in RET1_REGNUM, RET2_REGNUM. */ + regval =3D extract_unsigned_integer (valbuf, len > 4 ? 4 : len, byte_ord= er); + regcache_cooked_write_unsigned (regcache, FT32_R0_REGNUM, regval); + if (len > 4) + { + regval =3D 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) =3D=3D 0x84000000) +#define PUSH_REG(inst) (FT32_R0_REGNUM + (((inst) >> 15) & 0x1f)) +#define IS_LINK(inst) (((inst) & 0xffff0000) =3D=3D 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 =3D 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] =3D 0; + cache->framesize =3D 0; + + if (start_addr >=3D end_addr) + { + return end_addr; + } + + cache->established =3D 0; + for (next_addr =3D start_addr; next_addr < end_addr; ) + { + inst =3D read_memory_unsigned_integer (next_addr, 4, byte_order); + + if (IS_PUSH(inst)) + { + regnum =3D PUSH_REG(inst); + cache->framesize +=3D 4; + cache->saved_regs[regnum] =3D cache->framesize; + next_addr +=3D 4; + } + else + break; + } + for (regnum =3D FT32_R0_REGNUM; regnum < FT32_PC_REGNUM; regnum++) + { + if (cache->saved_regs[regnum] !=3D REG_UNAVAIL) + cache->saved_regs[regnum] =3D cache->framesize - cache->saved_regs= [regnum]; + } + cache->saved_regs[FT32_PC_REGNUM] =3D cache->framesize; + + // It is a LINK + if (next_addr < end_addr) + { + inst =3D read_memory_unsigned_integer (next_addr, 4, byte_order); + if (IS_LINK(inst)) + { + cache->established =3D 1; + for (regnum =3D FT32_R0_REGNUM; regnum < FT32_PC_REGNUM; regnum+= +) + { + if (cache->saved_regs[regnum] !=3D REG_UNAVAIL) + cache->saved_regs[regnum] +=3D 4; + } + cache->saved_regs[FT32_PC_REGNUM] =3D cache->framesize + 4; + cache->saved_regs[FT32_FP_REGNUM] =3D 0; + cache->framesize +=3D LINK_SIZE(inst); + next_addr +=3D 4; + } + } + // printf("(Framesize=3D%lld,cache->saved_regs[FT32_PC_REGNUM]=3D%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 =3D 0, func_end =3D 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 + =3D skip_prologue_using_sal (gdbarch, func_addr); + if (post_prologue_pc !=3D 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 =3D ft32_analyze_prologue (func_addr, + func_end, &cache, gdbarch); + /* Found a function. */ + sym =3D lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL); + /* Don't use line number debug info for assembly source + files. */ + if (sym && SYMBOL_LANGUAGE (sym) !=3D language_asm) + { + sal =3D 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 =3D get_regcache_arch (regcache); + enum bfd_endian byte_order =3D gdbarch_byte_order (gdbarch); + bfd_byte *valbuf =3D dst; + int len =3D 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, t= mp); + + /* 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 !=3D NULL) + ft32_extract_return_value (valtype, regcache, readbuf); + if (writebuf !=3D 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 =3D FRAME_OBSTACK_ZALLOC (struct ft32_frame_cache); + + cache->base =3D 0; + cache->saved_sp =3D 0; + cache->pc =3D 0; + cache->framesize =3D 0; + for (i =3D 0; i < FT32_NUM_REGS; ++i) + cache->saved_regs[i] =3D 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 =3D ft32_alloc_frame_cache (); + *this_cache =3D cache; + + cache->base =3D get_frame_register_unsigned (this_frame, FT32_FP_REGNUM); + if (cache->base =3D=3D 0) + return cache; + + cache->pc =3D get_frame_func (this_frame); + current_pc =3D get_frame_pc (this_frame); + if (cache->pc) + { + struct gdbarch *gdbarch =3D get_frame_arch (this_frame); + ft32_analyze_prologue (cache->pc, current_pc, cache, gdbarch); + if (!cache->established) + cache->base =3D get_frame_register_unsigned (this_frame, FT32_SP_R= EGNUM); + } + + cache->saved_sp =3D cache->base - 4; + + for (i =3D 0; i < FT32_NUM_REGS; ++i) + if (cache->saved_regs[i] !=3D REG_UNAVAIL) + cache->saved_regs[i] =3D 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 =3D ft32_frame_cache (this_frame, + this_prologue_cache); + + /* This marks the outermost frame. */ + if (cache->base =3D=3D 0) + return; + + *this_id =3D 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 =3D ft32_frame_cache (this_frame, + this_prologue_cache); + + gdb_assert (regnum >=3D 0); + + if (regnum =3D=3D 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] !=3D 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 =3D +{ + 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 =3D ft32_frame_cache (this_frame, + this_cache); + + return cache->base; +} + +static const struct frame_base ft32_frame_base =3D +{ + &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 =3D 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 =3D %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 =3D gdbarch_byte_order (gdbarch); + + if (record_debug > 1) + fprintf_unfiltered (gdb_stdlog, "Process record: ft32_process_record " + "addr =3D 0x%s\n", + paddress (target_gdbarch (), addr)); + + inst =3D (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 =3D (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 =3D (inst >> 12 & 0x3); + switch (opcode) + { + case 0x00: /* inc */ + case 0x01: /* dec */ + case 0x02: /* gsr */ + { + int reg =3D (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 =3D inst >> 8; + + switch (opcode) + { + case 0x00: /* nop */ + /* Do nothing. */ + break; + case 0x01: /* ldi.l (immediate) */ + case 0x02: /* mov (register-to-register) */ + { + int reg =3D (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 =3D 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 =3D (inst >> 4) & 0xf; + if (record_full_arch_list_add_reg (regcache, reg)) + return -1; + } + break; + case 0x06: /* push */ + { + int reg =3D (inst >> 4) & 0xf; + regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32); + tmpu32 =3D 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 =3D (inst >> 4) & 0xf; + int b =3D 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 =3D (inst >> 4) & 0xf; + if (record_full_arch_list_add_reg (regcache, reg)) + return -1; + } + break; + case 0x09: /* sta.l */ + { + tmpu32 =3D (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 =3D (inst >> 4) & 0xf; + if (record_full_arch_list_add_reg (regcache, reg)) + return -1; + } + break; + case 0x0b: /* st.l */ + { + int reg =3D (inst >> 4) & 0xf; + regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32); + tmpu32 =3D 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 =3D (inst >> 4) & 0xf; + if (record_full_arch_list_add_reg (regcache, reg)) + return -1; + } + break; + case 0x0d: /* sto.l */ + { + int reg =3D (inst >> 4) & 0xf; + uint32_t offset =3D (uint32_t) ft32_process_readu (addr+2, buf, 4, + byte_order); + regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32); + tmpu32 =3D extract_unsigned_integer ((gdb_byte *) & tmpu32, + 4, byte_order); + tmpu32 +=3D 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 =3D 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 =3D (inst >> 4) & 0xf; + if (record_full_arch_list_add_reg (regcache, reg)) + return -1; + } + break; + case 0x1e: /* st.b */ + { + int reg =3D (inst >> 4) & 0xf; + regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32); + tmpu32 =3D 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 =3D 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 =3D (inst >> 4) & 0xf; + if (record_full_arch_list_add_reg (regcache, reg)) + return -1; + } + break; + case 0x23: /* st.s */ + { + int reg =3D (inst >> 4) & 0xf; + regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32); + tmpu32 =3D 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 =3D 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 =3D (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 =3D 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 =3D 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 =3D extract_unsigned_integer ((gdb_byte *) & tmpu32, + 4, byte_order); + length =3D 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 =3D (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 =3D (inst >> 4) & 0xf; + if (record_full_arch_list_add_reg (regcache, reg)) + return -1; + } + break; + case 0x37: /* sto.b */ + { + int reg =3D (inst >> 4) & 0xf; + uint32_t offset =3D (uint32_t) ft32_process_readu (addr+2, buf, 4, + byte_order); + regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32); + tmpu32 =3D extract_unsigned_integer ((gdb_byte *) & tmpu32, + 4, byte_order); + tmpu32 +=3D offset; + if (record_full_arch_list_add_mem (tmpu32, 1)) + return -1; + } + break; + case 0x38: /* ldo.s */ + { + int reg =3D (inst >> 4) & 0xf; + if (record_full_arch_list_add_reg (regcache, reg)) + return -1; + } + break; + case 0x39: /* sto.s */ + { + int reg =3D (inst >> 4) & 0xf; + uint32_t offset =3D (uint32_t) ft32_process_readu (addr+2, buf, 4, + byte_order); + regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32); + tmpu32 =3D extract_unsigned_integer ((gdb_byte *) & tmpu32, + 4, byte_order); + tmpu32 +=3D 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 =3D gdbarch_list_lookup_by_info (arches, &info); + if (arches !=3D NULL) + return arches->gdbarch; + + /* Allocate space for the new architecture. */ + tdep =3D XNEW (struct gdbarch_tdep); + gdbarch =3D 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); +} diff --git a/gdb/ft32-tdep.h b/gdb/ft32-tdep.h new file mode 100644 index 0000000..f561392 --- /dev/null +++ b/gdb/ft32-tdep.h @@ -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 . = */ + +#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 =3D 32 /* Program counter. */ +}; + +/* Number of machine registers. */ +#define FT32_NUM_REGS 33 /* 32 real registers + PC */ + +#endif /* ft32-tdep.h */ diff --git a/sim/configure.tgt b/sim/configure.tgt index d112e72..443418e 100644 --- a/sim/configure.tgt +++ b/sim/configure.tgt @@ -111,6 +111,9 @@ case "${target}" in powerpc*-*-*) SIM_ARCH(ppc) ;; + ft32-*-*) + SIM_ARCH(ft32) + ;; v850*-*-*) SIM_ARCH(v850) sim_igen=3Dyes diff --git a/sim/ft32/Makefile.in b/sim/ft32/Makefile.in new file mode 100644 index 0000000..d0de231 --- /dev/null +++ b/sim/ft32/Makefile.in @@ -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 . + +## COMMON_PRE_CONFIG_FRAG + +dtbdir =3D @datadir@/gdb-`sed q ${srcdir}/../../gdb/version.in`/dtb + +SIM_OBJS =3D 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 =3D -lm -lz -ldl +SIM_EXTRA_CLEAN =3D ft32-clean +# SIM_EXTRA_INSTALL =3D install-dtb +# SIM_CFLAGS =3D -DDTB=3D"\"$(dtbdir)/ft32-gdb.dtb\"" + +## COMMON_POST_CONFIG_FRAG + +all: interp.o + +interp.o: interp.c + +ft32-clean: diff --git a/sim/ft32/config.in b/sim/ft32/config.in new file mode 100644 index 0000000..8de933c --- /dev/null +++ b/sim/ft32/config.in @@ -0,0 +1,154 @@ +/* config.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +#undef ENABLE_NLS + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the 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 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 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 header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the 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 header file. */ +#undef HAVE_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ZLIB_H + +/* Define to 1 if you have the `__setfpucw' function. */ +#undef HAVE___SETFPUCW + +/* Name of this package. */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent= . */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Additional package description */ +#undef PKGVERSION + +/* Bug reporting address */ +#undef REPORT_BUGS_TO + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif + +/* Define to 1 if on MINIX. */ +#undef _MINIX + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#undef _POSIX_1_SOURCE + +/* Define to 1 if you need to in order for `stat' and other things to work= . */ +#undef _POSIX_SOURCE diff --git a/sim/ft32/configure.ac b/sim/ft32/configure.ac new file mode 100644 index 0000000..4695c16 --- /dev/null +++ b/sim/ft32/configure.ac @@ -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 diff --git a/sim/ft32/interp.c b/sim/ft32/interp.c new file mode 100644 index 0000000..493706b --- /dev/null +++ b/sim/ft32/interp.c @@ -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 . */ + +#include "config.h" +#include +#include +#include +#include "sysdep.h" +#include +#include +#include /* 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 =3D 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 =3D (unsigned char *)addr; + unsigned char * endaddr =3D 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 =3D 0; + + for (p =3D endaddr; p > startaddr;) + retval =3D (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 =3D (unsigned char *)addr; + unsigned char * endaddr =3D startaddr + len; + + for (p =3D startaddr; p < endaddr; p++) + { + *p =3D val & 0xff; + val >>=3D 8; + } +} + +void +sim_size (int s) +{ +} + +static void +set_initial_gprs () +{ + int i; + long space; +} + +static void +interrupt () +{ + // cpu.asregs.exception =3D SIGINT; +} + +/* Write a 4 byte value to memory. */ + +static void INLINE +wlat (sim_cpu *scpu, word pc, word x, word v) +{ + address_word cia =3D CIA_GET (scpu); + + sim_core_write_aligned_4 (scpu, cia, write_map, x, v); +} + +static int tracing =3D 0; + +uint32_t cpu_pm_read(SIM_DESC sd, int dw, uint32_t ea) +{ + sim_cpu *scpu =3D STATE_CPU (sd, 0); /* FIXME */ + address_word cia =3D CIA_GET (scpu); + uint32_t r; + + if ((ea & ~0x3ffff) !=3D 0) + { + fprintf(stderr, "Illegal PM address %08x, pc %#x\n", ea, cpu.pc); + exit(0); + } + + switch (dw) + { + case 1: + ea &=3D ~1; + break; + case 2: + ea &=3D ~3; + break; + default: + break; + } + r =3D sim_core_read_aligned_1 (scpu, cia, read_map, ea); + if (1 <=3D dw) + { + r +=3D (sim_core_read_aligned_1 (scpu, cia, read_map, ea+1) << 8); + if (2 <=3D dw) + { + r +=3D (sim_core_read_aligned_1 (scpu, cia, read_map, ea+2) << 1= 6); + r +=3D (sim_core_read_aligned_1 (scpu, cia, read_map, ea+3) << 2= 4); + } + } + return r; +} + +static uint32_t safe_addr(uint32_t dw, uint32_t ea) +{ + if ((ea & ~0x1ffff) !=3D 0) + { + fprintf(stderr, "Illegal RAM address %08x, pc %#x\n", ea, cpu.pc); + exit(0); + } + ea &=3D 0x1ffff; + switch (dw) + { + case 1: + // if ((ea & 1) =3D=3D 0); + ea &=3D ~1; + break; + case 2: + // ASSERT((ea & 3) =3D=3D 0); + ea &=3D ~3; + break; + default: + break; + } + return ea; +} + +static uint32_t cpu_mem_read(uint32_t dw, uint32_t ea) +{ + uint32_t r; + + ea =3D safe_addr(dw, ea); + if ((ea & ~0xffff)) + { + switch (ea) + { + case 0x10000: + case 0x10020: + return getchar(); + case 0x10024: + return 1; + case 0x1fff4: + // printf("cycles =3D %lld, us =3D %u\n", cpu.cycles, (uint32_t)(c= pu.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 =3D cpu.ram[ea]; + if (1 <=3D dw) + { + r +=3D (cpu.ram[ea + 1] << 8); + if (2 <=3D dw) + { + r +=3D cpu.ram[ea + 2] << 16; + r +=3D 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 =3D 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 =3D (d =3D=3D 0x1337f7d1); + break; + case 0x1fc84: + cpu.pm_addr =3D d; + break; + case 0x1fc88: + { + sim_cpu *scpu =3D STATE_CPU (sd, 0); /* FIXME */ + address_word cia =3D 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 =3D (d & 0xffff) | ((d & 0xffff) << 16); + uint32_t d8 =3D (d16 & 0x00ff00ff) | ((d16 & 0x00ff00ff) << 8); + switch (dw) + { + case 0: d =3D d8; break; + case 1: d =3D d16; break; + } + printf("%08x\n", d); + } + break; + default: + fprintf(stderr, "Unknown IO write %08x to to %08x\n", d, ea); + } + } + else + { + cpu.ram[ea] =3D d & 0xff; + if (1 <=3D dw) + { + cpu.ram[ea + 1] =3D (d >> 8) & 0xff; + if (2 <=3D dw) + { + cpu.ram[ea + 2] =3D (d >> 16) & 0xff; + cpu.ram[ea + 3] =3D (d >> 24) & 0xff; + } + } + } +} + +static void ft32_push(SIM_DESC sd, uint32_t v) +{ + cpu.regs[31] -=3D 4; + cpu.regs[31] &=3D 0xffff; + cpu_mem_write(sd, 2, cpu.regs[31], v); +} + +static uint32_t ft32_pop() +{ + uint32_t r =3D cpu_mem_read(2, cpu.regs[31]); + cpu.regs[31] +=3D 4; + cpu.regs[31] &=3D 0xffff; + return r; +} + +static int nunsigned(int siz, int bits) +{ + int mask =3D (1L << siz) - 1; + return bits & mask; +} + +static int nsigned(int siz, int bits) +{ + int shift =3D (sizeof(int) * 8) - siz; + return (bits << shift) >> shift; +} + +static uint32_t ft32sdiv(uint32_t n, uint32_t d) +{ + if (n =3D=3D 0x80000000UL && d =3D=3D 0xffffffffUL) + return 0x80000000UL; + else + return (uint32_t)((int)n / (int)d); +} + +static uint32_t ft32smod(uint32_t n, uint32_t d) +{ + if (n =3D=3D 0x80000000UL && d =3D=3D 0xffffffffUL) + return 0; + else + return (uint32_t)((int)n % (int)d); +} + +static uint32_t ror(uint32_t n, uint32_t b) +{ + b &=3D 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 =3D ((1 << len) - 1) << pos; + return (d & ~mask) | ((f << pos) & mask); +} + +static uint32_t flip(uint32_t x, uint32_t b) +{ + if (b & 1) + x =3D (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1; + if (b & 2) + x =3D (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2; + if (b & 4) + x =3D (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4; + if (b & 8) + x =3D (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8; + if (b & 16) + x =3D (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 =3D STATE_CPU (sd, 0); /* FIXME */ + address_word cia =3D CIA_GET (scpu); + + sigsave =3D signal (SIGINT, interrupt); + cpu.reason =3D sim_stopped; + + do + { + if (cpu.cycles >=3D cpu.next_tick_cycle) + { + cpu.next_tick_cycle +=3D 100000; + ft32_push(sd, cpu.pc); + cpu.pc =3D 12; // interrupt 1 + } + uint32_t inst =3D cpu_pm_read(sd, 2, cpu.pc); + cpu.cycles +=3D 1; + // printf("inst at %04x: %08x\n", cpu.pc, inst); + + // Handle "call 8" (which is FT32's "break" equivalent) here + if (inst =3D=3D 0x00340002) + { + cpu.reason =3D sim_stopped; + goto escape; + } + uint32_t dw =3D (inst >> FT32_FLD_DW_BIT) & ((1U << FT= 32_FLD_DW_SIZ) - 1); + uint32_t cb =3D (inst >> FT32_FLD_CB_BIT) & ((1U << FT= 32_FLD_CB_SIZ) - 1); + uint32_t r_d =3D (inst >> FT32_FLD_R_D_BIT) & ((1U << F= T32_FLD_R_D_SIZ) - 1); + uint32_t cr =3D (inst >> FT32_FLD_CR_BIT) & ((1U << FT= 32_FLD_CR_SIZ) - 1); + uint32_t cv =3D (inst >> FT32_FLD_CV_BIT) & ((1U << FT= 32_FLD_CV_SIZ) - 1); + uint32_t bt =3D (inst >> FT32_FLD_BT_BIT) & ((1U << FT= 32_FLD_BT_SIZ) - 1); + uint32_t r_1 =3D (inst >> FT32_FLD_R_1_BIT) & ((1U << F= T32_FLD_R_1_SIZ) - 1); + uint32_t rimm =3D (inst >> FT32_FLD_RIMM_BIT) & ((1U << = FT32_FLD_RIMM_SIZ) - 1); + uint32_t r_2 =3D (inst >> FT32_FLD_R_2_BIT) & ((1U << F= T32_FLD_R_2_SIZ) - 1); + uint32_t k20 =3D nsigned(20, (inst >> FT32_FLD_K20_BIT) & ((1U << F= T32_FLD_K20_SIZ) - 1)); + uint32_t pa =3D (inst >> FT32_FLD_PA_BIT) & ((1U << FT= 32_FLD_PA_SIZ) - 1); + uint32_t aa =3D (inst >> FT32_FLD_AA_BIT) & ((1U << FT= 32_FLD_AA_SIZ) - 1); + uint32_t k16 =3D (inst >> FT32_FLD_K16_BIT) & ((1U << F= T32_FLD_K16_SIZ) - 1); + uint32_t k8 =3D nsigned(8, (inst >> FT32_FLD_K8_BIT) & ((1U << FT= 32_FLD_K8_SIZ) - 1)); + uint32_t al =3D (inst >> FT32_FLD_AL_BIT) & ((1U << FT= 32_FLD_AL_SIZ) - 1); + + uint32_t r_1v =3D cpu.regs[r_1]; + uint32_t rimmv =3D (rimm & 0x400) ? nsigned(10, rimm) : cpu.regs[rim= m & 0x1f]; + + uint32_t bit_pos =3D rimmv & 31; + uint32_t bit_len =3D 0xf & (rimmv >> 5); + if (bit_len =3D=3D 0) + bit_len =3D 16; + + uint32_t upper =3D (inst >> 27); + + uint32_t insnpc =3D cpu.pc; + cpu.pc +=3D 4; + switch (upper) + { + case FT32_PAT_TOC: + case FT32_PAT_TOCI: + { + int takeit =3D (cr =3D=3D 3) || ((1 & (cpu.regs[28 + cr] >> cb= )) =3D=3D cv); + if (takeit) + { + cpu.cycles +=3D 1; + if (bt) + { + /* this is a call */ + if (tracefile) + fprintf(tracefile, "r0=3D%08x r1=3D%08x r2=3D%08x r3= =3D%08x\n", cpu.regs[0], cpu.regs[1], cpu.regs[2], cpu.regs[3]); + ft32_push(sd, cpu.pc); + } + if (upper =3D=3D FT32_PAT_TOC) + { + cpu.pc =3D pa << 2; + } + else + { + if (tracefile) + fprintf(tracefile, "indirect r%d to %#x\n", r_2, cpu= .regs[r_2]); + cpu.pc =3D cpu.regs[r_2]; + } + if (cpu.pc =3D=3D 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 =3D r_1v + rimmv; break; + case 0x1: result =3D ror(r_1v, rimmv); break; + case 0x2: result =3D r_1v - rimmv; break; + case 0x3: result =3D (r_1v << 10) | (1023 & rimmv); break; + case 0x4: result =3D r_1v & rimmv; break; + case 0x5: result =3D r_1v | rimmv; break; + case 0x6: result =3D r_1v ^ rimmv; break; + case 0x7: result =3D ~(r_1v ^ rimmv); break; + case 0x8: result =3D r_1v << rimmv; break; + case 0x9: result =3D r_1v >> rimmv; break; + case 0xa: result =3D (int32_t)r_1v >> rimmv; break; + case 0xb: result =3D bins(r_1v, rimmv >> 10, bit_len, bit_po= s); break; + case 0xc: result =3D nsigned(bit_len, r_1v >> bit_pos); brea= k; + case 0xd: result =3D nunsigned(bit_len, r_1v >> bit_pos); br= eak; + case 0xe: result =3D flip(r_1v, rimmv); break; + default: + printf("Unhandled alu %#x\n", al); + goto escape; + } + if (upper =3D=3D FT32_PAT_ALUOP) + { + cpu.regs[r_d] =3D result; + } + else + { + uint32_t dwmask; + int dwsiz; + switch (dw) + { + case 0: dwsiz =3D 7; dwmask =3D 0xffU; break; + case 1: dwsiz =3D 15; dwmask =3D 0xffffU; break; + case 2: dwsiz =3D 31; dwmask =3D 0xffffffffU; break; + } + + int zero =3D (0 =3D=3D (result & dwmask)); + int sign =3D 1 & (result >> dwsiz); + int ahi =3D 1 & (r_1v >> dwsiz); + int bhi =3D 1 & (rimmv >> dwsiz); + int overflow =3D (sign !=3D ahi) & (ahi =3D=3D !bhi); + int carry; + int bit =3D (dwsiz + 1); + uint64_t ra =3D r_1v & dwmask; + uint64_t rb =3D rimmv & dwmask; + switch (al) + { + case 0x0: carry =3D 1 & ((ra + rb) >> bit); break; + case 0x2: carry =3D 1 & ((ra - rb) >> bit); break; + default: carry =3D 0; break; + } + int above =3D (!carry & !zero); + int greater =3D (sign =3D=3D overflow) & !zero; + int greatereq =3D (sign =3D=3D overflow); + + cpu.regs[r_d] =3D ( + (above << 6) | + (greater << 5) | + (greatereq << 4) | + (sign << 3) | + (overflow << 2) | + (carry << 1) | + (zero << 0)); + } + if (0) + fprintf(tracefile, "%06x: result=3D%08x, \n", cpu.pc, result= ); + } + break; + + case FT32_PAT_LDK: + cpu.regs[r_d] =3D k20; + break; + + case FT32_PAT_LPM: + cpu.cycles +=3D 1; + cpu.regs[r_d] =3D cpu_pm_read(sd, dw, pa << 2); + break; + + case FT32_PAT_LPMI: + cpu.cycles +=3D 1; + cpu.regs[r_d] =3D cpu_pm_read(sd, dw, cpu.regs[r_1] + k8); + if (tracefile) + fprintf(tracefile, "lpmi %x %08x\n", cpu.regs[r_1] + k8, cpu.r= egs[r_d]); + break; + + case FT32_PAT_STA: + cpu_mem_write(sd, dw, aa, cpu.regs[r_d]); + if (aa =3D=3D 0x1fffc) + { + cpu.reason =3D sim_exited; + goto escape; + } + break; + + case FT32_PAT_STI: + if (tracefile) + fprintf(tracefile, "STI %#x <=3D %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 +=3D 1; + cpu.regs[r_d] =3D cpu_mem_read(dw, aa); + break; + + case FT32_PAT_LDI: + cpu.cycles +=3D 1; + cpu.regs[r_d] =3D cpu_mem_read(dw, cpu.regs[r_1] + k8); + if (tracefile) + fprintf(tracefile, "LDI %#x <=3D %08x\n", cpu.regs[r_d], cpu.r= egs[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] =3D cpu.regs[31]; + cpu.regs[31] -=3D k16; + cpu.regs[31] &=3D 0xffff; + break; + + case FT32_PAT_UNLINK: + cpu.regs[31] =3D cpu.regs[r_d]; + cpu.regs[31] &=3D 0xffff; + cpu.regs[r_d] =3D ft32_pop(); + break; + + case FT32_PAT_POP: + cpu.cycles +=3D 1; + cpu.regs[r_d] =3D ft32_pop(); + break; + + case FT32_PAT_RETURN: + cpu.pc =3D ft32_pop(); + break; + + case FT32_PAT_FFUOP: + if (tracefile) + fprintf(tracefile, "ffu %#x\n", al); + switch (al) + { + case 0x0: cpu.regs[r_d] =3D r_1v / rimmv; break; + case 0x1: cpu.regs[r_d] =3D r_1v % rimmv; break; + case 0x2: cpu.regs[r_d] =3D ft32sdiv(r_1v, rimmv); break; + case 0x3: cpu.regs[r_d] =3D ft32smod(r_1v, rimmv); break; + + case 0x4: cpu.regs[r_d] =3D strcmp(cpu.ram + r_1v, cpu.ram + rim= mv); break; + case 0x5: memcpy(cpu.ram + cpu.regs[r_d], cpu.ram + r_1v, rimmv)= ; break; + case 0x6: cpu.regs[r_d] =3D 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] =3D r_1v * rimmv; break; + case 0x9: cpu.regs[r_d] =3D ((uint64_t)r_1v * (uint64_t)rimmv) >= > 32; break; + case 0xe: + { + // streamout + uint32_t i; + uint32_t src =3D cpu.regs[r_1]; + for (i =3D 0; i < rimmv; i +=3D (1 << dw)) + { + cpu_mem_write(sd, dw, cpu.regs[r_d], cpu_mem_read(dw, sr= c)); + src +=3D (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=3D%#x inst=3D%08x r%d=3D%08x\n", cpu.= num_i, insnpc, inst, r_d, cpu.regs[r_d]); + } + while (!step); +escape: + cpu.exception =3D step ? SIGTRAP : 0; + if (cpu.reason =3D=3D sim_exited) + { + cpu.exception =3D 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 =3D 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 -=3D 0x800000; + for (i =3D 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 =3D 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 -=3D 0x800000; + for (i =3D 0; i < size; i++) + buffer[i] =3D 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 <=3D rn && rn <=3D 32) + { + if (length =3D=3D 4) + { + long ival; + + /* misalignment safe */ + ival =3D ft32_extract_unsigned_integer (memory, 4); + if (rn =3D=3D 32) + cpu.pc =3D ival; + else + cpu.regs[rn] =3D 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 <=3D rn && rn <=3D 32) + { + if (length =3D=3D 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 =3D cpu.regs[29]; + break; + case 1: + ival =3D cpu.regs[31]; + break; + case 31: + ival =3D cpu.regs[30]; + break; + case 32: + ival =3D cpu.pc; + break; + default: + ival =3D cpu.regs[rn - 2]; + } + // printf("[sim_fetch_register(%d)=3D%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 =3D=3D 0) + tracefile =3D fopen("trace.csv", "wb"); + tracefile =3D stdout; + + tracing =3D 1; + + sim_resume (sd, 0, 0); + + // fclose(tracefile); + + tracing =3D 0; + + return 1; +} + +void +sim_stop_reason (sd, reason, sigrc) + SIM_DESC sd; + enum sim_stop * reason; + int * sigrc; +{ + *reason =3D cpu.reason; + *sigrc =3D cpu.exception; +} + + +int +sim_stop (sd) + SIM_DESC sd; +{ + // cpu.asregs.exception =3D SIGINT; + return 1; +} + + +void +sim_info (sd, verbose) + SIM_DESC sd; + int verbose; +{ + // callback->printf_filtered (callback, "\n\n# instructions executed %l= lu\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 =3D sim_state_alloc (kind, cb); + SIM_ASSERT (STATE_MAGIC (sd) =3D=3D SIM_MAGIC_NUMBER); + + if (sim_pre_argv_init (sd, argv[0]) !=3D SIM_RC_OK) + return 0; + + sim_do_command(sd," memory region 0x00000000,0x4000000") ; + sim_do_command(sd," memory region 0xE0000000,0x10000") ; + + myname =3D argv[0]; + callback =3D cb; + + if (kind =3D=3D SIM_OPEN_STANDALONE) + issue_messages =3D 1; + + set_initial_gprs (); /* Reset the GPR registers. */ + + /* Configure/verify the target byte order and other runtime + configuration options. */ + if (sim_config (sd) !=3D SIM_RC_OK) + { + sim_module_uninstall (sd); + return 0; + } + + if (sim_post_argv_init (sd) !=3D 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 =3D 0; + FILE *f =3D fopen (filename, "rb"); + char *buf; + sim_cpu *scpu =3D STATE_CPU (sd, 0); /* FIXME */ + if (f =3D=3D NULL) + { + printf ("WARNING: ``%s'' could not be opened.\n", filename); + return; + } + fseek (f, 0, SEEK_END); + size =3D ftell(f); + fseek (f, 0, SEEK_SET); + buf =3D alloca (size); + if (size !=3D 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] =3D 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 =3D 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 =3D sim_load_file (sd, myname, callback, prog, abfd, + sim_kind =3D=3D SIM_OPEN_DEBUG, + 0, sim_write); + if (prog_bfd =3D=3D NULL) + return SIM_RC_FAIL; + + if (abfd =3D=3D 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 =3D STATE_CPU (sd, 0); /* FIXME */ + + /* Set the initial register set. */ + l =3D issue_messages; + issue_messages =3D 0; + set_initial_gprs (); + issue_messages =3D l; + + // printf("start address %#lx\n", bfd_get_start_address (prog_bfd)); + cpu.pc =3D bfd_get_start_address (prog_bfd); + cpu.regs[31] =3D 0x00000; + cpu.num_i =3D 0; + cpu.cycles =3D 0; + cpu.next_tick_cycle =3D 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) !=3D 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 =3D ptr; +} diff --git a/sim/ft32/sim-main.h b/sim/ft32/sim-main.h new file mode 100644 index 0000000..89f0f72 --- /dev/null +++ b/sim/ft32/sim-main.h @@ -0,0 +1,61 @@ +/* Moxie Simulator definition. + Copyright (C) 2009-2013 Free Software Foundation, Inc. + Contributed by Anthony Green + +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 . */ + +#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] =3D (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 diff --git a/sim/ft32/sysdep.h b/sim/ft32/sysdep.h new file mode 100644 index 0000000..d82b70b --- /dev/null +++ b/sim/ft32/sysdep.h @@ -0,0 +1,94 @@ +/* System includes and definitions used by the FT32 simulator. + Copyright (C) 2008-2013 Free Software Foundation, Inc. + Contributed by FTDI + +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 . */ + +#ifndef __SYSDEP_H +#define __SYSDEP_H + +#ifndef hosts_std_host_H +#include +#include +#include +#include +#include +#include +#include +#include +#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 +/*#include */ +#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 +#endif /* STDC_HEADERS */ + +#endif /* __SYSDEP_H */ --=20 1.7.9.5