Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFA 3/5] New port: CR16: gdb port
@ 2012-10-04 10:22 Kaushik Phatak
  2012-10-04 14:48 ` Joel Brobecker
  2012-10-08  6:59 ` Yao Qi
  0 siblings, 2 replies; 29+ messages in thread
From: Kaushik Phatak @ 2012-10-04 10:22 UTC (permalink / raw)
  To: gdb-patches

Hi,
This patch adds the tdep related files to gdb.
The port uses basic structure of the Renesas RX port and some concepts borrowed 
from the ARM port. The linux port uses a different breakpoint instruction eliminating
external hardware requirement. The register set is slightly different for ELF
and Linux which gets set by set_gdbarch_register_name.
Kindly review the same and let me know if further modifications are required.

Additional Information on CR16 target:
The CR16 target saves the return address (right shifted by 1) onto the RA
register, which is later pushed onto the stack for leaf calls. The unwinder
takes care of this in the frame_prev_register call.
The CR16 target has a combination of 16 and 32 bit registers. R0 to R11 are
16 bits wide and can be accessed as 16 bit or 32 bit (register pair).
R12, R13, RA and SP are 32 bit registers.

Regards,
Kaushik

2012-10-04 Kaushik Phatak  <kaushik.phatak@kpitcummins.com>

	gdb/Changelog
	* cr16-linux-tdep.c: New file.
	* cr16-tdep.c: New file.
	* cr16-tdep.h: New file.

--- ./gdb_src.orig/gdb/cr16-linux-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-linux-tdep.c	2012-10-01 11:47:44.000000000 +0530
@@ -0,0 +1,64 @@
+/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
+
+   Copyright 2007-2012 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.pahatk@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "linux-tdep.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "cr16-tdep.h"
+
+const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };
+
+
+/* OS specific initialization of gdbarch.  */
+
+static void
+cr16_uclinux_init_abi (struct gdbarch_info info,
+                    struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  linux_init_abi (info, gdbarch);
+
+  /* The opcode of excp bpt is 0x00C8, however for uclinux we will use the 
+     excp flg (0x00C7) to insert a breakpoint. The excp bpt requires external
+     hardware support for breakpoints to work on CR16 target. Software based
+     breakpoints are implemented in the kernel using excp flg and tested on
+     the SC14452 target. Use 0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF
+     We represent the breakpoint in little endian format since CR16 supports
+     only little endian.
+   */
+  tdep->breakpoint = breakpoint_uclinux;
+
+}
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_linux_tdep;
+
+void
+_initialize_cr16_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_cr16, 0, GDB_OSABI_LINUX,
+                          cr16_uclinux_init_abi);
+}
+
+
--- ./gdb_src.orig/gdb/cr16-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.c	2012-10-04 15:23:27.000000000 +0530
@@ -0,0 +1,930 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2012 Free Software Foundation, Inc.
+ 
+   Contributed by Kaushik Phatak (kaushik.pahatk@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+   This file is part of GDB.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+#include "linux-tdep.h"
+#include "osabi.h"
+#include "cr16-tdep.h"
+
+const gdb_byte breakpoint_elf[] = { 0xC8, 0x00 };
+
+typedef unsigned short wordU;
+extern wordU words[3];
+extern ULONGLONG allWords;
+extern ins currInsn;
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Implement the "register_name" gdbarch method.  */
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  static const char *const reg_names[] = {
+    "r0",
+    "r1",
+    "r2",
+    "r3",
+    "r4",
+    "r5",
+    "r6",
+    "r7",
+    "r8",
+    "r9",
+    "r10",
+    "r11",
+    "r12",
+    "r13",
+    "ra",
+    "sp",
+    "pc",
+    "isp",
+    "usp",
+    "intbase",
+    "psr",
+    "cfg"
+  };
+
+  return reg_names[regnr];
+}
+
+static const char *
+cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  static const char *const reg_names[] = {
+    "r0",
+    "r1",
+    "r2",
+    "r3",
+    "r4",
+    "r5",
+    "r6",
+    "r7",
+    "r8",
+    "r9",
+    "r10",
+    "r11",
+    "r12",
+    "r13",
+    "ra",
+    "psr",
+    "pc",
+    "r0r1_orig",
+    "intbase",
+    "usp",
+    "cfg"
+  };
+
+  return reg_names[regnr];
+}
+
+/* Implement the "register_type" gdbarch method.  */
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note:PC in CR16 is of 24 bits  */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case CR16_FP_REGNUM:	/*Frame Pointer reg  */
+    case CR16_SP_REGNUM:	/*Stack Pointer reg  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+      return builtin_type (gdbarch)->builtin_uint32;
+      break;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+      break;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    default:
+      printf
+	("\nRegister Type not supported\nFunction : cr16_register_type\n");
+      return 0;
+      break;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+ 
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch, value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Use functions from opcodes/cr16-dis.c by making them non-static  */
+extern void make_instruction (void);
+extern int match_opcode (void);
+extern void get_words_at_PC (bfd_vma memaddr, struct disassemble_info *info);
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte buf[6];
+  char insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;               /* Nonzero means instruction has a match.  */
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      target_read_memory (pc, buf, 6);	/* Read 6 bytes, max 48 bit opcode  */
+      words[0] = buf[1] << 8 | buf[0];
+      words[1] = buf[3] << 8 | buf[2];
+      words[2] = buf[5] << 8 | buf[4];
+      allWords =
+	((ULONGLONG) words[0] << 32) + ((unsigned long) words[1] << 16) +
+	words[2];
+
+      /* Find a matching opcode in table.  */
+      is_decoded = match_opcode ();
+      make_instruction ();
+      length = currInsn.size;
+      next_pc = pc + length;
+      insn_byte1 = (words[0] >> 8) & 0xFF;
+      /* If PUSH, then save RA and other regs. */
+      if (insn_byte1 == 0x01)
+	{
+	  int r1, r2;
+	  int r;
+	  insn_byte2 = words[0];
+
+	  if (insn_byte2 & 0x80)
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+          /* Start Register=r1, 3 bit imm count=r2  */
+	  r1 = insn_byte2 & 0x0F;
+	  r2 = ((insn_byte2 & 0x70) >> 4);
+	  r2 = r2 + r1 + 1;
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+      /* Add constant to SP  */
+      else if (insn_byte1 == 0x60)
+	{
+	  int rdst;
+	  signed short addend;
+	  insn_byte2 = words[0];
+	  rdst = insn_byte2 & 0x0F;
+	  if (rdst == CR16_SP_REGNUM)
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      /* Check for MOVD insn  */
+      else if (insn_byte1 == 0x55)
+	{
+	  int rdst, rsrc;
+	  insn_byte2 = words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	{
+	  break;		/* Terminate the prologue scan.  */
+	}
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+
+/* Implement the "skip_prologue" gdbarch method.  */
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (!*this_prologue_cache)
+    {
+      CORE_ADDR func_start, stop_addr;
+
+      *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+
+      func_start = get_frame_func (this_frame);
+      stop_addr = get_frame_pc (this_frame);
+
+      /* If we couldn't find any function containing the PC, then
+         just initialize the prologue cache, but don't do anything.  */
+      if (!func_start)
+	stop_addr = func_start;
+
+      cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+    }
+
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+  int reg_size = register_size (get_frame_arch (this_frame), regnum);
+  ULONGEST ra_prev;
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA register,
+     CR16_R13_REGNUM. So, we need not adjust anything directly. We will 
+     analyze prologue as this RA register is pushed onto stack for further
+     leaf function calls to work  */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+    {
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+    }
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+    {
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+    }
+}
+
+static const struct frame_unwind cr16_frame_unwind = {
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  ULONGEST pc;
+
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  ULONGEST sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+static CORE_ADDR
+cr16_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)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments on the stack.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ``arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R15.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u =
+		    extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, if possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* We use different breakpoint instructions for ELF and uClinux.
+     See cr16-linux-tdep.c for more details. 
+  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  *lenptr = 2;
+  if (tdep == NULL || tdep->breakpoint == NULL)
+    {
+        return  breakpoint_elf;
+    }
+  return tdep->breakpoint;
+}
+
+
+
+/* Allocate and initialize a gdbarch object.  */
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xcalloc (1,sizeof (struct gdbarch_tdep));
+  tdep->elf_flags = elf_flags;
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  if(info.osabi == GDB_OSABI_LINUX)
+  {
+    set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
+    set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
+  }
+  else
+  {
+    set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+    set_gdbarch_register_name (gdbarch, cr16_register_name);
+  }
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+
+  /* Passing NULL  values in the following two functions
+     for the time being, to fix later  */
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* 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, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+
+  /* if we don't pass the option -mint32
+     To fix : add if else case depending on the option passed,
+     sp that we can have int size as 16 or 32 bits both. */
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
--- ./gdb_src.orig/gdb/cr16-tdep.h	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.h	2012-09-04 13:05:39.000000000 +0530
@@ -0,0 +1,36 @@
+/* GNU/Linux on  CR16 target support.
+   Copyright (C) 2011-2012 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.pahatk@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#define CR16_NUM_REGS  22
+#define CR16_LINUX_NUM_REGS  21
+
+extern const gdb_byte breakpoint_elf[];
+extern const gdb_byte breakpoint_linux[];
+
+/* Target-dependent structure in gdbarch.  */
+/* Architecture specific data.  */
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  const char *breakpoint; /* Breakpoint instruction.  */
+};



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2012-10-04 10:22 [RFA 3/5] New port: CR16: gdb port Kaushik Phatak
@ 2012-10-04 14:48 ` Joel Brobecker
  2012-10-05 11:44   ` Kaushik Phatak
  2012-10-08  6:59 ` Yao Qi
  1 sibling, 1 reply; 29+ messages in thread
From: Joel Brobecker @ 2012-10-04 14:48 UTC (permalink / raw)
  To: Kaushik Phatak; +Cc: gdb-patches

> 2012-10-04 Kaushik Phatak  <kaushik.phatak@kpitcummins.com>
> 
> 	gdb/Changelog
> 	* cr16-linux-tdep.c: New file.
> 	* cr16-tdep.c: New file.
> 	* cr16-tdep.h: New file.

A good start :-). I am running out of time for today, but I noticed
a few things you can work on right away:

The biggie is that I think that there is a log of stuff in cr16-tdep
that is actually linux-specific, and that you should move to
cr16-linux-tdep.c. You'll see that it'll simplify your gdbarch_init
phase a bit (the linux one will probably build on top of the bareboard
one).

also, everything entity needs to be properly documented. This applies
to new types, new constants, global variables and functions. Therefore:

> +const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };

Needs a comment. For global variables and constants, I think that
the general practice is to put the comment on the line just before
the definition:

    /* The breakpoint instruction to use when bla bla bla.  */
    const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };

For functions and types, however, we decided to have an empty line
between the documentation/comment and the function.

On formatting nits... (sorry - the GDB project is a little picky
about this, but for good reasons, IMO)

> +static void
> +cr16_uclinux_init_abi (struct gdbarch_info info,
> +                    struct gdbarch *gdbarch)

The last line isn't aligned properly.

> +  /* The opcode of excp bpt is 0x00C8, however for uclinux we will use the 
> +     excp flg (0x00C7) to insert a breakpoint. The excp bpt requires external
> +     hardware support for breakpoints to work on CR16 target. Software based
> +     breakpoints are implemented in the kernel using excp flg and tested on
> +     the SC14452 target. Use 0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF
> +     We represent the breakpoint in little endian format since CR16 supports
> +     only little endian.
> +   */

The recommended line limit is 70, with a hard limit of 80 characters.
So this paragraph needs to be reformatted.

Also, the GNU Coding Style requires that 2 spaces be used after periods.
This applies for instance to the second line.  Please also move the closing
"*/" to the end of the last line, with two spaces after the last period.
I will not highlight the other occurences of these formatting issues.
Can you make a pass over your code?

> +typedef unsigned short wordU;
> +extern wordU words[3];
> +extern ULONGLONG allWords;
> +extern ins currInsn;

This looks strange. Why extern, and where would they come from?
Needs a comment.

> +/* Use functions from opcodes/cr16-dis.c by making them non-static  */
> +extern void make_instruction (void);
> +extern int match_opcode (void);
> +extern void get_words_at_PC (bfd_vma memaddr, struct disassemble_info *info);

Don't these functions have declarations in opcode? This is really ugly,
and potentially dangerous if the function's profile get changed at
some point in the future. Please consider adding these to a header
file in opcodes, and have both opcodes and GDB inclulde those, to
ensure consistency.

> +static const struct frame_unwind cr16_frame_unwind = {

Formatting nit: The '{' needs to be on the next line. There are probably
other instances of this issue.

> +  /* We use different breakpoint instructions for ELF and uClinux.
> +     See cr16-linux-tdep.c for more details. 
> +  */

Trailing space at the end of the second line.  Please also move the closing
*/ to the second line as well.

> +extern const gdb_byte breakpoint_elf[];
> +extern const gdb_byte breakpoint_linux[];

I don't think these need to be in the .h file.  I couldn't find
a reference to the breakpoint_linux entity, and I think that
breakpoint_elf can be declared static in cr16-tdep.c.

> +/* Target-dependent structure in gdbarch.  */
> +/* Architecture specific data.  */
> +struct gdbarch_tdep

One comment is enough :). And empty line between comment and
type definition.

> +  /* The ELF header flags specify the multilib used.  */
> +  int elf_flags;
> +
> +  const char *breakpoint; /* Breakpoint instruction.  */

I'd rather you moved the last comment to just above the field
declaration, for consistency.  And the type should probably use
gdb_bytes.

-- 
Joel


^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [RFA 3/5] New port: CR16: gdb port
  2012-10-04 14:48 ` Joel Brobecker
@ 2012-10-05 11:44   ` Kaushik Phatak
  2012-10-05 12:21     ` Joel Brobecker
  0 siblings, 1 reply; 29+ messages in thread
From: Kaushik Phatak @ 2012-10-05 11:44 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

Hi Joel,
Thanks for all your inputs.
I will make another pass over the code and fix up the formatting.

> I think that there is a log of stuff in cr16-tdep that is actually 
> linux-specific, and that you should move to cr16-linux-tdep.c.
If you get time, could you point out which parts can be specifically moved 
out into cr16-linux-tdep.c? I have kept that file to a bare minimum as of now.

Regards,
Kaushik



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2012-10-05 11:44   ` Kaushik Phatak
@ 2012-10-05 12:21     ` Joel Brobecker
  2012-10-09 13:20       ` Kaushik Phatak
  0 siblings, 1 reply; 29+ messages in thread
From: Joel Brobecker @ 2012-10-05 12:21 UTC (permalink / raw)
  To: Kaushik Phatak; +Cc: gdb-patches

> If you get time, could you point out which parts can be specifically moved 
> out into cr16-linux-tdep.c? I have kept that file to a bare minimum as of now.

Unfortunately, I will likely not have time until the week after next.
Anything that is specific to linux basically can be moved there.
Take a look at how sparc is organized, or maybe (slightly more
complex, I think) amd64.

-- 
Joel


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2012-10-04 10:22 [RFA 3/5] New port: CR16: gdb port Kaushik Phatak
  2012-10-04 14:48 ` Joel Brobecker
@ 2012-10-08  6:59 ` Yao Qi
  2012-10-09 15:03   ` Kaushik Phatak
  1 sibling, 1 reply; 29+ messages in thread
From: Yao Qi @ 2012-10-08  6:59 UTC (permalink / raw)
  To: Kaushik Phatak; +Cc: gdb-patches

On 10/04/2012 06:20 PM, Kaushik Phatak wrote:

Hi, Kaushik,
I don't read your patch in details yet, just some small points I found...

> +const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };

Add 'static'.  It is not used out of this file.

