2007-01-04 Qinwei <qinwei@sunnorth.com.cn>
authorQinwei <qinwei@sunnorth.com.cn>
Thu, 4 Jan 2007 07:09:54 +0000 (07:09 +0000)
committerQinwei <qinwei@sunnorth.com.cn>
Thu, 4 Jan 2007 07:09:54 +0000 (07:09 +0000)
* NEWS: New port to S+core.
* MAINTAINERS (Write After Approval, Responsible Maintainers):
Add myself.

* Makefile.in: Add dependencies for S+core files.
* configure.tgt (score*, score-*-*): Add S+core target.
* config/score/embed.mt: New file.
* score-tdep.c: New file.
* score-tdep.h: New file.

gdb/ChangeLog
gdb/MAINTAINERS
gdb/Makefile.in
gdb/configure.tgt
gdb/score-tdep.c [new file with mode: 0644]
gdb/score-tdep.h [new file with mode: 0644]

index 7f47dab3c04b0ab8b20f31dfde1d7f41518cd64b..9851106ae9c2e117dfd0e14f4fa1f1abed734468 100644 (file)
@@ -1,3 +1,15 @@
+2007-01-04  Qinwei  <qinwei@sunnorth.com.cn>
+
+       * NEWS: New port to S+core.
+       * MAINTAINERS (Write After Approval, Responsible Maintainers):
+       Add myself.
+
+       * Makefile.in: Add dependencies for S+core files.
+       * configure.tgt (score*, score-*-*): Add S+core target.
+       * config/score/embed.mt: New file.
+       * score-tdep.c: New file.
+       * score-tdep.h: New file.
+
 2007-01-04  Joel Brobecker  <brobecker@adacore.com>
 
        * ada-lang.c (ada_evaluate_subexp) [OP_TYPE]: Return a value with
index a0b33ad85acc1654996e5951609b4f9a2ab7282f..58dfe108198679b0f6db833bf9b4ae51d7284169 100644 (file)
@@ -301,6 +301,9 @@ the native maintainer when resolving ABI issues.
 
        s390            --target=s390-linux-gnu ,-Werror
 
+       score   --target=score-elf
+                       Qinwei          qinwei@sunnorth.com.cn
+
        sh              --target=sh-elf ,-Werror
                        --target=sh64-elf ,-Werror
 
@@ -525,6 +528,7 @@ Hans-Peter Nilsson                          hp@bitrange.com
 David O'Brien                                  obrien@freebsd.org
 Alexandre Oliva                                        aoliva@redhat.com
 Vladimir Prus                                   vladimir@codesourcery.com
+Qinwei                                                 qinwei@sunnorth.com.cn
 Ramana Radhakrishnan                           ramana.radhakrishnan@codito.com
 Frederic Riss                                  frederic.riss@st.com
 Tom Rix                                                trix@redhat.com
index 361297d68054149ec3c51d3bdd57e8c7ea36c3ef..d03fa06da1f06a684d4a96fb40b9a2bd16b78e46 100644 (file)
@@ -783,6 +783,7 @@ rs6000_tdep_h = rs6000-tdep.h $(defs_h)
 s390_tdep_h = s390-tdep.h
 scm_lang_h = scm-lang.h $(scm_tags_h)
 scm_tags_h = scm-tags.h
+score_tdep_h = score-tdep.h
 sentinel_frame_h = sentinel-frame.h
 serial_h = serial.h
 ser_base_h = ser-base.h
@@ -1491,6 +1492,7 @@ ALLDEPFILES = \
        remote-st.c remote-utils.c dcache.c \
        rs6000-nat.c rs6000-tdep.c \
        s390-tdep.c s390-nat.c \
+       score-tdep.c \
        ser-go32.c ser-pipe.c ser-tcp.c ser-mingw.c \
        sh-tdep.c sh64-tdep.c shnbsd-tdep.c shnbsd-nat.c \
        sol2-tdep.c \
@@ -2568,6 +2570,10 @@ scm-lang.o: scm-lang.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(expression_h) \
 scm-valprint.o: scm-valprint.c $(defs_h) $(symtab_h) $(gdbtypes_h) \
        $(expression_h) $(parser_defs_h) $(language_h) $(value_h) \
        $(scm_lang_h) $(valprint_h) $(gdbcore_h) $(c_lang_h)
+score-tdep.o: score-tdep.c $(defs_h) $(gdb_assert_h) $(inferior_h) \
+       $(symtab_h) $(objfiles_h) $(gdbcore_h) $(target_h) \
+       $(arch_utils_h) $(regcache_h) $(dis_asm_h) $(frame_unwind_h) \
+       $(frame_base_h) $(trad_frame_h) $(dwarf2_frame_h) $(score_tdep_h)
 sentinel-frame.o: sentinel-frame.c $(defs_h) $(regcache_h) \
        $(sentinel_frame_h) $(inferior_h) $(frame_unwind_h)
 ser-e7kpc.o: ser-e7kpc.c $(defs_h) $(serial_h) $(gdb_string_h)
