From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 119240 invoked by alias); 28 Mar 2015 06:21:23 -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 119231 invoked by uid 89); 28 Mar 2015 06:21:22 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=1.3 required=5.0 tests=AWL,BAYES_50,KAM_STOCKGEN,SPF_PASS,T_RP_MATCHES_RCVD,UNSUBSCRIBE_BODY autolearn=no version=3.3.2 X-HELO: smtp.gentoo.org Received: from smtp.gentoo.org (HELO smtp.gentoo.org) (140.211.166.183) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Sat, 28 Mar 2015 06:21:15 +0000 Received: from vapier (localhost [127.0.0.1]) by smtp.gentoo.org (Postfix) with SMTP id 0498C34080A; Sat, 28 Mar 2015 06:21:12 +0000 (UTC) Date: Sat, 28 Mar 2015 06:21:00 -0000 From: Mike Frysinger To: James Bowman Cc: "gdb-patches@sourceware.org" Subject: Re: [PATCH, FT32] gdb and sim support Message-ID: <20150328062113.GE30239@vapier> Mail-Followup-To: James Bowman , "gdb-patches@sourceware.org" References: MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="pyE8wggRBhVBcj8z" Content-Disposition: inline In-Reply-To: X-IsSubscribed: yes X-SW-Source: 2015-03/txt/msg00931.txt.bz2 --pyE8wggRBhVBcj8z Content-Type: multipart/mixed; boundary="maH1Gajj2nflutpK" Content-Disposition: inline --maH1Gajj2nflutpK Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Content-length: 257 i moved the sim header to the sim patch and pushed that first, then the gdb= one.=20=20 i don't like having commits that are not bisectable, nor having to squash l= arge=20 ones to avoid. see attached patches for what went in. thanks for the port! -mike --maH1Gajj2nflutpK Content-Type: text/x-diff; charset=utf-8 Content-Disposition: attachment; filename="0001-sim-ft32-new-port.patch" Content-Transfer-Encoding: quoted-printable Content-length: 53653 =46rom f46e4eb78ba55e8bf8dedd98d7fe354729181710 Mon Sep 17 00:00:00 2001 From: James Bowman Date: Mon, 23 Mar 2015 19:20:59 +0000 Subject: [PATCH 1/2] sim: ft32: new port FT32 is a new high performance 32-bit RISC core developed by FTDI for embedded applications. --- include/gdb/ChangeLog | 4 + include/gdb/sim-ft32.h | 35 + sim/ChangeLog | 5 + sim/configure | 9 + sim/configure.tgt | 4 + sim/ft32/ChangeLog | 8 + sim/ft32/Makefile.in | 48 + sim/ft32/aclocal.m4 | 129 + sim/ft32/config.in | 163 + sim/ft32/configure | 15740 +++++++++++++++++++++++++++++= ++++ sim/ft32/configure.ac | 15 + sim/ft32/ft32-sim.h | 43 + sim/ft32/interp.c | 913 ++ sim/ft32/sim-main.h | 58 + sim/testsuite/ChangeLog | 4 + sim/testsuite/configure | 4 + sim/testsuite/sim/ft32/ChangeLog | 3 + sim/testsuite/sim/ft32/allinsn.exp | 15 + sim/testsuite/sim/ft32/basic.s | 862 ++ sim/testsuite/sim/ft32/testutils.inc | 65 + 20 files changed, 18127 insertions(+) create mode 100644 include/gdb/sim-ft32.h create mode 100644 sim/ft32/ChangeLog create mode 100644 sim/ft32/Makefile.in create mode 100644 sim/ft32/aclocal.m4 create mode 100644 sim/ft32/config.in create mode 100755 sim/ft32/configure create mode 100644 sim/ft32/configure.ac create mode 100644 sim/ft32/ft32-sim.h create mode 100644 sim/ft32/interp.c create mode 100644 sim/ft32/sim-main.h create mode 100644 sim/testsuite/sim/ft32/ChangeLog create mode 100644 sim/testsuite/sim/ft32/allinsn.exp create mode 100644 sim/testsuite/sim/ft32/basic.s create mode 100644 sim/testsuite/sim/ft32/testutils.inc diff --git a/include/gdb/ChangeLog b/include/gdb/ChangeLog index 88bd15c..d36d6b8 100644 --- a/include/gdb/ChangeLog +++ b/include/gdb/ChangeLog @@ -1,3 +1,7 @@ +2015-03-28 James Bowman + + * sim-ft32.h: New file. + 2015-05-15 Mike Frysinger =20 * remote-sim.h (struct host_callback_struct): Define. diff --git a/include/gdb/sim-ft32.h b/include/gdb/sim-ft32.h new file mode 100644 index 0000000..73c4f63 --- /dev/null +++ b/include/gdb/sim-ft32.h @@ -0,0 +1,35 @@ +/* This file defines the interface between the FT32 simulator and GDB. + + Copyright (C) 2005-2015 Free Software Foundation, Inc. + Contributed by FTDI. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . = */ + + +/* Register numbers of various important registers. */ +enum ft32_regnum +{ + FT32_FP_REGNUM, /* Address of executing stack frame. */ + FT32_SP_REGNUM, /* Address of top of stack. */ + FT32_R0_REGNUM, + FT32_R1_REGNUM, + FT32_CC_REGNUM =3D 31, + FT32_PC_REGNUM =3D 32 /* Program counter. */ +}; + +/* Number of machine registers. */ +#define FT32_NUM_REGS 33 /* 32 real registers + PC */ + diff --git a/sim/ChangeLog b/sim/ChangeLog index 37ee409..8b7fcb3 100644 --- a/sim/ChangeLog +++ b/sim/ChangeLog @@ -1,3 +1,8 @@ +2015-03-28 James Bowman + + * configure.tgt: Add FT32 entry. + * configure: Regenerate. + 2015-03-16 Mike Frysinger =20 * .gitignore: Delete tconfig.h. diff --git a/sim/configure b/sim/configure index 36d356e..740042a 100755 diff --git a/sim/configure.tgt b/sim/configure.tgt index d112e72..026b81f 100644 --- a/sim/configure.tgt +++ b/sim/configure.tgt @@ -111,6 +111,10 @@ case "${target}" in powerpc*-*-*) SIM_ARCH(ppc) ;; + ft32-*-*) + SIM_ARCH(ft32) + sim_testsuite=3Dyes + ;; v850*-*-*) SIM_ARCH(v850) sim_igen=3Dyes diff --git a/sim/ft32/ChangeLog b/sim/ft32/ChangeLog new file mode 100644 index 0000000..1479658 --- /dev/null +++ b/sim/ft32/ChangeLog @@ -0,0 +1,8 @@ +2015-03-28 James Bowman + + * Makefile.in: New file, FT32 sim Makefile. + * configure.ac: New file, FT32 sim config. + * ft32-sim.h: New file, FT32 sim CPU object. + * interp.c: New file, FT32 simulator. + * sim-main.h: New file, FT32 simulator wrapper. + * aclocal.m4, config.in, configure: Regenerate. diff --git a/sim/ft32/Makefile.in b/sim/ft32/Makefile.in new file mode 100644 index 0000000..f16039a --- /dev/null +++ b/sim/ft32/Makefile.in @@ -0,0 +1,48 @@ +# Makefile template for Configure for the ft32 sim library. +# Copyright (C) 2008-2015 Free Software Foundation, Inc. +# Written by FTDI +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +## COMMON_PRE_CONFIG_FRAG + + +SIM_OBJS =3D \ + $(SIM_NEW_COMMON_OBJS) \ + interp.o \ + sim-bits.o \ + sim-config.o \ + sim-core.o \ + sim-cpu.o \ + sim-endian.o \ + sim-engine.o \ + sim-events.o \ + sim-fpu.o \ + sim-hload.o \ + sim-io.o \ + sim-load.o \ + sim-memopt.o \ + sim-module.o \ + sim-options.o \ + sim-profile.o \ + sim-reason.o \ + sim-reg.o \ + sim-resume.o \ + sim-signal.o \ + sim-stop.o \ + sim-trace.o \ + sim-utils.o \ + $(SIM_EXTRA_OBJS) + +## COMMON_POST_CONFIG_FRAG diff --git a/sim/ft32/aclocal.m4 b/sim/ft32/aclocal.m4 new file mode 100644 index 0000000..517bc73 diff --git a/sim/ft32/config.in b/sim/ft32/config.in new file mode 100644 index 0000000..6003e58 diff --git a/sim/ft32/configure b/sim/ft32/configure new file mode 100755 index 0000000..1d18263 diff --git a/sim/ft32/configure.ac b/sim/ft32/configure.ac new file mode 100644 index 0000000..2107f74 --- /dev/null +++ b/sim/ft32/configure.ac @@ -0,0 +1,15 @@ +dnl Process this file with autoconf to produce a configure script. +AC_PREREQ(2.64)dnl +AC_INIT(Makefile.in) +sinclude(../common/acinclude.m4) + +SIM_AC_COMMON + +SIM_AC_OPTION_ENDIAN(LITTLE_ENDIAN) +SIM_AC_OPTION_ALIGNMENT(STRICT_ALIGNMENT) +SIM_AC_OPTION_HOSTENDIAN +SIM_AC_OPTION_ENVIRONMENT +SIM_AC_OPTION_INLINE +SIM_AC_OPTION_WARNINGS + +SIM_AC_OUTPUT diff --git a/sim/ft32/ft32-sim.h b/sim/ft32/ft32-sim.h new file mode 100644 index 0000000..1d664ba --- /dev/null +++ b/sim/ft32/ft32-sim.h @@ -0,0 +1,43 @@ +/* Simulator for the FT32 processor + + Copyright (C) 2008-2015 Free Software Foundation, Inc. + Contributed by FTDI + + This file is part of simulators. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . = */ + +#ifndef _FT32_SIM_H_ +#define _FT32_SIM_H_ + +#include + +#include "gdb/sim-ft32.h" + +#define FT32_HARD_FP 29 +#define FT32_HARD_CC 30 +#define FT32_HARD_SP 31 + +struct ft32_cpu_state { + uint32_t regs[32]; + uint32_t pc; + uint64_t num_i; + uint64_t cycles; + uint64_t next_tick_cycle; + int pm_unlock; + uint32_t pm_addr; + int exception; +}; + +#endif /* _FT32_SIM_H_ */ diff --git a/sim/ft32/interp.c b/sim/ft32/interp.c new file mode 100644 index 0000000..931ad2b --- /dev/null +++ b/sim/ft32/interp.c @@ -0,0 +1,913 @@ +/* Simulator for the FT32 processor + + Copyright (C) 2008-2015 Free Software Foundation, Inc. + Contributed by FTDI + + This file is part of simulators. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . = */ + +#include "config.h" +#include +#include +#include +#include + +#include "bfd.h" +#include "gdb/callback.h" +#include "libiberty.h" +#include "gdb/remote-sim.h" + +#include "sim-main.h" +#include "sim-options.h" + +#include "opcode/ft32.h" + +/* + * FT32 is a Harvard architecture: RAM and code occupy + * different address spaces. + * + * sim and gdb model FT32 memory by adding 0x800000 to RAM + * addresses. This means that sim/gdb can treat all addresses + * similarly. + * + * The address space looks like: + * + * 00000 start of code memory + * 3ffff end of code memory + * 800000 start of RAM + * 80ffff end of RAM + */ + +#define RAM_BIAS 0x800000 /* Bias added to RAM addresses. */ + +static unsigned long +ft32_extract_unsigned_integer (unsigned char *addr, int len) +{ + unsigned long retval; + unsigned char *p; + unsigned char *startaddr =3D (unsigned char *) addr; + unsigned char *endaddr =3D startaddr + len; + + /* 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; +} + +static void +ft32_store_unsigned_integer (unsigned char *addr, int len, unsigned long v= al) +{ + 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; + } +} + +/* + * Align EA according to its size DW. + * The FT32 ignores the low bit of a 16-bit addresss, + * and the low two bits of a 32-bit address. + */ +static uint32_t ft32_align (uint32_t dw, uint32_t ea) +{ + switch (dw) + { + case 1: + ea &=3D ~1; + break; + case 2: + ea &=3D ~3; + break; + default: + break; + } + return ea; +} + +/* Read an item from memory address EA, sized DW. */ +static uint32_t +ft32_read_item (SIM_DESC sd, int dw, uint32_t ea) +{ + sim_cpu *cpu =3D STATE_CPU (sd, 0); + address_word cia =3D CIA_GET (cpu); + uint8_t byte[4]; + uint32_t r; + + ea =3D ft32_align (dw, ea); + + switch (dw) { + case 0: + return sim_core_read_aligned_1 (cpu, cia, read_map, ea); + case 1: + return sim_core_read_aligned_2 (cpu, cia, read_map, ea); + case 2: + return sim_core_read_aligned_4 (cpu, cia, read_map, ea); + default: + abort (); + } +} + +/* Write item V to memory address EA, sized DW. */ +static void +ft32_write_item (SIM_DESC sd, int dw, uint32_t ea, uint32_t v) +{ + sim_cpu *cpu =3D STATE_CPU (sd, 0); + address_word cia =3D CIA_GET (cpu); + uint8_t byte[4]; + + ea =3D ft32_align (dw, ea); + + switch (dw) { + case 0: + sim_core_write_aligned_1 (cpu, cia, write_map, ea, v); + break; + case 1: + sim_core_write_aligned_2 (cpu, cia, write_map, ea, v); + break; + case 2: + sim_core_write_aligned_4 (cpu, cia, write_map, ea, v); + break; + default: + abort (); + } +} + +#define ILLEGAL() \ + sim_engine_halt (sd, cpu, NULL, insnpc, sim_signalled, SIM_SIGILL) + +static uint32_t cpu_mem_read (SIM_DESC sd, uint32_t dw, uint32_t ea) +{ + sim_cpu *cpu =3D STATE_CPU (sd, 0); + uint32_t insnpc =3D cpu->state.pc; + uint32_t r; + uint8_t byte[4]; + + ea &=3D 0x1ffff; + if (ea & ~0xffff) + { + /* Simulate some IO devices */ + switch (ea) + { + case 0x1fff4: + /* Read the simulator cycle timer. */ + return cpu->state.cycles / 100; + default: + sim_io_eprintf (sd, "Illegal IO read address %08x, pc %#x\n", + ea, insnpc); + ILLEGAL (); + } + } + return ft32_read_item (sd, dw, RAM_BIAS + ea); +} + +static void cpu_mem_write (SIM_DESC sd, uint32_t dw, uint32_t ea, uint32_t= d) +{ + sim_cpu *cpu =3D STATE_CPU (sd, 0); + ea &=3D 0x1ffff; + if (ea & 0x10000) + { + /* Simulate some IO devices */ + switch (ea) + { + case 0x10000: + /* Console output */ + putchar (d & 0xff); + break; + case 0x1fc80: + /* Unlock the PM write port */ + cpu->state.pm_unlock =3D (d =3D=3D 0x1337f7d1); + break; + case 0x1fc84: + /* Set the PM write address register */ + cpu->state.pm_addr =3D d; + break; + case 0x1fc88: + /* Write to PM */ + ft32_write_item (sd, dw, cpu->state.pm_addr, d); + break; + case 0x1fffc: + /* Normal exit. */ + sim_engine_halt (sd, cpu, NULL, cpu->state.pc, sim_exited, cpu->state.r= egs[0]); + break; + case 0x1fff8: + sim_io_printf (sd, "Debug write %08x\n", d); + break; + default: + sim_io_eprintf (sd, "Unknown IO write %08x to to %08x\n", d, ea); + } + } + else + ft32_write_item (sd, dw, RAM_BIAS + ea, d); +} + +#define GET_BYTE(ea) cpu_mem_read (sd, 0, (ea)) +#define PUT_BYTE(ea, d) cpu_mem_write (sd, 0, (ea), (d)) + +/* LSBS (n) is a mask of the least significant N bits. */ +#define LSBS(n) ((1U << (n)) - 1) + +static void ft32_push (SIM_DESC sd, uint32_t v) +{ + sim_cpu *cpu =3D STATE_CPU (sd, 0); + cpu->state.regs[FT32_HARD_SP] -=3D 4; + cpu->state.regs[FT32_HARD_SP] &=3D 0xffff; + cpu_mem_write (sd, 2, cpu->state.regs[FT32_HARD_SP], v); +} + +static uint32_t ft32_pop (SIM_DESC sd) +{ + sim_cpu *cpu =3D STATE_CPU (sd, 0); + uint32_t r =3D cpu_mem_read (sd, 2, cpu->state.regs[FT32_HARD_SP]); + cpu->state.regs[FT32_HARD_SP] +=3D 4; + cpu->state.regs[FT32_HARD_SP] &=3D 0xffff; + return r; +} + +/* Extract the low SIZ bits of N as an unsigned number. */ +static int nunsigned (int siz, int n) +{ + return n & LSBS (siz); +} + +/* Extract the low SIZ bits of N as a signed number. */ +static int nsigned (int siz, int n) +{ + int shift =3D (sizeof (int) * 8) - siz; + return (n << shift) >> shift; +} + +/* Signed division N / D, matching hw behavior for (MIN_INT, -1). */ +static uint32_t ft32sdiv (uint32_t n, uint32_t d) +{ + if (n =3D=3D 0x80000000UL && d =3D=3D 0xffffffffUL) + return 0x80000000UL; + else + return (uint32_t)((int)n / (int)d); +} + +/* Signed modulus N % D, matching hw behavior for (MIN_INT, -1). */ +static uint32_t ft32smod (uint32_t n, uint32_t d) +{ + if (n =3D=3D 0x80000000UL && d =3D=3D 0xffffffffUL) + return 0; + else + return (uint32_t)((int)n % (int)d); +} + +/* Circular rotate right N by B bits. */ +static uint32_t ror (uint32_t n, uint32_t b) +{ + b &=3D 31; + return (n >> b) | (n << (32 - b)); +} + +/* Implement the BINS machine instruction. + See FT32 Programmer's Reference for details. */ +static uint32_t bins (uint32_t d, uint32_t f, uint32_t len, uint32_t pos) +{ + uint32_t bitmask =3D LSBS (len) << pos; + return (d & ~bitmask) | ((f << pos) & bitmask); +} + +/* Implement the FLIP machine instruction. + See FT32 Programmer's Reference for details. */ +static uint32_t flip (uint32_t x, uint32_t b) +{ + if (b & 1) + x =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; +} + +static void +step_once (SIM_DESC sd) +{ + sim_cpu *cpu =3D STATE_CPU (sd, 0); + address_word cia =3D CIA_GET (cpu); + uint32_t inst; + uint32_t dw; + uint32_t cb; + uint32_t r_d; + uint32_t cr; + uint32_t cv; + uint32_t bt; + uint32_t r_1; + uint32_t rimm; + uint32_t r_2; + uint32_t k20; + uint32_t pa; + uint32_t aa; + uint32_t k16; + uint32_t k8; + uint32_t al; + uint32_t r_1v; + uint32_t rimmv; + uint32_t bit_pos; + uint32_t bit_len; + uint32_t upper; + uint32_t insnpc; + + if (cpu->state.cycles >=3D cpu->state.next_tick_cycle) + { + cpu->state.next_tick_cycle +=3D 100000; + ft32_push (sd, cpu->state.pc); + cpu->state.pc =3D 12; /* interrupt 1. */ + } + inst =3D ft32_read_item (sd, 2, cpu->state.pc); + cpu->state.cycles +=3D 1; + + /* Handle "call 8" (which is FT32's "break" equivalent) here. */ + if (inst =3D=3D 0x00340002) + { + sim_engine_halt (sd, cpu, NULL, + cpu->state.pc, + sim_stopped, SIM_SIGTRAP); + goto escape; + } + + dw =3D (inst >> FT32_FLD_DW_BIT) & LSBS (FT32_FLD_DW_SIZ); + cb =3D (inst >> FT32_FLD_CB_BIT) & LSBS (FT32_FLD_CB_SIZ); + r_d =3D (inst >> FT32_FLD_R_D_BIT) & LSBS (FT32_FLD_R_D_SI= Z); + cr =3D (inst >> FT32_FLD_CR_BIT) & LSBS (FT32_FLD_CR_SIZ); + cv =3D (inst >> FT32_FLD_CV_BIT) & LSBS (FT32_FLD_CV_SIZ); + bt =3D (inst >> FT32_FLD_BT_BIT) & LSBS (FT32_FLD_BT_SIZ); + r_1 =3D (inst >> FT32_FLD_R_1_BIT) & LSBS (FT32_FLD_R_1_SI= Z); + rimm =3D (inst >> FT32_FLD_RIMM_BIT) & LSBS (FT32_FLD_RIMM_= SIZ); + r_2 =3D (inst >> FT32_FLD_R_2_BIT) & LSBS (FT32_FLD_R_2_SI= Z); + k20 =3D nsigned (20, (inst >> FT32_FLD_K20_BIT) & LSBS (FT32_FLD_K20_SI= Z)); + pa =3D (inst >> FT32_FLD_PA_BIT) & LSBS (FT32_FLD_PA_SIZ); + aa =3D (inst >> FT32_FLD_AA_BIT) & LSBS (FT32_FLD_AA_SIZ); + k16 =3D (inst >> FT32_FLD_K16_BIT) & LSBS (FT32_FLD_K16_SI= Z); + k8 =3D nsigned (8, (inst >> FT32_FLD_K8_BIT) & LSBS (FT32_FLD_K8_SIZ)= ); + al =3D (inst >> FT32_FLD_AL_BIT) & LSBS (FT32_FLD_AL_SIZ); + + r_1v =3D cpu->state.regs[r_1]; + rimmv =3D (rimm & 0x400) ? nsigned (10, rimm) : cpu->state.regs[rimm & 0= x1f]; + + bit_pos =3D rimmv & 31; + bit_len =3D 0xf & (rimmv >> 5); + if (bit_len =3D=3D 0) + bit_len =3D 16; + + upper =3D (inst >> 27); + + insnpc =3D cpu->state.pc; + cpu->state.pc +=3D 4; + switch (upper) + { + case FT32_PAT_TOC: + case FT32_PAT_TOCI: + { + int take =3D (cr =3D=3D 3) || ((1 & (cpu->state.regs[28 + cr] >> cb)) =3D= =3D cv); + if (take) + { + cpu->state.cycles +=3D 1; + if (bt) + ft32_push (sd, cpu->state.pc); /* this is a call. */ + if (upper =3D=3D FT32_PAT_TOC) + cpu->state.pc =3D pa << 2; + else + cpu->state.pc =3D cpu->state.regs[r_2]; + if (cpu->state.pc =3D=3D 0x8) + 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_pos); break; + case 0xc: result =3D nsigned (bit_len, r_1v >> bit_pos); break; + case 0xd: result =3D nunsigned (bit_len, r_1v >> bit_pos); break; + case 0xe: result =3D flip (r_1v, rimmv); break; + default: + sim_io_eprintf (sd, "Unhandled alu %#x\n", al); + ILLEGAL (); + } + if (upper =3D=3D FT32_PAT_ALUOP) + cpu->state.regs[r_d] =3D result; + else + { + uint32_t dwmask =3D 0; + int dwsiz =3D 0; + int zero; + int sign; + int ahi; + int bhi; + int overflow; + int carry; + int bit; + uint64_t ra; + uint64_t rb; + int above; + int greater; + int greatereq; + + switch (dw) + { + case 0: dwsiz =3D 7; dwmask =3D 0xffU; break; + case 1: dwsiz =3D 15; dwmask =3D 0xffffU; break; + case 2: dwsiz =3D 31; dwmask =3D 0xffffffffU; break; + } + + zero =3D (0 =3D=3D (result & dwmask)); + sign =3D 1 & (result >> dwsiz); + ahi =3D 1 & (r_1v >> dwsiz); + bhi =3D 1 & (rimmv >> dwsiz); + overflow =3D (sign !=3D ahi) & (ahi =3D=3D !bhi); + bit =3D (dwsiz + 1); + ra =3D r_1v & dwmask; + 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; + } + above =3D (!carry & !zero); + greater =3D (sign =3D=3D overflow) & !zero; + greatereq =3D (sign =3D=3D overflow); + + cpu->state.regs[r_d] =3D ( + (above << 6) | + (greater << 5) | + (greatereq << 4) | + (sign << 3) | + (overflow << 2) | + (carry << 1) | + (zero << 0)); + } + } + break; + + case FT32_PAT_LDK: + cpu->state.regs[r_d] =3D k20; + break; + + case FT32_PAT_LPM: + cpu->state.regs[r_d] =3D ft32_read_item (sd, dw, pa << 2); + cpu->state.cycles +=3D 1; + break; + + case FT32_PAT_LPMI: + cpu->state.regs[r_d] =3D ft32_read_item (sd, dw, cpu->state.regs[r_1= ] + k8); + cpu->state.cycles +=3D 1; + break; + + case FT32_PAT_STA: + cpu_mem_write (sd, dw, aa, cpu->state.regs[r_d]); + break; + + case FT32_PAT_STI: + cpu_mem_write (sd, dw, cpu->state.regs[r_d] + k8, cpu->state.regs[r_= 1]); + break; + + case FT32_PAT_LDA: + cpu->state.regs[r_d] =3D cpu_mem_read (sd, dw, aa); + cpu->state.cycles +=3D 1; + break; + + case FT32_PAT_LDI: + cpu->state.regs[r_d] =3D cpu_mem_read (sd, dw, cpu->state.regs[r_1] = + k8); + cpu->state.cycles +=3D 1; + break; + + case FT32_PAT_EXA: + { + uint32_t tmp; + tmp =3D cpu_mem_read (sd, dw, aa); + cpu_mem_write (sd, dw, aa, cpu->state.regs[r_d]); + cpu->state.regs[r_d] =3D tmp; + cpu->state.cycles +=3D 1; + } + break; + + case FT32_PAT_EXI: + { + uint32_t tmp; + tmp =3D cpu_mem_read (sd, dw, cpu->state.regs[r_1] + k8); + cpu_mem_write (sd, dw, cpu->state.regs[r_1] + k8, cpu->state.regs[r_d]); + cpu->state.regs[r_d] =3D tmp; + cpu->state.cycles +=3D 1; + } + break; + + case FT32_PAT_PUSH: + ft32_push (sd, r_1v); + break; + + case FT32_PAT_LINK: + ft32_push (sd, cpu->state.regs[r_d]); + cpu->state.regs[r_d] =3D cpu->state.regs[FT32_HARD_SP]; + cpu->state.regs[FT32_HARD_SP] -=3D k16; + cpu->state.regs[FT32_HARD_SP] &=3D 0xffff; + break; + + case FT32_PAT_UNLINK: + cpu->state.regs[FT32_HARD_SP] =3D cpu->state.regs[r_d]; + cpu->state.regs[FT32_HARD_SP] &=3D 0xffff; + cpu->state.regs[r_d] =3D ft32_pop (sd); + break; + + case FT32_PAT_POP: + cpu->state.cycles +=3D 1; + cpu->state.regs[r_d] =3D ft32_pop (sd); + break; + + case FT32_PAT_RETURN: + cpu->state.pc =3D ft32_pop (sd); + break; + + case FT32_PAT_FFUOP: + switch (al) + { + case 0x0: + cpu->state.regs[r_d] =3D r_1v / rimmv; + break; + case 0x1: + cpu->state.regs[r_d] =3D r_1v % rimmv; + break; + case 0x2: + cpu->state.regs[r_d] =3D ft32sdiv (r_1v, rimmv); + break; + case 0x3: + cpu->state.regs[r_d] =3D ft32smod (r_1v, rimmv); + break; + + case 0x4: + { + /* strcmp instruction. */ + uint32_t a =3D r_1v; + uint32_t b =3D rimmv; + uint32_t i =3D 0; + while ((GET_BYTE (a + i) !=3D 0) && + (GET_BYTE (a + i) =3D=3D GET_BYTE (b + i))) + i++; + cpu->state.regs[r_d] =3D GET_BYTE (a + i) - GET_BYTE (b + i); + } + break; + + case 0x5: + { + /* memcpy instruction. */ + uint32_t src =3D r_1v; + uint32_t dst =3D cpu->state.regs[r_d]; + uint32_t i; + for (i =3D 0; i < rimmv; i++) + PUT_BYTE (dst + i, GET_BYTE (src + i)); + } + break; + case 0x6: + { + /* strlen instruction. */ + uint32_t src =3D r_1v; + uint32_t i; + for (i =3D 0; GET_BYTE (src + i) !=3D 0; i++) + ; + cpu->state.regs[r_d] =3D i; + } + break; + case 0x7: + { + /* memset instruction. */ + uint32_t dst =3D cpu->state.regs[r_d]; + uint32_t i; + for (i =3D 0; i < rimmv; i++) + PUT_BYTE (dst + i, r_1v); + } + break; + case 0x8: + cpu->state.regs[r_d] =3D r_1v * rimmv; + break; + case 0x9: + cpu->state.regs[r_d] =3D ((uint64_t)r_1v * (uint64_t)rimmv) >> 32; + break; + case 0xa: + { + /* stpcpy instruction. */ + uint32_t src =3D r_1v; + uint32_t dst =3D cpu->state.regs[r_d]; + uint32_t i; + for (i =3D 0; GET_BYTE (src + i) !=3D 0; i++) + PUT_BYTE (dst + i, GET_BYTE (src + i)); + PUT_BYTE (dst + i, 0); + cpu->state.regs[r_d] =3D dst + i; + } + break; + case 0xe: + { + /* streamout instruction. */ + uint32_t i; + uint32_t src =3D cpu->state.regs[r_1]; + for (i =3D 0; i < rimmv; i +=3D (1 << dw)) + { + cpu_mem_write (sd, + dw, + cpu->state.regs[r_d], + cpu_mem_read (sd, dw, src)); + src +=3D (1 << dw); + } + } + break; + default: + sim_io_eprintf (sd, "Unhandled ffu %#x at %08x\n", al, insnpc); + ILLEGAL (); + } + break; + + default: + sim_io_eprintf (sd, "Unhandled pattern %d at %08x\n", upper, insnpc); + ILLEGAL (); + } + cpu->state.num_i++; + +escape: + ; +} + +void +sim_engine_run (SIM_DESC sd, + int next_cpu_nr, /* ignore */ + int nr_cpus, /* ignore */ + int siggnal) /* ignore */ +{ + sim_cpu *cpu; + + SIM_ASSERT (STATE_MAGIC (sd) =3D=3D SIM_MAGIC_NUMBER); + + cpu =3D STATE_CPU (sd, 0); + + while (1) + { + step_once (sd); + if (sim_events_tick (sd)) + sim_events_process (sd); + } +} + +int +sim_write (SIM_DESC sd, + SIM_ADDR addr, + const unsigned char *buffer, + int size) +{ + sim_cpu *cpu =3D STATE_CPU (sd, 0); + + return sim_core_write_buffer (sd, cpu, write_map, buffer, addr, size); +} + +int +sim_read (SIM_DESC sd, + SIM_ADDR addr, + unsigned char *buffer, + int size) +{ + sim_cpu *cpu =3D STATE_CPU (sd, 0); + + return sim_core_read_buffer (sd, cpu, read_map, buffer, addr, size); +} + +static uint32_t * +ft32_lookup_register (SIM_CPU *cpu, int nr) +{ + /* Handle the register number translation here. + * Sim registers are 0-31. + * Other tools (gcc, gdb) use: + * 0 - fp + * 1 - sp + * 2 - r0 + * 31 - cc + */ + + if ((nr < 0) || (nr > 32)) + { + sim_io_eprintf (CPU_STATE (cpu), "unknown register %i\n", nr); + abort (); + } + + switch (nr) + { + case FT32_FP_REGNUM: + return &cpu->state.regs[FT32_HARD_FP]; + case FT32_SP_REGNUM: + return &cpu->state.regs[FT32_HARD_SP]; + case FT32_CC_REGNUM: + return &cpu->state.regs[FT32_HARD_CC]; + case FT32_PC_REGNUM: + return &cpu->state.pc; + default: + return &cpu->state.regs[nr - 2]; + } +} + +static int +ft32_reg_store (SIM_CPU *cpu, + int rn, + unsigned char *memory, + int length) +{ + if (0 <=3D rn && rn <=3D 32) + { + if (length =3D=3D 4) + *ft32_lookup_register (cpu, rn) =3D ft32_extract_unsigned_integer (memory= , 4); + + return 4; + } + else + return 0; +} + +static int +ft32_reg_fetch (SIM_CPU *cpu, + int rn, + unsigned char *memory, + int length) +{ + if (0 <=3D rn && rn <=3D 32) + { + if (length =3D=3D 4) + ft32_store_unsigned_integer (memory, 4, *ft32_lookup_register (cpu, rn)); + + return 4; + } + else + return 0; +} + +static sim_cia +ft32_pc_get (SIM_CPU *cpu) +{ + return 32; +} + +static void +ft32_pc_set (SIM_CPU *cpu, sim_cia newpc) +{ + cpu->state.pc =3D newpc; +} + +/* Cover function of sim_state_free to free the cpu buffers as well. */ + +static void +free_state (SIM_DESC sd) +{ + if (STATE_MODULES (sd) !=3D NULL) + sim_module_uninstall (sd); + sim_cpu_free_all (sd); + sim_state_free (sd); +} + +SIM_DESC +sim_open (SIM_OPEN_KIND kind, + host_callback *cb, + struct bfd *abfd, + char **argv) +{ + char c; + size_t i; + SIM_DESC sd =3D sim_state_alloc (kind, cb); + + /* The cpu data is kept in a separately allocated chunk of memory. */ + if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) !=3D SIM= _RC_OK) + { + free_state (sd); + return 0; + } + + if (sim_pre_argv_init (sd, argv[0]) !=3D SIM_RC_OK) + { + free_state (sd); + return 0; + } + + /* getopt will print the error message so we just have to exit if this f= ails. + FIXME: Hmmm... in the case of gdb we need getopt to call + print_filtered. */ + if (sim_parse_args (sd, argv) !=3D SIM_RC_OK) + { + free_state (sd); + return 0; + } + + /* Allocate external memory if none specified by user. + Use address 4 here in case the user wanted address 0 unmapped. */ + if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) =3D=3D 0) + { + sim_do_command (sd, "memory region 0x00000000,0x40000"); + sim_do_command (sd, "memory region 0x800000,0x10000"); + } + + /* Check for/establish the reference program image. */ + if (sim_analyze_program (sd, + (STATE_PROG_ARGV (sd) !=3D NULL + ? *STATE_PROG_ARGV (sd) + : NULL), abfd) !=3D SIM_RC_OK) + { + free_state (sd); + return 0; + } + + /* Configure/verify the target byte order and other runtime + configuration options. */ + if (sim_config (sd) !=3D SIM_RC_OK) + { + free_state (sd); + return 0; + } + + if (sim_post_argv_init (sd) !=3D SIM_RC_OK) + { + free_state (sd); + return 0; + } + + /* CPU specific initialization. */ + for (i =3D 0; i < MAX_NR_PROCESSORS; ++i) + { + SIM_CPU *cpu =3D STATE_CPU (sd, i); + + CPU_REG_FETCH (cpu) =3D ft32_reg_fetch; + CPU_REG_STORE (cpu) =3D ft32_reg_store; + CPU_PC_FETCH (cpu) =3D ft32_pc_get; + CPU_PC_STORE (cpu) =3D ft32_pc_set; + } + + return sd; +} + +void +sim_close (SIM_DESC sd, int quitting) +{ + sim_module_uninstall (sd); +} + +SIM_RC +sim_create_inferior (SIM_DESC sd, + struct bfd *abfd, + char **argv, + char **env) +{ + uint32_t addr; + sim_cpu *cpu =3D STATE_CPU (sd, 0); + + /* Set the PC. */ + if (abfd !=3D NULL) + addr =3D bfd_get_start_address (abfd); + else + addr =3D 0; + + if (STATE_OPEN_KIND (sd) =3D=3D SIM_OPEN_DEBUG) + { + freeargv (STATE_PROG_ARGV (sd)); + STATE_PROG_ARGV (sd) =3D dupargv (argv); + } + cpu->state.regs[FT32_HARD_SP] =3D addr; + cpu->state.num_i =3D 0; + cpu->state.cycles =3D 0; + cpu->state.next_tick_cycle =3D 100000; + + return SIM_RC_OK; +} diff --git a/sim/ft32/sim-main.h b/sim/ft32/sim-main.h new file mode 100644 index 0000000..6cb7c7e --- /dev/null +++ b/sim/ft32/sim-main.h @@ -0,0 +1,58 @@ +/* Simulator for FTDI FT32 processor. + + Copyright (C) 2009-2015 Free Software Foundation, Inc. + Contributed by FTDI + + This file is part of simulators. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . = */ + +#ifndef SIM_MAIN_H +#define SIM_MAIN_H + +#include "sim-basics.h" + +typedef address_word sim_cia; + +#include "sim-base.h" +#include "bfd.h" + +typedef struct _sim_cpu SIM_CPU; + +#include "ft32-sim.h" + +struct _sim_cpu { + + /* The following are internal simulator state variables: */ +#define CIA_GET(CPU) ((CPU)->state.pc + 0) +#define CIA_SET(CPU,CIA) ((CPU)->state.pc =3D (CIA)) + + struct ft32_cpu_state state; + + sim_cpu_base base; +}; + +struct sim_state { + + sim_cpu *cpu[MAX_NR_PROCESSORS]; +#if (WITH_SMP) +#define STATE_CPU(sd,n) ((sd)->cpu[n]) +#else +#define STATE_CPU(sd,n) ((sd)->cpu[0]) +#endif + + sim_state_base base; +}; + +#endif diff --git a/sim/testsuite/ChangeLog b/sim/testsuite/ChangeLog index be7ad56..7580586 100644 --- a/sim/testsuite/ChangeLog +++ b/sim/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2015-03-28 James Bowman + + * configure: Regenerate. + 2014-03-10 Mike Frysinger =20 * configure: Regenerate. diff --git a/sim/testsuite/configure b/sim/testsuite/configure index f90bd47..1dcaa41 100755 diff --git a/sim/testsuite/sim/ft32/ChangeLog b/sim/testsuite/sim/ft32/Chan= geLog new file mode 100644 index 0000000..a0cfa18 --- /dev/null +++ b/sim/testsuite/sim/ft32/ChangeLog @@ -0,0 +1,3 @@ +2015-02-28 James Bowman + + * basic.s, allinsn.exp, testutils.inc: New files. diff --git a/sim/testsuite/sim/ft32/allinsn.exp b/sim/testsuite/sim/ft32/al= linsn.exp new file mode 100644 index 0000000..730b422 --- /dev/null +++ b/sim/testsuite/sim/ft32/allinsn.exp @@ -0,0 +1,15 @@ +# ft32 simulator testsuite + +if [istarget ft32-*] { + # all machines + set all_machs "ft32" + + foreach src [lsort [glob -nocomplain $srcdir/$subdir/*.s]] { + # If we're only testing specific files and this isn't one of them, + # skip it. + if ![runtest_file_p $runtests $src] { + continue + } + run_sim_test $src $all_machs + } +} diff --git a/sim/testsuite/sim/ft32/basic.s b/sim/testsuite/sim/ft32/basic.s new file mode 100644 index 0000000..c92f295 --- /dev/null +++ b/sim/testsuite/sim/ft32/basic.s @@ -0,0 +1,862 @@ +# check that basic insns work. +# mach: ft32 + +.include "testutils.inc" + + start + + ldk $r4,10 + add $r4,$r4,23 + EXPECT $r4,33 + +# lda, sta + .data +tmp: .long 0 + .text + + xor.l $r0,$r0,$r0 + EXPECT $r0,0x00000000 + xor.l $r0,$r0,$r0 + add.l $r0,$r0,1 + EXPECT $r0,0x00000001 + + ldk.l $r0,0x4567 + EXPECT $r0,0x00004567 + + lpm.l $r0,k_12345678 + EXPECT $r0,0x12345678 + + sta.l tmp,$r0 + lda.l $r1,tmp + EXPECT $r1,0x12345678 + + lda.b $r1,tmp + EXPECT $r1,0x00000078 + + lda.b $r1,tmp+1 + EXPECT $r1,0x00000056 + + lda.b $r1,tmp+2 + EXPECT $r1,0x00000034 + + lda.b $r1,tmp+3 + EXPECT $r1,0x00000012 + + sta.b tmp+1,$r0 + lda.l $r1,tmp+0 + EXPECT $r1,0x12347878 + +# immediate + ldk.l $r1,12 + add.l $r1,$r1,4 + EXPECT $r1,0x00000010 + add.l $r1,$r1,0x1ff + EXPECT $r1,0x0000020f + add.l $r1,$r1,-0x200 + EXPECT $r1,0x0000000f + +# addk + xor.l $r1,$r0,$r0 + add.l $r2,$r1,127 + EXPECT $r2,0x0000007f + + add.l $r2,$r2,127 + EXPECT $r2,0x000000fe + + add.l $r2,$r2,-127 + EXPECT $r2,0x0000007f + + add.l $r2,$r2,-128 + EXPECT $r2,0xffffffff + + add.l $r2,$r2,1 + EXPECT $r2,0x00000000 + +# mul + ldk.l $r1,100 + ldk.l $r2,77 + mul.l $r3,$r1,$r2 + EXPECT $r3,0x00001e14 + + # 0x12345678 ** 2 =3D 0x14b66dc1df4d840L + mul.l $r3,$r0,$r0 + EXPECT $r3,0x1df4d840 + muluh.l $r3,$r0,$r0 + EXPECT $r3,0x014b66dc + +# push and pop + push.l $r0 + EXPECT $sp,0x0000fffc + ldi.l $r3,$sp,0 + EXPECT $r3,0x12345678 + + pop.l $r4 + EXPECT $sp,0x00000000 + EXPECT $r4,0x12345678 + + ldk.l $r1,0x1111 + push.l $r1 + ldk.l $r1,0x2222 + push.l $r1 + ldk.l $r1,0x3333 + push.l $r1 + ldk.l $r1,0x4444 + push.l $r1 + EXPECT $sp,0x0000fff0 + pop.l $r1 + EXPECT $r1,0x00004444 + pop.l $r1 + EXPECT $r1,0x00003333 + pop.l $r1 + EXPECT $r1,0x00002222 + pop.l $r1 + EXPECT $r1,0x00001111 + +# push and pop with $sp changes + ldk.l $r1,0xa111 + push.l $r1 + sub.l $sp,$sp,4 + ldk.l $r1,0xa222 + push.l $r1 + add.l $sp,$sp,-36 + add.l $sp,$sp,36 + pop.l $r1 + EXPECT $r1,0x0000a222 + add.l $sp,$sp,4 + pop.l $r1 + EXPECT $r1,0x0000a111 + +# sti + ldk.l $r2,80 + EXPECT $r2,0x00000050 + sti.l $r2,0,$r0 + lda.l $r1,80 + EXPECT $r1,0x12345678 + + ldk.l $r3,0xF0 + sti.b $r2,0,$r3 + lda.l $r1,80 + EXPECT $r1,0x123456f0 + + add.l $r2,$r2,1 + sti.l $r2,0,$r0 + sti.b $r2,0,$r3 + lda.l $r1,80 + EXPECT $r1,0x1234f078 + + add.l $r2,$r2,1 + sti.l $r2,0,$r0 + sti.b $r2,0,$r3 + lda.l $r1,80 + EXPECT $r1,0x12f05678 + + add.l $r2,$r2,1 + sti.l $r2,0,$r0 + sti.b $r2,0,$r3 + lda.l $r1,80 + EXPECT $r1,0xf0345678 + + ldk.l $r2,80 + sti.l $r2,0,$r0 + ldk.s $r3,0xbeef + sti.s $r2,0,$r3 + lda.l $r1,80 + EXPECT $r1,0x1234beef + add.l $r2,$r2,2 + sti.s $r2,0,$r3 + lda.l $r1,80 + EXPECT $r1,0xbeefbeef + +# lpmi + + ldk.l $r1,k_12345678 + lpmi.l $r2,$r1,0 + EXPECT $r2,0x12345678 + + lpmi.b $r2,$r1,0 + EXPECT $r2,0x00000078 + + add.l $r1,$r1,1 + lpmi.b $r2,$r1,0 + EXPECT $r2,0x00000056 + + add.l $r1,$r1,1 + lpmi.b $r2,$r1,0 + EXPECT $r2,0x00000034 + + add.l $r1,$r1,1 + lpmi.b $r2,$r1,0 + EXPECT $r2,0x00000012 + + lpmi.l $r2,$r1,4 + EXPECT $r2,0xabcdef01 + + lpmi.l $r2,$r1,-4 + EXPECT $r2,0x10111213 + + lpmi.b $r2,$r1,-4 + EXPECT $r2,0x00000010 + + ldk.l $r1,k_12345678 + lpmi.s $r2,$r1,0 + EXPECT $r2,0x00005678 + lpmi.s $r2,$r1,2 + EXPECT $r2,0x00001234 + lpmi.b $r2,$r1,6 + EXPECT $r2,0x000000cd + lpmi.b $r2,$r1,7 + EXPECT $r2,0x000000ab + lpmi.b $r2,$r1,-1 + EXPECT $r2,0x00000010 + lpmi.s $r2,$r1,-2 + EXPECT $r2,0x00001011 + + ldk.l $r1,k_12345678-127 + lpmi.b $r2,$r1,127 + EXPECT $r2,0x00000078 + + ldk.l $r1,k_12345678+128 + lpmi.b $r2,$r1,-128 + EXPECT $r2,0x00000078 + +# shifts + + lpm.l $r0,k_12345678 + ldk.l $r2,4 + ashl.l $r1,$r0,$r2 + EXPECT $r1,0x23456780 + lshr.l $r1,$r0,$r2 + EXPECT $r1,0x01234567 + ashr.l $r1,$r0,$r2 + EXPECT $r1,0x01234567 + + lpm.l $r0,k_abcdef01 + ashl.l $r1,$r0,$r2 + EXPECT $r1,0xbcdef010 + lshr.l $r1,$r0,$r2 + EXPECT $r1,0x0abcdef0 + ashr.l $r1,$r0,$r2 + EXPECT $r1,0xfabcdef0 + +# rotate right + + lpm.l $r0,k_12345678 + ror.l $r1,$r0,0 + EXPECT $r1,0x12345678 + ror.l $r1,$r0,12 + EXPECT $r1,0x67812345 + ror.l $r1,$r0,-4 + EXPECT $r1,0x23456781 + +# jmpx + ldk $r28,0xaaaaa + jmpx 0,$r28,1,failcase + jmpx 1,$r28,0,failcase + jmpx 2,$r28,1,failcase + jmpx 3,$r28,0,failcase + jmpx 4,$r28,1,failcase + jmpx 5,$r28,0,failcase + jmpx 6,$r28,1,failcase + jmpx 7,$r28,0,failcase + jmpx 8,$r28,1,failcase + jmpx 9,$r28,0,failcase + jmpx 10,$r28,1,failcase + jmpx 11,$r28,0,failcase + jmpx 12,$r28,1,failcase + jmpx 13,$r28,0,failcase + jmpx 14,$r28,1,failcase + jmpx 15,$r28,0,failcase + jmpx 16,$r28,1,failcase + jmpx 17,$r28,0,failcase + jmpx 18,$r28,1,failcase + jmpx 19,$r28,0,failcase + + move $r29,$r28 + ldk $r28,0 + jmpx 0,$r29,1,failcase + jmpx 1,$r29,0,failcase + jmpx 2,$r29,1,failcase + jmpx 3,$r29,0,failcase + jmpx 4,$r29,1,failcase + jmpx 5,$r29,0,failcase + jmpx 6,$r29,1,failcase + jmpx 7,$r29,0,failcase + jmpx 8,$r29,1,failcase + jmpx 9,$r29,0,failcase + jmpx 10,$r29,1,failcase + jmpx 11,$r29,0,failcase + jmpx 12,$r29,1,failcase + jmpx 13,$r29,0,failcase + jmpx 14,$r29,1,failcase + jmpx 15,$r29,0,failcase + jmpx 16,$r29,1,failcase + jmpx 17,$r29,0,failcase + jmpx 18,$r29,1,failcase + jmpx 19,$r29,0,failcase + + move $r30,$r29 + ldk $r29,0 + jmpx 0,$r30,1,failcase + jmpx 1,$r30,0,failcase + jmpx 2,$r30,1,failcase + jmpx 3,$r30,0,failcase + jmpx 4,$r30,1,failcase + jmpx 5,$r30,0,failcase + jmpx 6,$r30,1,failcase + jmpx 7,$r30,0,failcase + jmpx 8,$r30,1,failcase + jmpx 9,$r30,0,failcase + jmpx 10,$r30,1,failcase + jmpx 11,$r30,0,failcase + jmpx 12,$r30,1,failcase + jmpx 13,$r30,0,failcase + jmpx 14,$r30,1,failcase + jmpx 15,$r30,0,failcase + jmpx 16,$r30,1,failcase + jmpx 17,$r30,0,failcase + jmpx 18,$r30,1,failcase + jmpx 19,$r30,0,failcase + +# callx + ldk $r30,0xaaaaa + callx 0,$r30,0,skip1 + jmp failcase + callx 1,$r30,1,skip1 + jmp failcase + callx 2,$r30,0,skip1 + jmp failcase + callx 3,$r30,1,skip1 + jmp failcase + + callx 0,$r30,1,skip1 + ldk $r30,0x123 + EXPECT $r30,0x123 + +#define BIT(N,M) ((((N) & 15) << 5) | (M)) +# bextu + bextu.l $r1,$r0,(0<<5)|0 + EXPECT $r1,0x00005678 + bextu.l $r1,$r0,(4<<5)|0 + EXPECT $r1,0x00000008 + bextu.l $r1,$r0,(4<<5)|4 + EXPECT $r1,0x00000007 + bextu.l $r1,$r0,(4<<5)|28 + EXPECT $r1,0x00000001 + bextu.l $r1,$r0,(8<<5)|16 + EXPECT $r1,0x00000034 + ldk.l $r2,-1 + bextu.l $r1,$r2,(6<<5)|(3) + EXPECT $r1,0x0000003f + +# bexts + bexts.l $r1,$r0,(8<<5)|0 + EXPECT $r1,0x00000078 + bexts.l $r1,$r0,(0<<5)|16 + EXPECT $r1,0x00001234 + bexts.l $r1,$r0,(4<<5)|0 + EXPECT $r1,0xfffffff8 + # extract the '5' digit in widths 4-1 + bexts.l $r1,$r0,(4<<5)|12 + EXPECT $r1,0x00000005 + bexts.l $r1,$r0,(3<<5)|12 + EXPECT $r1,0xfffffffd + bexts.l $r1,$r0,(2<<5)|12 + EXPECT $r1,0x00000001 + bexts.l $r1,$r0,(1<<5)|12 + EXPECT $r1,0xffffffff + +# btst + # low four bits should be 0,0,0,1 + btst.l $r0,(1<<5)|0 + jmpc nz,failcase + btst.l $r0,(1<<5)|1 + jmpc nz,failcase + btst.l $r0,(1<<5)|2 + jmpc nz,failcase + btst.l $r0,(1<<5)|3 + jmpc z,failcase + + # the 6 bit field starting at position 24 is positive + btst.l $r0,(6<<5)|24 + jmpc s,failcase + # the 5 bit field starting at position 24 is negative + btst.l $r0,(5<<5)|24 + jmpc ns,failcase + + EXPECT $r0,0x12345678 + +# bins + bins.l $r1,$r0,(8 << 5) | (0) + EXPECT $r1,0x12345600 + + bins.l $r1,$r0,(0 << 5) | (8) + EXPECT $r1,0x12000078 + + ldk.l $r1,(0xff << 10) | (8 << 5) | (8) + bins.l $r1,$r0,$r1 + EXPECT $r1,0x1234ff78 + + call litr1 + .long (0x8dd1 << 10) | (0 << 5) | (0) + bins.l $r1,$r0,$r1 + EXPECT $r1,0x12348dd1 + + call litr1 + .long (0x8dd1 << 10) | (0 << 5) | (16) + bins.l $r1,$r0,$r1 + EXPECT $r1,0x8dd15678 + + ldk.l $r1,(0xde << 10) | (8 << 5) | (0) + bins.l $r1,$r0,$r1 + EXPECT $r1,0x123456de + +# ldl + ldk.l $r0,0 + ldl.l $r3,$r0,0 + EXPECT $r3,0x00000000 + ldk.l $r0,-1 + ldl.l $r3,$r0,-1 + EXPECT $r3,0xffffffff + ldk.l $r0,(0x12345678 >> 10) + ldl.l $r3,$r0,(0x12345678 & 0x3ff) + EXPECT $r3,0x12345678 + ldk.l $r0,(0xe2345678 >> 10) + ldl.l $r3,$r0,(0xe2345678 & 0x3ff) + EXPECT $r3,0xe2345678 + +# flip + ldk.l $r0,0x0000001 + flip.l $r1,$r0,0 + EXPECT $r1,0x00000001 + + lpm.l $r0,k_12345678 + flip.l $r1,$r0,0 + EXPECT $r1,0x12345678 + flip.l $r1,$r0,24 + EXPECT $r1,0x78563412 + flip.l $r1,$r0,31 + EXPECT $r1,0x1e6a2c48 + +# stack push pop + + EXPECT $sp,0x00000000 + ldk.l $r6,0x6666 + push.l $r6 + or.l $r0,$r0,$r0 # xxx + EXPECT $sp,0x0000fffc + ldi.l $r1,$sp,0 + EXPECT $r1,0x00006666 + pop.l $r1 + EXPECT $r1,0x00006666 + EXPECT $sp,0x00000000 + +# call/return + call fowia + push.l $r1 + call fowia + pop.l $r2 + sub.l $r1,$r1,$r2 + EXPECT $r1,0x00000008 + +# add,carry + + ldk.l $r0,0 + ldk.l $r1,0 + call add64 + EXPECT $r1,0x00000000 + EXPECT $r0,0x00000000 + + lpm.l $r0,k_abcdef01 + lpm.l $r1,k_abcdef01 + call add64 + EXPECT $r1,0x00000001 + EXPECT $r0,0x579bde02 + + ldk.l $r0,4 + ldk.l $r1,-5 + call add64 + EXPECT $r1,0x00000000 + EXPECT $r0,0xffffffff + + ldk.l $r0,5 + ldk.l $r1,-5 + call add64 + EXPECT $r1,0x00000001 + EXPECT $r0,0x00000000 + + lpm.l $r0,k_12345678 + ldk.l $r1,-1 + call add64 + EXPECT $r1,0x00000001 + EXPECT $r0,0x12345677 + + ldk.l $r0,-1 + ldk.l $r1,-1 + call add64 + EXPECT $r1,0x00000001 + EXPECT $r0,0xfffffffe + +# inline literal + call lit + .long 0xdecafbad + EXPECT $r0,0xdecafbad + + ldk.l $r1,0xee + call lit + ldk.l $r1,0xfe + EXPECT $r1,0x000000ee + + call lit + .long 0x01020304 + EXPECT $r0,0x01020304 + + call lit + .long lit + calli $r0 + .long 0xffaa55aa + EXPECT $r0,0xffaa55aa + +# comparisons + ldk.l $r0,-100 + ldk.l $r1,100 + cmp.l $r0,$r1 + + ldk.l $r2,0 + jmpc lt,.c1 + ldk.l $r2,1 +.c1: + EXPECT $r2,0x00000000 + + ldk.l $r2,0 + jmpc gt,.c2 + ldk.l $r2,1 +.c2: + EXPECT $r2,0x00000001 + + ldk.l $r2,0 + jmpc a,.c3 + ldk.l $r2,1 +.c3: + EXPECT $r2,0x00000000 + + ldk.l $r2,0 + jmpc b,.c4 + ldk.l $r2,1 +.c4: + EXPECT $r2,0x00000001 + + ldk.l $r2,0 + jmpc be,.c5 + ldk.l $r2,1 +.c5: + EXPECT $r2,0x00000001 + +# 8-bit comparisons + ldk.l $r0,0x8fe + ldk.l $r1,0x708 + cmp.b $r0,$r1 + + ldk.l $r2,0 + jmpc lt,.8c1 + ldk.l $r2,1 +.8c1: + EXPECT $r2,0x00000000 + + ldk.l $r2,0 + jmpc gt,.8c2 + ldk.l $r2,1 +.8c2: + EXPECT $r2,0x00000001 + + ldk.l $r2,0 + jmpc a,.8c3 + ldk.l $r2,1 +.8c3: + EXPECT $r2,0x00000000 + + ldk.l $r2,0 + jmpc b,.8c4 + ldk.l $r2,1 +.8c4: + EXPECT $r2,0x00000001 + + ldk.l $r2,0 + jmpc be,.8c5 + ldk.l $r2,1 +.8c5: + EXPECT $r2,0x00000001 + + ldk.l $r0,0x8aa + ldk.l $r1,0x7aa + cmp.b $r0,$r1 + + ldk.l $r2,0 + jmpc z,.8c6 + ldk.l $r2,1 +.8c6: + EXPECT $r2,0x00000000 + + ldk.b $r0,1 + ldk.b $r2,0xe0 + cmp.b $r2,0x1c0 + jmpc a,.8c7 + ldk.b $r0,0 +.8c7: + EXPECT $r0,0x00000001 + +# conditional call + cmp.l $r0,$r0 + callc z,lit + .long 0xccddeeff + callc nz,zr0 + EXPECT $r0,0xccddeeff + +# modify return address + ldk.l $r0,0x66 + call skip1 + ldk.l $r0,0xAA + EXPECT $r0,0x00000066 + + ldk.l $r0,0x77 + call skip2 + ldk.l $r0,0xBB + EXPECT $r0,0x00000077 + +# simple recursive function + ldk.l $r0,1 + call factorial + EXPECT $r0,0x00000001 + ldk.l $r0,2 + call factorial + EXPECT $r0,0x00000002 + ldk.l $r0,3 + call factorial + EXPECT $r0,0x00000006 + ldk.l $r0,4 + call factorial + EXPECT $r0,0x00000018 + ldk.l $r0,5 + call factorial + EXPECT $r0,0x00000078 + ldk.l $r0,6 + call factorial + EXPECT $r0,0x000002d0 + ldk.l $r0,7 + call factorial + EXPECT $r0,0x000013b0 + ldk.l $r0,12 + call factorial + EXPECT $r0,0x1c8cfc00 + +# read sp after a call + call nullfunc + EXPECT $sp,0x00000000 + +# CALLI->RETURN + ldk.l $r4,nullfunc + calli $r4 + EXPECT $sp,0x00000000 + +# Link/unlink + ldk.l $r14,0x17566 + + link $r14,48 + EXPECT $r14,0x0000fffc + sub.l $sp,$sp,200 + unlink $r14 + EXPECT $r14,0x00017566 + +# LINK->UNLINK + link $r14,48 + unlink $r14 + EXPECT $r14,0x00017566 + +# LINK->JUMPI + ldk.l $r3,.here + link $r14,48 + jmpi $r3 + jmp failcase +.here: + unlink $r14 + EXPECT $r14,0x00017566 + +# LINK->RETURN +# (This is a nonsense combination, but can still exericse it by +# using a negative parameter for the link. "link $r14,-4" leaves +# $sp exactly unchanged.) + ldk.l $r0,.returnhere + push.l $r0 + link $r14,0xfffc + return +.returnhere: + EXPECT $sp,0x00000000 + +# LPMI->CALLI + ldk.l $r0,k_abcdef01 + ldk.l $r1,increment + lpmi.l $r0,$r0,0 + calli $r1 + EXPECT $r0,0xabcdef02 + +# STRLen + lpm.l $r4,str3 + sta.l tmp,$r4 + ldk.l $r0,tmp + strlen.b $r1,$r0 + EXPECT $r1,0x00000003 + strlen.s $r1,$r0 + EXPECT $r1,0x00000003 + strlen.l $r1,$r0 + EXPECT $r1,0x00000003 + + ldk.l $r4,0 + sta.b 4,$r4 + strlen.l $r1,$r0 + EXPECT $r1,0x00000000 + + ldk.l $r4,-1 + sta.l 4,$r4 + lpm.l $r4,str3 + sta.l 8,$r4 + strlen.l $r1,$r0 + EXPECT $r1,0x00000007 + +# MEMSet + ldk.l $r0,4 + ldk.l $r1,0xaa + memset.s $r0,$r1,8 + ldk.l $r1,0x55 + memset.b $r0,$r1,5 + lda.l $r0,4 + EXPECT $r0,0x55555555 + lda.l $r0,8 + EXPECT $r0,0xaaaaaa55 + +# first cycle after mispredict + ldk.l $r0,3 + cmp.l $r0,$r0 + jmpc nz,failcase + add.l $r0,$r0,7 + EXPECT $r0,0x0000000a + jmpc nz,failcase + push.l $r0 + EXPECT $sp,0x0000fffc + pop.l $r0 + +# $sp access after stall + lpm.l $r13,0 + push.l $r0 + EXPECT $sp,0x0000fffc + pop.l $r0 + + push.l $r0 + add.l $sp,$sp,-484 + EXPECT $sp,0x0000fe18 + EXPECT $sp,0x0000fe18 + EXPECT $sp,0x0000fe18 + add.l $sp,$sp,484 + EXPECT $sp,0x0000fffc + pop.l $r0 + +# atomic exchange + lpm.l $r0,k_12345678 + lpm.l $r1,k_abcdef01 + sta.l 100,$r1 + exa.l $r0,100 + EXPECT $r0,0xabcdef01 + lda.l $r0,100 + EXPECT $r0,0x12345678 + + lpm.l $r0,k_12345678 + lpm.l $r1,k_abcdef01 + sta.l 144,$r1 + ldk.l $r7,20 + exi.l $r0,$r7,124 + EXPECT $r0,0xabcdef01 + lda.l $r0,144 + EXPECT $r0,0x12345678 + + lpm.l $r0,k_12345678 + lpm.l $r1,k_abcdef01 + push $r1 + exi.l $r0,$sp,0 + EXPECT $r0,0xabcdef01 + pop.l $r0 + EXPECT $r0,0x12345678 + +# final stack check + EXPECT $sp,0x00000000 + + PASS + +# -------------------------------------------------- + +skip1: # skip the instruction after the call + pop.l $r1 + add.l $r1,$r1,4 + push.l $r1 + return + +skipparent: # skip the instruction after the caller's call + ldi.l $r1,$sp,4 + add.l $r1,$r1,4 + sti.l $sp,4,$r1 + return +skip2: + call skipparent + return + +add64: + addcc.l $r0,$r1 + add.l $r0,$r0,$r1 + ldk.l $r1,0 + jmpc nc,.done + ldk.l $r1,1 +.done: + return + +fowia: # find out where I'm at + ldi.l $r1,$sp,0 + return + +lit: # load literal to $r0 + pop.l $r14 + lpmi.l $r0,$r14,0 + add.l $r14,$r14,4 + jmpi $r14 +zr0: + ldk.l $r0,0 + return +litr1: + ldi.l $r1,$sp,0 + add.l $r1,$r1,4 + sti.l $sp,0,$r1 + lpmi.l $r1,$r1,-4 + return + +factorial: + ldk.l $r1,1 + cmp.l $r0,$r1 + jmpc z,.factdone + push.l $r0 + add.l $r0,$r0,-1 + call factorial + pop.l $r1 + mul.l $r0,$r0,$r1 +.factdone: + return + +nullfunc: + return + +increment: + add.l $r0,$r0,1 + return + + .long 0x10111213 +k_12345678: + .long 0x12345678 +k_abcdef01: + .long 0xabcdef01 +str3: + .string "abc" diff --git a/sim/testsuite/sim/ft32/testutils.inc b/sim/testsuite/sim/ft32/= testutils.inc new file mode 100644 index 0000000..c07811f --- /dev/null +++ b/sim/testsuite/sim/ft32/testutils.inc @@ -0,0 +1,65 @@ + +# Write ch to the standard output + .macro outch ch + ldk $r0,\ch + sta 0x10000,$r0 + .endm + +# End the test with return code c + .macro exit c + ldk $r0,\c + sta 0x1fffc,$r0 + .endm + +# All assembler tests should start with this macro "start" + .macro start + .text + + jmp __start + jmp __start + reti + + .data +ccsave: .long 0 + .text + +# Fiddling to load $cc from the following word in program memory +loadcc: + exi $r29,$sp,0 + lpmi $cc,$r29,0 + add $r29,$r29,4 + exi $r29,$sp,0 + return + +failcase: + outch 'f' + outch 'a' + outch 'i' + outch 'l' + outch '\n' + exit 1 + +__start: + + .endm + +# At the end of the test, the code should reach this macro PASS + .macro PASS + outch 'p' + outch 'a' + outch 's' + outch 's' + outch '\n' + exit 0 + .endm + +# Confirm that reg has value, and fail immediately if not +# Preserves all registers + .macro EXPECT reg,value + sta ccsave,$cc + call loadcc + .long \value + cmp \reg,$cc + jmpc nz,failcase + lda $cc,ccsave + .endm --=20 2.3.3 --maH1Gajj2nflutpK Content-Type: text/x-diff; charset=utf-8 Content-Disposition: attachment; filename="0002-gdb-ft32-new-port.patch" Content-Transfer-Encoding: quoted-printable Content-length: 20274 =46rom 49d45b20c01da11b7493a5c28bdced7558999d6d Mon Sep 17 00:00:00 2001 From: James Bowman Date: Mon, 23 Mar 2015 19:15:32 +0000 Subject: [PATCH 2/2] gdb: ft32: new port FT32 is a new high performance 32-bit RISC core developed by FTDI for embedded applications. --- gdb/ChangeLog | 9 + gdb/Makefile.in | 5 +- gdb/configure.tgt | 5 + gdb/ft32-tdep.c | 549 ++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ gdb/ft32-tdep.h | 28 +++ 5 files changed, 595 insertions(+), 1 deletion(-) create mode 100644 gdb/ft32-tdep.c create mode 100644 gdb/ft32-tdep.h diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 6c6b94e..fe6811e 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,12 @@ +2015-03-28 James Bowman + + * Makefile.in (ALL_TARGET_OBS): Add ft32-tdep.o. + (HFILES_NO_SRCDIR): Add ft32-tdep.h. + (ALLDEPFILES): Add ft32-tdep.c. + * configure.tgt: Add FT32 entry. + * ft32-tdep.c: New file, FT32 target-dependent code. + * ft32-tdep.h: New file, FT32 target-dependent code. + 2015-03-27 Jan Kratochvil =20 Revert: diff --git a/gdb/Makefile.in b/gdb/Makefile.in index ae50041..907997b 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -651,6 +651,7 @@ ALL_TARGET_OBS =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-linux-tdep.o hppa-tdep.o \ @@ -949,7 +950,8 @@ psymtab.h psympriv.h progspace.h bfin-tdep.h \ amd64-darwin-tdep.h charset-list.h \ config/djgpp/langinfo.h config/djgpp/nl_types.h darwin-nat.h \ dicos-tdep.h filesystem.h gcore.h gdb_wchar.h hppabsd-tdep.h \ -i386-darwin-tdep.h x86-nat.h linux-record.h moxie-tdep.h nios2-tdep.h \ +i386-darwin-tdep.h i386-nat.h linux-record.h moxie-tdep.h nios2-tdep.h \ +ft32-tdep.h \ osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent= .h \ python/python-internal.h python/python.h ravenscar-thread.h record.h \ record-full.h solib-aix.h \ @@ -1655,6 +1657,7 @@ ALLDEPFILES =3D \ fbsd-nat.c \ fbsd-tdep.c \ fork-child.c \ + ft32-tdep.c \ glibc-tdep.c \ go32-nat.c h8300-tdep.c \ hppa-tdep.c \ diff --git a/gdb/configure.tgt b/gdb/configure.tgt index c97ebdd..8feda7c 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -615,6 +615,11 @@ xstormy16-*-*) # No simulator libraries are needed -- target uses SID. ;; =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..41a7191 --- /dev/null +++ b/gdb/ft32-tdep.c @@ -0,0 +1,549 @@ +/* Target-dependent code for FT32. + + Copyright (C) 2009-2015 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . = */ + +#include "defs.h" +#include "frame.h" +#include "frame-unwind.h" +#include "frame-base.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "gdbcmd.h" +#include "gdbcore.h" +#include "value.h" +#include "inferior.h" +#include "symfile.h" +#include "objfiles.h" +#include "osabi.h" +#include "language.h" +#include "arch-utils.h" +#include "regcache.h" +#include "trad-frame.h" +#include "dis-asm.h" +#include "record.h" + +#include "gdb_assert.h" + +#include "ft32-tdep.h" +#include "gdb/sim-ft32.h" + +#define RAM_BIAS 0x800000 /* Bias added to RAM addresses. */ + +/* Local functions. */ + +extern void _initialize_ft32_tdep (void); + +/* Use an invalid address -1 as 'not available' marker. */ +enum { REG_UNAVAIL =3D (CORE_ADDR) (-1) }; + +struct ft32_frame_cache +{ + /* Base address of the frame */ + CORE_ADDR base; + /* Function this frame belongs to */ + CORE_ADDR pc; + /* Total size of this frame */ + LONGEST framesize; + /* Saved registers in this frame */ + CORE_ADDR saved_regs[FT32_NUM_REGS]; + /* Saved SP in this frame */ + CORE_ADDR saved_sp; + /* Has the new frame been LINKed. */ + bfd_boolean established; +}; + +/* Implement the "frame_align" gdbarch method. */ + +static CORE_ADDR +ft32_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp) +{ + /* Align to the size of an instruction (so that they can safely be + pushed onto the stack. */ + return sp & ~1; +} + +/* Implement the "breakpoint_from_pc" gdbarch method. */ + +static const unsigned char * +ft32_breakpoint_from_pc (struct gdbarch *gdbarch, + CORE_ADDR *pcptr, int *lenptr) +{ + static const gdb_byte breakpoint[] =3D { 0x02, 0x00, 0x34, 0x00 }; + + *lenptr =3D sizeof (breakpoint); + return breakpoint; +} + +/* FT32 register names. */ + +static const char *const 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 gdb_byte *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 (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; + + 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; + } + } + + 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 !=3D NULL) && 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 pc; +} + +/* Implement the "read_pc" gdbarch method. */ + +static CORE_ADDR +ft32_read_pc (struct regcache *regcache) +{ + ULONGEST pc; + + regcache_cooked_read_unsigned (regcache, FT32_PC_REGNUM, &pc); + return pc; +} + +/* Implement the "write_pc" gdbarch method. */ + +static void +ft32_write_pc (struct regcache *regcache, CORE_ADDR val) +{ + regcache_cooked_write_unsigned (regcache, FT32_PC_REGNUM, val); +} + +/* Implement the "unwind_sp" gdbarch method. */ + +static CORE_ADDR +ft32_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + return frame_unwind_register_unsigned (next_frame, FT32_SP_REGNUM); +} + +/* Given a return value in `regbuf' with a type `valtype', + extract and copy its value into `valbuf'. */ + +static void +ft32_extract_return_value (struct type *type, struct regcache *regcache, + gdb_byte *dst) +{ + struct gdbarch *gdbarch =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); + + 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_REGNUM); + } + + 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, + RAM_BIAS | 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)); +} + +/* 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); + + return gdbarch; +} + +/* Register this machine's init routine. */ + +void +_initialize_ft32_tdep (void) +{ + register_gdbarch_init (bfd_arch_ft32, ft32_gdbarch_init); +} diff --git a/gdb/ft32-tdep.h b/gdb/ft32-tdep.h new file mode 100644 index 0000000..5c52480 --- /dev/null +++ b/gdb/ft32-tdep.h @@ -0,0 +1,28 @@ +/* Target-dependent code for the FT32. + + Copyright (C) 2002-2015 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . = */ + +#ifndef FT32_TDEP_H +#define FT32_TDEP_H + +struct gdbarch_tdep +{ + /* gdbarch target dependent data here. Currently unused for FT32. */ +}; + +#endif /* FT32_TDEP_H */ --=20 2.3.3 --maH1Gajj2nflutpK-- --pyE8wggRBhVBcj8z Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-length: 819 -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAEBCAAGBQJVFkhZAAoJEEFjO5/oN/WB+P4P/0wYMCSGZUpndT8YdWdylwca 7/vQpvbqybGdgNpsAmCb6PpGQFsVBIEIry4mW4VEHHS4nOTzF8N6uvOnLnO4/VAt Fc6VxBGf6oMoUkRN64jMKxq0nusELvm2mZFEQDlsfBzmmX9SQZU+VbJM39B4XSng 7zvdJ90ojsIMgPlRJeGPwRRmYWBDYImVaUkIUF5tNnnFhBMUcgdLEg7DlUN0a3DY aZ1aZJA1KQ9OKM1jfFiVWEoGz28boCzERTF3rMjFz3ua+wf6DKH5Ow3OGZ7FR4l4 yiwAvIdpQ1RgxTa3NhtfM18+ggTG/rJM0GgKYjh3aF+iyhqyu0HzGPoDUY9q4avW baRUYBzU1pgPoi2K7Q6kRIj3p4Or0oqqUqOeHhjUHjCNlc2Cgt2Am+gMTzDETZ2L 7xHfkCNSw6/S2sHIwVF3GR5watll0I/S4DSe+rQIslatbbj1XbKDkbavM6NpKzhg LOB95rwQVMvJdEz3Yusp6VREaSVfqhfPH89uBK4ONcfH9Q5Czvi5JrPTJcecJNc2 EmVPB5iI0gP4E+cKUqYbt5ayQDh5+ylu54YDhHWUU/WkdGyN98MhtHZDBp8HJZsU 8bwUsyxdV7eAWCwsMyiE2m4uMJg6fu9bWuzvlHsNYgKEyyjE7PpHXkv0p40bDzA+ vOHhUuA7FVttCztTosRW =KtA8 -----END PGP SIGNATURE----- --pyE8wggRBhVBcj8z--