> +/* Allocate and initialize a gdbarch object.  */
> +static struct gdbarch *
> +cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
> +{
> +  struct gdbarch *gdbarch;
> +  struct gdbarch_tdep *tdep;
> +  int elf_flags;
> +
> +  /* Extract the elf_flags if available.  */
> +  if (info.abfd != NULL
> +      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
> +    elf_flags = elf_elfheader (info.abfd)->e_flags;
> +  else
> +    elf_flags = 0;
> +
> +  /* Try to find the architecture in the list of already defined
> +     architectures.  */
> +  for (arches = gdbarch_list_lookup_by_info (arches, &info);
> +       arches != NULL;
> +       arches = gdbarch_list_lookup_by_info (arches->next, &info))
> +    {
> +      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
> +	continue;
> +
> +      return arches->gdbarch;
> +    }
> +  /* None found, create a new architecture from the information
> +     provided.  */
> +  tdep = (struct gdbarch_tdep *) xcalloc (1,sizeof (struct gdbarch_tdep));
> +  tdep->elf_flags = elf_flags;
> +  gdbarch = gdbarch_alloc (&info, tdep);
> +
> +  set_gdbarch_num_pseudo_regs (gdbarch, 0);
> +  if(info.osabi == GDB_OSABI_LINUX)
> +  {
> +    set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
> +    set_gdbarch_register_name (gdbarch, cr16_linux_register_name);

This part should be moved to function cr16_uclinux_init_abi, and then 
macro CR16_LINUX_NUM_REGS can be defined in cr16-linux-tdep.c instead of 
cr16-tdep.h.

> +  }
> +  else
> +  {
> +    set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
> +    set_gdbarch_register_name (gdbarch, cr16_register_name);
> +  }

> --- ./gdb_src.orig/gdb/cr16-tdep.h	1970-01-01 05:30:00.000000000 +0530
> +++ ./gdb_src/gdb/cr16-tdep.h	2012-09-04 13:05:39.000000000 +0530
> @@ -0,0 +1,36 @@
> +/* GNU/Linux on  CR16 target support.
> +   Copyright (C) 2011-2012 Free Software Foundation, Inc.
> +
> +   Contributed by Kaushik Phatak (kaushik.pahatk@kpitcummins.com)
> +   KPIT Cummins Infosystems Limited, Pune India.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see<http://www.gnu.org/licenses/>.  */
> +
> +#define CR16_NUM_REGS  22
> +#define CR16_LINUX_NUM_REGS  21

These two macros can be defined in cr16-tdep.c and cr16-linux-tdep.c 
respectively.

> +
> +extern const gdb_byte breakpoint_elf[];
> +extern const gdb_byte breakpoint_linux[];

They are not needed.  'breakpoint_elf' is only used in cr16-tdep.c, and 
'breakpoint_linux' doesn't exist at all.

-- 
Yao


^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [RFA 3/5] New port: CR16: gdb port
  2012-10-05 12:21     ` Joel Brobecker
@ 2012-10-09 13:20       ` Kaushik Phatak
  0 siblings, 0 replies; 29+ messages in thread
From: Kaushik Phatak @ 2012-10-09 13:20 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches, Yao Qi

Hi Joel,

> I think that there is a log of stuff in cr16-tdep that is actually
> linux-specific, and that you should move to cr16-linux-tdep.c
I have moved register initializations into the cr16-linux-tdep.c. This 
was also recommended by Yao. 

> Take a look at how sparc is organized, or maybe amd64.
The other targets like amd64 have plenty on stuff in this file, however it is
unrelated to this port. I feel the updated cr16-linux-tdep.c file should allow
it to build on top of the bareboard one. 

> Needs a comment. For global variables and constants
Added comments at appropriate location in the code.

> have an empty line between the documentation/comment and the function.
Added empty lines between comment and functions

>> +extern ins currInsn;
> This looks strange. Why extern, and where would they come from?
I have added comments for this and removed the unnecessary externs here.

> Don't these functions have declarations in opcode? This is really ugly
These prototypes were added recently and are part of a bfd patch. I forgot
to remove these in the last version.

> +extern const gdb_byte breakpoint_linux[];
I have removed this as it is not used in the later versions of the patch.

> The last line isn't aligned properly.
> So this paragraph needs to be reformatted.
> requires that 2 spaces be used after periods.
> Please also move the closing "*/" to the end of the last line
> The '{' needs to be on the next line.
> Trailing space at the end of the second line
> move the closing */ to the second line as well.
> And empty line between comment
> moved the last comment to just above the field

I have made another pass over the code and have taken care of the above 
mentioned points and other formatting nits which I could find. Thanks.

I have not attached my updated patch here. I am working on Yao's comments
and will attach it in that reply.

Regards,
Kaushik



^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [RFA 3/5] New port: CR16: gdb port
  2012-10-08  6:59 ` Yao Qi
@ 2012-10-09 15:03   ` Kaushik Phatak
  2012-10-22 22:41     ` Joel Brobecker
  0 siblings, 1 reply; 29+ messages in thread
From: Kaushik Phatak @ 2012-10-09 15:03 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches, Joel Brobecker

[-- Attachment #1: Type: text/plain, Size: 34697 bytes --]

Hi Yao,
Thanks for the review.

> Add 'static'. It is not used out of this file.
Ok, added this.

> +    set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
> +    set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
> This part should be moved to function cr16_uclinux_init_abi,
Moved these setup calls into cr16-linux-tdep.c file.

> These two macros can be defined in cr16-tdep.c and cr16-linux-tdep.c 
> respectively.
After making above changes, moved these macros into respective files.

> They are not needed. 'breakpoint_elf' is only used in cr16-tdep.c, 
> and 'breakpoint_linux' doesn't exist at all.
Removed these declarations, they were probably used in an earlier version.

Additionally, apart from these gdb specific changes, I have also merged
my patch [2/5] with this, which updates configure.tgt. 

Please find the updated patch below. I have also attached the same. 
I have tried to incorporate all the comments from Joel as mentioned 
in my reply,
http://sourceware.org/ml/gdb-patches/2012-10/msg00149.html

Please let me know if any further modification would be needed.

Regards,
Kaushik

----

2012-10-09 Kaushik Phatak  <kaushik.phatak@kpitcummins.com>

	gdb/Changelog
	* configure.tgt: Handle cr16*-*-*linux and cr16*-*-*.
	* cr16-linux-tdep.c: New file.
	* cr16-tdep.c: New file.
	* cr16-tdep.h: New file.


--- ./gdb_src.orig/gdb/configure.tgt	2012-08-02 01:18:44.000000000 +0530
+++ ./gdb_src/gdb/configure.tgt	2012-10-09 19:12:54.000000000 +0530
@@ -116,6 +116,18 @@ bfin-*-*)
 	gdb_sim=../sim/bfin/libsim.a
 	;;
 
+cr16*-*-*linux)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o cr16-linux-tdep.o linux-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
+cr16*-*-*)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
 cris*)
 	# Target: CRIS
 	gdb_target_obs="cris-tdep.o solib-svr4.o"
--- ./gdb_src.orig/gdb/cr16-linux-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-linux-tdep.c	2012-10-09 17:30:21.000000000 +0530
@@ -0,0 +1,102 @@
+/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
+
+   Copyright 2012 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.pahatk@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+#include "elf/cr16.h"
+#include "linux-tdep.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for Linux targets  */
+#define CR16_LINUX_NUM_REGS  21
+
+/* The breakpoint instruction used by uClinux target  */
+static const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  static const char *const reg_names[] = {
+    "r0",
+    "r1",
+    "r2",
+    "r3",
+    "r4",
+    "r5",
+    "r6",
+    "r7",
+    "r8",
+    "r9",
+    "r10",
+    "r11",
+    "r12",
+    "r13",
+    "ra",
+    "psr",
+    "pc",
+    "r0r1_orig",
+    "intbase",
+    "usp",
+    "cfg"
+  };
+
+  return reg_names[regnr];
+}
+
+/* OS specific initialization of gdbarch.  */
+
+static void
+cr16_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  linux_init_abi (info, gdbarch);
+
+  set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
+
+  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
+     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
+     requires external hardware support for breakpoints to work on
+     CR16 target.  Software based breakpoints are implemented in the
+     kernel using excp flg and tested on the SC14452 target.  Use
+     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We 
+     represent the breakpoint in little endian format since CR16
+     supports only little endian.  */
+  tdep->breakpoint = breakpoint_uclinux;
+
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_linux_tdep;
+
+void
+_initialize_cr16_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_cr16, 0, GDB_OSABI_LINUX,
+			  cr16_uclinux_init_abi);
+}
--- ./gdb_src.orig/gdb/cr16-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.c	2012-10-09 18:47:25.000000000 +0530
@@ -0,0 +1,915 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2012 Free Software Foundation, Inc.
+ 
+   Contributed by Kaushik Phatak (kaushik.pahatk@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+   This file is part of GDB.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+#include "linux-tdep.h"
+#include "osabi.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for ELF targets.  */
+#define CR16_NUM_REGS  22
+
+/* The breakpoint instruction used with sim for ELF targets.  */
+static const gdb_byte breakpoint_elf[] = { 0xC8, 0x00 };
+
+/* Data type to store instruction opcodes.  */
+typedef unsigned short wordU;
+
+/* Globals to store opcode related information.  */
+wordU words[3];
+ULONGLONG allWords;
+ins currInsn;
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  static const char *const reg_names[] = {
+    "r0",
+    "r1",
+    "r2",
+    "r3",
+    "r4",
+    "r5",
+    "r6",
+    "r7",
+    "r8",
+    "r9",
+    "r10",
+    "r11",
+    "r12",
+    "r13",
+    "ra",
+    "sp",
+    "pc",
+    "isp",
+    "usp",
+    "intbase",
+    "psr",
+    "cfg"
+  };
+
+  return reg_names[regnr];
+}
+
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note:PC in CR16 is of 24 bits.  */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case CR16_FP_REGNUM:	/*Frame Pointer reg.  */
+    case CR16_SP_REGNUM:	/*Stack Pointer reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+      return builtin_type (gdbarch)->builtin_uint32;
+      break;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+      break;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    default:
+      printf
+	("\nRegister Type not supported\nFunction : cr16_register_type\n");
+      return 0;
+      break;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+ 
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch, value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte buf[6];
+  char insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      /* Read 6 bytes, max 48 bit opcode.  */
+      target_read_memory (pc, buf, 6);
+      words[0] = buf[1] << 8 | buf[0];
+      words[1] = buf[3] << 8 | buf[2];
+      words[2] = buf[5] << 8 | buf[4];
+      allWords =
+	((ULONGLONG) words[0] << 32) + ((unsigned long) words[1] << 16) +
+	words[2];
+
+      /* Find a matching opcode in table.  
+         Nonzero means instruction has a match.  */
+      is_decoded = match_opcode ();
+      make_instruction ();
+      length = currInsn.size;
+      next_pc = pc + length;
+      insn_byte1 = (words[0] >> 8) & 0xFF;
+
+      /* If PUSH, then save RA and other regs.  */
+      if (insn_byte1 == 0x01)
+	{
+	  int r1, r2;
+	  int r;
+	  insn_byte2 = words[0];
+
+	  if (insn_byte2 & 0x80)
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+	  /* Start Register=r1, 3 bit imm count=r2.  */
+	  r1 = insn_byte2 & 0x0F;
+	  r2 = ((insn_byte2 & 0x70) >> 4);
+	  r2 = r2 + r1 + 1;
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+      /* Add constant to SP.  */
+      else if (insn_byte1 == 0x60)
+	{
+	  int rdst;
+	  signed short addend;
+	  insn_byte2 = words[0];
+	  rdst = insn_byte2 & 0x0F;
+	  if (rdst == CR16_SP_REGNUM)
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      /* Check for MOVD insn.  */
+      else if (insn_byte1 == 0x55)
+	{
+	  int rdst, rsrc;
+	  insn_byte2 = words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	{
+	  break;		/* Terminate the prologue scan.  */
+	}
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+
+/* Implement the "skip_prologue" gdbarch method.  */
+
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (!*this_prologue_cache)
+    {
+      CORE_ADDR func_start, stop_addr;
+
+      *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+
+      func_start = get_frame_func (this_frame);
+      stop_addr = get_frame_pc (this_frame);
+
+      /* If we couldn't find any function containing the PC, then
+         just initialize the prologue cache, but don't do anything.  */
+      if (!func_start)
+	stop_addr = func_start;
+
+      cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+    }
+
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+/* Implement the "frame_prev_register" method for unwinding frames.  */
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+  int reg_size = register_size (get_frame_arch (this_frame), regnum);
+  ULONGEST ra_prev;
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA 
+     register, CR16_R13_REGNUM.  So, we need not adjust anything
+     directly.  We will analyze prologue as this RA register is
+     pushed onto stack for further leaf function calls to work.  */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+    {
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+    }
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+    {
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+    }
+}
+
+static const struct frame_unwind cr16_frame_unwind = 
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  ULONGEST pc;
+
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  ULONGEST sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+cr16_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)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments on the stack.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ``arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R12.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u =
+		    extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, as possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* We use different breakpoint instructions for ELF and uClinux.
+     See cr16-linux-tdep.c for more details.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  *lenptr = 2;
+  if (tdep == NULL || tdep->breakpoint == NULL)
+    {
+      return breakpoint_elf;
+    }
+  return tdep->breakpoint;
+}
+
+/* Allocate and initialize a gdbarch object.  */
+
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xcalloc (1, sizeof (struct gdbarch_tdep));
+  tdep->elf_flags = elf_flags;
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_register_name);
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+
+  /* Passing NULL  values in the following two functions
+     for the time being, to fix later.  */
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* 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, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+
+  /* If we don't pass the option -mint32
+     FIXME: add if else case depending on the option passed,
+     sp that we can have int size as 16 or 32 bits both.  */
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
--- ./gdb_src.orig/gdb/cr16-tdep.h	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.h	2012-10-09 18:48:38.000000000 +0530
@@ -0,0 +1,32 @@
+/* GNU/Linux on  CR16 target support.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.pahatk@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* Target-dependent structure in gdbarch.  */
+
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  /* Breakpoint instruction.  */
+  const gdb_byte *breakpoint;
+};


[-- Attachment #2: cr16_gdb.diff --]
[-- Type: application/octet-stream, Size: 32230 bytes --]

--- ./gdb_src.orig/gdb/configure.tgt	2012-08-02 01:18:44.000000000 +0530
+++ ./gdb_src/gdb/configure.tgt	2012-10-09 19:12:54.000000000 +0530
@@ -116,6 +116,18 @@ bfin-*-*)
 	gdb_sim=../sim/bfin/libsim.a
 	;;
 
+cr16*-*-*linux)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o cr16-linux-tdep.o linux-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
+cr16*-*-*)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
 cris*)
 	# Target: CRIS
 	gdb_target_obs="cris-tdep.o solib-svr4.o"
--- ./gdb_src.orig/gdb/cr16-linux-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-linux-tdep.c	2012-10-09 17:30:21.000000000 +0530
@@ -0,0 +1,102 @@
+/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
+
+   Copyright 2012 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.pahatk@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+#include "elf/cr16.h"
+#include "linux-tdep.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for Linux targets  */
+#define CR16_LINUX_NUM_REGS  21
+
+/* The breakpoint instruction used by uClinux target  */
+static const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  static const char *const reg_names[] = {
+    "r0",
+    "r1",
+    "r2",
+    "r3",
+    "r4",
+    "r5",
+    "r6",
+    "r7",
+    "r8",
+    "r9",
+    "r10",
+    "r11",
+    "r12",
+    "r13",
+    "ra",
+    "psr",
+    "pc",
+    "r0r1_orig",
+    "intbase",
+    "usp",
+    "cfg"
+  };
+
+  return reg_names[regnr];
+}
+
+/* OS specific initialization of gdbarch.  */
+
+static void
+cr16_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  linux_init_abi (info, gdbarch);
+
+  set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
+
+  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
+     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
+     requires external hardware support for breakpoints to work on
+     CR16 target.  Software based breakpoints are implemented in the
+     kernel using excp flg and tested on the SC14452 target.  Use
+     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We 
+     represent the breakpoint in little endian format since CR16
+     supports only little endian.  */
+  tdep->breakpoint = breakpoint_uclinux;
+
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_linux_tdep;
+
+void
+_initialize_cr16_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_cr16, 0, GDB_OSABI_LINUX,
+			  cr16_uclinux_init_abi);
+}
--- ./gdb_src.orig/gdb/cr16-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.c	2012-10-09 18:47:25.000000000 +0530
@@ -0,0 +1,915 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2012 Free Software Foundation, Inc.
+ 
+   Contributed by Kaushik Phatak (kaushik.pahatk@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+   This file is part of GDB.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+#include "linux-tdep.h"
+#include "osabi.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for ELF targets.  */
+#define CR16_NUM_REGS  22
+
+/* The breakpoint instruction used with sim for ELF targets.  */
+static const gdb_byte breakpoint_elf[] = { 0xC8, 0x00 };
+
+/* Data type to store instruction opcodes.  */
+typedef unsigned short wordU;
+
+/* Globals to store opcode related information.  */
+wordU words[3];
+ULONGLONG allWords;
+ins currInsn;
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  static const char *const reg_names[] = {
+    "r0",
+    "r1",
+    "r2",
+    "r3",
+    "r4",
+    "r5",
+    "r6",
+    "r7",
+    "r8",
+    "r9",
+    "r10",
+    "r11",
+    "r12",
+    "r13",
+    "ra",
+    "sp",
+    "pc",
+    "isp",
+    "usp",
+    "intbase",
+    "psr",
+    "cfg"
+  };
+
+  return reg_names[regnr];
+}
+
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note:PC in CR16 is of 24 bits.  */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case CR16_FP_REGNUM:	/*Frame Pointer reg.  */
+    case CR16_SP_REGNUM:	/*Stack Pointer reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+      return builtin_type (gdbarch)->builtin_uint32;
+      break;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+      break;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    default:
+      printf
+	("\nRegister Type not supported\nFunction : cr16_register_type\n");
+      return 0;
+      break;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+ 
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch, value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte buf[6];
+  char insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      /* Read 6 bytes, max 48 bit opcode.  */
+      target_read_memory (pc, buf, 6);
+      words[0] = buf[1] << 8 | buf[0];
+      words[1] = buf[3] << 8 | buf[2];
+      words[2] = buf[5] << 8 | buf[4];
+      allWords =
+	((ULONGLONG) words[0] << 32) + ((unsigned long) words[1] << 16) +
+	words[2];
+
+      /* Find a matching opcode in table.  
+         Nonzero means instruction has a match.  */
+      is_decoded = match_opcode ();
+      make_instruction ();
+      length = currInsn.size;
+      next_pc = pc + length;
+      insn_byte1 = (words[0] >> 8) & 0xFF;
+
+      /* If PUSH, then save RA and other regs.  */
+      if (insn_byte1 == 0x01)
+	{
+	  int r1, r2;
+	  int r;
+	  insn_byte2 = words[0];
+
+	  if (insn_byte2 & 0x80)
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+	  /* Start Register=r1, 3 bit imm count=r2.  */
+	  r1 = insn_byte2 & 0x0F;
+	  r2 = ((insn_byte2 & 0x70) >> 4);
+	  r2 = r2 + r1 + 1;
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+      /* Add constant to SP.  */
+      else if (insn_byte1 == 0x60)
+	{
+	  int rdst;
+	  signed short addend;
+	  insn_byte2 = words[0];
+	  rdst = insn_byte2 & 0x0F;
+	  if (rdst == CR16_SP_REGNUM)
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      /* Check for MOVD insn.  */
+      else if (insn_byte1 == 0x55)
+	{
+	  int rdst, rsrc;
+	  insn_byte2 = words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	{
+	  break;		/* Terminate the prologue scan.  */
+	}
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+
+/* Implement the "skip_prologue" gdbarch method.  */
+
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (!*this_prologue_cache)
+    {
+      CORE_ADDR func_start, stop_addr;
+
+      *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+
+      func_start = get_frame_func (this_frame);
+      stop_addr = get_frame_pc (this_frame);
+
+      /* If we couldn't find any function containing the PC, then
+         just initialize the prologue cache, but don't do anything.  */
+      if (!func_start)
+	stop_addr = func_start;
+
+      cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+    }
+
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+/* Implement the "frame_prev_register" method for unwinding frames.  */
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+  int reg_size = register_size (get_frame_arch (this_frame), regnum);
+  ULONGEST ra_prev;
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA 
+     register, CR16_R13_REGNUM.  So, we need not adjust anything
+     directly.  We will analyze prologue as this RA register is
+     pushed onto stack for further leaf function calls to work.  */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+    {
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+    }
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+    {
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+    }
+}
+
+static const struct frame_unwind cr16_frame_unwind = 
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  ULONGEST pc;
+
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  ULONGEST sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+cr16_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)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments on the stack.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ``arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R12.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u =
+		    extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, as possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* We use different breakpoint instructions for ELF and uClinux.
+     See cr16-linux-tdep.c for more details.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  *lenptr = 2;
+  if (tdep == NULL || tdep->breakpoint == NULL)
+    {
+      return breakpoint_elf;
+    }
+  return tdep->breakpoint;
+}
+
+/* Allocate and initialize a gdbarch object.  */
+
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xcalloc (1, sizeof (struct gdbarch_tdep));
+  tdep->elf_flags = elf_flags;
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_register_name);
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+
+  /* Passing NULL  values in the following two functions
+     for the time being, to fix later.  */
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* 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, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+
+  /* If we don't pass the option -mint32
+     FIXME: add if else case depending on the option passed,
+     sp that we can have int size as 16 or 32 bits both.  */
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
--- ./gdb_src.orig/gdb/cr16-tdep.h	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.h	2012-10-09 18:48:38.000000000 +0530
@@ -0,0 +1,32 @@
+/* GNU/Linux on  CR16 target support.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.pahatk@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* Target-dependent structure in gdbarch.  */
+
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  /* Breakpoint instruction.  */
+  const gdb_byte *breakpoint;
+};

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2012-10-09 15:03   ` Kaushik Phatak
@ 2012-10-22 22:41     ` Joel Brobecker
  2012-10-23 13:03       ` Kaushik Phatak
  0 siblings, 1 reply; 29+ messages in thread
From: Joel Brobecker @ 2012-10-22 22:41 UTC (permalink / raw)
  To: Kaushik Phatak; +Cc: Yao Qi, gdb-patches

> 2012-10-09 Kaushik Phatak  <kaushik.phatak@kpitcummins.com>
> 
> 	gdb/Changelog
> 	* configure.tgt: Handle cr16*-*-*linux and cr16*-*-*.
> 	* cr16-linux-tdep.c: New file.
> 	* cr16-tdep.c: New file.
> 	* cr16-tdep.h: New file.

This looks pretty good. It's nice to see that you're using
prologue-value...

My comments below:

> +static const char *
> +cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
> +{
> +  static const char *const reg_names[] = {

Formatting: Could you move the '{' to the next line, please?

> +  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
> +     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
> +     requires external hardware support for breakpoints to work on
> +     CR16 target.  Software based breakpoints are implemented in the
> +     kernel using excp flg and tested on the SC14452 target.  Use
> +     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We 

Trailing space at the end of this line.  Can you do a pass with your
editor, and make sure that they are all removed?

> --- ./gdb_src.orig/gdb/cr16-tdep.c	1970-01-01 05:30:00.000000000 +0530
> +++ ./gdb_src/gdb/cr16-tdep.c	2012-10-09 18:47:25.000000000 +0530
[...]
> +#include "linux-tdep.h"

Intuitively, I don't think you would need to include this file from
the non-linux tdep, no?

> +/* Data type to store instruction opcodes.  */
> +typedef unsigned short wordU;
> +
> +/* Globals to store opcode related information.  */
> +wordU words[3];
> +ULONGLONG allWords;
> +ins currInsn;

These types of globals are a big no-no, and I don't really understand
how they are being used. Some of them seem to never be set, others
to be set but never read... Can you adjust your code to avoid those
globals?

> +static void
> +cr16_analyze_prologue (CORE_ADDR start_pc,
> +		       CORE_ADDR limit_pc, struct cr16_prologue *result)
> +{
> +  CORE_ADDR pc, next_pc;
> +  gdb_byte buf[6];

Can you move the declaration of this buffer to the scope where
it is used, please? It's clearer that way.

> +  char insn_byte1, insn_byte2;

I think you probably want to use gdb_byte, here.

> +      /* If PUSH, then save RA and other regs.  */
> +      if (insn_byte1 == 0x01)
> +	{
> +	  int r1, r2;
> +	  int r;
> +	  insn_byte2 = words[0];

Empty line between variable declarations and the rest of the code.
There are other locations where I saw the same issue.  Can you do a pass
over those, please?

> +static struct cr16_prologue *
> +cr16_analyze_frame_prologue (struct frame_info *this_frame,
> +			     void **this_prologue_cache)
> +{
> +  if (!*this_prologue_cache)

This is a bit of a nit, and you are welcome to keep the code as is,
but the typical usage in this case is to do:

    if (*this_prologue_cache)
      return *this_prologue_cache;

This allows to have the rest of the code less indented, which is
usually more easily readable.

> +static CORE_ADDR
> +cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
> +{
> +  ULONGEST pc;
> +
> +  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
> +  return pc;
> +}

Just curious: Why not just:

    return frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);

I have no doubt that the compiler is going to remove the local
variable, and so we'll end up with the same code. But then you have
your local variable's type being different from the return value type.

> +
> +/* Implement the "unwind_sp" gdbarch method.  */
> +
> +static CORE_ADDR
> +cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)

Same here.

> +		  u =
> +		    extract_unsigned_integer (arg_bits, arg_size, byte_order);

Nit: I think it's fine to format the entire statement into a single
line. It looks like it just fits 80 chars. Otherwise, i'd format it
like

                u = extract_unsigned_integer (arg_bits, arg_size,
                                              byte_order);


> +  /* If we don't pass the option -mint32
> +     FIXME: add if else case depending on the option passed,
> +     sp that we can have int size as 16 or 32 bits both.  */

Is there any way of handling this fixme easily?


> +/* Implement the "register_name" gdbarch method.  */
> +
> +static const char *
> +cr16_register_name (struct gdbarch *gdbarch, int regnr)
> +{
> +  static const char *const reg_names[] = {

Formatting - same as above.

> +    default:
> +      printf
> +	("\nRegister Type not supported\nFunction : cr16_register_type\n");
> +      return 0;
> +      break;

You cannot do that: We assume that that this function never NULL.
Depending on the reason for not "supporting" certain registers,
you can add a gdb_assert_not_reached if you know you've covered
all registers, or else return any type, like builtin_int32.

-- 
Joel


^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [RFA 3/5] New port: CR16: gdb port
  2012-10-22 22:41     ` Joel Brobecker
@ 2012-10-23 13:03       ` Kaushik Phatak
  2012-10-23 13:55         ` Joel Brobecker
  0 siblings, 1 reply; 29+ messages in thread
From: Kaushik Phatak @ 2012-10-23 13:03 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Yao Qi, gdb-patches

Hi Joel,
Thanks for your detailed review. I will make another pass over my code and
take care of the formatting nits.
To answer some of your questions,

>> These types of globals are a big no-no, Can you adjust your code to avoid
>> those globals?
These globals are actually declared in /opcodes/cr16-dis.c and my earlier
version of this patch had declared them extern here. Converting the disassembler
piece of code would be bit tricky as print_insn_cr16 and print_arg seem to use
these globals directly. Would it be OK just to leave them as extern here with
appropriate comments?

>> > +  ULONGEST pc;
>> > +
>> > +  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
>> > +  return pc;
>> Just curious: Why not just:
>> return frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);

I will make that change for unwind_pc and unwind_sp as well. The locals helped
me debug my code better, but I can remove them now.

>> > +  /* If we don't pass the option -mint32
>> > +     FIXME: add if else case depending on the option passed,
>> Is there any way of handling this fixme easily?
I think I can remove this fixme as the issue is actually at the sim end.
The host side gdb gets correct information about data types directly from
the symbol table. The simulator totally gets lost when -mint32 is passed.

>> you can add a gdb_assert_not_reached if you know you've covered
>> all registers, or else return any type, like builtin_int32.
OK, I think I will return builtin_int32 here as there are some targets with
additional debug registers.

Regards,
Kaushik



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2012-10-23 13:03       ` Kaushik Phatak
@ 2012-10-23 13:55         ` Joel Brobecker
  2012-10-26  5:15           ` Kaushik Phatak
  0 siblings, 1 reply; 29+ messages in thread
From: Joel Brobecker @ 2012-10-23 13:55 UTC (permalink / raw)
  To: Kaushik Phatak; +Cc: Yao Qi, gdb-patches

> These globals are actually declared in /opcodes/cr16-dis.c and my
> earlier version of this patch had declared them extern here.
> Converting the disassembler piece of code would be bit tricky as
> print_insn_cr16 and print_arg seem to use these globals directly.
> Would it be OK just to leave them as extern here with appropriate
> comments?

Can you declare those externs somewhere in opcode instead? That way,
both opcode and GDB would use the same declaration, and that would
ensure consistency.

> I will make that change for unwind_pc and unwind_sp as well. The locals helped
> me debug my code better, but I can remove them now.

You do not have to, if you prefer it the other way. But I would make
sure that the type of the variables match the return type.

> I think I can remove this fixme as the issue is actually at the sim end.
> The host side gdb gets correct information about data types directly from
> the symbol table. The simulator totally gets lost when -mint32 is passed.

Cool :).

-- 
Joel


^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [RFA 3/5] New port: CR16: gdb port
  2012-10-23 13:55         ` Joel Brobecker
@ 2012-10-26  5:15           ` Kaushik Phatak
  2012-11-15 17:43             ` Joel Brobecker
  0 siblings, 1 reply; 29+ messages in thread
From: Kaushik Phatak @ 2012-10-26  5:15 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Yao Qi, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 33804 bytes --]

Hi Joel,

>> Can you declare those externs somewhere in opcode instead?
Yes, taken care of. I have also moved the global declarations from
opcodes/cr16-dis.c as externs into opcode/cr16.h. This was, both cr16-dis.c and
cr16-tdep.c can use these.

>> But I would make sure that the type of the variables match the return type.
OK, I have taken care of this.

Please find below an updated patch for cr16 gdb. I have also attached the same.
Additionally I have also attached the bfd hunk which moves the globals into
externs in the opcodes file. I will submit that to binutils once my gdb port 
gets a go ahead.

Thanks again for taking time to review this port.

Regards,
Kaushik


2012-10-26 Kaushik Phatak  <kaushik.phatak@kpitcummins.com>

	gdb/Changelog
	* configure.tgt: Handle cr16*-*-*linux and cr16*-*-*.
	* cr16-linux-tdep.c: New file.
	* cr16-tdep.c: New file.
	* cr16-tdep.h: New file.
	
--- ./gdb_src.orig/gdb/configure.tgt	2012-08-02 01:18:44.000000000 +0530
+++ ./gdb_src/gdb/configure.tgt	2012-10-23 15:09:24.000000000 +0530
@@ -116,6 +116,18 @@ bfin-*-*)
 	gdb_sim=../sim/bfin/libsim.a
 	;;
 
+cr16*-*-*linux)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o cr16-linux-tdep.o linux-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
+cr16*-*-*)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
 cris*)
 	# Target: CRIS
 	gdb_target_obs="cris-tdep.o solib-svr4.o"
--- ./gdb_src.orig/gdb/cr16-linux-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-linux-tdep.c	2012-10-23 15:22:34.000000000 +0530
@@ -0,0 +1,103 @@
+/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
+
+   Copyright 2012 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+#include "elf/cr16.h"
+#include "linux-tdep.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for Linux targets  */
+#define CR16_LINUX_NUM_REGS  21
+
+/* The breakpoint instruction used by uClinux target  */
+static const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  static const char *const reg_names[] =
+  {
+    "r0",
+    "r1",
+    "r2",
+    "r3",
+    "r4",
+    "r5",
+    "r6",
+    "r7",
+    "r8",
+    "r9",
+    "r10",
+    "r11",
+    "r12",
+    "r13",
+    "ra",
+    "psr",
+    "pc",
+    "r0r1_orig",
+    "intbase",
+    "usp",
+    "cfg"
+  };
+
+  return reg_names[regnr];
+}
+
+/* OS specific initialization of gdbarch.  */
+
+static void
+cr16_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  linux_init_abi (info, gdbarch);
+
+  set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
+
+  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
+     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
+     requires external hardware support for breakpoints to work on
+     CR16 target.  Software based breakpoints are implemented in the
+     kernel using excp flg and tested on the SC14452 target.  Use
+     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We
+     represent the breakpoint in little endian format since CR16
+     supports only little endian.  */
+  tdep->breakpoint = breakpoint_uclinux;
+
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_linux_tdep;
+
+void
+_initialize_cr16_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_cr16, 0, GDB_OSABI_LINUX,
+			  cr16_uclinux_init_abi);
+}
--- ./gdb_src.orig/gdb/cr16-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.c	2012-10-25 10:44:15.000000000 +0530
@@ -0,0 +1,904 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2012 Free Software Foundation, Inc.
+ 
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+   This file is part of GDB.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+#include "osabi.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for ELF targets.  */
+#define CR16_NUM_REGS  22
+
+/* The breakpoint instruction used with sim for ELF targets.  */
+static const gdb_byte breakpoint_elf[] = { 0xC8, 0x00 };
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  static const char *const reg_names[] =
+  {
+    "r0",
+    "r1",
+    "r2",
+    "r3",
+    "r4",
+    "r5",
+    "r6",
+    "r7",
+    "r8",
+    "r9",
+    "r10",
+    "r11",
+    "r12",
+    "r13",
+    "ra",
+    "sp",
+    "pc",
+    "isp",
+    "usp",
+    "intbase",
+    "psr",
+    "cfg"
+  };
+
+  return reg_names[regnr];
+}
+
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note:PC in CR16 is of 24 bits.  */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case CR16_FP_REGNUM:	/*Frame Pointer reg.  */
+    case CR16_SP_REGNUM:	/*Stack Pointer reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+      return builtin_type (gdbarch)->builtin_uint32;
+      break;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+      break;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    default:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+ 
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch, value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      gdb_byte buf[6];
+
+      /* Read 6 bytes, max 48 bit opcode.  */
+      target_read_memory (pc, buf, 6);
+      words[0] = buf[1] << 8 | buf[0];
+      words[1] = buf[3] << 8 | buf[2];
+      words[2] = buf[5] << 8 | buf[4];
+      allWords =
+	((ULONGLONG) words[0] << 32) + ((unsigned long) words[1] << 16) +
+	words[2];
+
+      /* Find a matching opcode in table.
+         Nonzero means instruction has a match.  */
+      is_decoded = match_opcode ();
+      make_instruction ();
+      length = currInsn.size;
+      next_pc = pc + length;
+      insn_byte1 = (words[0] >> 8) & 0xFF;
+
+      /* If PUSH, then save RA and other regs.  */
+      if (insn_byte1 == 0x01)
+	{
+	  int r1, r2;
+	  int r;
+
+	  insn_byte2 = words[0];
+
+	  if (insn_byte2 & 0x80)
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+	  /* Start Register=r1, 3 bit imm count=r2.  */
+	  r1 = insn_byte2 & 0x0F;
+	  r2 = ((insn_byte2 & 0x70) >> 4);
+	  r2 = r2 + r1 + 1;
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+      /* Add constant to SP.  */
+      else if (insn_byte1 == 0x60)
+	{
+	  int rdst;
+	  signed short addend;
+
+	  insn_byte2 = words[0];
+	  rdst = insn_byte2 & 0x0F;
+	  if (rdst == CR16_SP_REGNUM)
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      /* Check for MOVD insn.  */
+      else if (insn_byte1 == 0x55)
+	{
+	  int rdst, rsrc;
+
+	  insn_byte2 = words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	{
+	  break;		/* Terminate the prologue scan.  */
+	}
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+
+/* Implement the "skip_prologue" gdbarch method.  */
+
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (*this_prologue_cache)
+    return *this_prologue_cache;
+
+  CORE_ADDR func_start, stop_addr;
+
+  *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+  func_start = get_frame_func (this_frame);
+  stop_addr = get_frame_pc (this_frame);
+
+ /* If we couldn't find any function containing the PC, then
+     just initialize the prologue cache, but don't do anything.  */
+  if (!func_start)
+    stop_addr = func_start;
+
+  cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+ 
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+/* Implement the "frame_prev_register" method for unwinding frames.  */
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+  int reg_size = register_size (get_frame_arch (this_frame), regnum);
+  ULONGEST ra_prev;
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA
+     register, CR16_R13_REGNUM.  So, we need not adjust anything
+     directly.  We will analyze prologue as this RA register is
+     pushed onto stack for further leaf function calls to work.  */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+    {
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+    }
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+    {
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+    }
+}
+
+static const struct frame_unwind cr16_frame_unwind = 
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR pc;
+  
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+cr16_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)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments on the stack.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ``arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R12.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u = extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, as possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* We use different breakpoint instructions for ELF and uClinux.
+     See cr16-linux-tdep.c for more details.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  *lenptr = 2;
+  if (tdep == NULL || tdep->breakpoint == NULL)
+    {
+      return breakpoint_elf;
+    }
+  return tdep->breakpoint;
+}
+
+/* Allocate and initialize a gdbarch object.  */
+
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xcalloc (1, sizeof (struct gdbarch_tdep));
+  tdep->elf_flags = elf_flags;
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_register_name);
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+
+  /* Passing NULL  values in the following two functions
+     for the time being, to fix later.  */
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* 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, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
--- ./gdb_src.orig/gdb/cr16-tdep.h	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.h	2012-10-23 15:22:53.000000000 +0530
@@ -0,0 +1,32 @@
+/* GNU/Linux on  CR16 target support.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* Target-dependent structure in gdbarch.  */
+
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  /* Breakpoint instruction.  */
+  const gdb_byte *breakpoint;
+};


[-- Attachment #2: cr16_gdb.diff --]
[-- Type: application/octet-stream, Size: 31806 bytes --]

--- ./gdb_src.orig/gdb/configure.tgt	2012-08-02 01:18:44.000000000 +0530
+++ ./gdb_src/gdb/configure.tgt	2012-10-23 15:09:24.000000000 +0530
@@ -116,6 +116,18 @@ bfin-*-*)
 	gdb_sim=../sim/bfin/libsim.a
 	;;
 
+cr16*-*-*linux)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o cr16-linux-tdep.o linux-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
+cr16*-*-*)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
 cris*)
 	# Target: CRIS
 	gdb_target_obs="cris-tdep.o solib-svr4.o"
--- ./gdb_src.orig/gdb/cr16-linux-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-linux-tdep.c	2012-10-23 15:22:34.000000000 +0530
@@ -0,0 +1,103 @@
+/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
+
+   Copyright 2012 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+#include "elf/cr16.h"
+#include "linux-tdep.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for Linux targets  */
+#define CR16_LINUX_NUM_REGS  21
+
+/* The breakpoint instruction used by uClinux target  */
+static const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  static const char *const reg_names[] =
+  {
+    "r0",
+    "r1",
+    "r2",
+    "r3",
+    "r4",
+    "r5",
+    "r6",
+    "r7",
+    "r8",
+    "r9",
+    "r10",
+    "r11",
+    "r12",
+    "r13",
+    "ra",
+    "psr",
+    "pc",
+    "r0r1_orig",
+    "intbase",
+    "usp",
+    "cfg"
+  };
+
+  return reg_names[regnr];
+}
+
+/* OS specific initialization of gdbarch.  */
+
+static void
+cr16_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  linux_init_abi (info, gdbarch);
+
+  set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
+
+  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
+     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
+     requires external hardware support for breakpoints to work on
+     CR16 target.  Software based breakpoints are implemented in the
+     kernel using excp flg and tested on the SC14452 target.  Use
+     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We
+     represent the breakpoint in little endian format since CR16
+     supports only little endian.  */
+  tdep->breakpoint = breakpoint_uclinux;
+
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_linux_tdep;
+
+void
+_initialize_cr16_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_cr16, 0, GDB_OSABI_LINUX,
+			  cr16_uclinux_init_abi);
+}
--- ./gdb_src.orig/gdb/cr16-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.c	2012-10-25 10:44:15.000000000 +0530
@@ -0,0 +1,904 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2012 Free Software Foundation, Inc.
+ 
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+   This file is part of GDB.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+#include "osabi.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for ELF targets.  */
+#define CR16_NUM_REGS  22
+
+/* The breakpoint instruction used with sim for ELF targets.  */
+static const gdb_byte breakpoint_elf[] = { 0xC8, 0x00 };
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  static const char *const reg_names[] =
+  {
+    "r0",
+    "r1",
+    "r2",
+    "r3",
+    "r4",
+    "r5",
+    "r6",
+    "r7",
+    "r8",
+    "r9",
+    "r10",
+    "r11",
+    "r12",
+    "r13",
+    "ra",
+    "sp",
+    "pc",
+    "isp",
+    "usp",
+    "intbase",
+    "psr",
+    "cfg"
+  };
+
+  return reg_names[regnr];
+}
+
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note:PC in CR16 is of 24 bits.  */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case CR16_FP_REGNUM:	/*Frame Pointer reg.  */
+    case CR16_SP_REGNUM:	/*Stack Pointer reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+      return builtin_type (gdbarch)->builtin_uint32;
+      break;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+      break;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    default:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+ 
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch, value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      gdb_byte buf[6];
+
+      /* Read 6 bytes, max 48 bit opcode.  */
+      target_read_memory (pc, buf, 6);
+      words[0] = buf[1] << 8 | buf[0];
+      words[1] = buf[3] << 8 | buf[2];
+      words[2] = buf[5] << 8 | buf[4];
+      allWords =
+	((ULONGLONG) words[0] << 32) + ((unsigned long) words[1] << 16) +
+	words[2];
+
+      /* Find a matching opcode in table.
+         Nonzero means instruction has a match.  */
+      is_decoded = match_opcode ();
+      make_instruction ();
+      length = currInsn.size;
+      next_pc = pc + length;
+      insn_byte1 = (words[0] >> 8) & 0xFF;
+
+      /* If PUSH, then save RA and other regs.  */
+      if (insn_byte1 == 0x01)
+	{
+	  int r1, r2;
+	  int r;
+
+	  insn_byte2 = words[0];
+
+	  if (insn_byte2 & 0x80)
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+	  /* Start Register=r1, 3 bit imm count=r2.  */
+	  r1 = insn_byte2 & 0x0F;
+	  r2 = ((insn_byte2 & 0x70) >> 4);
+	  r2 = r2 + r1 + 1;
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+      /* Add constant to SP.  */
+      else if (insn_byte1 == 0x60)
+	{
+	  int rdst;
+	  signed short addend;
+
+	  insn_byte2 = words[0];
+	  rdst = insn_byte2 & 0x0F;
+	  if (rdst == CR16_SP_REGNUM)
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      /* Check for MOVD insn.  */
+      else if (insn_byte1 == 0x55)
+	{
+	  int rdst, rsrc;
+
+	  insn_byte2 = words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	{
+	  break;		/* Terminate the prologue scan.  */
+	}
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+
+/* Implement the "skip_prologue" gdbarch method.  */
+
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (*this_prologue_cache)
+    return *this_prologue_cache;
+
+  CORE_ADDR func_start, stop_addr;
+
+  *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+  func_start = get_frame_func (this_frame);
+  stop_addr = get_frame_pc (this_frame);
+
+ /* If we couldn't find any function containing the PC, then
+     just initialize the prologue cache, but don't do anything.  */
+  if (!func_start)
+    stop_addr = func_start;
+
+  cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+ 
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+/* Implement the "frame_prev_register" method for unwinding frames.  */
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+  int reg_size = register_size (get_frame_arch (this_frame), regnum);
+  ULONGEST ra_prev;
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA
+     register, CR16_R13_REGNUM.  So, we need not adjust anything
+     directly.  We will analyze prologue as this RA register is
+     pushed onto stack for further leaf function calls to work.  */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+    {
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+    }
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+    {
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+    }
+}
+
+static const struct frame_unwind cr16_frame_unwind = 
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR pc;
+  
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+cr16_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)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments on the stack.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ``arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R12.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u = extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, as possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* We use different breakpoint instructions for ELF and uClinux.
+     See cr16-linux-tdep.c for more details.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  *lenptr = 2;
+  if (tdep == NULL || tdep->breakpoint == NULL)
+    {
+      return breakpoint_elf;
+    }
+  return tdep->breakpoint;
+}
+
+/* Allocate and initialize a gdbarch object.  */
+
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xcalloc (1, sizeof (struct gdbarch_tdep));
+  tdep->elf_flags = elf_flags;
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_register_name);
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+
+  /* Passing NULL  values in the following two functions
+     for the time being, to fix later.  */
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* 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, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
--- ./gdb_src.orig/gdb/cr16-tdep.h	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.h	2012-10-23 15:22:53.000000000 +0530
@@ -0,0 +1,32 @@
+/* GNU/Linux on  CR16 target support.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* Target-dependent structure in gdbarch.  */
+
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  /* Breakpoint instruction.  */
+  const gdb_byte *breakpoint;
+};

[-- Attachment #3: cr16_bfd.diff --]
[-- Type: application/octet-stream, Size: 1841 bytes --]

diff -uprN ./gdb_src.orig/opcodes/cr16-dis.c ./gdb_src/opcodes/cr16-dis.c
--- ./gdb_src.orig/opcodes/cr16-dis.c	2012-05-17 20:43:25.000000000 +0530
+++ ./gdb_src/opcodes/cr16-dis.c	2012-10-25 09:45:55.000000000 +0530
@@ -36,9 +36,6 @@
 /* Set Bit Mask - a mask to set all bits starting from offset 'offs'.  */
 #define SBM(offs)  ((((1 << (32 - offs)) -1) << (offs)))
 
-typedef unsigned long dwordU;
-typedef unsigned short wordU;
-
 typedef struct
 {
   dwordU val;
@@ -317,7 +314,7 @@ build_mask (void)
 
 /* Search for a matching opcode. Return 1 for success, 0 for failure.  */
 
-static int
+int
 match_opcode (void)
 {
   unsigned long mask;
@@ -734,7 +731,7 @@ print_arguments (ins *currentInsn, bfd_v
 
 /* Build the instruction's arguments.  */
 
-static void
+void
 make_instruction (void)
 {
   int i;
--- ./gdb_src.orig/bfd/config.bfd	2012-05-15 18:25:34.000000000 +0530
+++ ./gdb_src/bfd/config.bfd	2012-10-23 15:09:08.000000000 +0530
@@ -345,6 +345,11 @@ case "${targ}" in
     targ_underscore=yes
     ;;
 
+  cr16*-*-uclinux*)
+    targ_defvec=bfd_elf32_cr16_vec
+    targ_underscore=yes
+    ;;
+
   cr16c-*-elf*)
     targ_defvec=bfd_elf32_cr16c_vec
     targ_underscore=yes
--- ./gdb_src.orig/include/opcode/cr16.h	2010-04-15 15:56:09.000000000 +0530
+++ ./gdb_src/include/opcode/cr16.h	2012-10-25 10:17:02.000000000 +0530
@@ -435,4 +435,17 @@ extern const inst *instruction;
 typedef long long int LONGLONG;
 typedef unsigned long long ULONGLONG;
 
+/* Data types for opcode handling.  */
+typedef unsigned long dwordU;
+typedef unsigned short wordU;
+
+/* Globals to store opcode data and build the intruction.  */
+extern wordU words[3];
+extern ULONGLONG allWords;
+extern ins currInsn;
+
+/* Prototypes for function in cr16-dis.c  */
+void make_instruction (void);
+int match_opcode (void);
+
 #endif /* _CR16_H_ */

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2012-10-26  5:15           ` Kaushik Phatak
@ 2012-11-15 17:43             ` Joel Brobecker
  2012-11-20 13:01               ` Kaushik Phatak
  0 siblings, 1 reply; 29+ messages in thread
From: Joel Brobecker @ 2012-11-15 17:43 UTC (permalink / raw)
  To: Kaushik Phatak; +Cc: Yao Qi, gdb-patches

> Additionally I have also attached the bfd hunk which moves the globals into
> externs in the opcodes file. I will submit that to binutils once my gdb port 
> gets a go ahead.

Both bfd and opcode bits needs to be approved before the GDB part
can go ahead.

> 2012-10-26 Kaushik Phatak  <kaushik.phatak@kpitcummins.com>
> 
> 	gdb/Changelog
> 	* configure.tgt: Handle cr16*-*-*linux and cr16*-*-*.
> 	* cr16-linux-tdep.c: New file.
> 	* cr16-tdep.c: New file.
> 	* cr16-tdep.h: New file.

Below are my comments. They are mostly minor, so we should be pretty
close to approval.

The opcode and bfd bits are maintained by the binutils project,
however, and will need to be approved there, and then checked in,
before this patch can proceed.

> +/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
> +
> +   Copyright 2012 Free Software Foundation, Inc.

Small nit: Can you add the "(C)" after Copyright, please?

[in cr16-linux-tdep.c]
> +#include "solib-svr4.h"

Is this include really needed. This would be a little surprising
considering that solib-svr4.o is not part of the gdb_target_obs.

> +static const char *
> +cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
> +{
> +  static const char *const reg_names[] =
> +  {
[...]
> +  };
> +
> +  return reg_names[regnr];

Would you mind adding an assertion that REGNR is within acceptable
bounds, please? This will trigger an internal error instead of a
out-of-bound buffer access...

You could also possibly add an assertion that the number of elements
in your array is equal to CR16_LINUX_NUM_REGS, if that makes sense.

One other possible suggestion is to move the array outside of the
function, and to use a static assertion. The advantage, I believe,
is that the assertion will be computed by the compiler, and fail
at build time, rather than run time, if something every goes hinky.

> --- ./gdb_src.orig/gdb/cr16-tdep.c	1970-01-01 05:30:00.000000000 +0530
> +++ ./gdb_src/gdb/cr16-tdep.c	2012-10-25 10:44:15.000000000 +0530
> +static const char *
> +cr16_register_name (struct gdbarch *gdbarch, int regnr)
> +{
> +  static const char *const reg_names[] =
> +  {
[...]
> +  };
> +
> +  return reg_names[regnr];

Same as above.

> +}
> +
> +
> +/* Implement the "register_type" gdbarch method.  */
> +
> +static struct type *
> +cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
> +{
> +  switch (reg_nr)
> +    {
> +    case CR16_PC_REGNUM:	/* Note:PC in CR16 is of 24 bits.  */
                                   Can you add a space after the colon?

> +    case CR16_FP_REGNUM:	/*Frame Pointer reg.  */
> +    case CR16_SP_REGNUM:	/*Stack Pointer reg.  */

Can you add a space after "/*", please?  Although, FP an SP are so
common, the comment is hardly useful - but not harmful.

> +    case SIM_CR16_ISP_REGNUM:
> +    case SIM_CR16_USP_REGNUM:
> +    case SIM_CR16_INTBASE_REGNUM:
> +      return builtin_type (gdbarch)->builtin_int32;
> +      break;
> +
> +    case SIM_CR16_PSR_REGNUM:
> +    case SIM_CR16_CFG_REGNUM:
> +      return builtin_type (gdbarch)->builtin_uint32;
> +      break;

Why not merge all blocks that return builtin_int32? Same for any
other registers that return the same type (maybe less of an obvious
suggestion).  This are just suggestions, so please do not feel
obigated to follow them.

> +      allWords =
> +	((ULONGLONG) words[0] << 32) + ((unsigned long) words[1] << 16) +
> +	words[2];

Can you please void using the mixed-cap style for variables? For
instance, use all_words, not allWords.

Also, when breaking lines at a binary operator, you should break
before the operator, not after.

I think I understand the reason for the casts/promotion, but can we
cast to the same type for both pieces?

For long lines like these, the GNU Coding Standards require us to
enclose the rhs expression into parentheses. The parentheses are
superfluous, but help code formatters (or your editor's formatter).
Thus:

  all_words = (((ULONGLONG) words[0] << 32)
               + ((ULONGLONG) words[1] << 16)
               + words[2])

> +      else
> +	{
> +	  break;		/* Terminate the prologue scan.  */
> +	}

Can you remove the extra braces? They are unnecessary, and GDB's style
is to not use them in that case. Note that they would be used if
you had to add a a comment. Thus...

    else
      break;  /* Terminate.  */

... but also ...

    else
      {
        /* Terminate the loop because ...  */
        break;
      }

> +static struct value *
> +cr16_frame_prev_register (struct frame_info *this_frame,
> +			  void **this_prologue_cache, int regnum)
> +{
> +  struct cr16_prologue *p =
> +    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
> +  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
> +  int reg_size = register_size (get_frame_arch (this_frame), regnum);
> +  ULONGEST ra_prev;

It looks like ra_prev could be declared in the only else if block where
it is actually used. And reg_size appears to be unused.

> +  /* If prologue analysis says we saved this register somewhere,
> +     return a description of the stack slot holding it.  */
> +  else if (p->reg_offset[regnum] != 1)
> +    {
> +      return frame_unwind_got_memory (this_frame, regnum,
> +				      frame_base + p->reg_offset[regnum]);
> +    }
> +
> +  /* Otherwise, presume we haven't changed the value of this
> +     register, and get it from the next frame.  */
> +  else
> +    {
> +      return frame_unwind_got_register (this_frame, regnum, regnum);
> +    }

Can you also remove the unnecessary curly braces above, please?

> +  CORE_ADDR pc;
> +  

Trailing spaces here...

> +static const gdb_byte *
> +cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
> +			 int *lenptr)
[...]
> +  if (tdep == NULL || tdep->breakpoint == NULL)
> +    {
> +      return breakpoint_elf;
> +    }

Unnecessary braces...

> +  /* Passing NULL  values in the following two functions
> +     for the time being, to fix later.  */
> +  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
> +  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
> +  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);

I don't understand the comment...

> +  /* 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.  */

The generic_save_dummy_frame_tos function was deleted in 2004...
I suspect you copy/pasted this code from somewhere else.
Fortunately, I think that's easily fixed, as I don't see
the real benefit of the second sentence. The first one can be
used as visual cue that the frame ID code starts there, but
the second can just be deleted entirely.

> --- ./gdb_src.orig/gdb/configure.tgt	2012-08-02 01:18:44.000000000 +0530
> +++ ./gdb_src/gdb/configure.tgt	2012-10-23 15:09:24.000000000 +0530
> --- ./gdb_src.orig/gdb/cr16-linux-tdep.c	1970-01-01 05:30:00.000000000 +0530
> +++ ./gdb_src/gdb/cr16-linux-tdep.c	2012-10-23 15:22:34.000000000 +0530
> --- ./gdb_src.orig/gdb/cr16-tdep.c	1970-01-01 05:30:00.000000000 +0530
> +++ ./gdb_src/gdb/cr16-tdep.c	2012-10-25 10:44:15.000000000 +0530
> --- ./gdb_src.orig/gdb/cr16-tdep.h	1970-01-01 05:30:00.000000000 +0530
> +++ ./gdb_src/gdb/cr16-tdep.h	2012-10-23 15:22:53.000000000 +0530

? Looks like you have all these files twice in the patch you sent?
I'll assume a pilot error an not review the second instances.

-- 
Joel


^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [RFA 3/5] New port: CR16: gdb port
  2012-11-15 17:43             ` Joel Brobecker
@ 2012-11-20 13:01               ` Kaushik Phatak
  2012-11-22 17:50                 ` Joel Brobecker
  0 siblings, 1 reply; 29+ messages in thread
From: Kaushik Phatak @ 2012-11-20 13:01 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Yao Qi, gdb-patches

Hi Joel,
Thanks for another round of detailed review. I have tried to incorporate as 
much of this review in the attached version of this patch.
Please see below my comments and the updated cr16 gdb patch. I have not attached
the bfd part as this is unchanged as of now.

> Both bfd and opcode bits needs to be approved before the GDB part
> can go ahead.
Ok, understood. Once I clear up couple of points related to bfd functions
used in this port, I will resubmit it to binutils for approval.

> +#include "solib-svr4.h" Is this include really needed
Removed this from cr16-linux-tdep.c and cr16-tdep.c.

> return reg_names[regnr];
> Would you mind adding an assertion that REGNR is 
Added gdb_assert inside the register_name function.

> move the array outside of the function, and to use a static assertion.
Moved the array outside and added static_gdb_assert to both my files to check
the array using ARRAY_SIZE macro.

> +    case SIM_CR16_CFG_REGNUM:
> +      return builtin_type (gdbarch)->builtin_uint32;
> +      break;
> Why not merge all blocks that return builtin_int32?
Yes, that would make it little more cleaner. Have merged them as suggested.

> +      allWords =
> Can you please void using the mixed-cap style for variables?
This variable along with currInsn suffer from the same problem. However, they
have been borrowed from existing code from opcodes/cr16-dis.c
May I leave them here as is for now as it is used at several places in cr16-dis.c?

> > +  ULONGEST ra_prev;
> It looks like ra_prev could be declared in the only else if block where
> it is actually used.
Moved this declaration inside the else if block.

> And reg_size appears to be unused.
Removed this line of code. I had borrowed it from Renesas RX port and it
seems to be unused there as well,
http://sourceware.org/ml/gdb-patches/2009-12/msg00038.html

> I don't understand the comment...
Removed this comment, was added at very primitive stage of the port. Not required 
now.

>> +     PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos.  */
> The generic_save_dummy_frame_tos function was deleted in 2004...
Yes, this part was copy pasted from elsewhere. I have removed it in this version.

> add the "(C)" after Copyright
> /* Note:PC Can you add a space after the colon?
> Can you add a space after "/*", 
> you should break before the operator, not after.
> Can you remove the extra braces?
> Can you also remove the unnecessary curly braces above, please?
> Trailing spaces here...
> Unnecessary braces...
Fixed all the formatting related comments mentioned above. 
I should have caught few of them myself, but thanks.

> ? Looks like you have all these files twice in the patch you sent?
> I'll assume a pilot error an not review the second instances.
I am quite sure I had extracted the patch only once and attached it as is. 
Anyway, thanks again for spending time on this.

Regards,
Kaushik

---

2012-11-20 Kaushik Phatak  <kaushik.phatak@kpitcummins.com>

	gdb/Changelog
	* configure.tgt: Handle cr16*-*-*linux and cr16*-*-*.
	* cr16-linux-tdep.c: New file.
	* cr16-tdep.c: New file.
	* cr16-tdep.h: New file.
	
--- ./gdb_src.orig/gdb/configure.tgt	2012-08-02 01:18:44.000000000 +0530
+++ ./gdb_src/gdb/configure.tgt	2012-10-23 15:09:24.000000000 +0530
@@ -116,6 +116,18 @@ bfin-*-*)
 	gdb_sim=../sim/bfin/libsim.a
 	;;
 
+cr16*-*-*linux)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o cr16-linux-tdep.o linux-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
+cr16*-*-*)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
 cris*)
 	# Target: CRIS
 	gdb_target_obs="cris-tdep.o solib-svr4.o"
--- ./gdb_src.orig/gdb/cr16-linux-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-linux-tdep.c	2012-11-20 15:19:48.000000000 +0530
@@ -0,0 +1,108 @@
+/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
+
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+#include "elf/cr16.h"
+#include "linux-tdep.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for Linux targets  */
+#define CR16_LINUX_NUM_REGS  21
+
+/* The breakpoint instruction used by uClinux target  */
+static const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };
+
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "psr",
+  "pc",
+  "r0r1_orig",
+  "intbase",
+  "usp",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_LINUX_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_LINUX_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* OS specific initialization of gdbarch.  */
+
+static void
+cr16_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  linux_init_abi (info, gdbarch);
+
+  set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
+
+  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
+     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
+     requires external hardware support for breakpoints to work on
+     CR16 target.  Software based breakpoints are implemented in the
+     kernel using excp flg and tested on the SC14452 target.  Use
+     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We
+     represent the breakpoint in little endian format since CR16
+     supports only little endian.  */
+  tdep->breakpoint = breakpoint_uclinux;
+
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_linux_tdep;
+
+void
+_initialize_cr16_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_cr16, 0, GDB_OSABI_LINUX,
+			  cr16_uclinux_init_abi);
+}
--- ./gdb_src.orig/gdb/cr16-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.c	2012-11-20 15:19:40.000000000 +0530
@@ -0,0 +1,894 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2012 Free Software Foundation, Inc.
+ 
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+   This file is part of GDB.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+#include "osabi.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for ELF targets.  */
+#define CR16_NUM_REGS  22
+
+/* The breakpoint instruction used with sim for ELF targets.  */
+static const gdb_byte breakpoint_elf[] = { 0xC8, 0x00 };
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Hardware register name declaration.  */
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "sp",
+  "pc",
+  "isp",
+  "usp",
+  "intbase",
+  "psr",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note: PC in CR16 is of 24 bits.  */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case CR16_FP_REGNUM:	/* Frame Pointer reg.  */
+    case CR16_SP_REGNUM:	/* Stack Pointer reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+      break;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    default:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch, value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      gdb_byte buf[6];
+
+      /* Read 6 bytes, max 48 bit opcode.  */
+      target_read_memory (pc, buf, 6);
+      words[0] = buf[1] << 8 | buf[0];
+      words[1] = buf[3] << 8 | buf[2];
+      words[2] = buf[5] << 8 | buf[4];
+      allWords = (((ULONGLONG) words[0] << 32)
+		   + ((ULONGLONG) words[1] << 16)
+		   + words[2]);
+
+      /* Find a matching opcode in table.
+         Nonzero means instruction has a match.  */
+      is_decoded = match_opcode ();
+      make_instruction ();
+      length = currInsn.size;
+      next_pc = pc + length;
+      insn_byte1 = (words[0] >> 8) & 0xFF;
+
+      /* If PUSH, then save RA and other regs.  */
+      if (insn_byte1 == 0x01)
+	{
+	  int r1, r2;
+	  int r;
+
+	  insn_byte2 = words[0];
+
+	  if (insn_byte2 & 0x80)
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+	  /* Start Register=r1, 3 bit imm count=r2.  */
+	  r1 = insn_byte2 & 0x0F;
+	  r2 = ((insn_byte2 & 0x70) >> 4);
+	  r2 = r2 + r1 + 1;
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+      /* Add constant to SP.  */
+      else if (insn_byte1 == 0x60)
+	{
+	  int rdst;
+	  signed short addend;
+
+	  insn_byte2 = words[0];
+	  rdst = insn_byte2 & 0x0F;
+	  if (rdst == CR16_SP_REGNUM)
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      /* Check for MOVD insn.  */
+      else if (insn_byte1 == 0x55)
+	{
+	  int rdst, rsrc;
+
+	  insn_byte2 = words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	break;		/* Terminate the prologue scan.  */
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+
+/* Implement the "skip_prologue" gdbarch method.  */
+
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (*this_prologue_cache)
+    return *this_prologue_cache;
+
+  CORE_ADDR func_start, stop_addr;
+
+  *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+  func_start = get_frame_func (this_frame);
+  stop_addr = get_frame_pc (this_frame);
+
+ /* If we couldn't find any function containing the PC, then
+     just initialize the prologue cache, but don't do anything.  */
+  if (!func_start)
+    stop_addr = func_start;
+
+  cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+/* Implement the "frame_prev_register" method for unwinding frames.  */
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA
+     register, CR16_R13_REGNUM.  So, we need not adjust anything
+     directly.  We will analyze prologue as this RA register is
+     pushed onto stack for further leaf function calls to work.  */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ULONGEST ra_prev;
+
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+}
+
+static const struct frame_unwind cr16_frame_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR pc;
+
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+cr16_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)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments on the stack.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ``arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R12.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u = extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, as possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* We use different breakpoint instructions for ELF and uClinux.
+     See cr16-linux-tdep.c for more details.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  *lenptr = 2;
+  if (tdep == NULL || tdep->breakpoint == NULL)
+    return breakpoint_elf;
+
+  return tdep->breakpoint;
+}
+
+/* Allocate and initialize a gdbarch object.  */
+
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xcalloc (1, sizeof (struct gdbarch_tdep));
+  tdep->elf_flags = elf_flags;
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_register_name);
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* Methods for saving / extracting a dummy frame's ID.  */
+  set_gdbarch_dummy_id (gdbarch, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
--- ./gdb_src.orig/gdb/cr16-tdep.h	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.h	2012-11-16 10:04:08.000000000 +0530
@@ -0,0 +1,32 @@
+/* GNU/Linux on  CR16 target support.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* Target-dependent structure in gdbarch.  */
+
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  /* Breakpoint instruction.  */
+  const gdb_byte *breakpoint;
+};	


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2012-11-20 13:01               ` Kaushik Phatak
@ 2012-11-22 17:50                 ` Joel Brobecker
  2013-01-08 10:02                   ` Kaushik Phatak
  2013-01-15  9:31                   ` Kaushik Phatak
  0 siblings, 2 replies; 29+ messages in thread
From: Joel Brobecker @ 2012-11-22 17:50 UTC (permalink / raw)
  To: Kaushik Phatak; +Cc: Yao Qi, gdb-patches

> > +      allWords =
> > Can you please void using the mixed-cap style for variables?
> This variable along with currInsn suffer from the same problem. However, they
> have been borrowed from existing code from opcodes/cr16-dis.c
> May I leave them here as is for now as it is used at several places in cr16-dis.c?

Yes. I thought it was a variable declared inside GDB. This is fine.

> 2012-11-20 Kaushik Phatak  <kaushik.phatak@kpitcummins.com>
> 
> 	gdb/Changelog
> 	* configure.tgt: Handle cr16*-*-*linux and cr16*-*-*.
> 	* cr16-linux-tdep.c: New file.
> 	* cr16-tdep.c: New file.
> 	* cr16-tdep.h: New file.

A couple of very very minor nits. Pre-approved with the changes
requested below. Once you get approval for the BFD bits, you may
commit this patch. When you do, can you send us a notification,
as well as a copy of the patch that you commit (because it is
going to be different from the one posted here).

> +  if (p->has_frame_ptr)
> +    {
> +      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
> +      return fp - p->frame_ptr_offset;
> +    }
> +  else
> +    {
> +      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
> +      return sp - p->frame_size;
> +    }

Missing empty line after variable declaration in both blocks.

> +};	

Can you remov the trailing spaces?

Thank you,
-- 
Joel


^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [RFA 3/5] New port: CR16: gdb port
  2012-11-22 17:50                 ` Joel Brobecker
@ 2013-01-08 10:02                   ` Kaushik Phatak
  2013-01-15  9:31                   ` Kaushik Phatak
  1 sibling, 0 replies; 29+ messages in thread
From: Kaushik Phatak @ 2013-01-08 10:02 UTC (permalink / raw)
  To: Joel Brobecker
  Cc: gdb-patches, binutils, Pedro Alves, Yao Qi, nick clifton, Tom Tromey

[-- Attachment #1: Type: text/plain, Size: 34758 bytes --]

Hi Joel,
Thanks for your review and helpful feedback on this port.

> A couple of very very minor nits. Pre-approved with the changes
> requested below. Once you get approval for the BFD bits, you may
> commit this patch.

The BFD related changes have been approved and checked in,
http://sourceware.org/ml/gdb-patches/2013-01/msg00105.html

The exported names have been prefixed by 'cr16_' as requested by Pedro and Tom.
These changes are also reflected in cr16-tdep.c which uses these variables
and functions.
The below patch is updated from the last post as below,
- Fixed the requested formatting bits
- Re-based it against the latest snapshot, gdb-7.5.50.20130108.
- Use the new prefixed names for exported variables and functions
- Set the Copyright year to 2013

The only part which is still under the scanner is my gdbserver port. 
Pedro had some concerns about my usage of pseudo registers in this 
port in 'gdb/regformats/reg-cr16.dat',
http://sourceware.org/ml/gdb-patches/2012-12/msg00513.html

I have tried to provide my justifications here,
http://sourceware.org/ml/gdb-patches/2012-12/msg00832.html

If Pedro is happy, I may not need to make further changes to the below 
host side GDB patch.

Please let me know if the below patch (also attached) can be committed.
I do not have check-in rights here.

Thanks & Best Regards,
Kaushik

2013-01-08 Kaushik Phatak  <kaushik.phatak@kpitcummins.com>

	gdb/Changelog
	* configure.tgt: Handle cr16*-*-*linux and cr16*-*-*.
	* cr16-linux-tdep.c: New file.
	* cr16-tdep.c: New file.
	* cr16-tdep.h: New file.

diff -uprN ./gdb_src.orig/gdb/configure.tgt ./gdb_src/gdb/configure.tgt
--- ./gdb_src.orig/gdb/configure.tgt	2012-12-18 20:22:58.000000000 +0530
+++ ./gdb_src/gdb/configure.tgt	2013-01-08 12:56:31.000000000 +0530
@@ -116,6 +116,18 @@ bfin-*-*)
 	gdb_sim=../sim/bfin/libsim.a
 	;;
 
+cr16*-*-*linux)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o cr16-linux-tdep.o linux-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
+cr16*-*-*)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
 cris*)
 	# Target: CRIS
 	gdb_target_obs="cris-tdep.o solib-svr4.o"
diff -uprN ./gdb_src.orig/gdb/cr16-linux-tdep.c ./gdb_src/gdb/cr16-linux-tdep.c
--- ./gdb_src.orig/gdb/cr16-linux-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-linux-tdep.c	2013-01-08 12:59:27.000000000 +0530
@@ -0,0 +1,107 @@
+/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
+
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+#include "elf/cr16.h"
+#include "linux-tdep.h"
+#include "symtab.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for Linux targets  */
+#define CR16_LINUX_NUM_REGS  21
+
+/* The breakpoint instruction used by uClinux target  */
+static const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };
+
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "psr",
+  "pc",
+  "r0r1_orig",
+  "intbase",
+  "usp",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_LINUX_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_LINUX_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* OS specific initialization of gdbarch.  */
+
+static void
+cr16_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  linux_init_abi (info, gdbarch);
+
+  set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
+
+  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
+     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
+     requires external hardware support for breakpoints to work on
+     CR16 target.  Software based breakpoints are implemented in the
+     kernel using excp flg and tested on the SC14452 target.  Use
+     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We
+     represent the breakpoint in little endian format since CR16
+     supports only little endian.  */
+  tdep->breakpoint = breakpoint_uclinux;
+
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_linux_tdep;
+
+void
+_initialize_cr16_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_cr16, 0, GDB_OSABI_LINUX,
+			  cr16_uclinux_init_abi);
+}
diff -uprN ./gdb_src.orig/gdb/cr16-tdep.c ./gdb_src/gdb/cr16-tdep.c
--- ./gdb_src.orig/gdb/cr16-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.c	2013-01-08 12:59:13.000000000 +0530
@@ -0,0 +1,896 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2013 Free Software Foundation, Inc.
+ 
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+   This file is part of GDB.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+#include "osabi.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for ELF targets.  */
+#define CR16_NUM_REGS  22
+
+/* The breakpoint instruction used with sim for ELF targets.  */
+static const gdb_byte breakpoint_elf[] = { 0xC8, 0x00 };
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Hardware register name declaration.  */
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "sp",
+  "pc",
+  "isp",
+  "usp",
+  "intbase",
+  "psr",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note: PC in CR16 is of 24 bits.  */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case CR16_FP_REGNUM:	/* Frame Pointer reg.  */
+    case CR16_SP_REGNUM:	/* Stack Pointer reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+      break;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    default:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch(), value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch()));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      gdb_byte buf[6];
+
+      /* Read 6 bytes, max 48 bit opcode.  */
+      target_read_memory (pc, buf, 6);
+      cr16_words[0] = buf[1] << 8 | buf[0];
+      cr16_words[1] = buf[3] << 8 | buf[2];
+      cr16_words[2] = buf[5] << 8 | buf[4];
+      cr16_allWords = (((ULONGLONG) cr16_words[0] << 32)
+		      + ((ULONGLONG) cr16_words[1] << 16)
+		      + cr16_words[2]);
+
+      /* Find a matching opcode in table.
+         Nonzero means instruction has a match.  */
+      is_decoded = cr16_match_opcode ();
+      cr16_make_instruction ();
+      length = cr16_currInsn.size;
+      next_pc = pc + length;
+      insn_byte1 = (cr16_words[0] >> 8) & 0xFF;
+
+      /* If PUSH, then save RA and other regs.  */
+      if (insn_byte1 == 0x01)
+	{
+	  int r1, r2;
+	  int r;
+
+	  insn_byte2 = cr16_words[0];
+
+	  if (insn_byte2 & 0x80)
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+	  /* Start Register=r1, 3 bit imm count=r2.  */
+	  r1 = insn_byte2 & 0x0F;
+	  r2 = ((insn_byte2 & 0x70) >> 4);
+	  r2 = r2 + r1 + 1;
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+      /* Add constant to SP.  */
+      else if (insn_byte1 == 0x60)
+	{
+	  int rdst;
+	  signed short addend;
+
+	  insn_byte2 = cr16_words[0];
+	  rdst = insn_byte2 & 0x0F;
+	  if (rdst == CR16_SP_REGNUM)
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = cr16_words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      /* Check for MOVD insn.  */
+      else if (insn_byte1 == 0x55)
+	{
+	  int rdst, rsrc;
+
+	  insn_byte2 = cr16_words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	break;		/* Terminate the prologue scan.  */
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+
+/* Implement the "skip_prologue" gdbarch method.  */
+
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (*this_prologue_cache)
+    return *this_prologue_cache;
+
+  CORE_ADDR func_start, stop_addr;
+
+  *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+  func_start = get_frame_func (this_frame);
+  stop_addr = get_frame_pc (this_frame);
+
+ /* If we couldn't find any function containing the PC, then
+     just initialize the prologue cache, but don't do anything.  */
+  if (!func_start)
+    stop_addr = func_start;
+
+  cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+/* Implement the "frame_prev_register" method for unwinding frames.  */
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA
+     register, CR16_R13_REGNUM.  So, we need not adjust anything
+     directly.  We will analyze prologue as this RA register is
+     pushed onto stack for further leaf function calls to work.  */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ULONGEST ra_prev;
+
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+}
+
+static const struct frame_unwind cr16_frame_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR pc;
+
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+cr16_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)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments on the stack.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ``arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R12.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u = extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, as possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* We use different breakpoint instructions for ELF and uClinux.
+     See cr16-linux-tdep.c for more details.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  *lenptr = 2;
+  if (tdep == NULL || tdep->breakpoint == NULL)
+    return breakpoint_elf;
+
+  return tdep->breakpoint;
+}
+
+/* Allocate and initialize a gdbarch object.  */
+
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xcalloc (1, sizeof (struct gdbarch_tdep));
+  tdep->elf_flags = elf_flags;
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_register_name);
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* Methods for saving / extracting a dummy frame's ID.  */
+  set_gdbarch_dummy_id (gdbarch, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
diff -uprN ./gdb_src.orig/gdb/cr16-tdep.h gdb_src/gdb/cr16-tdep.h
--- ./gdb_src.orig/gdb/cr16-tdep.h	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.h	2013-01-08 12:59:20.000000000 +0530
@@ -0,0 +1,32 @@
+/* GNU/Linux on  CR16 target support.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* Target-dependent structure in gdbarch.  */
+
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  /* Breakpoint instruction.  */
+  const gdb_byte *breakpoint;
+};


[-- Attachment #2: cr16_gdb.diff --]
[-- Type: application/octet-stream, Size: 32076 bytes --]

diff -uprN ./gdb_src.orig/gdb/configure.tgt ./gdb_src/gdb/configure.tgt
--- ./gdb_src.orig/gdb/configure.tgt	2012-12-18 20:22:58.000000000 +0530
+++ ./gdb_src/gdb/configure.tgt	2013-01-08 12:56:31.000000000 +0530
@@ -116,6 +116,18 @@ bfin-*-*)
 	gdb_sim=../sim/bfin/libsim.a
 	;;
 
+cr16*-*-*linux)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o cr16-linux-tdep.o linux-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
+cr16*-*-*)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
 cris*)
 	# Target: CRIS
 	gdb_target_obs="cris-tdep.o solib-svr4.o"
