From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 23162 invoked by alias); 11 Jul 2013 14:06:51 -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 23150 invoked by uid 89); 11 Jul 2013 14:06:49 -0000 X-Spam-SWARE-Status: No, score=-0.3 required=5.0 tests=AWL,BAYES_50,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,KAM_STOCKGEN,KHOP_THREADED,RCVD_IN_DNSWL_LOW,RCVD_IN_HOSTKARMA_YE,SPF_PASS,TW_CF,TW_CN,TW_CP,TW_EG,TW_SM,TW_XS autolearn=no version=3.3.1 Received: from mail-la0-f54.google.com (HELO mail-la0-f54.google.com) (209.85.215.54) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Thu, 11 Jul 2013 14:06:44 +0000 Received: by mail-la0-f54.google.com with SMTP id ec20so6691015lab.41 for ; Thu, 11 Jul 2013 07:06:41 -0700 (PDT) MIME-Version: 1.0 X-Received: by 10.112.189.101 with SMTP id gh5mr17137271lbc.73.1373551601024; Thu, 11 Jul 2013 07:06:41 -0700 (PDT) Received: by 10.112.71.139 with HTTP; Thu, 11 Jul 2013 07:06:40 -0700 (PDT) In-Reply-To: <51DCF32E.9020303@codesourcery.com> References: <51DCF32E.9020303@codesourcery.com> Date: Thu, 11 Jul 2013 14:06:00 -0000 Message-ID: Subject: Re: [PATCH 1/5] Code for nds32 target From: Wei-cheng Wang To: Yao Qi Cc: gdb-patches@sourceware.org Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-SW-Source: 2013-07/txt/msg00314.txt.bz2 Hi Yao, I've fix the first patch according to your suggestions. Here is the revised version. 1. nds32-linux-tdep* are removed, since they are based on outdated glibc-2.= 5. 2. nds32-utils* are merged in nds32-tdep. 3. nds32-remote are removed. They are mainly monitor commands for communicating with our OpenOCD poring. http://openocd.zylin.com/#/c/125= 9/ We may contribute them later. 4. All the issues mentioned are fixed. a. Review and fix TODO/FIXME. b. Add static/const if possible. c. Fix and review comments. d. Use align_up/align_down. e. 16.1.4 C usage f. Use xsnprintf instead of sprintf. g. Fix missing blank line and unnecessary brackets. h. Fix skip_permanent_breakpoint Thank you for your great help. Wei-Cheng --- 2013-07-11 Wei-Cheng Wang * Makefile.in (ALL_TARGET_OBS): Add nds32-tdep.o. (ALLDEPFILES): Add nds32-tdep.c. * configure.tgt: Add nds32* as target. * nds32-tdep.c: New file. * nds32-tdep.h: New file. * features/nds32-core.xml: New file. --- diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 4694adc..3a4da94 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -574,6 +574,7 @@ ALL_TARGET_OBS =3D \ moxie-tdep.o \ msp430-tdep.o \ mt-tdep.o \ + nds32-tdep.o \ nios2-tdep.o nios2-linux-tdep.o \ nto-tdep.o \ ppc-linux-tdep.o ppcfbsd-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o \ @@ -1519,6 +1520,7 @@ ALLDEPFILES =3D \ mipsnbsd-nat.c mipsnbsd-tdep.c \ mips64obsd-nat.c mips64obsd-tdep.c \ msp430-tdep.c \ + nds32-tdep.c \ nios2-tdep.c nios2-linux-tdep.c \ nbsd-nat.c nbsd-tdep.c obsd-tdep.c \ solib-osf.c \ diff --git a/gdb/configure.host b/gdb/configure.host index 85f4491..22aff67 100644 --- a/gdb/configure.host +++ b/gdb/configure.host @@ -54,6 +54,7 @@ sh*) gdb_host_cpu=3Dsh ;; tilegx*) gdb_host_cpu=3Dtilegx ;; x86_64*) gdb_host_cpu=3Di386 ;; m32r*) gdb_host_cpu=3Dm32r ;; +nds32*) gdb_host_cpu=3Dnds32 ;; xtensa*) gdb_host_cpu=3Dxtensa ;; *) gdb_host_cpu=3D$host_cpu ;; diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 260a0df..50d7904 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -401,6 +401,12 @@ mt-*-*) gdb_target_obs=3D"mt-tdep.o" ;; +nds32*) + # Target: AndesTech nds32 core + gdb_target_obs=3D"nds32-tdep.o monitor.o dsrec.o" + gdb_sim=3D../sim/nds32/libsim.a + ;; + nios2*-*-linux*) # Target: Altera Nios II running Linux gdb_target_obs=3D"nios2-tdep.o nios2-linux-tdep.o solib-svr4.o \ diff --git a/gdb/features/nds32-core.xml b/gdb/features/nds32-core.xml new file mode 100644 index 0000000..6164a28 --- /dev/null +++ b/gdb/features/nds32-core.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/nds32-tdep.c b/gdb/nds32-tdep.c new file mode 100644 index 0000000..404a8e4 --- /dev/null +++ b/gdb/nds32-tdep.c @@ -0,0 +1,2756 @@ +/* Target-dependent code for NDS32 architecture, for GDB. + + Copyright (C) 2006-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + 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 +#include "frame.h" +#include "frame-unwind.h" +#include "frame-base.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "gdbcmd.h" +#include "gdbcore.h" +#include "gdb_string.h" +#include "value.h" +#include "reggroups.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 "gdb_assert.h" +#include "user-regs.h" +#include "elf-bfd.h" +#include "dwarf2-frame.h" +#include "ui-file.h" +#include "remote.h" +#include "target-descriptions.h" +#include "sim-regno.h" +#include "gdb/sim-nds32.h" + +#include "nds32-tdep.h" +#include "elf/nds32.h" +#include "opcode/nds32.h" + +/* Simple macro for chop LSB immediate bits from an instruction. */ +#define CHOP_BITS(insn, n) (insn & ~__MASK (n)) + +extern void _initialize_nds32_tdep (void); + +/* "break16 0" for breakpoint_from_pc. + It is always supported now, so always insert break16. */ +static const gdb_byte NDS32_BREAK16[] =3D { 0xEA, 0x00 }; + +/* The standard register names. */ +static const char *nds32_regnames[] =3D +{ + /* 32 GPRs. */ + "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", "fp", "gp", "lp", "sp", + + /* 5 User Registers. */ + "pc", "d0lo", "d0hi", "d1lo", "d1hi", +}; + +/* Mnemonic names for registers. */ +struct nds32_register_alias +{ + const char *name; + const char *alias; +}; + +/* Register alias for user_reg_map_name_to_regnum (). */ +static const struct nds32_register_alias nds32_register_aliases[] =3D +{ + {"r15", "ta"}, + {"r26", "p0"}, + {"r27", "p1"}, + {"fp", "r28"}, + {"gp", "r29"}, + {"lp", "r30"}, + {"sp", "r31"}, + + {"ir0", "psw"}, + {"ir1", "ipsw"}, + {"ir2", "p_psw"}, + {"ir3", "ivb"}, + {"ir4", "eva"}, + {"ir5", "p_eva"}, + {"ir6", "itype"}, + {"ir7", "p_itype"}, + {"ir8", "merr"}, + {"ir9", "ipc"}, + {"ir10", "p_ipc"}, + {"ir11", "oipc"}, + {"ir12", "p_p0"}, + {"ir13", "p_p1"}, + {"ir14", "int_mask"}, + {"ir15", "int_pend"}, + + {"cr0", "cpu_ver"}, + {"cr1", "icm_cfg"}, + {"cr2", "dcm_cfg"}, + {"cr3", "mmu_cfg"}, + {"cr4", "msc_cfg"}, + {"cr5", "core_id"}, + {"cr6", "fucop_exist"}, + + {"mr0", "mmu_ctl"}, + {"mr1", "l1_pptb"}, + {"mr2", "tlb_vpn"}, + {"mr3", "tlb_data"}, + {"mr4", "tlb_misc"}, + {"mr5", "vlpt_idx"}, + {"mr6", "ilmb"}, + {"mr7", "dlmb"}, + {"mr8", "cache_ctl"}, + {"mr9", "hsmp_saddr"}, + {"mr10", "hsmp_eaddr"}, + + {"pfr0", "pfmc0"}, + {"pfr1", "pfmc1"}, + {"pfr2", "pfmc2"}, + {"pfr3", "pfm_ctl"}, + + {"dmar0", "dma_cfg"}, + {"dmar1", "dma_gcsw"}, + {"dmar2", "dma_chnsel"}, + {"dmar3", "dma_act"}, + {"dmar4", "dma_setup"}, + {"dmar5", "dma_isaddr"}, + {"dmar6", "dma_esaddr"}, + {"dmar7", "dma_tcnt"}, + {"dmar8", "dma_status"}, + {"dmar9", "dma_2dset"}, + {"dmar10", "dma_2dsctl"}, +}; + +/* Value of a register alias. BATON is register name of the alias, + because system registers do not have fixed register number. + We must look-up them when access. */ + +static struct value * +nds32_value_of_reg (struct frame_info *frame, const void *baton) +{ + struct gdbarch *gdbarch =3D get_frame_arch (frame); + int regnum; + + regnum =3D user_reg_map_name_to_regnum (gdbarch, (const char *) baton, -= 1); + + return value_of_register (regnum, frame); +} + +/* Implement the gdbarch_frame_align method. */ + +static CORE_ADDR +nds32_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp) +{ + /* 8-byte aligned. */ + return align_down (sp, 8); +} + +/* Implement the gdbarch_breakpoint_from_pc method. */ + +static const gdb_byte * +nds32_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, + int *lenptr) +{ + gdb_assert (pcptr !=3D NULL); + gdb_assert (lenptr !=3D NULL); + + if ((*pcptr) & 1) + error (_("Bad address %p for inserting breakpoint.\n" + "Address must be at least 2-byte aligned."), (void *) *pcptr); + + /* Always insert 16-bit break instruction. */ + *lenptr =3D 2; + return NDS32_BREAK16; +} + +/* Implement the gdbarch_remote_breakpoint_from_pc method. */ + +static void +nds32_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, + int *kindptr) +{ + if ((*pcptr) & 1) + error (_("bad address %p for inserting breakpoint"), (void *) *pcptr); + + /* ICEman/AICE have trouble on reading memory when the pcptr is P/A, + but CPU is in V/A mode. This code prevent GDB from reading memory. + ICEman will read memory itself if needed. */ + + *kindptr =3D 2; +} + +/* Implement the gdbarch_dwarf2_reg_to_regnum method. + Map DWARF regnum from GCC to GDB regnum. */ + +static int +nds32_dwarf_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num) +{ + const int DXR =3D 34; + const int FSR =3D 38; + const int FDR =3D FSR + 32; + + if (num >=3D 0 && num < 32) /* R0 - R31 */ + return num; + else if (num >=3D DXR && num < DXR + 4) /* D0/D1 */ + return num - DXR + NDS32_D0LO_REGNUM; + else if (num >=3D FSR && num < FSR + 32) /* FS */ + return num - FSR + user_reg_map_name_to_regnum (gdbarch, "fs0", -1); + else if (num >=3D FDR && num < FDR + 32) /* FD */ + return num - FDR + user_reg_map_name_to_regnum (gdbarch, "fd0", -1); + + /* No match, return a inaccessible register number. */ + return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); +} + +/* Implement gdbarch_register_sim_regno method. */ + +static int +nds32_register_sim_regno (struct gdbarch *gdbarch, int regnum) +{ + /* Use target-descriptions for register mapping. */ + + /* Only makes sense to supply raw registers. */ + gdb_assert (regnum >=3D 0 && regnum < gdbarch_num_regs (gdbarch)); + + if (regnum < NDS32_NUM_REGS) + return regnum; + if (regnum >=3D NDS32_SIM_FD0_REGNUM && regnum < NDS32_SIM_FD0_REGNUM + = 32) + return SIM_NDS32_FD0_REGNUM + regnum - NDS32_SIM_FD0_REGNUM; + switch (regnum) + { + case NDS32_SIM_IFCLP_REGNUM: + return SIM_NDS32_IFCLP_REGNUM; + case NDS32_SIM_ITB_REGNUM: + return SIM_NDS32_ITB_REGNUM; + case NDS32_SIM_PSW_REGNUM: + return SIM_NDS32_PSW_REGNUM; + } + + return LEGACY_SIM_REGNO_IGNORE; +} +=0C +enum type_option +{ + NO_FLAGS =3D 0, + USE_FLAGS =3D 1, +}; + +/* Allocate a new type. Use this instead of arch_composite_type () or + arch_type () directly, because it must be a 4-byte word, but we may + not append all the fields. If `opt' is USE_FLAGS, then a field for + flags is appended. */ + +static struct type * +nds32_init_type (struct gdbarch *gdbarch, char *name, enum type_option opt) +{ + struct type *type; + + gdb_assert (opt =3D=3D USE_FLAGS || opt =3D=3D NO_FLAGS); + + type =3D arch_type (gdbarch, TYPE_CODE_STRUCT, 4, name); + TYPE_TAG_NAME (type) =3D name; + INIT_CPLUS_SPECIFIC (type); + + if (opt =3D=3D USE_FLAGS) + { + int i; + struct type *flags_type =3D + arch_flags_type (TYPE_OWNER (type).gdbarch, "nds32_dummy_flags_type", + TYPE_LENGTH (type)); + append_composite_type_field_raw (type, "", flags_type); + + /* Hide all the flags from users. Only explicitly appended flags + are shown to users. For example, + {[ #1 #3 #16 #17 #18 ], INTL =3D Lv1, POM =3D Superuser} + We don't want users to see this, INTL and POM should not be + displayed in the flags field. */ + for (i =3D 0; i < (int) TYPE_LENGTH (type) * TARGET_CHAR_BIT; i++) + append_flags_type_flag (flags_type, i, NULL); + } + + return type; +} + +/* Append a flags bit. */ + +static void +nds32_append_flag (struct type *type, int bitpos, char *name) +{ + int nfields; + + gdb_assert (TYPE_CODE (type) =3D=3D TYPE_CODE_STRUCT); + + nfields =3D TYPE_NFIELDS (type); + + if (nfields =3D=3D 0 + || TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) !=3D TYPE_CODE_FLAGS) + { + internal_error (__FILE__, __LINE__, + _("Pseudo field for flags must be the first one.")); + } + + /* Append flag in the first field. */ + append_flags_type_flag (TYPE_FIELD_TYPE (type, 0), bitpos, name); +} + +/* Append a bit-field. */ + +static void +nds32_append_bitfield (struct type *type, struct type *field_type, + int bitpos_from, int bitpos_to, char *name) +{ + struct field *f; + + gdb_assert (TYPE_CODE (type) =3D=3D TYPE_CODE_STRUCT); + gdb_assert (bitpos_to >=3D bitpos_from); + gdb_assert (TYPE_NFIELDS (type) !=3D 0 || strcmp (name, "") !=3D 0); + + f =3D append_composite_type_field_raw (type, xstrdup (name), field_type); + SET_FIELD_BITPOS (f[0], bitpos_from); + FIELD_BITSIZE (f[0]) =3D bitpos_to - bitpos_from + 1; +} + +/* Allocate an enumeration type. The only reason to call this function + is that we want it to be UNSIGNED instead. This is only useful for + enum-type bit-field. */ + +static struct type * +nds32_init_enum (struct gdbarch *gdbarch, char *name) +{ + struct type *type; + + type =3D arch_type (gdbarch, TYPE_CODE_ENUM, 4, name); + TYPE_UNSIGNED (type) =3D 1; + return type; +} + +static void +nds32_append_enum (struct type *type, int enumval, char *name) +{ + struct field *f; + + gdb_assert (TYPE_CODE (type) =3D=3D TYPE_CODE_ENUM); + f =3D append_composite_type_field_raw (type, name, NULL); + SET_FIELD_ENUMVAL (f[0], enumval); +} + +/* Register name and its type. */ + +struct type_entry +{ + const char *name; + struct type *type; +}; + +/* Hash code function. Simply a wrapper for htab_hash_string. + This function should only be called by htab_expand, + so PTR is the pointer to inserted entry. */ + +static hashval_t +type_hash_string (const PTR ptr) +{ + struct type_entry *pe =3D (struct type_entry *) ptr; + + return htab_hash_string (pe->name); +} + +/* Equal function for hash. Simply a wrapper for strcmp. + This function should only be called by htab_find[_slot]_with_hash, + so P2 the ELEMENT argument to it. */ + +static int +type_name_eq (const PTR p1, const PTR p2) +{ + struct type_entry *pe =3D (struct type_entry *) p1; + const char *name =3D (const char *) p2; + + return strcmp (pe->name, name) =3D=3D 0; +} + +/* Allocate a hash table for register/type pair. */ + +static htab_t +nds32_alloc_type_tab (int size) +{ + return htab_create_alloc (size, type_hash_string, type_name_eq, + NULL /* htab_del */ , + xcalloc, xfree); +} + +/* Look up a register by name. */ + +static struct type * +nds32_type_lookup (htab_t htab, const char *name) +{ + struct type_entry *pe; + hashval_t hash; + + hash =3D htab_hash_string (name); + pe =3D (struct type_entry *) htab_find_with_hash (htab, name, hash); + + if (pe =3D=3D NULL) + return NULL; + return pe->type; +} + +/* Insert a type for a specific register name. */ + +static void +nds32_type_insert (htab_t htab, const char *name, struct type *type) +{ + struct type_entry ent; + struct type_entry **pe; + hashval_t hash; + + hash =3D htab_hash_string (name); + pe =3D (struct type_entry **) + htab_find_slot_with_hash (htab, name, hash, INSERT); + + /* If the entry already exists, there must be a bug in nds32_alloc_types= . */ + gdb_assert (pe !=3D NULL && *pe =3D=3D NULL); + + *pe =3D xmalloc (sizeof (**pe)); + (*pe)->name =3D xstrdup (name); + (*pe)->type =3D type; +} + +/* Create types for registers and insert them to type table by name. */ + +static void +nds32_alloc_types (struct gdbarch *gdbarch) +{ + const struct builtin_type *bt =3D builtin_type (gdbarch); + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + struct type *type, *stype1, *stype2; + + tdep->type_tab =3D nds32_alloc_type_tab (24); + + /* fucpr */ + type =3D arch_flags_type (gdbarch, "builtin_type_nds32_fucpr", 4); + append_flags_type_flag (type, 0, "CP0EN"); + append_flags_type_flag (type, 1, "CP1EN"); + append_flags_type_flag (type, 2, "CP2EN"); + append_flags_type_flag (type, 3, "CP3EN"); + append_flags_type_flag (type, 31, "AUEN"); + nds32_type_insert (tdep->type_tab, "fucpr", type); + + /* fpcfg */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_fpcfg"); + nds32_append_enum (type, 0, "8SP_4DP"); + nds32_append_enum (type, 1, "16SP_8DP"); + nds32_append_enum (type, 2, "32SP_16DP"); + nds32_append_enum (type, 3, "32SP_32DP"); + stype1 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_fpcfg_type", USE_FLAGS); + nds32_append_flag (type, 0, "SP"); + nds32_append_flag (type, 1, "DP"); + nds32_append_bitfield (type, stype1, 2, 3, "FREG"); + nds32_append_flag (type, 4, "FMA"); + nds32_append_bitfield (type, bt->builtin_uint8, 22, 26, "IMVER"); + nds32_append_bitfield (type, bt->builtin_uint8, 27, 31, "AVER"); + nds32_type_insert (tdep->type_tab, "fpcfg", type); + + /* fpcsr */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_fpcsr_rm"); + nds32_append_enum (type, 0, "RTNE"); + nds32_append_enum (type, 1, "RTPI"); + nds32_append_enum (type, 2, "RTMI"); + nds32_append_enum (type, 3, "RTZ"); + stype1 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_fpcsr", USE_FLAGS= ); + nds32_append_bitfield (type, stype1, 0, 1, "RM"); + nds32_append_flag (type, 2, "IVO"); + nds32_append_flag (type, 3, "DBZ"); + nds32_append_flag (type, 4, "OVF"); + nds32_append_flag (type, 5, "UDF"); + nds32_append_flag (type, 6, "IEX"); + nds32_append_flag (type, 7, "IVOE"); + nds32_append_flag (type, 8, "DBZE"); + nds32_append_flag (type, 9, "OVFE"); + nds32_append_flag (type, 10, "UDFE"); + nds32_append_flag (type, 11, "IEXE"); + nds32_append_flag (type, 12, "DNZ"); + nds32_append_flag (type, 13, "IVOT"); + nds32_append_flag (type, 14, "DBZT"); + nds32_append_flag (type, 15, "OVFT"); + nds32_append_flag (type, 16, "UDFT"); + nds32_append_flag (type, 17, "IEXT"); + nds32_append_flag (type, 18, "DNIT"); + nds32_append_flag (type, 19, "RIT"); + nds32_type_insert (tdep->type_tab, "fpcsr", type); + + /* ir0 - processor status word register + ir1 - interruption PSW register + ir2 - previous IPSW register */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_psw_intl"); + nds32_append_enum (type, 0, "NO"); + nds32_append_enum (type, 1, "Lv1"); + nds32_append_enum (type, 2, "Lv2"); + nds32_append_enum (type, 3, "Lv3"); + stype1 =3D type; + + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_psw_pow"); + nds32_append_enum (type, 0, "User"); + nds32_append_enum (type, 1, "Superuser"); + nds32_append_enum (type, 2, "Reserved(2)"); + nds32_append_enum (type, 3, "Reserved(3)"); + stype2 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_psw", USE_FLAGS); + nds32_append_flag (type, 0, "GIE"); + nds32_append_bitfield (type, stype1, 1, 2, "INTL"); + nds32_append_bitfield (type, stype2, 3, 4, "POM"); + nds32_append_flag (type, 5, "BE"); + nds32_append_flag (type, 6, "IT"); + nds32_append_flag (type, 7, "DT"); + nds32_append_flag (type, 8, "IME"); + nds32_append_flag (type, 9, "DME"); + nds32_append_flag (type, 10, "DEX"); + nds32_append_flag (type, 11, "HSS"); + nds32_append_flag (type, 12, "DRBE"); + nds32_append_flag (type, 13, "AEN"); + nds32_append_flag (type, 14, "WBNA"); + nds32_append_flag (type, 15, "IFCON"); + nds32_append_flag (type, 20, "OV"); + nds32_type_insert (tdep->type_tab, "ir0", type); + nds32_type_insert (tdep->type_tab, "ir1", type); + nds32_type_insert (tdep->type_tab, "ir2", type); + + /* ir3 - Interrupt Vector Base Register */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_ivb_esz"); + nds32_append_enum (type, 0, "4_byte"); + nds32_append_enum (type, 1, "16_byte"); + nds32_append_enum (type, 2, "64_byte"); + nds32_append_enum (type, 3, "256_byte"); + stype1 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_ivb", USE_FLAGS); + nds32_append_flag (type, 13, "EVIC"); + nds32_append_bitfield (type, stype1, 14, 15, "ESZ"); + nds32_append_bitfield (type, bt->builtin_uint16, 16, 31, "IVBASE"); + nds32_type_insert (tdep->type_tab, "ir3", type); + + /* ir6 - Interruption Type Register + ir7 - Previous ITYPE */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_itype", USE_FLAGS= ); + nds32_append_bitfield (type, bt->builtin_uint8, 0, 3, "ETYPE"); + nds32_append_flag (type, 4, "INST"); + nds32_append_bitfield (type, bt->builtin_uint16, 16, 30, "SWID"); + nds32_type_insert (tdep->type_tab, "ir6", type); + nds32_type_insert (tdep->type_tab, "ir7", type); + + /* ir14 - Interruption Masking Register */ + type =3D arch_flags_type (gdbarch, "builtin_type_nds32_int_mask", 4); + append_flags_type_flag (type, 0, "H0IM"); + append_flags_type_flag (type, 1, "H1IM"); + append_flags_type_flag (type, 2, "H2IM"); + append_flags_type_flag (type, 3, "H3IM"); + append_flags_type_flag (type, 4, "H4IM"); + append_flags_type_flag (type, 5, "H5IM"); + append_flags_type_flag (type, 16, "SIM"); + append_flags_type_flag (type, 29, "ALZ"); + append_flags_type_flag (type, 30, "IDIVZE"); + append_flags_type_flag (type, 31, "DSSIM"); + nds32_type_insert (tdep->type_tab, "ir14", type); + + /* ir18 - Interruption Prioirty Register */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_int_pri", NO_FLAG= S); + nds32_append_bitfield (type, bt->builtin_uint8, 0, 1, "H0PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 2, 3, "H1PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 4, 5, "H2PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 6, 7, "H3PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 8, 9, "H4PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 10, 11, "H5PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 12, 13, "H6PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 14, 15, "H7PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 16, 17, "H8PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 18, 19, "H9PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 20, 21, "H10PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 22, 23, "H11PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 24, 25, "H12PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 26, 27, "H13PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 28, 29, "H14PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 30, 31, "H15PRI"); + nds32_type_insert (tdep->type_tab, "ir18", type); + + /* mr0 - MMU Control Register */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_mmuctl_ntc"); + nds32_append_enum (type, 0, "NCA_NCO"); + nds32_append_enum (type, 1, "NCA_CO"); + nds32_append_enum (type, 2, "CA_WB"); + nds32_append_enum (type, 3, "CA_WT"); + stype1 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_mmu_ctl", USE_FLA= GS); + nds32_append_flag (type, 0, "D"); + nds32_append_bitfield (type, stype1, 1, 2, "NTC0"); + nds32_append_bitfield (type, stype1, 3, 4, "NTC1"); + nds32_append_bitfield (type, stype1, 5, 6, "NTC2"); + nds32_append_bitfield (type, stype1, 7, 8, "NTC3"); + nds32_append_flag (type, 9, "TBALCK"); + nds32_append_flag (type, 10, "MPZIU"); + nds32_append_bitfield (type, bt->builtin_uint8, 11, 12, "NTM0"); + nds32_append_bitfield (type, bt->builtin_uint8, 13, 14, "NTM1"); + nds32_append_bitfield (type, bt->builtin_uint8, 15, 16, "NTM2"); + nds32_append_bitfield (type, bt->builtin_uint8, 17, 18, "NTM3"); + nds32_append_flag (type, 19, "DREE"); + nds32_type_insert (tdep->type_tab, "mr0", type); + + /* mr1 */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_l1_pptb", USE_FLA= GS); + nds32_append_flag (type, 0, "NV"); + nds32_append_bitfield (type, bt->builtin_uint32, 12, 31, "L1_PPT_BASE"); + nds32_type_insert (tdep->type_tab, "mr1", type); + + /* mr2 */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_tlb_vpn", NO_FLAG= S); + nds32_append_bitfield (type, bt->builtin_uint32, 12, 31, "VPN"); + nds32_type_insert (tdep->type_tab, "mr2", type); + + /* mr3 */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_tlb_data", USE_FL= AGS); + nds32_append_flag (type, 0, "V"); + nds32_append_bitfield (type, bt->builtin_uint8, 1, 3, "M"); + nds32_append_flag (type, 4, "D"); + nds32_append_flag (type, 5, "X"); + nds32_append_flag (type, 6, "A"); + nds32_append_flag (type, 7, "G"); + nds32_append_bitfield (type, bt->builtin_uint8, 8, 10, "C"); + nds32_append_bitfield (type, bt->builtin_uint32, 12, 31, "PPN"); + nds32_type_insert (tdep->type_tab, "mr3", type); + + /* mr4 - TLB Access Misc Register */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_tlb_misc_acc_psz"= ); + nds32_append_enum (type, 0, "4KB"); + nds32_append_enum (type, 1, "8KB"); + nds32_append_enum (type, 2, "16KB"); + nds32_append_enum (type, 3, "64KB"); + nds32_append_enum (type, 4, "256KB"); + nds32_append_enum (type, 5, "1MB"); + nds32_append_enum (type, 6, "4MB"); + nds32_append_enum (type, 7, "16MB"); + nds32_append_enum (type, 8, "64MB"); + nds32_append_enum (type, 9, "256MB"); + stype1 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_tlb_misc", NO_FLA= GS); + nds32_append_bitfield (type, stype1, 0, 3, "ACC_PSZ"); + nds32_append_bitfield (type, bt->builtin_uint32, 4, 12, "CID"); + nds32_type_insert (tdep->type_tab, "mr4", type); + + /* mr6 */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_ilm_size"); + nds32_append_enum (type, 0, "4KB"); + nds32_append_enum (type, 1, "8KB"); + nds32_append_enum (type, 2, "16KB"); + nds32_append_enum (type, 3, "32KB"); + nds32_append_enum (type, 4, "64KB"); + nds32_append_enum (type, 5, "128KB"); + nds32_append_enum (type, 6, "256KB"); + nds32_append_enum (type, 7, "512KB"); + nds32_append_enum (type, 8, "1024KB"); + nds32_append_enum (type, 9, "1KB"); + nds32_append_enum (type, 10, "2KB"); + nds32_append_enum (type, 15, "0KB"); + stype1 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_ilmb", NO_FLAGS); + nds32_append_bitfield (type, bt->builtin_uint8, 0, 0, "IEN"); + nds32_append_bitfield (type, stype1, 1, 4, "ILMSZ"); + nds32_append_bitfield (type, bt->builtin_data_ptr, 0, 31, "(raw)"); + nds32_type_insert (tdep->type_tab, "mr6", type); + + /* mr7 */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_dlm_size"); + nds32_append_enum (type, 0, "4KB"); + nds32_append_enum (type, 1, "8KB"); + nds32_append_enum (type, 2, "16KB"); + nds32_append_enum (type, 3, "32KB"); + nds32_append_enum (type, 4, "64KB"); + nds32_append_enum (type, 5, "128KB"); + nds32_append_enum (type, 6, "256KB"); + nds32_append_enum (type, 7, "512KB"); + nds32_append_enum (type, 8, "1024KB"); + nds32_append_enum (type, 9, "1KB"); + nds32_append_enum (type, 10, "2KB"); + nds32_append_enum (type, 15, "0KB"); + stype1 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_dlmb", NO_FLAGS); + nds32_append_bitfield (type, bt->builtin_uint8, 0, 0, "DEN"); + nds32_append_bitfield (type, stype1, 1, 4, "DLMSZ"); + nds32_append_bitfield (type, bt->builtin_uint8, 5, 5, "DBM"); + nds32_append_bitfield (type, bt->builtin_uint8, 6, 6, "DBB"); + nds32_append_bitfield (type, bt->builtin_data_ptr, 0, 31, "(raw)"); + nds32_type_insert (tdep->type_tab, "mr7", type); + + /* mr8 - Cache Control Register */ + type =3D arch_flags_type (gdbarch, "builtin_type_nds32_cache_ctl", 4); + append_flags_type_flag (type, 0, "IC_EN"); + append_flags_type_flag (type, 1, "DC_EN"); + append_flags_type_flag (type, 2, "ICALCK"); + append_flags_type_flag (type, 3, "DCALCK"); + append_flags_type_flag (type, 4, "DCCWF"); + append_flags_type_flag (type, 5, "DCPMW"); + nds32_type_insert (tdep->type_tab, "mr8", type); + + /* dr40 - EDM Configuration Register */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_edm_cfg", USE_FLA= GS); + nds32_append_bitfield (type, bt->builtin_uint8, 0, 2, "BC"); + nds32_append_flag (type, 3, "DIMU"); + nds32_append_flag (type, 4, "DALM"); + nds32_append_bitfield (type, bt->builtin_uint16, 16, 31, "VER"); + nds32_type_insert (tdep->type_tab, "dr40", type); + + /* dmar0 - DMA Configuration Register */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_dma_cfg", USE_FLA= GS); + nds32_append_bitfield (type, bt->builtin_uint8, 0, 1, "NCHN"); + nds32_append_flag (type, 2, "UNEA"); + nds32_append_flag (type, 3, "2DET"); + nds32_append_bitfield (type, bt->builtin_uint16, 16, 31, "VER"); + nds32_type_insert (tdep->type_tab, "dmar0", type); + + /* cr0 - CPU Version Register */ + type =3D arch_flags_type (gdbarch, "builtin_type_nds32_cpuver_cfgid", 2); + append_flags_type_flag (type, 0, "PERF_EXT"); + append_flags_type_flag (type, 1, "16_EXT"); + append_flags_type_flag (type, 2, "PERF_EXT2"); + append_flags_type_flag (type, 3, "COP_EXT"); + append_flags_type_flag (type, 4, "STR_EXT"); + stype1 =3D type; + + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_cpuver_cpuid"); + nds32_append_enum (type, 0x8, "N8"); + nds32_append_enum (type, 0x9, "N9"); + nds32_append_enum (type, 0xA, "N10"); + nds32_append_enum (type, 0xC, "N12"); + nds32_append_enum (type, 0xD, "N13"); + nds32_append_enum (type, 0xE, "N14"); + stype2 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_cpuver", NO_FLAGS= ); + nds32_append_bitfield (type, stype1, 0, 15, "CFGID"); + nds32_append_bitfield (type, bt->builtin_uint8, 16, 23, "REV"); + nds32_append_bitfield (type, stype2, 24, 31, "CPUID"); + nds32_type_insert (tdep->type_tab, "cr0", type); + + /* cr4 - Misc Configuration Register */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_msc_cfg", USE_FLA= GS); + nds32_append_flag (type, 0, "EDM"); + nds32_append_flag (type, 1, "LMDMA"); + nds32_append_flag (type, 2, "PFM"); + nds32_append_flag (type, 3, "HSMP"); + nds32_append_flag (type, 4, "TRACE"); + nds32_append_flag (type, 5, "DIV"); + nds32_append_flag (type, 6, "MAC"); + nds32_append_bitfield (type, bt->builtin_uint8, 7, 8, "AUDIO"); + nds32_append_flag (type, 9, "L2c"); + nds32_append_flag (type, 10, "RDREG"); + nds32_append_flag (type, 11, "ADR24"); + nds32_append_flag (type, 12, "INTLC"); + nds32_append_bitfield (type, bt->builtin_uint8, 13, 15, "BASEV"); + nds32_append_flag (type, 16, "NOD"); + nds32_append_flag (type, 17, "IMV"); + nds32_append_flag (type, 18, "IMR"); + nds32_append_flag (type, 19, "IFC"); + nds32_append_flag (type, 20, "MCU"); + nds32_type_insert (tdep->type_tab, "cr4", type); + + /* cr6 - FPU and Coprocessor Existence Configuration Register */ + type =3D arch_flags_type (gdbarch, "builtin_type_nds32_fucop_exist", 4); + append_flags_type_flag (type, 0, "CP0EX"); + append_flags_type_flag (type, 1, "CP1EX"); + append_flags_type_flag (type, 2, "CP2EX"); + append_flags_type_flag (type, 3, "CP3EX"); + append_flags_type_flag (type, 31, "AUEX"); + nds32_type_insert (tdep->type_tab, "cr6", type); +} + +/* Implement gdbarch_register_type method. + + Return the GDB type object for the "standard" data type of data in + register REGNUM. It get pretty messy here. I want to specify a type + on a bit-field for better representation, but they cannot be done by + tdesc-xml. */ + +static struct type * +nds32_register_type (struct gdbarch *gdbarch, int regnum) +{ + int num_regs =3D gdbarch_num_regs (gdbarch); + const struct builtin_type *bt =3D builtin_type (gdbarch); + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + struct type *type; + const char *reg_name; + + /* Currently, only FSR are supported. */ + if (regnum >=3D num_regs && regnum < num_regs + 32) + return builtin_type (gdbarch)->builtin_float; + else if (regnum >=3D num_regs) + return NULL; + + /* NDS32 predefined types for specific registers. */ + if (tdep->type_tab =3D=3D NULL) + nds32_alloc_types (gdbarch); + + reg_name =3D user_reg_map_regnum_to_name (gdbarch, regnum); + if (reg_name =3D=3D NULL) + reg_name =3D ""; + type =3D nds32_type_lookup (tdep->type_tab, reg_name); + if (type !=3D NULL) + return type; + + /* Type provided by target-description. */ + if (tdesc_has_registers (gdbarch_target_desc (gdbarch))) + { + type =3D tdesc_register_type (gdbarch, regnum); + if (type !=3D NULL) + return type; + } + + /* Floating pointer registers. e.g., fs0 or fd0. */ + if (strlen (reg_name) >=3D 3 && reg_name[0] =3D=3D 'f' && reg_name[2] >= =3D '0' + && reg_name[2] <=3D '9') + { + if (reg_name[1] =3D=3D 's') + return bt->builtin_float; + else if (reg_name[1] =3D=3D 'd') + return bt->builtin_double; + } + + /* GPRs. */ + if (regnum =3D=3D NDS32_PC_REGNUM || regnum =3D=3D NDS32_LP_REGNUM) + return bt->builtin_func_ptr; + else if (regnum =3D=3D NDS32_SP_REGNUM || regnum =3D=3D NDS32_FP_REGNUM + || regnum =3D=3D NDS32_GP_REGNUM) + return bt->builtin_data_ptr; + else if (regnum < 32) + return bt->builtin_int32; + + /* We don't know. Display it in hex-form. */ + return bt->builtin_data_ptr; +} +=0C + +/* nds32 register groups. */ +static struct reggroup *nds32_cr_reggroup; +static struct reggroup *nds32_ir_reggroup; +static struct reggroup *nds32_mr_reggroup; +static struct reggroup *nds32_dr_reggroup; +static struct reggroup *nds32_pfr_reggroup; +static struct reggroup *nds32_dmar_reggroup; +static struct reggroup *nds32_racr_reggroup; +static struct reggroup *nds32_idr_reggroup; +static struct reggroup *nds32_audio_reggroup; + +static void +nds32_init_reggroups (void) +{ + /* gpr usr sr */ + nds32_cr_reggroup =3D reggroup_new ("cr", USER_REGGROUP); + nds32_ir_reggroup =3D reggroup_new ("ir", USER_REGGROUP); + nds32_mr_reggroup =3D reggroup_new ("mr", USER_REGGROUP); + nds32_dr_reggroup =3D reggroup_new ("dr", USER_REGGROUP); + nds32_pfr_reggroup =3D reggroup_new ("pfr", USER_REGGROUP); + nds32_dmar_reggroup =3D reggroup_new ("dmar", USER_REGGROUP); + nds32_racr_reggroup =3D reggroup_new ("racr", USER_REGGROUP); + nds32_idr_reggroup =3D reggroup_new ("idr", USER_REGGROUP); + + nds32_audio_reggroup =3D reggroup_new ("audio", USER_REGGROUP); +} + +static void +nds32_add_reggroups (struct gdbarch *gdbarch) +{ + /* Target-independent groups. */ + reggroup_add (gdbarch, general_reggroup); + reggroup_add (gdbarch, float_reggroup); + reggroup_add (gdbarch, all_reggroup); + reggroup_add (gdbarch, system_reggroup); + + /* System register groups. */ + reggroup_add (gdbarch, nds32_cr_reggroup); + reggroup_add (gdbarch, nds32_ir_reggroup); + reggroup_add (gdbarch, nds32_mr_reggroup); + reggroup_add (gdbarch, nds32_dr_reggroup); + reggroup_add (gdbarch, nds32_pfr_reggroup); + reggroup_add (gdbarch, nds32_dmar_reggroup); + reggroup_add (gdbarch, nds32_racr_reggroup); + reggroup_add (gdbarch, nds32_idr_reggroup); +} + +/* Implement the gdbarch_register_reggroup_p method. */ + +static int +nds32_register_reggroup_p (struct gdbarch *gdbarch, int regnum, + struct reggroup *group) +{ + int i; + struct reggroup *groups[] =3D + { + nds32_cr_reggroup, nds32_ir_reggroup, nds32_mr_reggroup, + nds32_dr_reggroup, nds32_pfr_reggroup, nds32_dmar_reggroup, + nds32_racr_reggroup, nds32_idr_reggroup + }; + static const char *prefix[] =3D + { + "cr", "ir", "mr", "dr", "pfr", "dmar", "racr", "idr" + }; + + gdb_assert (ARRAY_SIZE (groups) =3D=3D ARRAY_SIZE (prefix)); + + /* GPRs. */ + if (group =3D=3D general_reggroup) + return regnum <=3D NDS32_PC_REGNUM; + + /* System Registers are grouped by prefix. */ + else if (group =3D=3D system_reggroup) + return (regnum > NDS32_PC_REGNUM) + && TYPE_CODE (register_type (gdbarch, regnum)) !=3D TYPE_CODE_FLT; + + for (i =3D 0; i < (int) ARRAY_SIZE (groups); i++) + { + if (group =3D=3D groups[i]) + { + const char *regname =3D tdesc_register_name (gdbarch, regnum); + + if (!regname) + return 0; + return strstr (regname, prefix[i]) =3D=3D regname; + } + } + + return default_register_reggroup_p (gdbarch, regnum, group); +} + +/* Implement the tdesc_pseudo_register_name method. + + This function is called when + 1. Target-description is used, and the register is pseudo. + 2. Target-description is NOT used, because + i. the target is simulator, + ii. or the target is legacy target, so tdesc is not supported. */ + +static const char * +nds32_register_name (struct gdbarch *gdbarch, int regnum) +{ + static const char *fpu_pseudo_names[] =3D + { + "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", + "fs8", "fs9", "fs10", "fs11", "fs12", "fs13", "fs14", "fs15", + "fs16", "fs17", "fs18", "fs19", "fs20", "fs21", "fs22", "fs23", + "fs24", "fs25", "fs26", "fs27", "fs28", "fs29", "fs30", "fs31" + }; + static const char *sim_names[] =3D + { + "fd0", "fd1", "fd2", "fd3", "fd4", "fd5", "fd6", "fd7", + "fd8", "fd9", "fd10", "fd11", "fd12", "fd13", "fd14", "fd15", + "fd16", "fd17", "fd18", "fd19", "fd20", "fd21", "fd22", "fd23", + "fd24", "fd25", "fd26", "fd27", "fd28", "fd29", "fd30", "fd31", + "ifclp", "itb", "ir0" + }; + int num_regs =3D gdbarch_num_regs (gdbarch); + + /* Currently, only pseudo FSR are supported. */ + if (regnum >=3D num_regs && regnum < num_regs + 32) + return fpu_pseudo_names[regnum - num_regs]; + + /* GPRs. */ + if (regnum < (int) ARRAY_SIZE (nds32_regnames)) + return nds32_regnames[regnum]; + + /* Registers between NUM_REGS and SMI_NUM_REGS are + simulator registers. */ + if (regnum >=3D NDS32_NUM_REGS && regnum < NDS32_SIM_NUM_REGS) + return sim_names[regnum - NDS32_NUM_REGS]; + + warning (_("Unknown nds32 pseudo register %d."), regnum); + return NULL; +} + +/* Implement the gdbarch_pseudo_register_read method. + + For legacy target, target-description and FPRs are not support. + Use Rcmd to access FPU registers. */ + +static enum register_status +nds32_pseudo_register_read (struct gdbarch *gdbarch, + struct regcache *regcache, int regnum, + gdb_byte *buf) +{ + char name_buf[8]; + gdb_byte reg_buf[8]; + int offset; + enum register_status status =3D REG_UNKNOWN; + + /* Sanity check. */ + regnum -=3D gdbarch_num_regs (gdbarch); + if (regnum > gdbarch_num_pseudo_regs (gdbarch)) + return status; + + /* Currently, only FSR are supported. */ + if (regnum < 32) + { + int fd_regnum; + + /* fs0 is always the high-part of fd0. */ + if (gdbarch_byte_order (gdbarch) =3D=3D BFD_ENDIAN_BIG) + offset =3D (regnum & 1) ? 4 : 0; + else + offset =3D (regnum & 1) ? 0 : 4; + + xsnprintf (name_buf, sizeof (name_buf), "fd%d", regnum >> 1); + fd_regnum =3D user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + status =3D regcache_raw_read (regcache, fd_regnum, reg_buf); + if (status =3D=3D REG_VALID) + memcpy (buf, reg_buf + offset, 4); + } + + return status; +} + +/* Implement the gdbarch_pseudo_register_write method. */ + +static void +nds32_pseudo_register_write (struct gdbarch *gdbarch, + struct regcache *regcache, int regnum, + const gdb_byte *buf) +{ + char name_buf[8]; + gdb_byte reg_buf[8]; + int offset; + + /* Sanity check. */ + regnum -=3D gdbarch_num_regs (gdbarch); + if (regnum > gdbarch_num_pseudo_regs (gdbarch)) + return; + + /* Currently, only FSR are supported. */ + if (regnum < 32) + { + int fd_regnum; + + /* fs0 is always the high-part of fd0. */ + if (gdbarch_byte_order (gdbarch) =3D=3D BFD_ENDIAN_BIG) + offset =3D (regnum & 1) ? 4 : 0; + else + offset =3D (regnum & 1) ? 0 : 4; + + xsnprintf (name_buf, sizeof (name_buf), "fd%d", regnum >> 1); + fd_regnum =3D user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + regcache_raw_read (regcache, fd_regnum, reg_buf); + memcpy (reg_buf + offset, buf, 4); + regcache_raw_write (regcache, fd_regnum, reg_buf); + } + + return; +} + +/* Skip prologue should be conservative, and frame-unwind should be + relative-aggressive.*/ + +static int +nds32_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, + CORE_ADDR scan_limit, CORE_ADDR *pl_endptr) +{ + uint32_t insn; + CORE_ADDR cpc =3D -1; /* Candidate PC if no suitable PC is found. */ + + /* If there is no buffer to store result, ignore this prologue decoding.= */ + if (pl_endptr =3D=3D NULL) + return 0; + + /* Look up end of prologue. */ + for (; pc < scan_limit; ) + { + insn =3D read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG); + + if ((insn & 0x80000000) =3D=3D 0) + { + /* 32-bit instruction. */ + + pc +=3D 4; + if (insn =3D=3D N32_ALU1 (ADD, REG_GP, REG_TA, REG_GP)) + { + /* add $gp, $ta, $gp */ + continue; + } + else if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (ADDI, REG_SP, REG_SP, 0= )) + { + /* addi $sp, $sp, imm15 */ + cpc =3D pc; + continue; + } + else if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (ADDI, REG_FP, REG_FP, 0= )) + { + /* addi $fp, $sp, imm15 */ + cpc =3D pc; + continue; + } + else if (insn =3D=3D N32_ALU2 (MFUSR, REG_TA, 31, 0)) + { + /* mfusr $ta, PC ; group=3D0, sub=3D0x20=3Dmfusr */ + continue; + } + else if (CHOP_BITS (insn, 20) =3D=3D N32_TYPE1 (MOVI, REG_TA, 0)) + { + /* movi $ta, imm20s */ + continue; + } + else if (CHOP_BITS (insn, 20) =3D=3D N32_TYPE1 (SETHI, REG_GP, 0)) + { + /* sethi $gp, imm20 */ + continue; + } + else if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (ORI, REG_GP, REG_GP, 0)) + { + /* ori $gp, $gp, imm15 */ + continue; + } + else if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (SWI, REG_LP, REG_FP, 0)) + { + /* Unlike swi, we should stop when lwi. */ + /* swi $lp, [$sp + (imm15s<<2)] */ + continue; + } + else if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (SWI_BI, REG_LP, REG_FP,= 0)) + { + /* swi.bi $rt, [$sp], (imm15s<<2) */ + continue; + } + else if (N32_OP6 (insn) =3D=3D N32_OP6_LSMW && (insn & __BIT (5))) + { + /* bit-5 for SMW */ + + /* smwa?.(a|b)(d|i)m? rb,[ra],re,enable4 */ + int ra; + + ra =3D N32_RA5 (insn); + + switch (ra) + { + case NDS32_FP_REGNUM: + case NDS32_SP_REGNUM: + cpc =3D pc; + continue; /* found and continue */ + default: + break; + } + } + + if (N32_OP6 (insn) =3D=3D N32_OP6_COP && N32_COP_CP (insn) =3D=3D 0 + && (N32_COP_SUB (insn) =3D=3D N32_FPU_FSS + || N32_COP_SUB (insn) =3D=3D N32_FPU_FSD) + && (N32_RA5 (insn) =3D=3D REG_SP || N32_RA5 (insn) =3D=3D REG_FP)) + { + /* CP shoud be CP0 */ + /* fs[sd][.bi] $fst, [$sp + ($r0 << sv)] */ + continue; + } + + /* fssi $fst, [$ra + (imm12s << 2)] + fssi.bi $fst, [$ra], (imm12s << 2) + fsdi $fdt, [$ra + (imm12s << 2)] + fsdi.bi $fdt, [$ra], (imm12s << 2) */ + if ((N32_OP6 (insn) =3D=3D N32_OP6_SWC || N32_OP6 (insn) =3D=3D N32_OP6= _SDC) + && (N32_RA5 (insn) =3D=3D REG_SP || N32_RA5 (insn) =3D=3D REG_FP)) + { + /* BI bit is dont-care. */ + continue; + } + + pc -=3D 4; + break; + } + else + { + /* 16-bit instruction */ + pc +=3D 2; + insn >>=3D 16; + + /* 1. If the instruction is j/b, then we stop + i.e., OP starts with 10, and beqzs8, bnezs8. + 2. If the operations will change sp/fp or based on sp/fp, + then we are in the prologue. + 3. If we don't know what's it, then stop. */ + + if (CHOP_BITS (insn, 10) =3D=3D N16_TYPE10 (ADDI10S, 0)) + { + /* addi10s */ + continue; + } + else if (__GF (insn, 7, 8) =3D=3D N16_T25_PUSH25) + { + /* push25 */ + continue; + } + else if (insn =3D=3D N16_TYPE55 (MOV55, REG_FP, REG_SP)) + { + /* mov55 fp, sp */ + continue; + } + + /* swi450 */ + switch (insn & ~__MF (-1, 5, 4)) + { + case N16_TYPE45 (SWI450, 0, REG_SP): + case N16_TYPE45 (SWI450, 0, REG_FP): + break; + } + /* swi37 - implied fp */ + if (__GF (insn, 11, 4) =3D=3D N16_T37_XWI37 + && (insn & __BIT (7))) + continue; + + /* swi37sp - implied */ + if (__GF (insn, 11, 4) =3D=3D N16_T37_XWI37SP + && (insn & __BIT (7))) + continue; + + /* If the a instruction is not accepted, + don't go futher. */ + pc -=3D 2; + break; + } + } + + if (pc >=3D scan_limit) + { + /* If we can not find end of prologue before scan_limit, + we assume that end of prologue is on pc_after_stack_adject. */ + if (cpc !=3D -1) + pc =3D cpc; + } + + *pl_endptr =3D pc; + + return 0; +} + +/* Implement the gdbarch_skip_prologue method. + + Find the end of function prologue. */ + +static CORE_ADDR +nds32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + CORE_ADDR func_addr, func_end; + struct symtab_and_line sal =3D { 0 }; + LONGEST return_value; + const char *func_name; + enum bfd_endian byte_order =3D gdbarch_byte_order (gdbarch); + const int search_limit =3D 128; + + /* See what the symbol table says */ + if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end)) + { + sal =3D find_pc_line (func_addr, 0); + + if (sal.line !=3D 0 && sal.end <=3D func_end) + func_end =3D sal.end; + else + { + /* Either there's no line info, or the line after the prologue + is after the end of the function. In this case, there probably + isn't a prologue. */ + func_end =3D min (func_end, func_addr + search_limit); + } + } + else + func_end =3D pc + search_limit; + + /* If current instruction is not readable, just quit. */ + if (!safe_read_memory_integer (pc, 4, byte_order, &return_value)) + return pc; + + /* Find the end of prologue. */ + if (nds32_analyze_prologue (gdbarch, pc, func_end, &sal.end) < 0) + return pc; + + return sal.end; +} + +struct nds32_unwind_cache +{ + /* The previous frame's inner most stack address. + Used as this frame ID's stack_addr. */ + CORE_ADDR prev_sp; + + /* The frame's base, optionally used by the high-level debug info. */ + CORE_ADDR base; + int size; + + /* How far the SP and FP have been offset from the start of + the stack frame (as defined by the previous frame's stack + pointer). */ + LONGEST sp_offset; + LONGEST fp_offset; + int use_frame; + + /* Table indicating the location of each and every register. */ + struct trad_frame_saved_reg *saved_regs; +}; + +static struct nds32_unwind_cache * +nds32_alloc_frame_cache (struct frame_info *this_frame) +{ + struct nds32_unwind_cache *cache; + + cache =3D FRAME_OBSTACK_ZALLOC (struct nds32_unwind_cache); + cache->saved_regs =3D trad_frame_alloc_saved_regs (this_frame); + cache->size =3D 0; + cache->sp_offset =3D 0; + cache->fp_offset =3D 0; + cache->use_frame =3D 0; + cache->base =3D 0; + + return cache; +} + +/* Implement the gdbarch_in_function_epilogue_p method. */ + +static int +nds32_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR addr) +{ + uint32_t insn; + int r =3D 0; + + insn =3D read_memory_unsigned_integer (addr, 4, BFD_ENDIAN_BIG); + if ((insn & 0x80000000) =3D=3D 0) + { + /* 32-bit instruction */ + + /* ret */ + if (insn =3D=3D N32_JREG (JR, 0, REG_LP, 0, 1)) + r =3D 1; + /* iret */ + else if (insn =3D=3D N32_TYPE0 (MISC, N32_MISC_IRET)) + r =3D 2; + } + else + { + if (insn =3D=3D N16_TYPE5 (RET5, REG_LP)) + r =3D 3; + } + return r > 0; +} + +/* Put here the code to store, into fi->saved_regs, the addresses of + the saved registers of frame described by FRAME_INFO. This + includes special registers such as pc and fp saved in special ways + in the stack frame. sp is even more special: the address we return + for it IS the sp for the next frame. */ + +static struct nds32_unwind_cache * +nds32_frame_unwind_cache (struct frame_info *this_frame, + void **this_prologue_cache) +{ + CORE_ADDR pc, scan_limit; + ULONGEST prev_sp; + ULONGEST next_base; + ULONGEST fp_base; + int i; + uint32_t insn; + struct nds32_unwind_cache *info; + struct gdbarch *gdbarch =3D get_frame_arch (this_frame); + + if ((*this_prologue_cache)) + return (*this_prologue_cache); + + info =3D nds32_alloc_frame_cache (this_frame); + + info->base =3D get_frame_register_unsigned (this_frame, NDS32_FP_REGNUM); + (*this_prologue_cache) =3D info; + + if (info->base =3D=3D 0) + return info; + + pc =3D get_frame_func (this_frame); + scan_limit =3D get_frame_pc (this_frame); + + for (; pc > 0 && pc < scan_limit; ) + { + insn =3D read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG); + + if ((insn & 0x80000000) =3D=3D 0) + { + /* 32-bit instruction */ + + pc +=3D 4; + if (insn =3D=3D N32_ALU1 (ADD, REG_GP, REG_TA, REG_GP)) + { + /* add $gp, $ta, $gp */ + continue; + } + if (N32_OP6 (insn) =3D=3D N32_OP6_ADDI) + { + int rt =3D N32_RT5 (insn); + int ra =3D N32_RA5 (insn); + int imm15s =3D N32_IMM15S (insn); + + if (rt =3D=3D ra && rt =3D=3D NDS32_SP_REGNUM) + { + info->sp_offset +=3D imm15s; + continue; + } + else if (rt =3D=3D NDS32_FP_REGNUM && ra =3D=3D NDS32_SP_REGNUM) + { + info->fp_offset =3D info->sp_offset + imm15s; + info->use_frame =3D 1; + continue; + } + else if (rt =3D=3D ra) + /* Prevent stop analyzing form iframe. */ + continue; + } + + if (insn =3D=3D N32_ALU2 (MFUSR, REG_TA, 31, 0)) + { + /* mfusr $ta, PC ; group=3D0, sub=3D0x20=3Dmfusr */ + continue; + } + if (CHOP_BITS (insn, 20) =3D=3D N32_TYPE1 (MOVI, REG_TA, 0)) + { + /* movi $ta, imm20s */ + continue; + } + if (CHOP_BITS (insn, 20) =3D=3D N32_TYPE1 (SETHI, REG_GP, 0)) + { + /* sethi $gp, imm20 */ + continue; + } + if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (ORI, REG_GP, REG_GP, 0)) + { + /* ori $gp, $gp, imm15 */ + continue; + } + if (N32_OP6 (insn) =3D=3D N32_OP6_LSMW && (insn & __BIT (5))) + { + /* smwa?.(a|b)(d|i)m? rb,[ra],re,enable4 */ + + int rb, re, ra, enable4, i; + int aligned; + int m =3D 0; + int di; /* dec=3D-1 or inc=3D1 */ + int rn; /* number of registers. */ + char enb4map[2][4] =3D { + {0, 1, 2, 3} /* smw */, + {3, 1, 2, 0} /* smwa */ }; + /* `base' is the highest/last address for access memory. + e.g., [ lp ] ___ base shoule be here. + [ fp ] + [ r6 ] */ + ULONGEST base =3D -1; + + rb =3D N32_RT5 (insn); + ra =3D N32_RA5 (insn); + re =3D N32_RB5 (insn); + enable4 =3D (insn >> 6) & 0x0F; + aligned =3D (insn & 3) ? 1 : 0; + di =3D (insn & (1 << 3)) ? -1 : 1; + + rn =3D 0; + rn +=3D (enable4 & 0x1) ? 1 : 0; + rn +=3D (enable4 & 0x2) ? 1 : 0; + rn +=3D (enable4 & 0x4) ? 1 : 0; + rn +=3D (enable4 & 0x8) ? 1 : 0; + if (rb < NDS32_FP_REGNUM && re < NDS32_FP_REGNUM) + { + /* reg-list should not include fp,gp,lp,sp + ie, the rb=3D=3Dre=3D=3Dsp case, anyway... */ + rn +=3D (re - rb) + 1; + } + + /* Let's consider how Ra should update. */ + if (insn & (1 << 0x2)) /* m-bit is set */ + { + m =3D rn * 4; /* 4*TNReg */ + } + else + m =3D 0; /* don't update Ra */ + + switch (ra) + { + case NDS32_FP_REGNUM: + base =3D info->fp_offset; + info->fp_offset +=3D m * di; + break; + case NDS32_SP_REGNUM: + base =3D info->sp_offset; + info->sp_offset +=3D m * di; + break; + default: + /* Only RA is FP or SP is handled. */ + base =3D -1; + break; + } + if (base =3D=3D -1) + break; /* Exit the loop. */ + + if (insn & (1 << 0x4)) /* b:0, a:1 */ + base +=3D 4 * di; /* a: use Ra+4 (for i), + or Ra-4 (for d) */ + /* else base =3D base; b use Ra */ + + /* We should consider both increasing and decreasing case. + + Either case stores registers in the same order. + To simplify the code (yes, the loops), + I used the same pushing order, but from different side. */ + + if (di =3D=3D 1) /* Increasing. */ + base +=3D (rn * 4 - 4); + /* else, in des case, we already are on the top */ + + for (i =3D 0; i < 4; i++) + { + if (enable4 & (1 << enb4map[aligned][i])) + { + info->saved_regs[NDS32_SP_REGNUM - + (enb4map[aligned][i])].addr =3D base; + base -=3D 4; + } + } + + /* Skip re =3D=3D rb =3D=3D sp > fp. */ + for (i =3D re; i >=3D rb && rb < NDS32_FP_REGNUM; i--) + { + info->saved_regs[i].addr =3D base; + base -=3D 4; + } + + continue; + } + /* swi $lp, [$sp + (imm15s << 2)] */ + /* We must check if $rt is $lp to determine it is + in prologue or not. */ + if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (SWI, REG_LP, REG_FP, 0)) + { + int imm15s; + + /* swi $lp, [$sp + (imm15s<<2)] */ + imm15s =3D N32_IMM15S (insn); + info->saved_regs[NDS32_LP_REGNUM].addr =3D info->sp_offset + + (imm15s << 2); + continue; + } + /* swi.bi $rt, [$sp], (imm15s << 2) */ + if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (SWI_BI, REG_LP, REG_FP, 0)) + { + unsigned int rt5 =3D 0; + unsigned int ra5 =3D 0; + int imm15s =3D 0; + rt5 =3D N32_RT5 (insn); + ra5 =3D N32_RA5 (insn); + imm15s =3D N32_IMM15S (insn); + + if (ra5 =3D=3D NDS32_SP_REGNUM) + { + info->saved_regs[rt5].addr =3D info->sp_offset; + info->sp_offset +=3D (imm15s << 2); + } + else if (ra5 =3D=3D NDS32_FP_REGNUM) + { + info->saved_regs[rt5].addr =3D info->fp_offset; + info->fp_offset +=3D (imm15s << 2); + } + continue; + } + + if (N32_OP6 (insn) =3D=3D N32_OP6_COP && N32_COP_CP (insn) =3D=3D 0 + && (N32_COP_SUB (insn) =3D=3D N32_FPU_FSS + || N32_COP_SUB (insn) =3D=3D N32_FPU_FSD) + && (N32_RA5 (insn) =3D=3D REG_SP || N32_RA5 (insn) =3D=3D REG_FP)) + { + /* CP shoud be CP0 */ + /* fs[sd][.bi] $fst, [$sp + ($r0 << sv)] */ + continue; + } + + /* fssi $fst, [$ra + (imm12s << 2)] + fssi.bi $fst, [$ra], (imm12s << 2) + fsdi $fdt, [$ra + (imm12s << 2)] + fsdi.bi $fdt, [$ra], (imm12s << 2) */ + if ((N32_OP6 (insn) =3D=3D N32_OP6_SWC || N32_OP6 (insn) =3D=3D N32_OP6= _SDC) + && (N32_RA5 (insn) =3D=3D REG_SP || N32_RA5 (insn) =3D=3D REG_FP)) + { + /* fssi and fsdi have the same form. */ + /* Only .bi form should be handled to adjust reg. */ + unsigned int ra5 =3D 0; + int imm12s =3D 0; + + ra5 =3D N32_RA5 (insn); + imm12s =3D N32_IMM12S (insn); + + if (imm12s & 0x800) + imm12s =3D (imm12s - (0x800 << 1)); + + switch (ra5) + { + case NDS32_FP_REGNUM: + info->fp_offset +=3D (imm12s << 2); + break; + case NDS32_SP_REGNUM: + info->sp_offset +=3D (imm12s << 2); + break; + } + + continue; + } + + break; + } + else + { + /* 16-bit instruction */ + pc +=3D 2; + insn >>=3D 16; + + /* 1. If the instruction is j/b, then we stop + i.e., OP starts with 10, and beqzs8, bnezs8. + 2. If the operations will change sp/fp or based on sp/fp, + then we are in the prologue. + 3. If we don't know what's it, then stop. */ + + if (__GF (insn, 13, 2) =3D=3D 2) + { + /* These are all branch instructions. */ + pc -=3D 2; + break; + } + else if (__GF (insn, 9, 6) =3D=3D 0x34) + { + /* beqzs8, bnezs8 */ + pc -=3D 2; + break; + } + + if (CHOP_BITS (insn, 10) =3D=3D N16_TYPE10 (ADDI10S, 0)) + { + /* addi10s */ + info->sp_offset +=3D N16_IMM10S (insn); + continue; + } + + if (__GF (insn, 7, 8) =3D=3D N16_T25_PUSH25) + { + /* push25 */ + int imm8u =3D (insn & 0x1f) << 3; + int re =3D ((insn & 0x60) >> 5) & 0x3; + int m[] =3D {4, 6, 8, 12}; + + /* Operation 1 - smw.adm R6, [sp], Re, #0xe */ + info->saved_regs[NDS32_LP_REGNUM].addr =3D info->sp_offset - 0x4; + info->saved_regs[NDS32_GP_REGNUM].addr =3D info->sp_offset - 0x8; + info->saved_regs[NDS32_FP_REGNUM].addr =3D info->sp_offset - 0xC; + info->sp_offset -=3D m[re] * 4; + + switch (re) + { + case 3: + info->saved_regs[14].addr =3D info->sp_offset + 0x20; + info->saved_regs[13].addr =3D info->sp_offset + 0x1C; + info->saved_regs[12].addr =3D info->sp_offset + 0x18; + info->saved_regs[11].addr =3D info->sp_offset + 0x14; + case 2: + info->saved_regs[10].addr =3D info->sp_offset + 0x10; + info->saved_regs[9].addr =3D info->sp_offset + 0xC; + case 1: + info->saved_regs[8].addr =3D info->sp_offset + 0x8; + info->saved_regs[7].addr =3D info->sp_offset + 0x4; + case 0: + info->saved_regs[6].addr =3D info->sp_offset; + } + + /* Operation 2 - sp =3D sp - imm5u<<3 */ + info->sp_offset -=3D imm8u; + + /* Operation 3 - if (Re >=3D 1) R8 =3D concat (PC(31,2), 2`b0) */ + continue; + } + + /* mov55 fp, sp */ + if (insn =3D=3D N16_TYPE55 (MOV55, REG_FP, REG_SP)) + { + info->fp_offset =3D info->sp_offset; + info->use_frame =3D 1; + continue; + } + /* swi450 */ + switch (insn & ~__MF (-1, 5, 4)) + { + case N16_TYPE45 (SWI450, 0, REG_SP): + case N16_TYPE45 (SWI450, 0, REG_FP): + break; + } + /* swi37 - implied fp */ + if (__GF (insn, 11, 4) =3D=3D N16_T37_XWI37 + && (insn & __BIT (7))) + continue; + + /* swi37sp - implied */ + if (__GF (insn, 11, 4) =3D=3D N16_T37_XWI37SP + && (insn & __BIT (7))) + continue; + + break; + } + } + + info->size =3D -info->sp_offset; + /* Compute the previous frame's stack pointer (which is also the + frame's ID's stack address), and this frame's base pointer. + + Assume that the FP is this frame's SP but with that pushed + stack space added back. */ + next_base =3D get_frame_register_unsigned (this_frame, NDS32_SP_REGNUM); + prev_sp =3D next_base + info->size; + fp_base =3D get_frame_register_unsigned (this_frame, NDS32_FP_REGNUM); + if (info->use_frame && fp_base > 0) + { + /* Try to use FP if possible. */ + prev_sp =3D fp_base - info->fp_offset; + } + + /* Convert that SP/BASE into real addresses. */ + info->prev_sp =3D prev_sp; + info->base =3D next_base; + + /* Adjust all the saved registers so that they contain addresses and + not offsets. */ + for (i =3D 0; i < gdbarch_num_regs (gdbarch) - 1; i++) + { + if (trad_frame_addr_p (info->saved_regs, i)) + { + info->saved_regs[i].addr =3D info->prev_sp + info->saved_regs[i].addr; + } + } + + /* The previous frame's SP needed to be computed. + Save the computed value. */ + trad_frame_set_value (info->saved_regs, NDS32_SP_REGNUM, prev_sp); + + return info; +} + +/* Implement the gdbarch_skip_permanent_breakpoint method. */ + +static void +nds32_skip_permanent_breakpoint (struct regcache *regcache) +{ + gdb_byte insn[2]; + CORE_ADDR current_pc =3D regcache_read_pc (regcache); + + target_read_memory (current_pc, insn, sizeof (insn)); + + if (memcmp (insn, NDS32_BREAK16, sizeof (insn)) !=3D 0) + return; + + current_pc +=3D 2; + regcache_write_pc (regcache, current_pc); +} + +/* Implement the gdbarch_read_pc method. */ + +static CORE_ADDR +nds32_read_pc (struct regcache *regcache) +{ + ULONGEST pc; + regcache_cooked_read_unsigned (regcache, NDS32_PC_REGNUM, &pc); + return pc; +} + +/* Implement the gdbarch_write_pc method. */ + +static void +nds32_write_pc (struct regcache *regcache, CORE_ADDR val) +{ + regcache_cooked_write_unsigned (regcache, NDS32_PC_REGNUM, val); +} + +/* Implement the gdbarch_unwind_pc method. */ + +static CORE_ADDR +nds32_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame) +{ + /* This snippet code is a mess. + + In most case, LP is the actually register being saved. + Hence when unwinding pc for backtrace, LP should be the one. + That is, for frames (level > 0), unwinding the PC means + unwinding LP from the this_frame. + + However, for a top frame (level=3D=3D0), unwinding PC means + the current program counter (PC). + Besides, for dummy frame, PC stored in dummy_frame is the one + we want. + + We have to have these cases to make backtrace work properly. */ + + CORE_ADDR pc; + pc =3D frame_unwind_register_unsigned (this_frame, NDS32_PC_REGNUM); + return pc; +} + +/* Implement the gdbarch_unwind_sp method. */ + +static CORE_ADDR +nds32_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame) +{ + return frame_unwind_register_unsigned (this_frame, NDS32_SP_REGNUM); +} + +/* If these is exactly one float point type field in the struct, + the alignment of the struct is the size of the float pointer type. */ + +static int +nds32_float_in_struct (struct type *type) +{ + struct type *actual_type; + + type =3D check_typedef (type); + if (TYPE_CODE (type) !=3D TYPE_CODE_STRUCT || TYPE_NFIELDS (type) !=3D 1) + return 0; + + actual_type =3D check_typedef (TYPE_FIELD_TYPE (type, 0)); + if (TYPE_CODE (actual_type) =3D=3D TYPE_CODE_FLT) + { + gdb_assert (TYPE_LENGTH (type) =3D=3D 8 || TYPE_LENGTH (type) =3D=3D= 4); + return TYPE_LENGTH (type); + } + return 0; +} + +/* Get the alignment of the type. + + The alignment requirement of a structure is the largest alignment + requirement of its member, so we should traverse every member to + find the largest alignment. + + For example, + struct { int a; int b; char c } is 4-byte aligned, + and + struct {long long a; char c} is 8-byte aligned. */ + +static int +nds32_type_align (struct type *type) +{ + int align =3D 0; /* Current max alignment. */ + int i; + + gdb_assert (type !=3D NULL); + if (type =3D=3D NULL) + return 0; + + if (type->main_type->nfields =3D=3D 0) + return type->length; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + return nds32_type_align (TYPE_TARGET_TYPE (type)); + case TYPE_CODE_ENUM: + return TYPE_LENGTH (type); + } + + /* For structs with only one float/double are treated as float/double. = */ + align =3D nds32_float_in_struct (type); + if (align !=3D 0) + return align; + + for (i =3D 0; i < TYPE_NFIELDS (type); i++) + { + int r =3D nds32_type_align (TYPE_FIELD_TYPE (type, i)); + + if (r > align) + align =3D r; + } + + return align; +} + +/* Implement the gdbarch_push_dummy_call method. */ + +static CORE_ADDR +nds32_push_dummy_call (struct gdbarch *gdbarch, struct value *function, + struct regcache *regcache, CORE_ADDR bp_addr, + int nargs, struct value **args, CORE_ADDR sp, + int struct_return, CORE_ADDR struct_addr) +{ + const int REND =3D 6; /* Max arguments number. */ + int goff =3D 0; /* Current gpr for argument. */ + int foff =3D 0; /* Currnet gpr for argument. */ + int soff =3D 0; /* Current stack offset. */ + int i; + enum type_code typecode; + CORE_ADDR regval; + enum bfd_endian byte_order =3D gdbarch_byte_order (gdbarch); + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + int fs0_regnum =3D -1, fd0_regnum =3D -1; + + if (tdep->abi_use_fpr) + { + /* Use FP registers to pass arguments. */ + fs0_regnum =3D user_reg_map_name_to_regnum (gdbarch, "fs0", -1); + fd0_regnum =3D user_reg_map_name_to_regnum (gdbarch, "fd0", -1); + } + + /* Set the return address. For the nds32, the return breakpoint is + always at BP_ADDR. */ + regcache_cooked_write_unsigned (regcache, NDS32_LP_REGNUM, bp_addr); + + /* If STRUCT_RETURN is true, then the struct return address (in + STRUCT_ADDR) will consume the first argument-passing register. + Both adjust the register count and store that value. */ + if (struct_return) + { + regcache_cooked_write_unsigned (regcache, NDS32_R0_REGNUM, struct_ad= dr); + goff++; + } + + /* Now make sure there's space on the stack */ + for (i =3D 0; i < nargs; i++) + { + struct type *type =3D value_type (args[i]); + int align =3D nds32_type_align (type); + + /* If align is zero, it may be an empty struct. + Just ignore the argument of empty struct. */ + if (align =3D=3D 0) + continue; + + sp -=3D align_up (TYPE_LENGTH (type), 4); + sp =3D align_down (sp, align); + } + + /* Allocate 24-byte for ABI V1. */ + sp -=3D 24; + /* Stack must be 8-byte aligned. */ + sp =3D align_down (sp, 8); + + soff =3D 0; + for (i =3D 0; i < nargs; i++) + { + const gdb_byte *val; + int align, len; + struct type *type; + + type =3D value_type (args[i]); + typecode =3D TYPE_CODE (type); + align =3D nds32_float_in_struct (type); + if (align) + typecode =3D TYPE_CODE_FLT; + else + align =3D nds32_type_align (type); + len =3D TYPE_LENGTH (type); + + /* For current ABI, the caller pushes arguments in registers, + callee stores unnamed arguments in stack, + and then va_arg fetch arguments in stack. + Therefore, we don't have to handle variadic function specially. */ + + val =3D value_contents (args[i]); + + /* Once we start using stack, all arguments should go to stack + When use_fpr, all flt must go to fs/fd; otherwise go to stack. */ + if (tdep->abi_use_fpr && typecode =3D=3D TYPE_CODE_FLT) + { + /* Adjust alignment. */ + if ((align >> 2) > 0) + foff =3D align_up (foff, align >> 2); + + if (foff < REND && !soff) + { + if (tdep->abi_use_fpr && fs0_regnum =3D=3D -1) + goto error_no_fpr; + + switch (len) + { + case 4: + regcache_cooked_write (regcache, fs0_regnum + foff, val); + foff++; + continue; + case 8: + regcache_cooked_write (regcache, fd0_regnum + foff / 2, val); + foff +=3D 2; + continue; + default: + /* Long double? */ + internal_error (__FILE__, __LINE__, + "Do not know how to handle %d-byte double.\n", + len); + break; + } + } + } + else if (!soff) + { + /* Adjust alignment, and only adjust one time for one argument. */ + if ((align >> 2) > 0) + goff =3D align_up (goff, align >> 2); + if (!tdep->abi_split && len > (REND - goff) * 4) + goff =3D REND; + } + + /* + When passing arguments, + + * A composite type not larger than 4 bytes is passed + in $rN. The format is as if the value is loaded with + load instruction of corresponding size. (i.g., LB, LH, LW) + + For example, + + r0 + 31 0 + little: [x x b a] + BIG: [x x a b] + + * Otherwise, a composite type is passed in consective registers. + The size is rounded up to the nearest multiple of 4. + The successive registers hold the parts of the argument as if + were loaded using lmw instructions. + + For example, + + r0 r1 + 31 0 31 0 + little: [d c b a] [x x x e] + BIG: [a b c d] [e x x x] + + + When push an argument in stack, + + * A composite type not larger than 4 bytes is copied + to memory at the next free space, in little-endian. + In big-endian, the last byte of the argument is aligned + at the next word address. For example, + + sp [ - ] [ b ] hi + [ - ] [ a ] + [ b ] [ - ] + [ a ] [ - ] lo + little BIG + */ + + if (len > 4) + len =3D align_up (len, 4); + + while (len > 0) + { + if (soff + || (typecode =3D=3D TYPE_CODE_FLT && tdep->abi_use_fpr && foff =3D= =3D REND) + || goff =3D=3D REND) + { + int rlen =3D (len > 4) ? 4 : len; + + if (byte_order =3D=3D BFD_ENDIAN_BIG) + write_memory (sp + soff + 4 - rlen, val, rlen); + else + write_memory (sp + soff, val, rlen); + soff +=3D 4; + } + else + { + regval =3D extract_unsigned_integer (val, (len > 4) ? 4 : len, + byte_order); + regcache_cooked_write_unsigned (regcache, + goff + NDS32_R0_REGNUM, regval); + goff++; + } + + len -=3D register_size (gdbarch, goff); + val +=3D register_size (gdbarch, goff); + } + } + + /* Finally, update the SP register. */ + regcache_cooked_write_unsigned (regcache, NDS32_SP_REGNUM, sp); + + return sp; + +error_no_fpr: + /* If use_fpr, but no floating-point register exists, + then it is an error. */ + error (_("Fail to call. FS0-FS5 is required.")); +} + +/* Extract the value to be returned from REGCACHE and copy it into + REGBUF. */ + +static void +nds32_extract_return_value (struct type *type, struct regcache *regcache, + gdb_byte *readbuf) +{ + int len =3D TYPE_LENGTH (type); + int typecode =3D TYPE_CODE (type); + struct gdbarch *gdbarch =3D get_regcache_arch (regcache); + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + int fs0_regnum, fd0_regnum; + + /* Although struct are returned in r0/r1 registers, but struct have + only one single/double floating-point member are returned in FS/FD + registers. */ + gdb_assert (TYPE_LENGTH (type) <=3D 8); + if (nds32_float_in_struct (type)) + typecode =3D TYPE_CODE_FLT; + + if (typecode =3D=3D TYPE_CODE_FLT && tdep->abi_use_fpr) + { + fs0_regnum =3D user_reg_map_name_to_regnum (gdbarch, "fs0", -1); + fd0_regnum =3D user_reg_map_name_to_regnum (gdbarch, "fd0", -1); + + if (len =3D=3D 4) + regcache_cooked_read (regcache, fs0_regnum, readbuf); + else if (len =3D=3D 8) + regcache_cooked_read (regcache, fd0_regnum, readbuf); + else + internal_error (__FILE__, __LINE__, + _("Cannot extract return value of %d bytes " + "long floating point."), + len); + } + else + { + /* When returning result, + + * A composite type not larger than 4 bytes is returned + in $r0. The format is as if the result is loaded with + load instruction of corresponding size. (i.g., LB, LH, LW) + + For example, + + r0 + 31 0 + little: [x x b a] + BIG: [x x a b] + + * Otherwise, a composite type not larger than 8 bytes + is returned in $r0 and $r1. In little-endian, the first + word is loaded in $r0. In big-endian, the last word + is loaded in $r1. + + For example, + + r0 r1 + 31 0 31 0 + little: [d c b a] [x x x e] + BIG: [x x x a] [b c d e] + */ + + if (len <=3D 4) + { + if (gdbarch_byte_order (gdbarch) =3D=3D BFD_ENDIAN_BIG) + regcache_raw_read_part (regcache, NDS32_R0_REGNUM, 4 - len, len, + readbuf); + else + regcache_raw_read_part (regcache, NDS32_R0_REGNUM, 0, len, + readbuf); + } + else if (len <=3D 8) + { + int partial =3D len - 4; + + if (gdbarch_byte_order (gdbarch) =3D=3D BFD_ENDIAN_BIG) + { + regcache_raw_read_part (regcache, NDS32_R0_REGNUM, 4 - partial, + partial, readbuf); + regcache_raw_read (regcache, NDS32_R0_REGNUM + 1, + readbuf + partial); + + } + else + { + regcache_raw_read (regcache, NDS32_R0_REGNUM, readbuf); + regcache_raw_read_part (regcache, NDS32_R0_REGNUM + 1, 0, + partial, readbuf + 4); + } + } + else + internal_error (__FILE__, __LINE__, + _("Cannot extract return value of %d bytes long."), + len); + } +} + +/* Store the return value of TYPE in WRITEBUF into REGCACHE. */ + +static void +nds32_store_return_value (struct type *type, struct regcache *regcache, + const gdb_byte *writebuf) +{ + int len =3D TYPE_LENGTH (type); + int typecode =3D TYPE_CODE (type); + struct gdbarch *gdbarch =3D get_regcache_arch (regcache); + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + int fs0_regnum, fd0_regnum; + + /* Although struct are returned in r0/r1 registers, but struct have + only one single/double floating-point member are returned in FS/FD + registers. */ + gdb_assert (TYPE_LENGTH (type) <=3D 8); + if (nds32_float_in_struct (type)) + typecode =3D TYPE_CODE_FLT; + + if (typecode =3D=3D TYPE_CODE_FLT && tdep->abi_use_fpr) + { + fs0_regnum =3D user_reg_map_name_to_regnum (gdbarch, "fs0", -1); + fd0_regnum =3D user_reg_map_name_to_regnum (gdbarch, "fd0", -1); + + if (len =3D=3D 4) + regcache_cooked_write (regcache, fs0_regnum, writebuf); + else if (len =3D=3D 8) + regcache_cooked_write (regcache, fd0_regnum, writebuf); + else + internal_error (__FILE__, __LINE__, + _("Cannot store return value of %d bytes long " + "floating point."), + len); + } + else + { + if (len <=3D 4) + { + if (gdbarch_byte_order (gdbarch) =3D=3D BFD_ENDIAN_BIG) + regcache_raw_write_part (regcache, NDS32_R0_REGNUM, 4 - len, len, + writebuf); + else + regcache_raw_write_part (regcache, NDS32_R0_REGNUM, 0, len, + writebuf); + } + else if (len <=3D 8) + { + int partial =3D len - 4; + + if (gdbarch_byte_order (gdbarch) =3D=3D BFD_ENDIAN_BIG) + { + regcache_raw_write_part (regcache, NDS32_R0_REGNUM, 4 - partial, + partial, writebuf); + regcache_raw_write (regcache, NDS32_R0_REGNUM + 1, + writebuf + partial); + + } + else + { + regcache_raw_write (regcache, NDS32_R0_REGNUM, writebuf); + regcache_raw_write_part (regcache, NDS32_R0_REGNUM + 1, 0, + partial, writebuf + 4); + } + } + else + internal_error (__FILE__, __LINE__, + _("Cannot store return value of %d bytes long."), + len); + } +} + +/* Implement the gdbarch_return_value method. */ + +static enum return_value_convention +nds32_return_value (struct gdbarch *gdbarch, struct value *func_type, + struct type *type, struct regcache *regcache, + gdb_byte *readbuf, const gdb_byte *writebuf) +{ + if (TYPE_LENGTH (type) > 8) + { + return RETURN_VALUE_STRUCT_CONVENTION; + } + else + { + /* `readbuf' is used for 'call' to get the return value. + `writebuf' is used for 'return' to set the return value. */ + if (readbuf !=3D NULL) + nds32_extract_return_value (type, regcache, readbuf); + if (writebuf !=3D NULL) + nds32_store_return_value (type, regcache, writebuf); + return RETURN_VALUE_REGISTER_CONVENTION; + } +} + +/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that + dummy frame. The frame ID's base needs to match the TOS value + saved by save_dummy_frame_tos(), and the PC match the dummy frame's + breakpoint. */ + +static struct frame_id +nds32_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) +{ + CORE_ADDR sp, pc; + + sp =3D get_frame_register_unsigned (this_frame, NDS32_SP_REGNUM); + pc =3D get_frame_pc (this_frame); + return frame_id_build (sp, pc); +} + +/* 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 +nds32_frame_this_id (struct frame_info *this_frame, + void **this_prologue_cache, struct frame_id *this_id) +{ + struct nds32_unwind_cache *info; + CORE_ADDR base; + CORE_ADDR func; + struct frame_id id; + + info =3D nds32_frame_unwind_cache (this_frame, this_prologue_cache); + + /* Get function entry address */ + func =3D get_frame_func (this_frame); + + /* Hopefully the prologue analysis either correctly determined the + frame's base (which is the SP from the previous frame), or set + that base to "NULL". */ + base =3D info->prev_sp; + if (base =3D=3D 0) + return; + + id =3D frame_id_build (base, func); + (*this_id) =3D id; +} + +/* Get the value of register REGNUM in previous frame. */ + +static struct value * +nds32_frame_prev_register (struct frame_info *this_frame, + void **this_prologue_cache, int regnum) +{ + struct nds32_unwind_cache *cache; + cache =3D nds32_frame_unwind_cache (this_frame, this_prologue_cache); + + if (regnum =3D=3D NDS32_PC_REGNUM) + { + CORE_ADDR lr; + + lr =3D frame_unwind_register_unsigned (this_frame, NDS32_LP_REGNUM); + return frame_unwind_got_constant (this_frame, regnum, lr); + } + + return trad_frame_get_prev_register (this_frame, cache->saved_regs, regn= um); +} + +/* The register in previous frame. For example, the previous PC is + current LP. */ + +static struct value * +nds32_dwarf2_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + CORE_ADDR lp; + + switch (regnum) + { + case NDS32_PC_REGNUM: + lp =3D frame_unwind_register_unsigned (this_frame, NDS32_LP_REGNUM); + return frame_unwind_got_constant (this_frame, regnum, lp); + default: + internal_error (__FILE__, __LINE__, + _("Unexpected register %d"), regnum); + } + + return NULL; +} + +/* Callback of dwarf2_frame_set_init_reg. */ + +static void +nds32_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, + struct dwarf2_frame_state_reg *reg, + struct frame_info *this_frame) +{ + switch (regnum) + { + case NDS32_PC_REGNUM: + reg->how =3D DWARF2_FRAME_REG_FN; + reg->loc.fn =3D nds32_dwarf2_prev_register; + break; + case NDS32_SP_REGNUM: + reg->how =3D DWARF2_FRAME_REG_CFA; + break; + } +} + +/* Implement the gdbarch_get_longjmp_target method. */ + +static int +nds32_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) +{ + gdb_byte buf[4]; + CORE_ADDR jmp_buf_p; + struct gdbarch *gdbarch =3D get_frame_arch (frame); + enum bfd_endian byte_order =3D gdbarch_byte_order (gdbarch); + jmp_buf_p =3D get_frame_register_unsigned (frame, 0); + + /* Key is in setjmp(): + lmw.bim r6, [r0], r14 + lmw.bim r16, [r0], r19, 0xf */ + + if (target_read_memory (jmp_buf_p + 15 * 4, buf, 4)) + return 0; + + *pc =3D extract_unsigned_integer (buf, 4, byte_order); + + return 1; +} + +static const struct frame_unwind nds32_frame_unwind =3D +{ + NORMAL_FRAME, + default_frame_unwind_stop_reason, + nds32_frame_this_id, + nds32_frame_prev_register, + NULL /* unwind_data */, + default_frame_sniffer, + NULL /* dealloc_cache */, + NULL /* prev_arch */ +}; + +static CORE_ADDR +nds32_frame_base_address (struct frame_info *this_frame, void **this_cache) +{ + struct nds32_unwind_cache *info; + + info =3D nds32_frame_unwind_cache (this_frame, this_cache); + + return info->base; +} + +static const struct frame_base nds32_frame_base =3D +{ + &nds32_frame_unwind, + nds32_frame_base_address, + nds32_frame_base_address, + nds32_frame_base_address +}; + +/* Implement the gdbarch_overlay_update method. */ + +static void +nds32_simple_overlay_update (struct obj_section *osect) +{ + struct minimal_symbol *minsym =3D NULL; + + minsym =3D lookup_minimal_symbol (".nds32.fixed.size", NULL, NULL); + if (minsym !=3D NULL && osect !=3D NULL) + { + bfd *obfd =3D osect->objfile->obfd; + asection *bsect =3D osect->the_bfd_section; + if (bfd_section_vma (obfd, bsect) < SYMBOL_VALUE_ADDRESS (minsym)) + { + osect->ovly_mapped =3D 1; + return; + } + } + + simple_overlay_update (osect); +} + +/* Implement gdbarch_print_insn method. */ + +static int +gdb_print_insn_nds32 (bfd_vma memaddr, disassemble_info *info) +{ + struct obj_section * s =3D find_pc_section (memaddr); + + /* When disassembling ex9 instructions, they are annotated with + the original instructions at the end of line. For example, + + 0x00500122 <+82>: ex9.it #4 ! movi $r13, 10 + + Dissembler needs the symbol table to extract the original instruction + in _ITB_BASE_ table. If the object file is changed, reload symbol + table. */ + + if (s =3D=3D NULL || info->section !=3D s->the_bfd_section) + { + xfree (info->symtab); + info->symtab =3D NULL; + info->symtab_size =3D 0; + } + + if (info->symtab =3D=3D NULL && s && s->the_bfd_section) + { + long storage =3D bfd_get_symtab_upper_bound (s->objfile->obfd); + + if (storage <=3D 0) + goto done; + + info->section =3D s->the_bfd_section; + info->symtab =3D xmalloc (storage); + info->symtab_size =3D + bfd_canonicalize_symtab (s->the_bfd_section->owner, info->symtab); + } + +done: + return print_insn_nds32 (memaddr, info); +} + +/* Callback for gdbarch_init. */ + +static struct gdbarch * +nds32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) +{ + struct gdbarch *gdbarch; + struct gdbarch_tdep *tdep; + struct gdbarch_list *best_arch; + const struct target_desc *tdesc =3D NULL; + struct tdesc_arch_data *tdesc_data =3D NULL; + int i; + + /* Allocate space for the new architecture. */ + tdep =3D XCALLOC (1, struct gdbarch_tdep); + gdbarch =3D gdbarch_alloc (&info, tdep); + + if (tdesc_has_registers (info.target_desc)) + { + int valid_p; + int fpregs =3D -1; + static const char *const nds32_fp_names[] =3D { "r28", "fp", NULL }; + static const char *const nds32_lp_names[] =3D { "r30", "lp", NULL }; + static const char *const nds32_sp_names[] =3D { "r31", "sp", NULL }; + const struct tdesc_feature *feature; + + /* Validate and initialize target-description here. */ + tdesc =3D info.target_desc; + tdesc_data =3D tdesc_data_alloc (); + + info.tdep_info =3D (void *) tdesc_data; + + feature =3D tdesc_find_feature (tdesc, "org.gnu.gdb.nds32.core"); + if (!feature) + return 0; + + /* Validate for FP, LP, GP, PC. */ + valid_p =3D 1; + valid_p &=3D tdesc_numbered_register_choices (feature, tdesc_data, + NDS32_FP_REGNUM, + nds32_fp_names); + valid_p &=3D tdesc_numbered_register_choices (feature, tdesc_data, + NDS32_LP_REGNUM, + nds32_lp_names); + valid_p &=3D tdesc_numbered_register_choices (feature, tdesc_data, + NDS32_SP_REGNUM, + nds32_sp_names); + valid_p &=3D tdesc_numbered_register (feature, tdesc_data, + NDS32_PC_REGNUM, "pc"); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + xfree (tdep); + gdbarch_free (gdbarch); + return NULL; + } + + /* Number R0-R27. */ + for (i =3D NDS32_R0_REGNUM; i < NDS32_FP_REGNUM; i++) + tdesc_numbered_register (feature, tdesc_data, i, nds32_regnames[i]); + + /* Number D0 and D1. */ + for (i =3D NDS32_D0LO_REGNUM; i <=3D NDS32_D1HI_REGNUM; i++) + tdesc_numbered_register (feature, tdesc_data, i, nds32_regnames[i]); + + /* Find register configuration of FPU. */ + feature =3D tdesc_find_feature (tdesc, "org.gnu.gdb.nds32.fpu"); + if (feature !=3D NULL) + { + if (tdesc_unnumbered_register (feature, "fd31")) + fpregs =3D 3; + else if (tdesc_unnumbered_register (feature, "fd15")) + fpregs =3D 2; + else if (tdesc_unnumbered_register (feature, "fd7")) + fpregs =3D 1; + else if (tdesc_unnumbered_register (feature, "fd3")) + fpregs =3D 0; + } + tdep->fpu_freg =3D fpregs; + + /* If FS registers do not exist, make them pseudo registers + of FD registers. */ + if (fpregs !=3D -1 && tdesc_unnumbered_register (feature, "fs0") =3D= =3D 0) + { + int fsregs =3D (fpregs + 1) * 8; + + if (fsregs > 32) + fsregs =3D 32; + + set_gdbarch_num_pseudo_regs (gdbarch, fsregs); + set_gdbarch_pseudo_register_read (gdbarch, nds32_pseudo_register_read); + set_gdbarch_pseudo_register_write (gdbarch, nds32_pseudo_register_write= ); + set_tdesc_pseudo_register_name (gdbarch, nds32_register_name); + } + + set_gdbarch_num_regs (gdbarch, NDS32_NUM_REGS); + tdesc_use_registers (gdbarch, tdesc, tdesc_data); + } + else + { + /* Simulator or legacy target. */ + + /* Physical 32 FD registers. */ + set_gdbarch_num_regs (gdbarch, NDS32_SIM_NUM_REGS); + set_gdbarch_register_name (gdbarch, nds32_register_name); + + /* Pseudo 32 FS registers. */ + set_gdbarch_num_pseudo_regs (gdbarch, 32); + set_gdbarch_pseudo_register_read (gdbarch, nds32_pseudo_register_rea= d); + set_gdbarch_pseudo_register_write (gdbarch, nds32_pseudo_register_wr= ite); + } + + /* Extract the elf_flags, if available. */ + if (info.abfd && bfd_get_flavour (info.abfd) =3D=3D bfd_target_elf_flavo= ur) + { + int eflags =3D elf_elfheader (info.abfd)->e_flags; + int nds32_abi =3D eflags & EF_NDS_ABI; + + /* Split large arguments by default. */ + tdep->abi_split =3D TRUE; + /* Do not use FPRs by default. */ + tdep->abi_use_fpr =3D FALSE; + switch (nds32_abi) + { + case E_NDS_ABI_V2FP: + tdep->abi_use_fpr =3D TRUE; + /* Fall-through. */ + case E_NDS_ABI_V2: + tdep->abi_split =3D FALSE; + } + } + + /* If there is already a candidate, use it. */ + for (best_arch =3D gdbarch_list_lookup_by_info (arches, &info); + best_arch !=3D NULL; + best_arch =3D gdbarch_list_lookup_by_info (best_arch->next, &info)) + { + struct gdbarch_tdep *idep =3D gdbarch_tdep (best_arch->gdbarch); + + if (tdep->abi_split !=3D idep->abi_split) + continue; + if (tdep->abi_use_fpr !=3D idep->abi_use_fpr) + continue; + + /* Check FPU registers. */ + if (idep->fpu_freg !=3D tdep->fpu_freg) + continue; + + /* Found a match. */ + break; + } + + if (best_arch !=3D NULL) + { + xfree (tdep); + gdbarch_free (gdbarch); + return best_arch->gdbarch; + } + + nds32_add_reggroups (gdbarch); + + gdbarch_init_osabi (info, gdbarch); + + /* Override tdesc_register callbacks for system registers. */ + set_gdbarch_register_reggroup_p (gdbarch, nds32_register_reggroup_p); + set_gdbarch_register_type (gdbarch, nds32_register_type); + + set_gdbarch_sp_regnum (gdbarch, NDS32_SP_REGNUM); + set_gdbarch_pc_regnum (gdbarch, NDS32_PC_REGNUM); + set_gdbarch_read_pc (gdbarch, nds32_read_pc); + set_gdbarch_write_pc (gdbarch, nds32_write_pc); + set_gdbarch_unwind_sp (gdbarch, nds32_unwind_sp); + set_gdbarch_unwind_pc (gdbarch, nds32_unwind_pc); + set_gdbarch_in_function_epilogue_p (gdbarch, nds32_in_function_epilogue_= p); + set_gdbarch_dwarf2_reg_to_regnum (gdbarch, nds32_dwarf_dwarf2_reg_to_reg= num); + set_gdbarch_register_sim_regno (gdbarch, nds32_register_sim_regno); + set_gdbarch_push_dummy_call (gdbarch, nds32_push_dummy_call); + set_gdbarch_return_value (gdbarch, nds32_return_value); + set_gdbarch_skip_prologue (gdbarch, nds32_skip_prologue); + set_gdbarch_inner_than (gdbarch, core_addr_lessthan); + set_gdbarch_breakpoint_from_pc (gdbarch, nds32_breakpoint_from_pc); + set_gdbarch_remote_breakpoint_from_pc (gdbarch, + nds32_remote_breakpoint_from_pc); + + set_gdbarch_frame_align (gdbarch, nds32_frame_align); + frame_base_set_default (gdbarch, &nds32_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, nds32_dummy_id); + set_gdbarch_print_insn (gdbarch, gdb_print_insn_nds32); + set_gdbarch_skip_permanent_breakpoint (gdbarch, + nds32_skip_permanent_breakpoint); + /* Support simple overlay manager. */ + set_gdbarch_overlay_update (gdbarch, nds32_simple_overlay_update); + + /* Handle longjmp. */ + set_gdbarch_get_longjmp_target (gdbarch, nds32_get_longjmp_target); + + /* The order of appending is the order it check frame. */ + dwarf2_frame_set_init_reg (gdbarch, nds32_dwarf2_frame_init_reg); + dwarf2_append_unwinders (gdbarch); + frame_unwind_append_unwinder (gdbarch, &nds32_frame_unwind); + + /* Add nds32 register aliases. */ + /* FIXME: This is a simple workaround to force user-reg being + initialized before gdbarch initialized. + Without this, calling user_reg_map_name_to_regnum () + will crash. */ + user_reg_add (gdbarch, "r0", nds32_value_of_reg, "r0"); + for (i =3D 0; i < (int) ARRAY_SIZE (nds32_register_aliases); i++) + { + int regnum; + + regnum =3D user_reg_map_name_to_regnum + (gdbarch, nds32_register_aliases[i].name, -1); + + if (regnum =3D=3D -1) + continue; + + user_reg_add (gdbarch, nds32_register_aliases[i].alias, + nds32_value_of_reg, nds32_register_aliases[i].name); + } + + return gdbarch; +} + +void +_initialize_nds32_tdep (void) +{ + /* Initialize gdbarch. */ + register_gdbarch_init (bfd_arch_nds32, nds32_gdbarch_init); + + nds32_init_reggroups (); + + register_remote_support_xml ("nds32"); +} diff --git a/gdb/nds32-tdep.h b/gdb/nds32-tdep.h new file mode 100644 index 0000000..a5767f4 --- /dev/null +++ b/gdb/nds32-tdep.h @@ -0,0 +1,72 @@ +/* Target-dependent header for NDS32 architecture, for GDB. + + Copyright (C) 2006-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + 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 __NDS32_TDEP_H__ +#define __NDS32_TDEP_H__ + +/* NDS32 virtual registers layout for GDB. */ +enum nds32_regnum +{ + /* General purpose registers. */ + NDS32_R0_REGNUM =3D 0, + NDS32_R5_REGNUM =3D 5, + NDS32_TA_REGNUM =3D 15, /* Temp for assembler. */ + NDS32_FP_REGNUM =3D 28, /* Frame register. */ + NDS32_GP_REGNUM =3D 29, /* Global register. */ + NDS32_LP_REGNUM =3D 30, /* Link pointer. */ + NDS32_SP_REGNUM =3D 31, /* Address of stack top. */ + + /* Pseudo PC. */ + NDS32_PC_REGNUM =3D 32, + + /* D0/D1 User Registers. */ + NDS32_D0LO_REGNUM =3D 33, + NDS32_D0HI_REGNUM =3D 34, + NDS32_D1LO_REGNUM =3D 35, + NDS32_D1HI_REGNUM =3D 36, + + /* If target-description is not supported, only assume above + registers are supported. */ + NDS32_NUM_REGS, + + /* These are only used by simulator. */ + NDS32_SIM_FD0_REGNUM =3D NDS32_NUM_REGS, + NDS32_SIM_IFCLP_REGNUM =3D NDS32_SIM_FD0_REGNUM + 32, + NDS32_SIM_ITB_REGNUM, + NDS32_SIM_PSW_REGNUM, + + NDS32_SIM_NUM_REGS, +}; + +struct htab; +struct gdbarch_tdep +{ + /* The configuration of FPU FREG. */ + int fpu_freg; + + /* Large arguments are split between registers and stack. */ + int abi_split; + /* Set if fs0-fs5 are used to pass arguments. */ + int abi_use_fpr; + + /* Type table for registers. */ + struct htab *type_tab; +}; +#endif