index a9e657f44c318e1540e937aa503d1d25c77312a8..3682b4620d9aa4465732dea3163a543723beecd6 100644 (file)
@@ -24,6 +24,7 @@ powerpc*)             gdb_target_cpu=powerpc ;;
 sparc*)                        gdb_target_cpu=sparc ;;
 thumb*)                        gdb_target_cpu=arm ;;
 s390*)                 gdb_target_cpu=s390 ;;
+score*)                        gdb_target_cpu=score ;;
 sh*)                   gdb_target_cpu=sh ;;
 spu*)                  gdb_target_cpu=spu ;;
 strongarm*)            gdb_target_cpu=arm ;;
@@ -179,6 +180,7 @@ s390*-*-*)          gdb_target=s390
                        build_gdbserver=yes
                        ;;
 
+score-*-*)             gdb_target=embed ;;
 sh*-*-pe)              gdb_target=wince ;;
 sh-*-coff*)            gdb_target=embed ;;
 sh-*-elf*)             gdb_target=embed ;;
diff --git a/gdb/score-tdep.c b/gdb/score-tdep.c
new file mode 100644 (file)
index 0000000..dd8cb49
--- /dev/null
@@ -0,0 +1,906 @@
+/* Target-dependent code for the S+core architecture, for GDB,
+   the GNU Debugger.
+
+   Copyright (C) 2006
+   Free Software Foundation, Inc.
+
+   Contributed by Qinwei (qinwei@sunnorth.com.cn)
+   Contributed by Ching-Peng Lin (cplin@sunplus.com)
+
+   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 2 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, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "defs.h"
+#include "gdb_assert.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "objfiles.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "dis-asm.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+#include "dwarf2-frame.h"
+#include "score-tdep.h"
+
+#define G_FLD(_i,_ms,_ls)   (((_i) << (31 - (_ms))) >> (31 - (_ms) + (_ls)))
+#define RM_PBITS(_raw)      ((G_FLD(_raw, 31, 16) << 15) | G_FLD(_raw, 14, 0))
+
+typedef struct{
+    unsigned int v;
+    unsigned int raw;
+    char         is15;
+}inst_t;
+
+struct score_frame_cache
+{
+  CORE_ADDR base;
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+#if 0
+/* If S+core GCC will generate these instructions in the prologue:
+
+   lw   rx, imm1
+   addi rx, -imm2
+   mv!  r2, rx
+
+   then .pdr section is used.  */
+
+#define P_SIZE          8
+#define PI_SYM          0
+#define PI_R_MSK        1
+#define PI_R_OFF        2
+#define PI_R_LEF        4
+#define PI_F_OFF        5
+#define PI_F_REG        6
+#define PI_RAREG        7
+
+typedef struct frame_extra_info
+{
+  CORE_ADDR p_frame;
+  unsigned int pdr[P_SIZE];
+} extra_info_t;
+
+struct obj_priv
+{
+  bfd_size_type size;
+  char *contents;
+};
+
+static bfd *the_bfd;
+
+static int
+score_compare_pdr_entries (const void *a, const void *b)
+{
+  CORE_ADDR lhs = bfd_get_32 (the_bfd, (bfd_byte *) a);
+  CORE_ADDR rhs = bfd_get_32 (the_bfd, (bfd_byte *) b);
+  if (lhs < rhs)
+    return -1;
+  else if (lhs == rhs)
+    return 0;
+  else
+    return 1;
+}
+
+static void
+score_analyze_pdr_section (CORE_ADDR startaddr, CORE_ADDR pc,
+                           struct frame_info *next_frame,
+                           struct score_frame_cache *this_cache)
+{
+  struct symbol *sym;
+  struct obj_section *sec;
+  extra_info_t *fci_ext;
+  CORE_ADDR leaf_ra_stack_addr = -1;
+
+  gdb_assert (startaddr <= pc);
+  gdb_assert (this_cache != NULL);
+
+  fci_ext = frame_obstack_zalloc (sizeof (extra_info_t));
+  if ((sec = find_pc_section (pc)) == NULL)
+    {
+      error ("Can't find section in file:%s, line:%d!", __FILE__, __LINE__);
+      return;
+    }
+
+  /* Anylyze .pdr section and get coresponding fields.  */
+  {
+    static struct obj_priv *priv = NULL;
+
+    if (priv == NULL)
+      {
+        asection *bfdsec;
+        priv = obstack_alloc (&sec->objfile->objfile_obstack,
+                              sizeof (struct obj_priv));
+        if ((bfdsec = bfd_get_section_by_name (sec->objfile->obfd, ".pdr")))
+          {
+            priv->size = bfd_section_size (sec->objfile->obfd, bfdsec);
+            priv->contents = obstack_alloc (&sec->objfile->objfile_obstack,
+                                            priv->size);
+            bfd_get_section_contents (sec->objfile->obfd, bfdsec,
+                                      priv->contents, 0, priv->size);
+            the_bfd = sec->objfile->obfd;
+            qsort (priv->contents, priv->size / 32, 32,
+                   score_compare_pdr_entries);
+            the_bfd = NULL;
+          }
+        else
+          priv->size = 0;
+      }
+    if (priv->size != 0)
+      {
+        int low = 0, mid, high = priv->size / 32;
+        char *ptr;
+        do
+
+          {
+            CORE_ADDR pdr_pc;
+            mid = (low + high) / 2;
+            ptr = priv->contents + mid * 32;
+            pdr_pc = bfd_get_signed_32 (sec->objfile->obfd, ptr);
+            pdr_pc += ANOFFSET (sec->objfile->section_offsets,
+                                SECT_OFF_TEXT (sec->objfile));
+            if (pdr_pc == startaddr)
+              break;
+            if (pdr_pc > startaddr)
+              high = mid;
+            else
+              low = mid + 1;
+          }
+        while (low != high);
+
+        if (low != high)
+          {
+            gdb_assert (bfd_get_32 (sec->objfile->obfd, ptr) == startaddr);
+#define EXT_PDR(_pi)    bfd_get_32(sec->objfile->obfd, ptr+((_pi)<<2))
+            fci_ext->pdr[PI_SYM] = EXT_PDR (PI_SYM);
+            fci_ext->pdr[PI_R_MSK] = EXT_PDR (PI_R_MSK);
+            fci_ext->pdr[PI_R_OFF] = EXT_PDR (PI_R_OFF);
+            fci_ext->pdr[PI_R_LEF] = EXT_PDR (PI_R_LEF);
+            fci_ext->pdr[PI_F_OFF] = EXT_PDR (PI_F_OFF);
+            fci_ext->pdr[PI_F_REG] = EXT_PDR (PI_F_REG);
+            fci_ext->pdr[PI_RAREG] = EXT_PDR (PI_RAREG);
+#undef EXT_PDR
+          }
+      }
+  }
+}
+#endif
+
+static struct type *
+score_register_type (struct gdbarch *gdbarch, int regnum)
+{
+  gdb_assert (regnum >= 0 && regnum < SCORE_NUM_REGS);
+  return builtin_type_uint32;
+}
+
+static LONGEST
+score_read_unsigned_register (int regnum)
+{
+  LONGEST val;
+  regcache_cooked_read_unsigned (current_regcache, regnum, &val);
+  return val;
+}
+
+static CORE_ADDR
+score_read_sp (void)
+{
+  return score_read_unsigned_register (SCORE_SP_REGNUM);
+}
+
+static CORE_ADDR
+score_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, SCORE_PC_REGNUM);
+}
+
+static const char *
+score_register_name (int regnum)
+{
+  const char *score_register_names[] = {
+    "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", "r29", "r30", "r31",
+
+    "PSR",   "COND",   "ECR",    "EXCPVEC",
+    "CCR",   "EPC",    "EMA",    "TLBLOCK",
+    "TLBPT", "PEADDR", "TLBRPT", "PEVN",
+    "PECTX", "LIMPFN", "LDMPFN", "PREV",
+    "DREG",  "PC",     "DSAVE",  "COUNTER",
+    "LDCR",  "STCR",   "CEH",    "CEL",
+  };
+
+  gdb_assert (regnum >= 0 && regnum < SCORE_NUM_REGS);
+  return score_register_names[regnum];
+}
+
+static int
+score_register_sim_regno (int regnum)
+{
+  gdb_assert (regnum >= 0 && regnum < SCORE_NUM_REGS);
+  return regnum;
+}
+
+static int
+score_print_insn (bfd_vma memaddr, struct disassemble_info *info)
+{
+  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+    return print_insn_big_score (memaddr, info);
+  else
+    return print_insn_little_score (memaddr, info);
+}
+
+static const gdb_byte *
+score_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+{
+  gdb_byte buf[SCORE_INSTLEN] = { 0 };
+  int ret;
+  unsigned int raw;
+
+  if ((ret = target_read_memory (*pcptr & ~0x3, buf, SCORE_INSTLEN)) != 0)
+    {
+      memory_error (ret, *pcptr);
+    }
+  raw = extract_unsigned_integer (buf, SCORE_INSTLEN);
+
+  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+    {
+      if (!(raw & 0x80008000))
+        {
+          /* 16bits instruction.  */
+          static gdb_byte big_breakpoint16[] = { 0x60, 0x02 };
+          *pcptr &= ~0x1;
+          *lenptr = sizeof (big_breakpoint16);
+          return big_breakpoint16;
+        }
+      else
+        {
+          /* 32bits instruction.  */
+          static gdb_byte big_breakpoint32[] = { 0x80, 0x00, 0x80, 0x06 };
+          *pcptr &= ~0x3;
+          *lenptr = sizeof (big_breakpoint32);
+          return big_breakpoint32;
+        }
+    }
+  else
+    {
+      if (!(raw & 0x80008000))
+        {
+          /* 16bits instruction.  */
+          static gdb_byte little_breakpoint16[] = { 0x02, 0x60 };
+          *pcptr &= ~0x1;
+          *lenptr = sizeof (little_breakpoint16);
+          return little_breakpoint16;
+        }
+      else
+        {
+          /* 32bits instruction.  */
+          static gdb_byte little_breakpoint32[] = { 0x06, 0x80, 0x00, 0x80 };
+          *pcptr &= ~0x3;
+          *lenptr = sizeof (little_breakpoint32);
+          return little_breakpoint32;
+        }
+    }
+}
+
+static CORE_ADDR
+score_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  return align_down (addr, 16);
+}
+
+static void
+score_xfer_register (struct regcache *regcache, int regnum, int length,
+                     enum bfd_endian endian, gdb_byte *readbuf,
+                     const gdb_byte *writebuf, int buf_offset)
+{
+  int reg_offset = 0;
+  gdb_assert (regnum >= 0 && regnum < SCORE_NUM_REGS);
+
+  switch (endian)
+    {
+    case BFD_ENDIAN_BIG:
+      reg_offset = SCORE_REGSIZE - length;
+      break;
+    case BFD_ENDIAN_LITTLE:
+      reg_offset = 0;
+      break;
+    case BFD_ENDIAN_UNKNOWN:
+      reg_offset = 0;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, _("score_xfer_register error!"));
+    }
+
+  if (readbuf != NULL)
+    regcache_cooked_read_part (regcache, regnum, reg_offset, length,
+                               readbuf + buf_offset);
+  if (writebuf != NULL)
+    regcache_cooked_write_part (regcache, regnum, reg_offset, length,
+                                writebuf + buf_offset);
+}
+
+static enum return_value_convention
+score_return_value (struct gdbarch *gdbarch, struct type *type,
+                    struct regcache *regcache,
+                    gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+      || TYPE_CODE (type) == TYPE_CODE_UNION
+      || TYPE_CODE (type) == TYPE_CODE_ARRAY)
+    return RETURN_VALUE_STRUCT_CONVENTION;
+  else
+    {
+      int offset;
+      int regnum;
+      for (offset = 0, regnum = SCORE_A0_REGNUM;
+           offset < TYPE_LENGTH (type);
+           offset += SCORE_REGSIZE, regnum++)
+        {
+          int xfer = SCORE_REGSIZE;
+          if (offset + xfer > TYPE_LENGTH (type))
+            xfer = TYPE_LENGTH (type) - offset;
+          score_xfer_register (regcache, regnum, xfer, TARGET_BYTE_ORDER,
+                               readbuf, writebuf, offset);
+        }
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+}
+
+static struct frame_id
+score_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_id_build (
+           frame_unwind_register_unsigned (next_frame, SCORE_SP_REGNUM),
+           frame_pc_unwind (next_frame));
+}
+
+static int
+score_type_needs_double_align (struct type *type)
+{
+  enum type_code typecode = TYPE_CODE (type);
+
+  if (typecode == TYPE_CODE_INT && TYPE_LENGTH (type) == 8)
+    return 1;
+  if (typecode == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8)
+    return 1;
+  else if (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)
+    {
+      int i, n;
+
+      n = TYPE_NFIELDS (type);
+      for (i = 0; i < n; i++)
+        if (score_type_needs_double_align (TYPE_FIELD_TYPE (type, i)))
+          return 1;
+      return 0;
+    }
+  return 0;
+}
+
+static CORE_ADDR
+score_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)
+{
+  int argnum;
+  int argreg;
+  int arglen = 0;
+  CORE_ADDR stack_offset = 0;
+  CORE_ADDR addr = 0;
+
+  /* Step 1, Save RA.  */
+  regcache_cooked_write_unsigned (regcache, SCORE_RA_REGNUM, bp_addr);
+
+  /* Step 2, Make space on the stack for the args.  */
+  struct_addr = align_down (struct_addr, 16);
+  sp = align_down (sp, 16);
+  for (argnum = 0; argnum < nargs; argnum++)
+    arglen += align_up (TYPE_LENGTH (value_type (args[argnum])),
+                        SCORE_REGSIZE);
+  sp -= align_up (arglen, 16);
+
+  argreg = SCORE_BEGIN_ARG_REGNUM;
+
+  /* Step 3, Check if struct return then save the struct address to r4 and
+     increase the stack_offset by 4.  */
+  if (struct_return)
+    {
+      regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
+      stack_offset += SCORE_REGSIZE;
+    }
+
+  /* Step 4, Load arguments:
+     If arg length is too long (> 4 bytes),
+     then split the arg and save every parts.  */
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      struct value *arg = args[argnum];
+      struct type *arg_type = check_typedef (value_type (arg));
+      arglen = TYPE_LENGTH (arg_type);
+      enum type_code typecode = TYPE_CODE (arg_type);
+      const gdb_byte *val = value_contents (arg);
+      int downward_offset = 0;
+
+      int odd_sized_struct_p = (arglen > SCORE_REGSIZE
+                                && arglen % SCORE_REGSIZE != 0);
+      int arg_last_part_p = 0;
+
+      /* If a arg should be aligned to 8 bytes (long long or double),
+         the value should be put to even register numbers.  */
+      if (score_type_needs_double_align (arg_type))
+        {
+          if (argreg & 1)
+            argreg++;
+        }
+
+      /* If sizeof a block < SCORE_REGSIZE, then Score GCC will chose
+         the default "downward"/"upward" method:
+
+         Example:
+
+         struct struc
+         {
+           char a; char b; char c;
+         } s = {'a', 'b', 'c'};
+
+         Big endian:    s = {X, 'a', 'b', 'c'}
+         Little endian: s = {'a', 'b', 'c', X}
+
+         Where X is a hole.  */
+
+      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+          && (typecode == TYPE_CODE_STRUCT
+              || typecode == TYPE_CODE_UNION)
+          && argreg > SCORE_LAST_ARG_REGNUM
+          && arglen < SCORE_REGSIZE)
+        downward_offset += (SCORE_REGSIZE - arglen);
+
+      while (arglen > 0)
+        {
+          int partial_len = arglen < SCORE_REGSIZE ? arglen : SCORE_REGSIZE;
+          ULONGEST regval = extract_unsigned_integer (val, partial_len);
+
+          /* The last part of a arg should shift left when
+             TARGET_BYTE_ORDER is BFD_ENDIAN_BIG.  */
+          if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+              && arg_last_part_p == 1
+              && (typecode == TYPE_CODE_STRUCT
+                  || typecode == TYPE_CODE_UNION))
+            regval <<= ((SCORE_REGSIZE - partial_len) * TARGET_CHAR_BIT);
+
+          /* Always increase the stack_offset and save args to stack.  */
+          addr = sp + stack_offset + downward_offset;
+          write_memory (addr, val, partial_len);
+
+          if (argreg <= SCORE_LAST_ARG_REGNUM)
+            {
+              regcache_cooked_write_unsigned (regcache, argreg++, regval);
+              if (arglen > SCORE_REGSIZE && arglen < SCORE_REGSIZE * 2)
+                arg_last_part_p = 1;
+            }
+
+          val += partial_len;
+          arglen -= partial_len;
+          stack_offset += align_up (partial_len, SCORE_REGSIZE);
+        }
+    }
+
+  /* Step 5, Save SP.  */
+  regcache_cooked_write_unsigned (regcache, SCORE_SP_REGNUM, sp);
+
+  return sp;
+}
+
+static inst_t *
+score_fetch_instruction (CORE_ADDR addr)
+{
+  static inst_t inst = { 0, 0 };
+  char buf[SCORE_INSTLEN];
+  int big;
+  int ret = target_read_memory (addr & ~0x3, buf, SCORE_INSTLEN);
+  unsigned int raw;
+
+  if (ret)
+    {
+      memory_error (ret, addr);
+      return 0;
+    }
+  inst.raw = extract_unsigned_integer (buf, SCORE_INSTLEN);
+  inst.is15 = !(inst.raw & 0x80008000);
+  inst.v = RM_PBITS (inst.raw);
+  big = (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG);
+
+  if (inst.is15)
+    {
+      if (big ^ ((addr & 0x2) == 2))
+        inst.v = G_FLD (inst.v, 29, 15);
+      else
+        inst.v = G_FLD (inst.v, 14, 0);
+    }
+  return &inst;
+}
+
+static CORE_ADDR
+score_skip_prologue (CORE_ADDR pc)
+{
+  CORE_ADDR cpc = pc;
+  int iscan = 32, stack_sub = 0;
+  while (iscan-- > 0)
+    {
+      inst_t *inst = score_fetch_instruction (cpc);
+      if (!inst)
+        break;
+      if (!inst->is15 && !stack_sub
+          && (G_FLD (inst->v, 29, 25) == 0x1
+              && G_FLD (inst->v, 24, 20) == 0x0))
+        {
+          /* addi r0, offset */
+          pc = stack_sub = cpc + SCORE_INSTLEN;
+        }
+      else if (!inst->is15
+               && inst->v == RM_PBITS (0x8040bc56))
+        {
+          /* mv r2, r0  */
+          pc = cpc + SCORE_INSTLEN;
+          break;
+        }
+      else if (inst->is15
+               && inst->v == RM_PBITS (0x0203))
+        {
+          /* mv! r2, r0 */
+          pc = cpc + SCORE16_INSTLEN;
+          break;
+        }
+      else if (inst->is15
+               && ((G_FLD (inst->v, 14, 12) == 3)    /* j15 form */
+                   || (G_FLD (inst->v, 14, 12) == 4) /* b15 form */
+                   || (G_FLD (inst->v, 14, 12) == 0x0
+                       && G_FLD (inst->v, 3, 0) == 0x4))) /* br! */
+        break;
+      else if (!inst->is15
+               && ((G_FLD (inst->v, 29, 25) == 2)    /* j32 form */
+                   || (G_FLD (inst->v, 29, 25) == 4) /* b32 form */
+                   || (G_FLD (inst->v, 29, 25) == 0x0
+                       && G_FLD (inst->v, 6, 1) == 0x4)))  /* br */
+        break;
+
+      cpc += inst->is15 ? SCORE16_INSTLEN : SCORE_INSTLEN;
+    }
+  return pc;
+}
+
+static int
+score_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR cur_pc)
+{
+  inst_t *inst = score_fetch_instruction (cur_pc);
+
+  if (inst->v == 0x23)
+    return 1;   /* mv! r0, r2 */
+  else if (G_FLD (inst->v, 14, 12) == 0x2
+           && G_FLD (inst->v, 3, 0) == 0xa)
+    return 1;   /* pop! */
+  else if (G_FLD (inst->v, 14, 12) == 0x0
+           && G_FLD (inst->v, 7, 0) == 0x34)
+    return 1;   /* br! r3 */
+  else if (G_FLD (inst->v, 29, 15) == 0x2
+           && G_FLD (inst->v, 6, 1) == 0x2b)
+    return 1;   /* mv r0, r2 */
+  else if (G_FLD (inst->v, 29, 25) == 0x0
+           && G_FLD (inst->v, 6, 1) == 0x4
+           && G_FLD (inst->v, 19, 15) == 0x3)
+    return 1;   /* br r3 */
+  else
+    return 0;
+}
+
+static void
+score_analyze_prologue (CORE_ADDR startaddr, CORE_ADDR pc,
+                        struct frame_info *next_frame,
+                        struct score_frame_cache *this_cache)
+{
+  CORE_ADDR sp;
+  CORE_ADDR cur_pc = startaddr;
+
+  int sp_offset = 0;
+  int ra_offset = 0;
+  int fp_offset = 0;
+  int ra_offset_p = 0;
+  int fp_offset_p = 0;
+  int inst_len = 0;
+
+  sp = frame_unwind_register_unsigned (next_frame, SCORE_SP_REGNUM);
+
+  for (; cur_pc < pc; cur_pc += inst_len)
+    {
+      inst_t *inst = score_fetch_instruction (cur_pc);
+      if (inst->is15 == 1)
+        {
+          inst_len = SCORE16_INSTLEN;
+
+          if (G_FLD (inst->v, 14, 12) == 0x2
+              && G_FLD (inst->v, 3, 0) == 0xe)
+            {
+              /* push! */
+              sp_offset += 4;
+
+              if (G_FLD (inst->v, 11, 7) == 0x6
+                  && ra_offset_p == 0)
+                {
+                  /* push! r3, [r0] */
+                  ra_offset = sp_offset;
+                  ra_offset_p = 1;
+                }
+              else if (G_FLD (inst->v, 11, 7) == 0x4
+                       && fp_offset_p == 0)
+                {
+                  /* push! r2, [r0] */
+                  fp_offset = sp_offset;
+                  fp_offset_p = 1;
+                }
+            }
+          else if (G_FLD (inst->v, 14, 12) == 0x2
+                   && G_FLD (inst->v, 3, 0) == 0xa)
+            {
+              /* pop! */
+              sp_offset -= 4;
+            }
+          else if (G_FLD (inst->v, 14, 7) == 0xc1
+                   && G_FLD (inst->v, 2, 0) == 0x0)
+            {
+              /* subei! r0, n */
+              sp_offset += (int) pow (2, G_FLD (inst->v, 6, 3));
+            }
+          else if (G_FLD (inst->v, 14, 7) == 0xc0
+                   && G_FLD (inst->v, 2, 0) == 0x0)
+            {
+              /* addei! r0, n */
+              sp_offset -= (int) pow (2, G_FLD (inst->v, 6, 3));
+            }
+        }
+      else
+        {
+          inst_len = SCORE_INSTLEN;
+
+          if (G_FLD (inst->v, 29, 15) == 0xc60
+              && G_FLD (inst->v, 2, 0) == 0x4)
+            {
+              /* sw r3, [r0, offset]+ */
+              sp_offset += SCORE_INSTLEN;
+              if (ra_offset_p == 0)
+                {
+                  ra_offset = sp_offset;
+                  ra_offset_p = 1;
+                }
+            }
+          if (G_FLD (inst->v, 29, 15) == 0xc40
+              && G_FLD (inst->v, 2, 0) == 0x4)
+            {
+              /* sw r2, [r0, offset]+ */
+              sp_offset += SCORE_INSTLEN;
+              if (fp_offset_p == 0)
+                {
+                  fp_offset = sp_offset;
+                  fp_offset_p = 1;
+                }
+            }
+          else if (G_FLD (inst->v, 29, 15) == 0x1c60
+                   && G_FLD (inst->v, 2, 0) == 0x0)
+            {
+              /* lw r3, [r0]+, 4 */
+              sp_offset -= SCORE_INSTLEN;
+              ra_offset_p = 1;
+            }
+          else if (G_FLD (inst->v, 29, 15) == 0x1c40
+                   && G_FLD (inst->v, 2, 0) == 0x0)
+            {
+              /* lw r2, [r0]+, 4 */
+              sp_offset -= SCORE_INSTLEN;
+              fp_offset_p = 1;
+            }
+
+          else if (G_FLD (inst->v, 29, 17) == 0x100
+                   && G_FLD (inst->v, 0, 0) == 0x0)
+            {
+              /* addi r0, -offset */
+              sp_offset += 65536 - G_FLD (inst->v, 16, 1);
+            }
+          else if (G_FLD (inst->v, 29, 17) == 0x110
+                   && G_FLD (inst->v, 0, 0) == 0x0)
+            {
+              /* addi r2, offset */
+              if (pc - cur_pc > 4)
+                {
+                  unsigned int save_v = inst->v;
+                  inst_t *inst2 =
+                    score_fetch_instruction (cur_pc + SCORE_INSTLEN);
+                  if (inst2->v == 0x23)
+                    /* mv! r0, r2 */
+                    sp_offset -= G_FLD (save_v, 16, 1);
+                }
+            }
+        }
+    }
+
+  /* Save RA.  */
+  if (ra_offset_p == 1)
+    {
+      if (this_cache->saved_regs[SCORE_PC_REGNUM].addr == -1)
+        this_cache->saved_regs[SCORE_PC_REGNUM].addr =
+          sp + sp_offset - ra_offset;
+    }
+  else
+    {
+      this_cache->saved_regs[SCORE_PC_REGNUM] =
+        this_cache->saved_regs[SCORE_RA_REGNUM];
+    }
+
+  /* Save FP.  */
+  if (fp_offset_p == 1)
+    {
+      if (this_cache->saved_regs[SCORE_FP_REGNUM].addr == -1)
+        this_cache->saved_regs[SCORE_FP_REGNUM].addr =
+          sp + sp_offset - fp_offset;
+    }
+
+  /* Save SP.  */
+  this_cache->base =
+    frame_unwind_register_unsigned (next_frame, SCORE_SP_REGNUM) + sp_offset;
+}
+
+static struct score_frame_cache *
+score_make_prologue_cache (struct frame_info *next_frame, void **this_cache)
+{
+  struct score_frame_cache *cache;
+
+  if ((*this_cache) != NULL)
+    return (*this_cache);
+
+  cache = FRAME_OBSTACK_ZALLOC (struct score_frame_cache);
+  (*this_cache) = cache;
+  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+  /* Analyze the prologue.  */
+  {
+    const CORE_ADDR pc = frame_pc_unwind (next_frame);
+    CORE_ADDR start_addr;
+
+    find_pc_partial_function (pc, NULL, &start_addr, NULL);
+    if (start_addr == 0)
+      return cache;
+    score_analyze_prologue (start_addr, pc, next_frame, *this_cache);
+  }
+
+  /* Save SP.  */
+  trad_frame_set_value (cache->saved_regs, SCORE_SP_REGNUM, cache->base);
+
+  return (*this_cache);
+}
+
+static void
+score_prologue_this_id (struct frame_info *next_frame, void **this_cache,
+                        struct frame_id *this_id)
+{
+  struct score_frame_cache *info = score_make_prologue_cache (next_frame,
+                                                              this_cache);
+  (*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
+}
+
+static void
+score_prologue_prev_register (struct frame_info *next_frame,
+                              void **this_cache,
+                              int regnum, int *optimizedp,
+                              enum lval_type *lvalp, CORE_ADDR * addrp,
+                              int *realnump, gdb_byte * valuep)
+{
+  struct score_frame_cache *info = score_make_prologue_cache (next_frame,
+                                                              this_cache);
+  trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
+                                optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind score_prologue_unwind =
+{
+  NORMAL_FRAME,
+  score_prologue_this_id,
+  score_prologue_prev_register
+};
+
+static const struct frame_unwind *
+score_prologue_sniffer (struct frame_info *next_frame)
+{
+  return &score_prologue_unwind;
+}
+
+static CORE_ADDR
+score_prologue_frame_base_address (struct frame_info *next_frame,
+                                   void **this_cache)
+{
+  struct score_frame_cache *info =
+    score_make_prologue_cache (next_frame, this_cache);
+  return info->base;
+}
+
+static const struct frame_base score_prologue_frame_base =
+{
+  &score_prologue_unwind,
+  score_prologue_frame_base_address,
+  score_prologue_frame_base_address,
+  score_prologue_frame_base_address,
+};
+
+static const struct frame_base *
+score_prologue_frame_base_sniffer (struct frame_info *next_frame)
+{
+  return &score_prologue_frame_base;
+}
+
+static struct gdbarch *
+score_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+
+  arches = gdbarch_list_lookup_by_info (arches, &info);
+  if (arches != NULL)
+    {
+      return (arches->gdbarch);
+    }
+  gdbarch = gdbarch_alloc (&info, 0);
+
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 32);
+  set_gdbarch_float_bit (gdbarch, 32);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_register_sim_regno (gdbarch, score_register_sim_regno);
+  set_gdbarch_pc_regnum (gdbarch, SCORE_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, SCORE_SP_REGNUM);
+  set_gdbarch_num_regs (gdbarch, SCORE_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, score_register_name);
+  set_gdbarch_breakpoint_from_pc (gdbarch, score_breakpoint_from_pc);
+  set_gdbarch_register_type (gdbarch, score_register_type);
+  set_gdbarch_frame_align (gdbarch, score_frame_align);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_read_sp (gdbarch, score_read_sp);
+  set_gdbarch_unwind_pc (gdbarch, score_unwind_pc);
+  set_gdbarch_print_insn (gdbarch, score_print_insn);
+  set_gdbarch_skip_prologue (gdbarch, score_skip_prologue);
+  set_gdbarch_in_function_epilogue_p (gdbarch, score_in_function_epilogue_p);
+  set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+  set_gdbarch_return_value (gdbarch, score_return_value);
+  set_gdbarch_unwind_dummy_id (gdbarch, score_unwind_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, score_push_dummy_call);
+
+  frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+  frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
+  frame_unwind_append_sniffer (gdbarch, score_prologue_sniffer);
+  frame_base_append_sniffer (gdbarch, score_prologue_frame_base_sniffer);
+
+  return gdbarch;
+}
+
+extern initialize_file_ftype _initialize_score_tdep;
+
+void
+_initialize_score_tdep (void)
+{
+  gdbarch_register (bfd_arch_score, score_gdbarch_init, NULL);
+}
diff --git a/gdb/score-tdep.h b/gdb/score-tdep.h
new file mode 100644 (file)
index 0000000..122e886
--- /dev/null
@@ -0,0 +1,51 @@
+/* Target-dependent code for the S+core architecture, for GDB,
+   the GNU Debugger.
+
+   Copyright (C) 2006
+   Free Software Foundation, Inc.
+
+   Contributed by Qinwei (qinwei@sunnorth.com.cn)
+   Contributed by Ching-Peng Lin (cplin@sunplus.com)
+
+   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 2 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, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#ifndef SCORE_TDEP_H
+#define SCORE_TDEP_H
+#include "math.h"
+
+enum gdb_regnum
+{
+  SCORE_SP_REGNUM = 0,
+  SCORE_FP_REGNUM = 2,
+  SCORE_RA_REGNUM = 3,
+  SCORE_A0_REGNUM = 4,
+  SCORE_AL_REGNUM = 7,
+  SCORE_PC_REGNUM = 49,
+};
+
+#define SCORE_A0_REGNUM        4
+#define SCORE_A1_REGNUM        5
+#define SCORE_REGSIZE          4
+#define SCORE_NUM_REGS         56
+#define SCORE_BEGIN_ARG_REGNUM 4
+#define SCORE_LAST_ARG_REGNUM  7
+
+#define SCORE_INSTLEN          4
+#define SCORE16_INSTLEN        2
+
+#endif /* SCORE_TDEP_H */