diff -uprN ./gdb_src.orig/gdb/cr16-linux-tdep.c ./gdb_src/gdb/cr16-linux-tdep.c
--- ./gdb_src.orig/gdb/cr16-linux-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-linux-tdep.c	2013-01-08 12:59:27.000000000 +0530
@@ -0,0 +1,107 @@
+/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
+
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+#include "elf/cr16.h"
+#include "linux-tdep.h"
+#include "symtab.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for Linux targets  */
+#define CR16_LINUX_NUM_REGS  21
+
+/* The breakpoint instruction used by uClinux target  */
+static const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };
+
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "psr",
+  "pc",
+  "r0r1_orig",
+  "intbase",
+  "usp",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_LINUX_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_LINUX_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* OS specific initialization of gdbarch.  */
+
+static void
+cr16_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  linux_init_abi (info, gdbarch);
+
+  set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
+
+  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
+     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
+     requires external hardware support for breakpoints to work on
+     CR16 target.  Software based breakpoints are implemented in the
+     kernel using excp flg and tested on the SC14452 target.  Use
+     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We
+     represent the breakpoint in little endian format since CR16
+     supports only little endian.  */
+  tdep->breakpoint = breakpoint_uclinux;
+
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_linux_tdep;
+
+void
+_initialize_cr16_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_cr16, 0, GDB_OSABI_LINUX,
+			  cr16_uclinux_init_abi);
+}
diff -uprN ./gdb_src.orig/gdb/cr16-tdep.c ./gdb_src/gdb/cr16-tdep.c
--- ./gdb_src.orig/gdb/cr16-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.c	2013-01-08 12:59:13.000000000 +0530
@@ -0,0 +1,896 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2013 Free Software Foundation, Inc.
+ 
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+   This file is part of GDB.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+#include "osabi.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for ELF targets.  */
+#define CR16_NUM_REGS  22
+
+/* The breakpoint instruction used with sim for ELF targets.  */
+static const gdb_byte breakpoint_elf[] = { 0xC8, 0x00 };
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Hardware register name declaration.  */
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "sp",
+  "pc",
+  "isp",
+  "usp",
+  "intbase",
+  "psr",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note: PC in CR16 is of 24 bits.  */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case CR16_FP_REGNUM:	/* Frame Pointer reg.  */
+    case CR16_SP_REGNUM:	/* Stack Pointer reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+      break;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    default:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch(), value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch()));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      gdb_byte buf[6];
+
+      /* Read 6 bytes, max 48 bit opcode.  */
+      target_read_memory (pc, buf, 6);
+      cr16_words[0] = buf[1] << 8 | buf[0];
+      cr16_words[1] = buf[3] << 8 | buf[2];
+      cr16_words[2] = buf[5] << 8 | buf[4];
+      cr16_allWords = (((ULONGLONG) cr16_words[0] << 32)
+		      + ((ULONGLONG) cr16_words[1] << 16)
+		      + cr16_words[2]);
+
+      /* Find a matching opcode in table.
+         Nonzero means instruction has a match.  */
+      is_decoded = cr16_match_opcode ();
+      cr16_make_instruction ();
+      length = cr16_currInsn.size;
+      next_pc = pc + length;
+      insn_byte1 = (cr16_words[0] >> 8) & 0xFF;
+
+      /* If PUSH, then save RA and other regs.  */
+      if (insn_byte1 == 0x01)
+	{
+	  int r1, r2;
+	  int r;
+
+	  insn_byte2 = cr16_words[0];
+
+	  if (insn_byte2 & 0x80)
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+	  /* Start Register=r1, 3 bit imm count=r2.  */
+	  r1 = insn_byte2 & 0x0F;
+	  r2 = ((insn_byte2 & 0x70) >> 4);
+	  r2 = r2 + r1 + 1;
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+      /* Add constant to SP.  */
+      else if (insn_byte1 == 0x60)
+	{
+	  int rdst;
+	  signed short addend;
+
+	  insn_byte2 = cr16_words[0];
+	  rdst = insn_byte2 & 0x0F;
+	  if (rdst == CR16_SP_REGNUM)
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = cr16_words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      /* Check for MOVD insn.  */
+      else if (insn_byte1 == 0x55)
+	{
+	  int rdst, rsrc;
+
+	  insn_byte2 = cr16_words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	break;		/* Terminate the prologue scan.  */
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+
+/* Implement the "skip_prologue" gdbarch method.  */
+
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (*this_prologue_cache)
+    return *this_prologue_cache;
+
+  CORE_ADDR func_start, stop_addr;
+
+  *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+  func_start = get_frame_func (this_frame);
+  stop_addr = get_frame_pc (this_frame);
+
+ /* If we couldn't find any function containing the PC, then
+     just initialize the prologue cache, but don't do anything.  */
+  if (!func_start)
+    stop_addr = func_start;
+
+  cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+/* Implement the "frame_prev_register" method for unwinding frames.  */
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA
+     register, CR16_R13_REGNUM.  So, we need not adjust anything
+     directly.  We will analyze prologue as this RA register is
+     pushed onto stack for further leaf function calls to work.  */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ULONGEST ra_prev;
+
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+}
+
+static const struct frame_unwind cr16_frame_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR pc;
+
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+cr16_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)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments on the stack.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ``arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R12.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u = extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, as possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* We use different breakpoint instructions for ELF and uClinux.
+     See cr16-linux-tdep.c for more details.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  *lenptr = 2;
+  if (tdep == NULL || tdep->breakpoint == NULL)
+    return breakpoint_elf;
+
+  return tdep->breakpoint;
+}
+
+/* Allocate and initialize a gdbarch object.  */
+
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xcalloc (1, sizeof (struct gdbarch_tdep));
+  tdep->elf_flags = elf_flags;
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_register_name);
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* Methods for saving / extracting a dummy frame's ID.  */
+  set_gdbarch_dummy_id (gdbarch, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
diff -uprN ./gdb_src.orig/gdb/cr16-tdep.h gdb_src/gdb/cr16-tdep.h
--- ./gdb_src.orig/gdb/cr16-tdep.h	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.h	2013-01-08 12:59:20.000000000 +0530
@@ -0,0 +1,32 @@
+/* GNU/Linux on  CR16 target support.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* Target-dependent structure in gdbarch.  */
+
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  /* Breakpoint instruction.  */
+  const gdb_byte *breakpoint;
+};

^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [RFA 3/5] New port: CR16: gdb port
  2012-11-22 17:50                 ` Joel Brobecker
  2013-01-08 10:02                   ` Kaushik Phatak
@ 2013-01-15  9:31                   ` Kaushik Phatak
  2013-01-17  8:59                     ` Joel Brobecker
  1 sibling, 1 reply; 29+ messages in thread
From: Kaushik Phatak @ 2013-01-15  9:31 UTC (permalink / raw)
  To: gdb-patches
  Cc: binutils, Pedro Alves, Yao Qi, nick clifton, Tom Tromey, Joel Brobecker

[-- Attachment #1: Type: text/plain, Size: 33859 bytes --]

Hi,

> Pedro Alves wrote "Please always base the work you submit against the current
> development. For GDB, that is:  http://sourceware.org/gdb/current/"

I have extracted a cvs diff below. A read only CVS did not allow me to add
new files, so I had to add them to CVS/Entries. The diff appears to be 
against /dev/null. Please let me know if this is OK.


Regards,
Kaushik

	gdb/Changelog
	* configure.tgt: Handle cr16*-*-*linux and cr16*-*-*.
	* cr16-linux-tdep.c: New file.
	* cr16-tdep.c: New file.
	* cr16-tdep.h: New file.
	
Index: gdb/configure.tgt
===================================================================
RCS file: /cvs/src/src/gdb/configure.tgt,v
retrieving revision 1.261
diff -u -a -r1.261 configure.tgt
--- gdb/configure.tgt	18 Dec 2012 14:52:58 -0000	1.261
+++ gdb/configure.tgt	15 Jan 2013 07:30:06 -0000
@@ -116,6 +116,18 @@
 	gdb_sim=../sim/bfin/libsim.a
 	;;
 
+cr16*-*-*linux)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o cr16-linux-tdep.o linux-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
+cr16*-*-*)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
 cris*)
 	# Target: CRIS
 	gdb_target_obs="cris-tdep.o solib-svr4.o"
Index: gdb/cr16-linux-tdep.c
===================================================================
RCS file: gdb/cr16-linux-tdep.c
diff -N gdb/cr16-linux-tdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/cr16-linux-tdep.c	15 Jan 2013 07:30:06 -0000
@@ -0,0 +1,107 @@
+/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
+
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+#include "elf/cr16.h"
+#include "linux-tdep.h"
+#include "symtab.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for Linux targets  */
+#define CR16_LINUX_NUM_REGS  21
+
+/* The breakpoint instruction used by uClinux target  */
+static const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };
+
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "psr",
+  "pc",
+  "r0r1_orig",
+  "intbase",
+  "usp",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_LINUX_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_LINUX_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* OS specific initialization of gdbarch.  */
+
+static void
+cr16_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  linux_init_abi (info, gdbarch);
+
+  set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
+
+  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
+     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
+     requires external hardware support for breakpoints to work on
+     CR16 target.  Software based breakpoints are implemented in the
+     kernel using excp flg and tested on the SC14452 target.  Use
+     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We
+     represent the breakpoint in little endian format since CR16
+     supports only little endian.  */
+  tdep->breakpoint = breakpoint_uclinux;
+
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_linux_tdep;
+
+void
+_initialize_cr16_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_cr16, 0, GDB_OSABI_LINUX,
+			  cr16_uclinux_init_abi);
+}
Index: gdb/cr16-tdep.c
===================================================================
RCS file: gdb/cr16-tdep.c
diff -N gdb/cr16-tdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/cr16-tdep.c	15 Jan 2013 07:30:07 -0000
@@ -0,0 +1,896 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2013 Free Software Foundation, Inc.
+ 
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+   This file is part of GDB.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+#include "osabi.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for ELF targets.  */
+#define CR16_NUM_REGS  22
+
+/* The breakpoint instruction used with sim for ELF targets.  */
+static const gdb_byte breakpoint_elf[] = { 0xC8, 0x00 };
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Hardware register name declaration.  */
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "sp",
+  "pc",
+  "isp",
+  "usp",
+  "intbase",
+  "psr",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note: PC in CR16 is of 24 bits.  */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case CR16_FP_REGNUM:	/* Frame Pointer reg.  */
+    case CR16_SP_REGNUM:	/* Stack Pointer reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+      break;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    default:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch(), value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch()));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      gdb_byte buf[6];
+
+      /* Read 6 bytes, max 48 bit opcode.  */
+      target_read_memory (pc, buf, 6);
+      cr16_words[0] = buf[1] << 8 | buf[0];
+      cr16_words[1] = buf[3] << 8 | buf[2];
+      cr16_words[2] = buf[5] << 8 | buf[4];
+      cr16_allWords = (((ULONGLONG) cr16_words[0] << 32)
+		      + ((ULONGLONG) cr16_words[1] << 16)
+		      + cr16_words[2]);
+
+      /* Find a matching opcode in table.
+         Nonzero means instruction has a match.  */
+      is_decoded = cr16_match_opcode ();
+      cr16_make_instruction ();
+      length = cr16_currInsn.size;
+      next_pc = pc + length;
+      insn_byte1 = (cr16_words[0] >> 8) & 0xFF;
+
+      /* If PUSH, then save RA and other regs.  */
+      if (insn_byte1 == 0x01)
+	{
+	  int r1, r2;
+	  int r;
+
+	  insn_byte2 = cr16_words[0];
+
+	  if (insn_byte2 & 0x80)
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+	  /* Start Register=r1, 3 bit imm count=r2.  */
+	  r1 = insn_byte2 & 0x0F;
+	  r2 = ((insn_byte2 & 0x70) >> 4);
+	  r2 = r2 + r1 + 1;
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+      /* Add constant to SP.  */
+      else if (insn_byte1 == 0x60)
+	{
+	  int rdst;
+	  signed short addend;
+
+	  insn_byte2 = cr16_words[0];
+	  rdst = insn_byte2 & 0x0F;
+	  if (rdst == CR16_SP_REGNUM)
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = cr16_words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      /* Check for MOVD insn.  */
+      else if (insn_byte1 == 0x55)
+	{
+	  int rdst, rsrc;
+
+	  insn_byte2 = cr16_words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	break;		/* Terminate the prologue scan.  */
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+
+/* Implement the "skip_prologue" gdbarch method.  */
+
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (*this_prologue_cache)
+    return *this_prologue_cache;
+
+  CORE_ADDR func_start, stop_addr;
+
+  *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+  func_start = get_frame_func (this_frame);
+  stop_addr = get_frame_pc (this_frame);
+
+ /* If we couldn't find any function containing the PC, then
+     just initialize the prologue cache, but don't do anything.  */
+  if (!func_start)
+    stop_addr = func_start;
+
+  cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+/* Implement the "frame_prev_register" method for unwinding frames.  */
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA
+     register, CR16_R13_REGNUM.  So, we need not adjust anything
+     directly.  We will analyze prologue as this RA register is
+     pushed onto stack for further leaf function calls to work.  */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ULONGEST ra_prev;
+
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+}
+
+static const struct frame_unwind cr16_frame_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR pc;
+
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+cr16_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)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments on the stack.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ``arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R12.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u = extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, as possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* We use different breakpoint instructions for ELF and uClinux.
+     See cr16-linux-tdep.c for more details.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  *lenptr = 2;
+  if (tdep == NULL || tdep->breakpoint == NULL)
+    return breakpoint_elf;
+
+  return tdep->breakpoint;
+}
+
+/* Allocate and initialize a gdbarch object.  */
+
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xcalloc (1, sizeof (struct gdbarch_tdep));
+  tdep->elf_flags = elf_flags;
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_register_name);
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* Methods for saving / extracting a dummy frame's ID.  */
+  set_gdbarch_dummy_id (gdbarch, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
Index: gdb/cr16-tdep.h
===================================================================
RCS file: gdb/cr16-tdep.h
diff -N gdb/cr16-tdep.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/cr16-tdep.h	15 Jan 2013 07:30:07 -0000
@@ -0,0 +1,32 @@
+/* GNU/Linux on  CR16 target support.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* Target-dependent structure in gdbarch.  */
+
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  /* Breakpoint instruction.  */
+  const gdb_byte *breakpoint;
+};


[-- Attachment #2: cr16_gdb.diff --]
[-- Type: application/octet-stream, Size: 32223 bytes --]

Index: gdb/configure.tgt
===================================================================
RCS file: /cvs/src/src/gdb/configure.tgt,v
retrieving revision 1.261
diff -u -a -r1.261 configure.tgt
--- gdb/configure.tgt	18 Dec 2012 14:52:58 -0000	1.261
+++ gdb/configure.tgt	15 Jan 2013 07:30:06 -0000
@@ -116,6 +116,18 @@
 	gdb_sim=../sim/bfin/libsim.a
 	;;
 
+cr16*-*-*linux)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o cr16-linux-tdep.o linux-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
+cr16*-*-*)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
 cris*)
 	# Target: CRIS
 	gdb_target_obs="cris-tdep.o solib-svr4.o"
Index: gdb/cr16-linux-tdep.c
===================================================================
RCS file: gdb/cr16-linux-tdep.c
diff -N gdb/cr16-linux-tdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/cr16-linux-tdep.c	15 Jan 2013 07:30:06 -0000
@@ -0,0 +1,107 @@
+/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
+
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+#include "elf/cr16.h"
+#include "linux-tdep.h"
+#include "symtab.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for Linux targets  */
+#define CR16_LINUX_NUM_REGS  21
+
+/* The breakpoint instruction used by uClinux target  */
+static const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };
+
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "psr",
+  "pc",
+  "r0r1_orig",
+  "intbase",
+  "usp",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_LINUX_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_LINUX_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* OS specific initialization of gdbarch.  */
+
+static void
+cr16_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  linux_init_abi (info, gdbarch);
+
+  set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
+
+  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
+     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
+     requires external hardware support for breakpoints to work on
+     CR16 target.  Software based breakpoints are implemented in the
+     kernel using excp flg and tested on the SC14452 target.  Use
+     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We
+     represent the breakpoint in little endian format since CR16
+     supports only little endian.  */
+  tdep->breakpoint = breakpoint_uclinux;
+
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_linux_tdep;
+
+void
+_initialize_cr16_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_cr16, 0, GDB_OSABI_LINUX,
+			  cr16_uclinux_init_abi);
+}
Index: gdb/cr16-tdep.c
===================================================================
RCS file: gdb/cr16-tdep.c
diff -N gdb/cr16-tdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/cr16-tdep.c	15 Jan 2013 07:30:07 -0000
@@ -0,0 +1,896 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2013 Free Software Foundation, Inc.
+ 
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+   This file is part of GDB.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+#include "osabi.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for ELF targets.  */
+#define CR16_NUM_REGS  22
+
+/* The breakpoint instruction used with sim for ELF targets.  */
+static const gdb_byte breakpoint_elf[] = { 0xC8, 0x00 };
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Hardware register name declaration.  */
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "sp",
+  "pc",
+  "isp",
+  "usp",
+  "intbase",
+  "psr",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note: PC in CR16 is of 24 bits.  */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case CR16_FP_REGNUM:	/* Frame Pointer reg.  */
+    case CR16_SP_REGNUM:	/* Stack Pointer reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+      break;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    default:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch(), value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch()));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      gdb_byte buf[6];
+
+      /* Read 6 bytes, max 48 bit opcode.  */
+      target_read_memory (pc, buf, 6);
+      cr16_words[0] = buf[1] << 8 | buf[0];
+      cr16_words[1] = buf[3] << 8 | buf[2];
+      cr16_words[2] = buf[5] << 8 | buf[4];
+      cr16_allWords = (((ULONGLONG) cr16_words[0] << 32)
+		      + ((ULONGLONG) cr16_words[1] << 16)
+		      + cr16_words[2]);
+
+      /* Find a matching opcode in table.
+         Nonzero means instruction has a match.  */
+      is_decoded = cr16_match_opcode ();
+      cr16_make_instruction ();
+      length = cr16_currInsn.size;
+      next_pc = pc + length;
+      insn_byte1 = (cr16_words[0] >> 8) & 0xFF;
+
+      /* If PUSH, then save RA and other regs.  */
+      if (insn_byte1 == 0x01)
+	{
+	  int r1, r2;
+	  int r;
+
+	  insn_byte2 = cr16_words[0];
+
+	  if (insn_byte2 & 0x80)
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+	  /* Start Register=r1, 3 bit imm count=r2.  */
+	  r1 = insn_byte2 & 0x0F;
+	  r2 = ((insn_byte2 & 0x70) >> 4);
+	  r2 = r2 + r1 + 1;
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+      /* Add constant to SP.  */
+      else if (insn_byte1 == 0x60)
+	{
+	  int rdst;
+	  signed short addend;
+
+	  insn_byte2 = cr16_words[0];
+	  rdst = insn_byte2 & 0x0F;
+	  if (rdst == CR16_SP_REGNUM)
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = cr16_words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      /* Check for MOVD insn.  */
+      else if (insn_byte1 == 0x55)
+	{
+	  int rdst, rsrc;
+
+	  insn_byte2 = cr16_words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	break;		/* Terminate the prologue scan.  */
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+
+/* Implement the "skip_prologue" gdbarch method.  */
+
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (*this_prologue_cache)
+    return *this_prologue_cache;
+
+  CORE_ADDR func_start, stop_addr;
+
+  *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+  func_start = get_frame_func (this_frame);
+  stop_addr = get_frame_pc (this_frame);
+
+ /* If we couldn't find any function containing the PC, then
+     just initialize the prologue cache, but don't do anything.  */
+  if (!func_start)
+    stop_addr = func_start;
+
+  cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+/* Implement the "frame_prev_register" method for unwinding frames.  */
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA
+     register, CR16_R13_REGNUM.  So, we need not adjust anything
+     directly.  We will analyze prologue as this RA register is
+     pushed onto stack for further leaf function calls to work.  */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ULONGEST ra_prev;
+
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+}
+
+static const struct frame_unwind cr16_frame_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR pc;
+
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+cr16_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)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments on the stack.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ``arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R12.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u = extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, as possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* We use different breakpoint instructions for ELF and uClinux.
+     See cr16-linux-tdep.c for more details.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  *lenptr = 2;
+  if (tdep == NULL || tdep->breakpoint == NULL)
+    return breakpoint_elf;
+
+  return tdep->breakpoint;
+}
+
+/* Allocate and initialize a gdbarch object.  */
+
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xcalloc (1, sizeof (struct gdbarch_tdep));
+  tdep->elf_flags = elf_flags;
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_register_name);
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* Methods for saving / extracting a dummy frame's ID.  */
+  set_gdbarch_dummy_id (gdbarch, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
Index: gdb/cr16-tdep.h
===================================================================
RCS file: gdb/cr16-tdep.h
diff -N gdb/cr16-tdep.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/cr16-tdep.h	15 Jan 2013 07:30:07 -0000
@@ -0,0 +1,32 @@
+/* GNU/Linux on  CR16 target support.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* Target-dependent structure in gdbarch.  */
+
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  /* Breakpoint instruction.  */
+  const gdb_byte *breakpoint;
+};

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2013-01-15  9:31                   ` Kaushik Phatak
@ 2013-01-17  8:59                     ` Joel Brobecker
  2013-01-18  7:41                       ` Kaushik Phatak
  2013-01-18 18:25                       ` Pedro Alves
  0 siblings, 2 replies; 29+ messages in thread
From: Joel Brobecker @ 2013-01-17  8:59 UTC (permalink / raw)
  To: Kaushik Phatak
  Cc: gdb-patches, binutils, Pedro Alves, Yao Qi, nick clifton, Tom Tromey

> I have extracted a cvs diff below. A read only CVS did not allow me to add
> new files, so I had to add them to CVS/Entries. The diff appears to be 
> against /dev/null. Please let me know if this is OK.

Yes, this is fine. Or you could have simply attached the new file,
instead of making a diff version /dev/null. Either way works for me.

> +/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
> +
> +   Copyright (C) 2013 Free Software Foundation, Inc.

The copyright years should cover the years that the work was committed
to a medium (hard drive). IIRC, you submitted this work in 2012, so
it should contain at least 2012:

   Copyright (C) 2012-2013 Free Softward Foundation, Inc.

> +static struct type *
> +cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
> +{
> +  switch (reg_nr)
> +    {
> +    case CR16_PC_REGNUM:	/* Note: PC in CR16 is of 24 bits.  */
> +      return builtin_type (gdbarch)->builtin_func_ptr;
> +
> +    case CR16_RA_REGNUM:	/* Return address reg.  */
> +      return builtin_type (gdbarch)->builtin_data_ptr;
> +      break;

Pedro remarked on one of my patches that the "break" statement
after a return is useless, and he's right. Let's remove all of
them (more of those in the same function).

> +static void
> +check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
> +{
> +  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
> +
> +  if (value.kind == pvk_register
> +      && value.k == 0
> +      && pv_is_register (addr, CR16_SP_REGNUM)
> +      && size == register_size (target_gdbarch(), value.reg))

Missing space after "target_gdbarch".

> +  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch()));

Same here.

> +      /* Read 6 bytes, max 48 bit opcode.  */
> +      target_read_memory (pc, buf, 6);
> +      cr16_words[0] = buf[1] << 8 | buf[0];
> +      cr16_words[1] = buf[3] << 8 | buf[2];
> +      cr16_words[2] = buf[5] << 8 | buf[4];
> +      cr16_allWords = (((ULONGLONG) cr16_words[0] << 32)
> +		      + ((ULONGLONG) cr16_words[1] << 16)
> +		      + cr16_words[2]);
> +
> +      /* Find a matching opcode in table.
> +         Nonzero means instruction has a match.  */
> +      is_decoded = cr16_match_opcode ();
> +      cr16_make_instruction ();
> +      length = cr16_currInsn.size;

It hurts every time I read this code... Nothing you can do short
of improving opcode, but this is really awful :-(.

> +  /* Functions with a variable number of arguments have all of their
> +     variable arguments and the last non-variable argument passed
> +     on the stack.
> +
> +     Otherwise, we can pass up to four arguments on the stack.

Up to 4 arguments on the stack? Or by register?

> +static const gdb_byte *
> +cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
> +			 int *lenptr)
> +{
> +  /* We use different breakpoint instructions for ELF and uClinux.
> +     See cr16-linux-tdep.c for more details.  */
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +
> +  *lenptr = 2;
> +  if (tdep == NULL || tdep->breakpoint == NULL)
> +    return breakpoint_elf;

The above does not look right. tdep should never be NULL, and
I suggest that tdep->breakpoint always be initialized (by
cr16_gdbarch_init).

> +  return tdep->breakpoint;

So the contents of the function should be limited to this last line.

The rest still looks pretty good to me :)

-- 
Joel


^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [RFA 3/5] New port: CR16: gdb port
  2013-01-17  8:59                     ` Joel Brobecker
@ 2013-01-18  7:41                       ` Kaushik Phatak
  2013-01-18 14:17                         ` Joel Brobecker
  2013-01-18 18:25                       ` Pedro Alves
  1 sibling, 1 reply; 29+ messages in thread
From: Kaushik Phatak @ 2013-01-18  7:41 UTC (permalink / raw)
  To: Joel Brobecker
  Cc: gdb-patches, binutils, Pedro Alves, Yao Qi, nick clifton, Tom Tromey

[-- Attachment #1: Type: text/plain, Size: 36424 bytes --]

Hi Joel,
Thanks for spending time on this. I have tried to address all your 
points in this updated patch.

> Or you could have simply attached the new file, 
> instead of making a diff version /dev/null. Either way works for me.
I have continued to use the diff here.

> Copyright (C) 2012-2013 Free Softward Foundation, Inc.
Fixed the copyright to add 2012.

>> +    case CR16_RA_REGNUM:	/* Return address reg.  */
>> +      return builtin_type (gdbarch)->builtin_data_ptr;
>> +      break;
> Pedro remarked on one of my patches that the "break" statement
> after a return is useless, and he's right. 
Removed all unnecessary breaks from this function. Ran through rest 
of the code as well. Should not contain unnecessary breaks now.

> Missing space after "target_gdbarch".
Fixed this at two places.

>> +      is_decoded = cr16_match_opcode ();
>> +      cr16_make_instruction ();
> It hurts every time I read this code... Nothing you can do short
> of improving opcode, but this is really awful :-(.
Yes, the bfd code has been lying around for a long time. Using this
as-is except that these symbols are prefixed and exported in cr16.h

>> +     Otherwise, we can pass up to four arguments on the stack.
> Up to 4 arguments on the stack? Or by register?
Fixed this comment to "up to four arguments via registers"

>> +  if (tdep == NULL || tdep->breakpoint == NULL)
>> +    return breakpoint_elf;
> The above does not look right. tdep should never be NULL, and
> I suggest that tdep->breakpoint always be initialized (by
> cr16_gdbarch_init).
OK. I have removed this code. The gdbarch_init is able to take care 
of this for elf and uclinux variants. Ran some tests on hardware and sim.

>> +  return tdep->breakpoint;
>So the contents of the function should be limited to this last line.
This function is now limited to this line.

> The rest still looks pretty good to me :)
Thanks :)

Regards,
Kaushik

2013-01-18 Kaushik Phatak  <kaushik.phatak@kpitcummins.com>
	gdb/Changelog
	* configure.tgt: Handle cr16*-*-*linux and cr16*-*-*.
	* cr16-linux-tdep.c: New file.
	* cr16-tdep.c: New file.
	* cr16-tdep.h: New file.
	
Index: configure
===================================================================
RCS file: /cvs/src/src/configure,v
retrieving revision 1.441
diff -u -r1.441 configure
--- configure	15 Jan 2013 21:47:01 -0000	1.441
+++ configure	18 Jan 2013 05:52:41 -0000
@@ -3600,6 +3600,9 @@
   tic54x-*-*)
     noconfigdirs="$noconfigdirs target-libgloss gdb"
     ;;
+  cr16-*-*)
+    noconfigdirs="$noconfigdirs target-libgloss"
+    ;;
   d10v-*-*)
     noconfigdirs="$noconfigdirs target-libgloss"
     ;;
Index: configure.ac
===================================================================
RCS file: /cvs/src/src/configure.ac,v
retrieving revision 1.185
diff -u -r1.185 configure.ac
--- configure.ac	15 Jan 2013 21:47:02 -0000	1.185
+++ configure.ac	18 Jan 2013 05:52:41 -0000
@@ -939,6 +939,9 @@
   tic54x-*-*)
     noconfigdirs="$noconfigdirs target-libgloss gdb"
     ;;
+  cr16-*-*)
+    noconfigdirs="$noconfigdirs target-libgloss"
+    ;;
   d10v-*-*)
     noconfigdirs="$noconfigdirs target-libgloss"
     ;;
Index: gdb/configure.tgt
===================================================================
RCS file: /cvs/src/src/gdb/configure.tgt,v
retrieving revision 1.261
diff -u -r1.261 configure.tgt
--- gdb/configure.tgt	18 Dec 2012 14:52:58 -0000	1.261
+++ gdb/configure.tgt	18 Jan 2013 05:52:42 -0000
@@ -116,6 +116,18 @@
 	gdb_sim=../sim/bfin/libsim.a
 	;;
 
+cr16*-*-*linux)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o cr16-linux-tdep.o linux-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
+cr16*-*-*)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
 cris*)
 	# Target: CRIS
 	gdb_target_obs="cris-tdep.o solib-svr4.o"
Index: gdb/cr16-linux-tdep.c
===================================================================
RCS file: gdb/cr16-linux-tdep.c
diff -N gdb/cr16-linux-tdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/cr16-linux-tdep.c	18 Jan 2013 05:52:42 -0000
@@ -0,0 +1,107 @@
+/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
+
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+#include "elf/cr16.h"
+#include "linux-tdep.h"
+#include "symtab.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for Linux targets  */
+#define CR16_LINUX_NUM_REGS  21
+
+/* The breakpoint instruction used by uClinux target  */
+static const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };
+
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "psr",
+  "pc",
+  "r0r1_orig",
+  "intbase",
+  "usp",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_LINUX_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_LINUX_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* OS specific initialization of gdbarch.  */
+
+static void
+cr16_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  linux_init_abi (info, gdbarch);
+
+  set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
+
+  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
+     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
+     requires external hardware support for breakpoints to work on
+     CR16 target.  Software based breakpoints are implemented in the
+     kernel using excp flg and tested on the SC14452 target.  Use
+     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We
+     represent the breakpoint in little endian format since CR16
+     supports only little endian.  */
+  tdep->breakpoint = breakpoint_uclinux;
+
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_linux_tdep;
+
+void
+_initialize_cr16_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_cr16, 0, GDB_OSABI_LINUX,
+			  cr16_uclinux_init_abi);
+}
Index: gdb/cr16-tdep.c
===================================================================
RCS file: gdb/cr16-tdep.c
diff -N gdb/cr16-tdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/cr16-tdep.c	18 Jan 2013 05:52:42 -0000
@@ -0,0 +1,888 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+ 
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+   This file is part of GDB.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+#include "osabi.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for ELF targets.  */
+#define CR16_NUM_REGS  22
+
+/* The breakpoint instruction used with sim for ELF targets.  */
+static const gdb_byte breakpoint_elf[] = { 0xC8, 0x00 };
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Hardware register name declaration.  */
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "sp",
+  "pc",
+  "isp",
+  "usp",
+  "intbase",
+  "psr",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note: PC in CR16 is of 24 bits.  */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+
+    case CR16_FP_REGNUM:	/* Frame Pointer reg.  */
+    case CR16_SP_REGNUM:	/* Stack Pointer reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+
+    default:
+      return builtin_type (gdbarch)->builtin_int32;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch (), value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch ()));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      gdb_byte buf[6];
+
+      /* Read 6 bytes, max 48 bit opcode.  */
+      target_read_memory (pc, buf, 6);
+      cr16_words[0] = buf[1] << 8 | buf[0];
+      cr16_words[1] = buf[3] << 8 | buf[2];
+      cr16_words[2] = buf[5] << 8 | buf[4];
+      cr16_allWords = (((ULONGLONG) cr16_words[0] << 32)
+		      + ((ULONGLONG) cr16_words[1] << 16)
+		      + cr16_words[2]);
+
+      /* Find a matching opcode in table.
+         Nonzero means instruction has a match.  */
+      is_decoded = cr16_match_opcode ();
+      cr16_make_instruction ();
+      length = cr16_currInsn.size;
+      next_pc = pc + length;
+      insn_byte1 = (cr16_words[0] >> 8) & 0xFF;
+
+      /* If PUSH, then save RA and other regs.  */
+      if (insn_byte1 == 0x01)
+	{
+	  int r1, r2;
+	  int r;
+
+	  insn_byte2 = cr16_words[0];
+
+	  if (insn_byte2 & 0x80)
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+	  /* Start Register=r1, 3 bit imm count=r2.  */
+	  r1 = insn_byte2 & 0x0F;
+	  r2 = ((insn_byte2 & 0x70) >> 4);
+	  r2 = r2 + r1 + 1;
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+      /* Add constant to SP.  */
+      else if (insn_byte1 == 0x60)
+	{
+	  int rdst;
+	  signed short addend;
+
+	  insn_byte2 = cr16_words[0];
+	  rdst = insn_byte2 & 0x0F;
+	  if (rdst == CR16_SP_REGNUM)
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = cr16_words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      /* Check for MOVD insn.  */
+      else if (insn_byte1 == 0x55)
+	{
+	  int rdst, rsrc;
+
+	  insn_byte2 = cr16_words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	break;		/* Terminate the prologue scan.  */
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+
+/* Implement the "skip_prologue" gdbarch method.  */
+
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (*this_prologue_cache)
+    return *this_prologue_cache;
+
+  CORE_ADDR func_start, stop_addr;
+
+  *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+  func_start = get_frame_func (this_frame);
+  stop_addr = get_frame_pc (this_frame);
+
+ /* If we couldn't find any function containing the PC, then
+     just initialize the prologue cache, but don't do anything.  */
+  if (!func_start)
+    stop_addr = func_start;
+
+  cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+/* Implement the "frame_prev_register" method for unwinding frames.  */
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA
+     register, CR16_R13_REGNUM.  So, we need not adjust anything
+     directly.  We will analyze prologue as this RA register is
+     pushed onto stack for further leaf function calls to work.  */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ULONGEST ra_prev;
+
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+}
+
+static const struct frame_unwind cr16_frame_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR pc;
+
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+cr16_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)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments via registers.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ``arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R12.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u = extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, as possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* We use different breakpoint instructions for ELF and uClinux.
+     See cr16-linux-tdep.c for more details.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  *lenptr = 2;
+  return tdep->breakpoint;
+}
+
+/* Allocate and initialize a gdbarch object.  */
+
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xcalloc (1, sizeof (struct gdbarch_tdep));
+  tdep->elf_flags = elf_flags;
+  tdep->breakpoint = breakpoint_elf;
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_register_name);
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* Methods for saving / extracting a dummy frame's ID.  */
+  set_gdbarch_dummy_id (gdbarch, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
Index: gdb/cr16-tdep.h
===================================================================
RCS file: gdb/cr16-tdep.h
diff -N gdb/cr16-tdep.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/cr16-tdep.h	18 Jan 2013 05:52:42 -0000
@@ -0,0 +1,32 @@
+/* GNU/Linux on  CR16 target support.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* Target-dependent structure in gdbarch.  */
+
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  /* Breakpoint instruction.  */
+  const gdb_byte *breakpoint;
+};


[-- Attachment #2: cr16_gdb.diff --]
[-- Type: application/octet-stream, Size: 33128 bytes --]

Index: configure
===================================================================
RCS file: /cvs/src/src/configure,v
retrieving revision 1.441
diff -u -r1.441 configure
--- configure	15 Jan 2013 21:47:01 -0000	1.441
+++ configure	18 Jan 2013 05:52:41 -0000
@@ -3600,6 +3600,9 @@
   tic54x-*-*)
     noconfigdirs="$noconfigdirs target-libgloss gdb"
     ;;
+  cr16-*-*)
+    noconfigdirs="$noconfigdirs target-libgloss"
+    ;;
   d10v-*-*)
     noconfigdirs="$noconfigdirs target-libgloss"
     ;;
Index: configure.ac
===================================================================
RCS file: /cvs/src/src/configure.ac,v
retrieving revision 1.185
diff -u -r1.185 configure.ac
--- configure.ac	15 Jan 2013 21:47:02 -0000	1.185
+++ configure.ac	18 Jan 2013 05:52:41 -0000
@@ -939,6 +939,9 @@
   tic54x-*-*)
     noconfigdirs="$noconfigdirs target-libgloss gdb"
     ;;
+  cr16-*-*)
+    noconfigdirs="$noconfigdirs target-libgloss"
+    ;;
   d10v-*-*)
     noconfigdirs="$noconfigdirs target-libgloss"
     ;;
Index: gdb/configure.tgt
===================================================================
RCS file: /cvs/src/src/gdb/configure.tgt,v
retrieving revision 1.261
diff -u -r1.261 configure.tgt
--- gdb/configure.tgt	18 Dec 2012 14:52:58 -0000	1.261
+++ gdb/configure.tgt	18 Jan 2013 05:52:42 -0000
@@ -116,6 +116,18 @@
 	gdb_sim=../sim/bfin/libsim.a
 	;;
 
+cr16*-*-*linux)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o cr16-linux-tdep.o linux-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
+cr16*-*-*)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
 cris*)
 	# Target: CRIS
 	gdb_target_obs="cris-tdep.o solib-svr4.o"
Index: gdb/cr16-linux-tdep.c
===================================================================
RCS file: gdb/cr16-linux-tdep.c
diff -N gdb/cr16-linux-tdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/cr16-linux-tdep.c	18 Jan 2013 05:52:42 -0000
@@ -0,0 +1,107 @@
+/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
+
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+#include "elf/cr16.h"
+#include "linux-tdep.h"
+#include "symtab.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for Linux targets  */
+#define CR16_LINUX_NUM_REGS  21
+
+/* The breakpoint instruction used by uClinux target  */
+static const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };
+
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "psr",
+  "pc",
+  "r0r1_orig",
+  "intbase",
+  "usp",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_LINUX_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_LINUX_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* OS specific initialization of gdbarch.  */
+
+static void
+cr16_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  linux_init_abi (info, gdbarch);
+
+  set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
+
+  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
+     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
+     requires external hardware support for breakpoints to work on
+     CR16 target.  Software based breakpoints are implemented in the
+     kernel using excp flg and tested on the SC14452 target.  Use
+     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We
+     represent the breakpoint in little endian format since CR16
+     supports only little endian.  */
+  tdep->breakpoint = breakpoint_uclinux;
+
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_linux_tdep;
+
+void
+_initialize_cr16_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_cr16, 0, GDB_OSABI_LINUX,
+			  cr16_uclinux_init_abi);
+}
Index: gdb/cr16-tdep.c
===================================================================
RCS file: gdb/cr16-tdep.c
diff -N gdb/cr16-tdep.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/cr16-tdep.c	18 Jan 2013 05:52:42 -0000
@@ -0,0 +1,888 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+ 
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+   This file is part of GDB.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+#include "osabi.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for ELF targets.  */
+#define CR16_NUM_REGS  22
+
+/* The breakpoint instruction used with sim for ELF targets.  */
+static const gdb_byte breakpoint_elf[] = { 0xC8, 0x00 };
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Hardware register name declaration.  */
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "sp",
+  "pc",
+  "isp",
+  "usp",
+  "intbase",
+  "psr",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note: PC in CR16 is of 24 bits.  */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+
+    case CR16_FP_REGNUM:	/* Frame Pointer reg.  */
+    case CR16_SP_REGNUM:	/* Stack Pointer reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+
+    default:
+      return builtin_type (gdbarch)->builtin_int32;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch (), value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch ()));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      gdb_byte buf[6];
+
+      /* Read 6 bytes, max 48 bit opcode.  */
+      target_read_memory (pc, buf, 6);
+      cr16_words[0] = buf[1] << 8 | buf[0];
+      cr16_words[1] = buf[3] << 8 | buf[2];
+      cr16_words[2] = buf[5] << 8 | buf[4];
+      cr16_allWords = (((ULONGLONG) cr16_words[0] << 32)
+		      + ((ULONGLONG) cr16_words[1] << 16)
+		      + cr16_words[2]);
+
+      /* Find a matching opcode in table.
+         Nonzero means instruction has a match.  */
+      is_decoded = cr16_match_opcode ();
+      cr16_make_instruction ();
+      length = cr16_currInsn.size;
+      next_pc = pc + length;
+      insn_byte1 = (cr16_words[0] >> 8) & 0xFF;
+
+      /* If PUSH, then save RA and other regs.  */
+      if (insn_byte1 == 0x01)
+	{
+	  int r1, r2;
+	  int r;
+
+	  insn_byte2 = cr16_words[0];
+
+	  if (insn_byte2 & 0x80)
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+	  /* Start Register=r1, 3 bit imm count=r2.  */
+	  r1 = insn_byte2 & 0x0F;
+	  r2 = ((insn_byte2 & 0x70) >> 4);
+	  r2 = r2 + r1 + 1;
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+      /* Add constant to SP.  */
+      else if (insn_byte1 == 0x60)
+	{
+	  int rdst;
+	  signed short addend;
+
+	  insn_byte2 = cr16_words[0];
+	  rdst = insn_byte2 & 0x0F;
+	  if (rdst == CR16_SP_REGNUM)
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = cr16_words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      /* Check for MOVD insn.  */
+      else if (insn_byte1 == 0x55)
+	{
+	  int rdst, rsrc;
+
+	  insn_byte2 = cr16_words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	break;		/* Terminate the prologue scan.  */
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+
+/* Implement the "skip_prologue" gdbarch method.  */
+
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (*this_prologue_cache)
+    return *this_prologue_cache;
+
+  CORE_ADDR func_start, stop_addr;
+
+  *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+  func_start = get_frame_func (this_frame);
+  stop_addr = get_frame_pc (this_frame);
+
+ /* If we couldn't find any function containing the PC, then
+     just initialize the prologue cache, but don't do anything.  */
+  if (!func_start)
+    stop_addr = func_start;
+
+  cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+/* Implement the "frame_prev_register" method for unwinding frames.  */
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA
+     register, CR16_R13_REGNUM.  So, we need not adjust anything
+     directly.  We will analyze prologue as this RA register is
+     pushed onto stack for further leaf function calls to work.  */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ULONGEST ra_prev;
+
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+}
+
+static const struct frame_unwind cr16_frame_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR pc;
+
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+cr16_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)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments via registers.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ``arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R12.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u = extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, as possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* We use different breakpoint instructions for ELF and uClinux.
+     See cr16-linux-tdep.c for more details.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  *lenptr = 2;
+  return tdep->breakpoint;
+}
+
+/* Allocate and initialize a gdbarch object.  */
+
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xcalloc (1, sizeof (struct gdbarch_tdep));
+  tdep->elf_flags = elf_flags;
+  tdep->breakpoint = breakpoint_elf;
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_register_name);
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* Methods for saving / extracting a dummy frame's ID.  */
+  set_gdbarch_dummy_id (gdbarch, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
Index: gdb/cr16-tdep.h
===================================================================
RCS file: gdb/cr16-tdep.h
diff -N gdb/cr16-tdep.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/cr16-tdep.h	18 Jan 2013 05:52:42 -0000
@@ -0,0 +1,32 @@
+/* GNU/Linux on  CR16 target support.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* Target-dependent structure in gdbarch.  */
+
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  /* Breakpoint instruction.  */
+  const gdb_byte *breakpoint;
+};

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2013-01-18  7:41                       ` Kaushik Phatak
@ 2013-01-18 14:17                         ` Joel Brobecker
  2013-01-22 13:49                           ` Kaushik Phatak
  0 siblings, 1 reply; 29+ messages in thread
From: Joel Brobecker @ 2013-01-18 14:17 UTC (permalink / raw)
  To: Kaushik Phatak
  Cc: gdb-patches, binutils, Pedro Alves, Yao Qi, nick clifton, Tom Tromey

> Thanks for spending time on this. I have tried to address all your 
> points in this updated patch.

And I confirm you did :).

> 2013-01-18 Kaushik Phatak  <kaushik.phatak@kpitcummins.com>
> 	gdb/Changelog
> 	* configure.tgt: Handle cr16*-*-*linux and cr16*-*-*.
> 	* cr16-linux-tdep.c: New file.
> 	* cr16-tdep.c: New file.
> 	* cr16-tdep.h: New file.

Looks good to me.

One warning, though: You added src/configure.ac and src/configure
to the patch. JIC we hadn't mentioned this, this part is controlled
by GCC, and needs to be approved there. You can go ahead and commit
the GDB part.

-- 
Joel


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2013-01-17  8:59                     ` Joel Brobecker
  2013-01-18  7:41                       ` Kaushik Phatak
@ 2013-01-18 18:25                       ` Pedro Alves
  1 sibling, 0 replies; 29+ messages in thread
From: Pedro Alves @ 2013-01-18 18:25 UTC (permalink / raw)
  To: Joel Brobecker
  Cc: Kaushik Phatak, gdb-patches, binutils, Pedro Alves, Yao Qi,
	nick clifton, Tom Tromey

On 01/17/2013 08:59 AM, Joel Brobecker wrote:

>> +      /* Read 6 bytes, max 48 bit opcode.  */
>> +      target_read_memory (pc, buf, 6);
>> +      cr16_words[0] = buf[1] << 8 | buf[0];
>> +      cr16_words[1] = buf[3] << 8 | buf[2];
>> +      cr16_words[2] = buf[5] << 8 | buf[4];
>> +      cr16_allWords = (((ULONGLONG) cr16_words[0] << 32)
>> +		      + ((ULONGLONG) cr16_words[1] << 16)
>> +		      + cr16_words[2]);
>> +
>> +      /* Find a matching opcode in table.
>> +         Nonzero means instruction has a match.  */
>> +      is_decoded = cr16_match_opcode ();
>> +      cr16_make_instruction ();
>> +      length = cr16_currInsn.size;
> 
> It hurts every time I read this code... Nothing you can do short
> of improving opcode, but this is really awful :-(.

This seems pretty isolated.  How about exporting a function that
hides these opcodes details?  I don't even pretend to understand
what the code is trying to do, and it'd be an opportunity to
comment it in the function description.  :-)

     /* Take BUF, do something with it, and write length
        to LENGTH.  Blah, blah.  */
     cr16_do_something (buf, *length, ...);




> static const char *const reg_names[] =
> +{
...
> +  "r0r1_orig",

This too looks like a ptrace detail escaping all the
way to the user, similar to the gdbserver issues.
Any reason not to split those up?  I think it'd be nicer.

...
> +};

Joel Brobecker wrote:
> The rest still looks pretty good to me :)

I agree.  :-)

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [RFA 3/5] New port: CR16: gdb port
  2013-01-18 14:17                         ` Joel Brobecker
@ 2013-01-22 13:49                           ` Kaushik Phatak
  2013-01-22 15:43                             ` Pedro Alves
  0 siblings, 1 reply; 29+ messages in thread
From: Kaushik Phatak @ 2013-01-22 13:49 UTC (permalink / raw)
  To: Joel Brobecker
  Cc: gdb-patches, binutils, Pedro Alves, Yao Qi, nick clifton, Tom Tromey

Hi Joel,

> And I confirm you did :).
Thanks for the review.

> src/configure.ac and src/configure
> this part is controlled by GCC, and needs to be approved there. 
Ok, I will split up that part and commit it to GCC.
I am working on few points raised by Pedro on the gdbserver, hopefully that 
would not affect my gdb code.

> You can go ahead and commit the GDB part.
I do not have check-in rights to this repository. Do I need to request somebody
to do that for me?

Thanks,
Kaushik



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2013-01-22 13:49                           ` Kaushik Phatak
@ 2013-01-22 15:43                             ` Pedro Alves
  2013-01-23 14:22                               ` Kaushik Phatak
  0 siblings, 1 reply; 29+ messages in thread
From: Pedro Alves @ 2013-01-22 15:43 UTC (permalink / raw)
  To: Kaushik Phatak; +Cc: Joel Brobecker, gdb-patches, Yao Qi, Tom Tromey

(trimming CC)

On 01/22/2013 01:49 PM, Kaushik Phatak wrote:

> I am working on few points raised by Pedro on the gdbserver, hopefully that 
> would not affect my gdb code.

I think we should hold the gdb bits until the gdbserver parts are settled,
as we're discussing core register numbering issues.

What did you think of my suggestions/comments to the gdb patch?

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [RFA 3/5] New port: CR16: gdb port
  2013-01-22 15:43                             ` Pedro Alves
@ 2013-01-23 14:22                               ` Kaushik Phatak
  2013-01-23 14:26                                 ` Pedro Alves
  2013-01-23 15:34                                 ` Pedro Alves
  0 siblings, 2 replies; 29+ messages in thread
From: Kaushik Phatak @ 2013-01-23 14:22 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Joel Brobecker, gdb-patches, Yao Qi, Tom Tromey

> I think we should hold the gdb bits until the gdbserver parts are settled,
> as we're discussing core register numbering issues.
> What did you think of my suggestions/comments to the gdb patch?
Yes, I do want to address those as well :)

> How about exporting a function that hides these opcodes details?  
> I don't even pretend to understand what the code is trying to do, 
> and it'd be an opportunity to comment it in the function description.
>   /* Take BUF, do something with it, and write length
>        to LENGTH.  Blah, blah.  */
>    cr16_do_something (buf, *length, ...);

I think this can be done and it will make this code look cleaner.
An exported function in bfd would make my code look like this,
...
   target_read_memory (pc, buf, 6);
   cr16_get_insn_length (buf, *length, ...);
   next_pc = pc + length;
    ...

> > +  "r0r1_orig",
> This too looks like a ptrace detail escaping all the
> way to the user, similar to the gdbserver issues.
> Any reason not to split those up?  I think it'd be nicer.	
This is a kernel scratch register and it part of PT_REGS.
Would be OK to leave it as is as it may help in debugging?

Thanks,
Kaushik



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2013-01-23 14:22                               ` Kaushik Phatak
@ 2013-01-23 14:26                                 ` Pedro Alves
  2013-01-23 15:34                                 ` Pedro Alves
  1 sibling, 0 replies; 29+ messages in thread
From: Pedro Alves @ 2013-01-23 14:26 UTC (permalink / raw)
  To: Kaushik Phatak; +Cc: Joel Brobecker, gdb-patches, Yao Qi, Tom Tromey

On 01/23/2013 02:22 PM, Kaushik Phatak wrote:
>> > How about exporting a function that hides these opcodes details?  
>> > I don't even pretend to understand what the code is trying to do, 
>> > and it'd be an opportunity to comment it in the function description.
>> >   /* Take BUF, do something with it, and write length
>> >        to LENGTH.  Blah, blah.  */
>> >    cr16_do_something (buf, *length, ...);
> I think this can be done and it will make this code look cleaner.
> An exported function in bfd would make my code look like this,
> ...
>    target_read_memory (pc, buf, 6);
>    cr16_get_insn_length (buf, *length, ...);
>    next_pc = pc + length;
>     ...
> 

If it's the instruction length you need, then did you
try gdb_buffered_insn_length or gdb_insn_length?

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2013-01-23 14:22                               ` Kaushik Phatak
  2013-01-23 14:26                                 ` Pedro Alves
@ 2013-01-23 15:34                                 ` Pedro Alves
  2013-06-19 13:30                                   ` Kaushik Phatak
  1 sibling, 1 reply; 29+ messages in thread
From: Pedro Alves @ 2013-01-23 15:34 UTC (permalink / raw)
  To: Kaushik Phatak; +Cc: Joel Brobecker, gdb-patches, Yao Qi, Tom Tromey

On 01/23/2013 02:22 PM, Kaushik Phatak wrote:

>>> +  "r0r1_orig",
>> This too looks like a ptrace detail escaping all the
>> way to the user, similar to the gdbserver issues.
>> Any reason not to split those up?  I think it'd be nicer.	
> This is a kernel scratch register and it part of PT_REGS.
> Would be OK to leave it as is as it may help in debugging?

Debugging gdb, or a user debugging an application?
If users expect to see that as a pair, fine.  If users/scripts
driving gdb would always want to read the values separately,
then I'd think it better to have separate (r0_orig,
r1_orig), or even hide one of them -- does the syscall abi
use both r0/r1 for syscall return, or is one of them in
orig just because that's how ptrace pushes registers
into the buffer?  But it's up to you, really.  The
orig_ registers aren't normally user visible.
I'm just pointing at things that looked fishy on first
sight, and it looked inconsistent to not have a pair
for r0/r1 but have it for the orig_ version.

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [RFA 3/5] New port: CR16: gdb port
  2013-01-23 15:34                                 ` Pedro Alves
@ 2013-06-19 13:30                                   ` Kaushik Phatak
  2013-06-25 18:42                                     ` Pedro Alves
  0 siblings, 1 reply; 29+ messages in thread
From: Kaushik Phatak @ 2013-06-19 13:30 UTC (permalink / raw)
  To: gdb-patches; +Cc: Pedro Alves, Joel Brobecker, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 35871 bytes --]

Hi,
Please find below an updated patch for the gdb port of the CR16 target.
This has been updated from my previous attempts of the same,
http://sourceware.org/ml/gdb-patches/2013-01/msg00299.html

The gdb port required cleanup and some tweaking and is largely unchanged, 
however the gdbserver port required some structural changes in the RSP for 
register access.
The below gdb port has following changes,
1. Removed pseudo register "r0r1_orig" which is not part of user visible 
registers and used internally by the kernel.
2. Added support for debug registers in the ELF port. This will make it consistent 
with the current simulator port which already supports them.
3. Use gdb_insn_length to read the length of the current instruction. This removes
a lot of the bfd code that used exported functions and globals. Pedro and Joel had
concerns over using this piece of code, which is now removed.
4. Use local variable "cr16_insn_words" instead of global "cr16_words" for opcode
analysis in cr16_analyze_prologue.

I will also be posting an updated gdbserver port which will compliment this port.
I am copying gcc-patches here, as there are changes to configure.ac.

2013-06-19 Kaushik Phatak  <kaushik.phatak@kpitcummins.com>
	gdb/Changelog
	* configure.tgt: Handle cr16*-*-*linux and cr16*-*-*.
	* cr16-linux-tdep.c: New file.
	* cr16-tdep.c: New file.
	* cr16-tdep.h: New file.
	* configure.ac : Add support for cr16-*-*
	* configure: Regenerate.

Index: configure
===================================================================
RCS file: /cvs/src/src/configure,v
retrieving revision 1.445
diff -u -r1.445 configure
--- configure	22 Apr 2013 15:25:08 -0000	1.445
+++ configure	19 Jun 2013 12:44:08 -0000
@@ -3622,6 +3622,9 @@
   tic54x-*-*)
     noconfigdirs="$noconfigdirs target-libgloss gdb"
     ;;
+  cr16-*-*)
+    noconfigdirs="$noconfigdirs target-libgloss"
+    ;;
   d10v-*-*)
     noconfigdirs="$noconfigdirs target-libgloss"
     ;;
Index: configure.ac
===================================================================
RCS file: /cvs/src/src/configure.ac,v
retrieving revision 1.188
diff -u -r1.188 configure.ac
--- configure.ac	22 Apr 2013 15:25:09 -0000	1.188
+++ configure.ac	19 Jun 2013 12:44:09 -0000
@@ -961,6 +961,9 @@
   tic54x-*-*)
     noconfigdirs="$noconfigdirs target-libgloss gdb"
     ;;
+  cr16-*-*)
+    noconfigdirs="$noconfigdirs target-libgloss"
+    ;;
   d10v-*-*)
     noconfigdirs="$noconfigdirs target-libgloss"
     ;;
Index: gdb/configure.tgt
===================================================================
RCS file: /cvs/src/src/gdb/configure.tgt,v
retrieving revision 1.276
diff -u -r1.276 configure.tgt
--- gdb/configure.tgt	7 May 2013 01:09:28 -0000	1.276
+++ gdb/configure.tgt	19 Jun 2013 12:44:10 -0000
@@ -129,6 +129,18 @@
 	gdb_sim=../sim/bfin/libsim.a
 	;;
 
+cr16*-*-*linux)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o cr16-linux-tdep.o linux-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
+cr16*-*-*)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
 cris*)
 	# Target: CRIS
 	gdb_target_obs="cris-tdep.o solib-svr4.o"
Index: gdb/cr16-linux-tdep.c
===================================================================
RCS file: gdb/cr16-linux-tdep.c
diff -N gdb/cr16-linux-tdep.c
--- /dev/null	2013-05-10 19:36:04.372328500 +0530
+++ ./gdb/cr16-linux-tdep.c	2013-06-17 12:49:05.000000000 +0530
@@ -0,0 +1,106 @@
+/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
+
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+#include "elf/cr16.h"
+#include "linux-tdep.h"
+#include "symtab.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for Linux targets  */
+#define CR16_LINUX_NUM_REGS  20
+
+/* The breakpoint instruction used by uClinux target  */
+static const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };
+
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "psr",
+  "pc",
+  "intbase",
+  "usp",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_LINUX_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_LINUX_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* OS specific initialization of gdbarch.  */
+
+static void
+cr16_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  linux_init_abi (info, gdbarch);
+
+  set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
+
+  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
+     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
+     requires external hardware support for breakpoints to work on
+     CR16 target.  Software based breakpoints are implemented in the
+     kernel using excp flg and tested on the SC14452 target.  Use
+     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We
+     represent the breakpoint in little endian format since CR16
+     supports only little endian.  */
+  tdep->breakpoint = breakpoint_uclinux;
+
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_linux_tdep;
+
+void
+_initialize_cr16_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_cr16, 0, GDB_OSABI_LINUX,
+			  cr16_uclinux_init_abi);
+}
Index: gdb/cr16-tdep.c
===================================================================
RCS file: gdb/cr16-tdep.c
diff -N gdb/cr16-tdep.c
--- /dev/null	2013-05-10 19:36:04.372328500 +0530
+++ ./gdb/cr16-tdep.c	2013-06-18 10:11:46.000000000 +0530
@@ -0,0 +1,894 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+ 
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+   This file is part of GDB.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+#include "osabi.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for ELF targets.  */
+#define CR16_NUM_REGS  27
+
+/* The breakpoint instruction used with sim for ELF targets.  */
+static const gdb_byte breakpoint_elf[] = { 0xC8, 0x00 };
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Hardware register name declaration.  */
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "sp",
+  "pc",
+  "isp",
+  "usp",
+  "intbase",
+  "dbs",
+  "dcrl",
+  "dsr",
+  "car0",
+  "car1",
+  "cfg",
+  "psr"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note: PC in CR16 is of 24 bits.  */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+
+    case CR16_FP_REGNUM:	/* Frame Pointer reg.  */
+    case CR16_SP_REGNUM:	/* Stack Pointer reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+    case SIM_CR16_DBS_REGNUM:
+    case SIM_CR16_DCR_REGNUM:
+    case SIM_CR16_DSR_REGNUM:
+    case SIM_CR16_CAR0_REGNUM:
+    case SIM_CR16_CAR1_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+
+    default:
+      return builtin_type (gdbarch)->builtin_int32;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch (), value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;
+  short cr16_insn_words[3];
+  struct gdbarch *gdbarch;
+
+  gdbarch = target_gdbarch ();
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch ()));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      gdb_byte buf[6];
+
+      /* Read 6 bytes, max 48 bit opcode.  */
+      target_read_memory (pc, buf, 6);
+      cr16_insn_words[0] = buf[1] << 8 | buf[0];
+      cr16_insn_words[1] = buf[3] << 8 | buf[2];
+      cr16_insn_words[2] = buf[5] << 8 | buf[4];
+
+      /* Read the length of the instruction  */
+      length = gdb_insn_length (gdbarch, pc);
+      next_pc = pc + length;
+      insn_byte1 = (cr16_insn_words[0] >> 8) & 0xFF;
+
+      /* If PUSH, then save RA and other regs.  */
+      if (insn_byte1 == 0x01)
+	{
+	  int r1, r2;
+	  int r;
+
+	  insn_byte2 = cr16_insn_words[0];
+
+	  if (insn_byte2 & 0x80)
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+	  /* Start Register=r1, 3 bit imm count=r2.  */
+	  r1 = insn_byte2 & 0x0F;
+	  r2 = ((insn_byte2 & 0x70) >> 4);
+	  r2 = r2 + r1 + 1;
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+      /* Add constant to SP.  */
+      else if (insn_byte1 == 0x60)
+	{
+	  int rdst;
+	  signed short addend;
+
+	  insn_byte2 = cr16_insn_words[0];
+	  rdst = insn_byte2 & 0x0F;
+	  if (rdst == CR16_SP_REGNUM)
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = cr16_insn_words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      /* Check for MOVD insn.  */
+      else if (insn_byte1 == 0x55)
+	{
+	  int rdst, rsrc;
+
+	  insn_byte2 = cr16_insn_words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	break;		/* Terminate the prologue scan.  */
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+/* Implement the "skip_prologue" gdbarch method.  */
+
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (*this_prologue_cache)
+    return *this_prologue_cache;
+
+  CORE_ADDR func_start, stop_addr;
+
+  *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+  func_start = get_frame_func (this_frame);
+  stop_addr = get_frame_pc (this_frame);
+
+  /* If we couldn't find any function containing the PC, then
+     just initialize the prologue cache, but don't do anything.  */
+  if (!func_start)
+    stop_addr = func_start;
+
+  cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+/* Implement the "frame_prev_register" method for unwinding frames.  */
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA
+     register, CR16_R13_REGNUM.  So, we need not adjust anything
+     directly.  We will analyze prologue as this RA register is
+     pushed onto stack for further leaf function calls to work.  */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ULONGEST ra_prev;
+
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+}
+
+static const struct frame_unwind cr16_frame_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR pc;
+
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+cr16_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)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments via registers.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ''arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R12.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u = extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, as possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* We use different breakpoint instructions for ELF and uClinux.
+     See cr16-linux-tdep.c for more details.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  *lenptr = 2;
+  return tdep->breakpoint;
+}
+
+/* Allocate and initialize a gdbarch object.  */
+
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xcalloc (1, sizeof (struct gdbarch_tdep));
+  tdep->elf_flags = elf_flags;
+  tdep->breakpoint = breakpoint_elf;
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_register_name);
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* Methods for saving / extracting a dummy frame's ID.  */
+  set_gdbarch_dummy_id (gdbarch, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
Index: gdb/cr16-tdep.h
===================================================================
RCS file: gdb/cr16-tdep.h
diff -N gdb/cr16-tdep.h
--- /dev/null	2013-05-10 19:36:04.372328500 +0530
+++ ./gdb/cr16-tdep.h	2013-06-17 12:49:05.000000000 +0530
@@ -0,0 +1,32 @@
+/* GNU/Linux on  CR16 target support.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* Target-dependent structure in gdbarch.  */
+
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  /* Breakpoint instruction.  */
+  const gdb_byte *breakpoint;
+};


[-- Attachment #2: cr16_gdb.diff --]
[-- Type: application/octet-stream, Size: 33271 bytes --]

Index: configure
===================================================================
RCS file: /cvs/src/src/configure,v
retrieving revision 1.445
diff -u -r1.445 configure
--- configure	22 Apr 2013 15:25:08 -0000	1.445
+++ configure	19 Jun 2013 12:44:08 -0000
@@ -3622,6 +3622,9 @@
   tic54x-*-*)
     noconfigdirs="$noconfigdirs target-libgloss gdb"
     ;;
+  cr16-*-*)
+    noconfigdirs="$noconfigdirs target-libgloss"
+    ;;
   d10v-*-*)
     noconfigdirs="$noconfigdirs target-libgloss"
     ;;
Index: configure.ac
===================================================================
RCS file: /cvs/src/src/configure.ac,v
retrieving revision 1.188
diff -u -r1.188 configure.ac
--- configure.ac	22 Apr 2013 15:25:09 -0000	1.188
+++ configure.ac	19 Jun 2013 12:44:09 -0000
@@ -961,6 +961,9 @@
   tic54x-*-*)
     noconfigdirs="$noconfigdirs target-libgloss gdb"
     ;;
+  cr16-*-*)
+    noconfigdirs="$noconfigdirs target-libgloss"
+    ;;
   d10v-*-*)
     noconfigdirs="$noconfigdirs target-libgloss"
     ;;
Index: gdb/configure.tgt
===================================================================
RCS file: /cvs/src/src/gdb/configure.tgt,v
retrieving revision 1.276
diff -u -r1.276 configure.tgt
--- gdb/configure.tgt	7 May 2013 01:09:28 -0000	1.276
+++ gdb/configure.tgt	19 Jun 2013 12:44:10 -0000
@@ -129,6 +129,18 @@
 	gdb_sim=../sim/bfin/libsim.a
 	;;
 
+cr16*-*-*linux)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o cr16-linux-tdep.o linux-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
+cr16*-*-*)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	;;
+
 cris*)
 	# Target: CRIS
 	gdb_target_obs="cris-tdep.o solib-svr4.o"
Index: gdb/cr16-linux-tdep.c
===================================================================
RCS file: gdb/cr16-linux-tdep.c
diff -N gdb/cr16-linux-tdep.c
--- /dev/null	2013-05-10 19:36:04.372328500 +0530
+++ ./gdb/cr16-linux-tdep.c	2013-06-17 12:49:05.000000000 +0530
@@ -0,0 +1,106 @@
+/* Target-dependent code for GNU/Linux on the Sitel CR16 processors.
+
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+#include "elf/cr16.h"
+#include "linux-tdep.h"
+#include "symtab.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for Linux targets  */
+#define CR16_LINUX_NUM_REGS  20
+
+/* The breakpoint instruction used by uClinux target  */
+static const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };
+
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "psr",
+  "pc",
+  "intbase",
+  "usp",
+  "cfg"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_LINUX_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_linux_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_LINUX_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* OS specific initialization of gdbarch.  */
+
+static void
+cr16_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  linux_init_abi (info, gdbarch);
+
+  set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
+
+  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
+     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
+     requires external hardware support for breakpoints to work on
+     CR16 target.  Software based breakpoints are implemented in the
+     kernel using excp flg and tested on the SC14452 target.  Use
+     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We
+     represent the breakpoint in little endian format since CR16
+     supports only little endian.  */
+  tdep->breakpoint = breakpoint_uclinux;
+
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_linux_tdep;
+
+void
+_initialize_cr16_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_cr16, 0, GDB_OSABI_LINUX,
+			  cr16_uclinux_init_abi);
+}
Index: gdb/cr16-tdep.c
===================================================================
RCS file: gdb/cr16-tdep.c
diff -N gdb/cr16-tdep.c
--- /dev/null	2013-05-10 19:36:04.372328500 +0530
+++ ./gdb/cr16-tdep.c	2013-06-18 10:11:46.000000000 +0530
@@ -0,0 +1,894 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+ 
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+   This file is part of GDB.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+#include "osabi.h"
+#include "cr16-tdep.h"
+
+/* Number of registers available for ELF targets.  */
+#define CR16_NUM_REGS  27
+
+/* The breakpoint instruction used with sim for ELF targets.  */
+static const gdb_byte breakpoint_elf[] = { 0xC8, 0x00 };
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Hardware register name declaration.  */
+static const char *const reg_names[] =
+{
+  "r0",
+  "r1",
+  "r2",
+  "r3",
+  "r4",
+  "r5",
+  "r6",
+  "r7",
+  "r8",
+  "r9",
+  "r10",
+  "r11",
+  "r12",
+  "r13",
+  "ra",
+  "sp",
+  "pc",
+  "isp",
+  "usp",
+  "intbase",
+  "dbs",
+  "dcrl",
+  "dsr",
+  "car0",
+  "car1",
+  "cfg",
+  "psr"
+};
+
+/* Verify register array size is within hardware register limit.  */
+
+gdb_static_assert (ARRAY_SIZE (reg_names) <= CR16_NUM_REGS);
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  gdb_assert (regnr >= 0 && regnr < CR16_NUM_REGS);
+  return reg_names[regnr];
+}
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note: PC in CR16 is of 24 bits.  */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+
+    case CR16_FP_REGNUM:	/* Frame Pointer reg.  */
+    case CR16_SP_REGNUM:	/* Stack Pointer reg.  */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+    case SIM_CR16_DBS_REGNUM:
+    case SIM_CR16_DCR_REGNUM:
+    case SIM_CR16_DSR_REGNUM:
+    case SIM_CR16_CAR0_REGNUM:
+    case SIM_CR16_CAR1_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+
+    default:
+      return builtin_type (gdbarch)->builtin_int32;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch (), value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;
+  short cr16_insn_words[3];
+  struct gdbarch *gdbarch;
+
+  gdbarch = target_gdbarch ();
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch ()));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      gdb_byte buf[6];
+
+      /* Read 6 bytes, max 48 bit opcode.  */
+      target_read_memory (pc, buf, 6);
+      cr16_insn_words[0] = buf[1] << 8 | buf[0];
+      cr16_insn_words[1] = buf[3] << 8 | buf[2];
+      cr16_insn_words[2] = buf[5] << 8 | buf[4];
+
+      /* Read the length of the instruction  */
+      length = gdb_insn_length (gdbarch, pc);
+      next_pc = pc + length;
+      insn_byte1 = (cr16_insn_words[0] >> 8) & 0xFF;
+
+      /* If PUSH, then save RA and other regs.  */
+      if (insn_byte1 == 0x01)
+	{
+	  int r1, r2;
+	  int r;
+
+	  insn_byte2 = cr16_insn_words[0];
+
+	  if (insn_byte2 & 0x80)
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+	  /* Start Register=r1, 3 bit imm count=r2.  */
+	  r1 = insn_byte2 & 0x0F;
+	  r2 = ((insn_byte2 & 0x70) >> 4);
+	  r2 = r2 + r1 + 1;
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+      /* Add constant to SP.  */
+      else if (insn_byte1 == 0x60)
+	{
+	  int rdst;
+	  signed short addend;
+
+	  insn_byte2 = cr16_insn_words[0];
+	  rdst = insn_byte2 & 0x0F;
+	  if (rdst == CR16_SP_REGNUM)
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = cr16_insn_words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      /* Check for MOVD insn.  */
+      else if (insn_byte1 == 0x55)
+	{
+	  int rdst, rsrc;
+
+	  insn_byte2 = cr16_insn_words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	break;		/* Terminate the prologue scan.  */
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+/* Implement the "skip_prologue" gdbarch method.  */
+
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (*this_prologue_cache)
+    return *this_prologue_cache;
+
+  CORE_ADDR func_start, stop_addr;
+
+  *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+  func_start = get_frame_func (this_frame);
+  stop_addr = get_frame_pc (this_frame);
+
+  /* If we couldn't find any function containing the PC, then
+     just initialize the prologue cache, but don't do anything.  */
+  if (!func_start)
+    stop_addr = func_start;
+
+  cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+/* Implement the "frame_prev_register" method for unwinding frames.  */
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA
+     register, CR16_R13_REGNUM.  So, we need not adjust anything
+     directly.  We will analyze prologue as this RA register is
+     pushed onto stack for further leaf function calls to work.  */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ULONGEST ra_prev;
+
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+}
+
+static const struct frame_unwind cr16_frame_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR pc;
+
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+cr16_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)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments via registers.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ''arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R12.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u = extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, as possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* We use different breakpoint instructions for ELF and uClinux.
+     See cr16-linux-tdep.c for more details.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  *lenptr = 2;
+  return tdep->breakpoint;
+}
+
+/* Allocate and initialize a gdbarch object.  */
+
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xcalloc (1, sizeof (struct gdbarch_tdep));
+  tdep->elf_flags = elf_flags;
+  tdep->breakpoint = breakpoint_elf;
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, cr16_register_name);
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* Methods for saving / extracting a dummy frame's ID.  */
+  set_gdbarch_dummy_id (gdbarch, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
Index: gdb/cr16-tdep.h
===================================================================
RCS file: gdb/cr16-tdep.h
diff -N gdb/cr16-tdep.h
--- /dev/null	2013-05-10 19:36:04.372328500 +0530
+++ ./gdb/cr16-tdep.h	2013-06-17 12:49:05.000000000 +0530
@@ -0,0 +1,32 @@
+/* GNU/Linux on  CR16 target support.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+   Contributed by Kaushik Phatak (kaushik.phatak@kpitcummins.com)
+   KPIT Cummins Infosystems Limited, Pune India.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* Target-dependent structure in gdbarch.  */
+
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  /* Breakpoint instruction.  */
+  const gdb_byte *breakpoint;
+};

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2013-06-19 13:30                                   ` Kaushik Phatak
@ 2013-06-25 18:42                                     ` Pedro Alves
  2013-06-26  7:08                                       ` Kaushik Phatak
  0 siblings, 1 reply; 29+ messages in thread
From: Pedro Alves @ 2013-06-25 18:42 UTC (permalink / raw)
  To: Kaushik Phatak; +Cc: gdb-patches, Joel Brobecker

(dropping gcc-patches@)

On 06/19/2013 02:14 PM, Kaushik Phatak wrote:
> Hi,
> Please find below an updated patch for the gdb port of the CR16 target.
> This has been updated from my previous attempts of the same,
> http://sourceware.org/ml/gdb-patches/2013-01/msg00299.html
> 
> The gdb port required cleanup and some tweaking and is largely unchanged, 
> however the gdbserver port required some structural changes in the RSP for 
> register access.
> The below gdb port has following changes,
> 1. Removed pseudo register "r0r1_orig" which is not part of user visible 
> registers and used internally by the kernel.

Hmm.  Just to be clear, isn't exposing r0_orig to gDB necessary for
syscall restarting, like orig_eax/orig_rax on x86/x86_64, orig_r3 on ppc,
orig_r2 on s390, etc.?  See e.g., i386_linux_write_pc, amd64_linux_write_pc,
ppc_linux_write_pc, s390_write_pc.

> 2. Added support for debug registers in the ELF port. This will make it consistent 
> with the current simulator port which already supports them.

Are these always present in all versions of CR16 silicon?  IOW, are
we safe with adding them to the core register set (*)?  Otherwise,
you should really split them to a separate target description feature.

(*) which registers are those btw?  I'm not that familiar with CR16.  :-)

> 3. Use gdb_insn_length to read the length of the current instruction. This removes
> a lot of the bfd code that used exported functions and globals. Pedro and Joel had
> concerns over using this piece of code, which is now removed.

Excellent.

> 4. Use local variable "cr16_insn_words" instead of global "cr16_words" for opcode
> analysis in cr16_analyze_prologue.
> 
> I will also be posting an updated gdbserver port which will compliment this port.
> I am copying gcc-patches here, as there are changes to configure.ac.
> 

This otherwise looks very good.  Thanks for the update.  A few minor
comments below.

> 2013-06-19 Kaushik Phatak  <kaushik.phatak@kpitcummins.com>
> 	gdb/Changelog
> 	* configure.tgt: Handle cr16*-*-*linux and cr16*-*-*.
> 	* cr16-linux-tdep.c: New file.
> 	* cr16-tdep.c: New file.
> 	* cr16-tdep.h: New file.
> 	* configure.ac : Add support for cr16-*-*

No space before ':'.

> 	* configure: Regenerate.

> Index: gdb/cr16-linux-tdep.c
> ===================================================================
> RCS file: gdb/cr16-linux-tdep.c
> diff -N gdb/cr16-linux-tdep.c

> +
> +/* Number of registers available for Linux targets  */

Full stop and double space.

/* Number of registers available for Linux targets.  */

> +#define CR16_LINUX_NUM_REGS  20
> +
> +/* The breakpoint instruction used by uClinux target  */

Ditto.  "by the uClinux".

> +static const gdb_byte breakpoint_uclinux[] = { 0xC7, 0x00 };


> +/* OS specific initialization of gdbarch.  */
> +
> +static void
> +cr16_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> +{
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +
> +  linux_init_abi (info, gdbarch);
> +
> +  set_gdbarch_num_regs (gdbarch, CR16_LINUX_NUM_REGS);
> +  set_gdbarch_register_name (gdbarch, cr16_linux_register_name);
> +
> +  /* The opcode of excp bpt is 0x00C8, however for uclinux we will
> +     use the excp flg (0x00C7) to insert a breakpoint.  The excp bpt
> +     requires external hardware support for breakpoints to work on
> +     CR16 target.  Software based breakpoints are implemented in the

"on _the_ CR16 target".

> +     kernel using excp flg and tested on the SC14452 target.  Use
> +     0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF.  We
> +     represent the breakpoint in little endian format since CR16
> +     supports only little endian.  */
> +  tdep->breakpoint = breakpoint_uclinux;



> +/* Implement the "frame_this_id" method for unwinding frames.  */
> +
> +static void
> +cr16_frame_this_id (struct frame_info *this_frame,
> +		    void **this_prologue_cache, struct frame_id *this_id)
> +{
> +  *this_id =
> +    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),

= goes on the next line.

> +		    get_frame_func (this_frame));
> +}
> +
> +/* Implement the "frame_prev_register" method for unwinding frames.  */
> +
> +static struct value *
> +cr16_frame_prev_register (struct frame_info *this_frame,
> +			  void **this_prologue_cache, int regnum)
> +{
> +  struct cr16_prologue *p =
> +    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);

Ditto.

> +
> +/* Implement the "return_value" gdbarch method.  */
> +
> +static enum return_value_convention
> +cr16_return_value (struct gdbarch *gdbarch,
> +		   struct type *func_type,
> +		   struct type *valtype,
> +		   struct regcache *regcache,
> +		   gdb_byte * readbuf, const gdb_byte * writebuf)
> +{
...
> +
> +  if (readbuf)

  if (readbuf != NULL)

> +    {
> +      ULONGEST u;
> +      int argreg = CR16_R0_REGNUM;
> +      int offset = 0;
> +
> +      while (valtype_len > 0)
> +	{
> +	  int len = min (valtype_len, 4);
> +
> +	  regcache_cooked_read_unsigned (regcache, argreg, &u);
> +	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
> +	  valtype_len -= len;
> +	  offset += len;
> +	  argreg++;
> +	}
> +    }
> +
> +  if (writebuf)

 if (writebuf != NULL)

> Index: gdb/cr16-tdep.h
> ===================================================================
> RCS file: gdb/cr16-tdep.h
> diff -N gdb/cr16-tdep.h
> --- /dev/null	2013-05-10 19:36:04.372328500 +0530
> +++ ./gdb/cr16-tdep.h	2013-06-17 12:49:05.000000000 +0530
> @@ -0,0 +1,32 @@
> +/* GNU/Linux on  CR16 target support.

Nope, this is not the GNU/Linux file.  Also spurious double space
there.

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [RFA 3/5] New port: CR16: gdb port
  2013-06-25 18:42                                     ` Pedro Alves
@ 2013-06-26  7:08                                       ` Kaushik Phatak
  2013-06-26 10:37                                         ` Pedro Alves
  0 siblings, 1 reply; 29+ messages in thread
From: Kaushik Phatak @ 2013-06-26  7:08 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Joel Brobecker

Hi Pedro,
Thanks for another round of detailed review.

>> Hmm.  Just to be clear, isn't exposing r0_orig to gDB necessary for
>> syscall restarting, like orig_eax/orig_rax on x86/x86_64, orig_r3 on ppc,
>> orig_r2 on s390, etc.?  See e.g., i386_linux_write_pc, amd64_linux_write_pc,
>> ppc_linux_write_pc, s390_write_pc.

The original PTRACE implementation disallowed write to orig_r0and1, however read
was permitted. We can implement this as suggested above, so user may write a -1 to 
this register to prevent a SIGSEGV or SIGILL similar to amd64_linux_write_pc.
The signal handler checks for "regs->orig_r0and1 >= 0" before performing a -ERESTARTSYS
I will add this register to linux-tdep in gdb as well as the gdbserver port, ok?

>> Are these always present in all versions of CR16 silicon?  IOW, are
>> we safe with adding them to the core register set (*)?  
>> (*) which registers are those btw?  I'm not that familiar with CR16.  :-)
The following 5 registers have been added to this patch, which are debug registers,
"dbs","dcrl","dsr","car0","car1"
These registers are not part of every silicon and can be an optional feature.
However, the current simulator port seems to support these by default.

>> you should really split them to a separate target description feature.
Is there any other port i can refer for this?  

I will run through my code again and work on the other formatting related comments
provided.

Thanks,
Kaushik



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFA 3/5] New port: CR16: gdb port
  2013-06-26  7:08                                       ` Kaushik Phatak
@ 2013-06-26 10:37                                         ` Pedro Alves
  0 siblings, 0 replies; 29+ messages in thread
From: Pedro Alves @ 2013-06-26 10:37 UTC (permalink / raw)
  To: Kaushik Phatak; +Cc: gdb-patches, Joel Brobecker

On 06/26/2013 08:02 AM, Kaushik Phatak wrote:
> Hi Pedro,
> Thanks for another round of detailed review.
> 
>>> Hmm.  Just to be clear, isn't exposing r0_orig to gDB necessary for
>>> syscall restarting, like orig_eax/orig_rax on x86/x86_64, orig_r3 on ppc,
>>> orig_r2 on s390, etc.?  See e.g., i386_linux_write_pc, amd64_linux_write_pc,
>>> ppc_linux_write_pc, s390_write_pc.
> 
> The original PTRACE implementation disallowed write to orig_r0and1, however read
> was permitted. We can implement this as suggested above, so user may write a -1 to 
> this register to prevent a SIGSEGV or SIGILL similar to amd64_linux_write_pc.
> The signal handler checks for "regs->orig_r0and1 >= 0" before performing a -ERESTARTSYS
> I will add this register to linux-tdep in gdb as well as the gdbserver port, ok?

Sounds good.  You should put that register in a separate target description
feature.  See:

$ find features/ -name "*.xml" | xargs grep orig_
features/s390x-linux64v2.xml:    <reg name="orig_r2" bitsize="64" type="uint64" group="system"/>
features/rs6000/power-linux.xml:  <reg name="orig_r3" bitsize="32" regnum="71"/>
features/rs6000/power64-linux.xml:  <reg name="orig_r3" bitsize="64" regnum="71"/>
features/s390-linux64v2.xml:    <reg name="orig_r2" bitsize="32" type="uint32" group="system"/>
features/s390-linux64.xml:    <reg name="orig_r2" bitsize="32" type="uint32" group="system"/>
features/s390-linux64v1.xml:    <reg name="orig_r2" bitsize="32" type="uint32" group="system"/>
features/s390-linux32v2.xml:    <reg name="orig_r2" bitsize="32" type="uint32" group="system"/>
features/s390x-linux64v1.xml:    <reg name="orig_r2" bitsize="64" type="uint64" group="system"/>
features/i386/32bit-linux.xml:  <reg name="orig_eax" bitsize="32" type="int" regnum="41"/>
features/i386/64bit-linux.xml:  <reg name="orig_rax" bitsize="64" type="int" regnum="57"/>
features/s390-linux32.xml:    <reg name="orig_r2" bitsize="32" type="uint32" group="system"/>
features/s390-linux32v1.xml:    <reg name="orig_r2" bitsize="32" type="uint32" group="system"/>
features/s390x-linux64.xml:    <reg name="orig_r2" bitsize="64" type="uint64" group="system"/>

And:

$ grep tdesc_find_feature * | grep linux
amd64-linux-tdep.c:  feature = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.linux");
amd64-linux-tdep.c:  feature = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.linux");
i386-linux-tdep.c:  feature = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.linux");
i386-linux-tdep.c:  if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx"))
i386-linux-tdep.c:  else if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.sse"))
mips-linux-tdep.c:      feature = tdesc_find_feature (info.target_desc,
ppc-linux-tdep.c:      if (tdesc_find_feature (info.target_desc,
ppc-linux-tdep.c:      else if (tdesc_find_feature (info.target_desc,
ppc-linux-tdep.c:      if (tdesc_find_feature (info.target_desc,
ppc-linux-tdep.c:      else if (tdesc_find_feature (info.target_desc,
ppc-linux-tdep.c:      feature = tdesc_find_feature (info.target_desc,
s390-tdep.c:      feature = tdesc_find_feature (tdesc, "org.gnu.gdb.s390.linux");

> 
>>> Are these always present in all versions of CR16 silicon?  IOW, are
>>> we safe with adding them to the core register set (*)?  
>>> (*) which registers are those btw?  I'm not that familiar with CR16.  :-)
> The following 5 registers have been added to this patch, which are debug registers,
> "dbs","dcrl","dsr","car0","car1"
> These registers are not part of every silicon and can be an optional feature.
> However, the current simulator port seems to support these by default.

Sure, but remote debugging such part with e.g., jtag should still be
supported.

> 
>>> you should really split them to a separate target description feature.
> Is there any other port i can refer for this?  

Look for tdesc_find_feature.  Maybe tic6x_gdbarch_init would be a simple
enough reference.

> I will run through my code again and work on the other formatting related comments
> provided.

Thanks.

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2013-06-26 10:32 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-04 10:22 [RFA 3/5] New port: CR16: gdb port Kaushik Phatak
2012-10-04 14:48 ` Joel Brobecker
2012-10-05 11:44   ` Kaushik Phatak
2012-10-05 12:21     ` Joel Brobecker
2012-10-09 13:20       ` Kaushik Phatak
2012-10-08  6:59 ` Yao Qi
2012-10-09 15:03   ` Kaushik Phatak
2012-10-22 22:41     ` Joel Brobecker
2012-10-23 13:03       ` Kaushik Phatak
2012-10-23 13:55         ` Joel Brobecker
2012-10-26  5:15           ` Kaushik Phatak
2012-11-15 17:43             ` Joel Brobecker
2012-11-20 13:01               ` Kaushik Phatak
2012-11-22 17:50                 ` Joel Brobecker
2013-01-08 10:02                   ` Kaushik Phatak
2013-01-15  9:31                   ` Kaushik Phatak
2013-01-17  8:59                     ` Joel Brobecker
2013-01-18  7:41                       ` Kaushik Phatak
2013-01-18 14:17                         ` Joel Brobecker
2013-01-22 13:49                           ` Kaushik Phatak
2013-01-22 15:43                             ` Pedro Alves
2013-01-23 14:22                               ` Kaushik Phatak
2013-01-23 14:26                                 ` Pedro Alves
2013-01-23 15:34                                 ` Pedro Alves
2013-06-19 13:30                                   ` Kaushik Phatak
2013-06-25 18:42                                     ` Pedro Alves
2013-06-26  7:08                                       ` Kaushik Phatak
2013-06-26 10:37                                         ` Pedro Alves
2013-01-18 18:25                       ` Pedro Alves

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox