]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
This commit was manufactured by cvs2svn to create branch
authornobody <>
Tue, 17 Sep 2002 20:42:02 +0000 (20:42 +0000)
committernobody <>
Tue, 17 Sep 2002 20:42:02 +0000 (20:42 +0000)
'carlton_dictionary-branch'.

Cherrypick from gdb_5_3-branch 2002-09-03 22:29:15 UTC nobody 'This commit was manufactured by cvs2svn to create branch 'gdb_5_3-branch'.':
    gdb/ns32k-tdep.c
    gdb/sh3-rom.c
    gdb/vax-tdep.c
Cherrypick from master 2002-09-17 20:42:01 UTC Andrew Cagney <cagney@redhat.com> '2002-09-17  Andrew Cagney  <cagney@redhat.com>':
    gdb/cris-tdep.c
    gdb/mcore-tdep.c

gdb/cris-tdep.c [new file with mode: 0644]
gdb/mcore-tdep.c [new file with mode: 0644]
gdb/ns32k-tdep.c [new file with mode: 0644]
gdb/sh3-rom.c [new file with mode: 0644]
gdb/vax-tdep.c [new file with mode: 0644]

diff --git a/gdb/cris-tdep.c b/gdb/cris-tdep.c
new file mode 100644 (file)
index 0000000..0bfb5b3
--- /dev/null
@@ -0,0 +1,4348 @@
+/* Target dependent code for CRIS, for GDB, the GNU debugger.
+   Copyright 2001 Free Software Foundation, Inc.
+   Contributed by Axis Communications AB.
+   Written by Hendrik Ruijter, Stefan Andersson, and Orjan Friberg.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "symtab.h"
+#include "inferior.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "value.h"
+#include "opcode/cris.h"
+#include "arch-utils.h"
+#include "regcache.h"
+
+/* To get entry_point_address.  */
+#include "symfile.h"
+
+#include "solib.h"              /* Support for shared libraries. */
+#include "solib-svr4.h"         /* For struct link_map_offsets.  */
+
+
+enum cris_num_regs
+{
+  /* There are no floating point registers.  Used in gdbserver low-linux.c.  */
+  NUM_FREGS = 0,
+  
+  /* There are 16 general registers.  */
+  NUM_GENREGS = 16,
+  
+  /* There are 16 special registers.  */
+  NUM_SPECREGS = 16
+};
+
+/* Register numbers of various important registers.
+   FP_REGNUM   Contains address of executing stack frame.
+   STR_REGNUM  Contains the address of structure return values.
+   RET_REGNUM  Contains the return value when shorter than or equal to 32 bits
+   ARG1_REGNUM Contains the first parameter to a function.
+   ARG2_REGNUM Contains the second parameter to a function.
+   ARG3_REGNUM Contains the third parameter to a function.
+   ARG4_REGNUM Contains the fourth parameter to a function. Rest on stack.
+   SP_REGNUM   Contains address of top of stack.
+   PC_REGNUM   Contains address of next instruction.
+   SRP_REGNUM  Subroutine return pointer register.
+   BRP_REGNUM  Breakpoint return pointer register.  */
+
+/* FP_REGNUM = 8, SP_REGNUM = 14, and PC_REGNUM = 15 have been incorporated
+   into the multi-arch framework.  */
+
+enum cris_regnums
+{
+  /* Enums with respect to the general registers, valid for all 
+     CRIS versions.  */
+  STR_REGNUM  = 9,
+  RET_REGNUM  = 10,
+  ARG1_REGNUM = 10,
+  ARG2_REGNUM = 11,
+  ARG3_REGNUM = 12,
+  ARG4_REGNUM = 13,
+  
+  /* Enums with respect to the special registers, some of which may not be
+     applicable to all CRIS versions.  */
+  P0_REGNUM   = 16,
+  VR_REGNUM   = 17,
+  P2_REGNUM   = 18,
+  P3_REGNUM   = 19,
+  P4_REGNUM   = 20,
+  CCR_REGNUM  = 21,
+  MOF_REGNUM  = 23,
+  P8_REGNUM   = 24,
+  IBR_REGNUM  = 25,
+  IRP_REGNUM  = 26,
+  SRP_REGNUM  = 27,
+  BAR_REGNUM  = 28,
+  DCCR_REGNUM = 29,
+  BRP_REGNUM  = 30,
+  USP_REGNUM  = 31
+};
+
+extern const struct cris_spec_reg cris_spec_regs[];
+
+/* CRIS version, set via the user command 'set cris-version'.  Affects
+   register names and sizes.*/
+static int usr_cmd_cris_version;
+
+/* Indicates whether to trust the above variable.  */
+static int usr_cmd_cris_version_valid = 0;
+
+/* CRIS mode, set via the user command 'set cris-mode'.  Affects availability
+   of some registers.  */
+static const char *usr_cmd_cris_mode;
+
+/* Indicates whether to trust the above variable.  */
+static int usr_cmd_cris_mode_valid = 0;
+
+static const char CRIS_MODE_USER[] = "CRIS_MODE_USER";
+static const char CRIS_MODE_SUPERVISOR[] = "CRIS_MODE_SUPERVISOR";
+static const char *cris_mode_enums[] = 
+{
+  CRIS_MODE_USER,
+  CRIS_MODE_SUPERVISOR,
+  0
+};
+
+/* CRIS ABI, set via the user command 'set cris-abi'.  
+   There are two flavours:
+   1. Original ABI with 32-bit doubles, where arguments <= 4 bytes are 
+   passed by value.
+   2. New ABI with 64-bit doubles, where arguments <= 8 bytes are passed by 
+   value.  */
+static const char *usr_cmd_cris_abi;
+
+/* Indicates whether to trust the above variable.  */
+static int usr_cmd_cris_abi_valid = 0;
+
+/* These variables are strings instead of enums to make them usable as 
+   parameters to add_set_enum_cmd.  */
+static const char CRIS_ABI_ORIGINAL[] = "CRIS_ABI_ORIGINAL";
+static const char CRIS_ABI_V2[] = "CRIS_ABI_V2";
+static const char CRIS_ABI_SYMBOL[] = ".$CRIS_ABI_V2";
+static const char *cris_abi_enums[] = 
+{
+  CRIS_ABI_ORIGINAL,
+  CRIS_ABI_V2,
+  0
+};
+
+/* CRIS architecture specific information.  */
+struct gdbarch_tdep
+{
+  int cris_version;
+  const char *cris_mode;
+  const char *cris_abi;
+};
+
+/* Functions for accessing target dependent data.  */
+
+static int
+cris_version (void)
+{
+  return (gdbarch_tdep (current_gdbarch)->cris_version);
+}
+
+static const char *
+cris_mode (void)
+{
+  return (gdbarch_tdep (current_gdbarch)->cris_mode);
+}
+
+static const char *
+cris_abi (void)
+{
+  return (gdbarch_tdep (current_gdbarch)->cris_abi);
+}
+
+/* For saving call-clobbered contents in R9 when returning structs.  */
+static CORE_ADDR struct_return_address;
+
+struct frame_extra_info
+{
+  CORE_ADDR return_pc;
+  int leaf_function;
+};
+
+/* The instruction environment needed to find single-step breakpoints.  */
+typedef 
+struct instruction_environment
+{
+  unsigned long reg[NUM_GENREGS];
+  unsigned long preg[NUM_SPECREGS];
+  unsigned long branch_break_address;
+  unsigned long delay_slot_pc;
+  unsigned long prefix_value;
+  int   branch_found;
+  int   prefix_found;
+  int   invalid;
+  int   slot_needed;
+  int   delay_slot_pc_active;
+  int   xflag_found;
+  int   disable_interrupt;
+} inst_env_type;
+
+/* Save old breakpoints in order to restore the state before a single_step. 
+   At most, two breakpoints will have to be remembered.  */
+typedef 
+char binsn_quantum[BREAKPOINT_MAX];
+static binsn_quantum break_mem[2];
+static CORE_ADDR next_pc = 0;
+static CORE_ADDR branch_target_address = 0;
+static unsigned char branch_break_inserted = 0;
+
+/* Machine-dependencies in CRIS for opcodes.  */
+
+/* Instruction sizes.  */
+enum cris_instruction_sizes
+{
+  INST_BYTE_SIZE  = 0,
+  INST_WORD_SIZE  = 1,
+  INST_DWORD_SIZE = 2
+};
+
+/* Addressing modes.  */
+enum cris_addressing_modes
+{
+  REGISTER_MODE = 1,
+  INDIRECT_MODE = 2,
+  AUTOINC_MODE  = 3
+};
+
+/* Prefix addressing modes.  */
+enum cris_prefix_addressing_modes
+{
+  PREFIX_INDEX_MODE  = 2,
+  PREFIX_ASSIGN_MODE = 3,
+
+  /* Handle immediate byte offset addressing mode prefix format.  */
+  PREFIX_OFFSET_MODE = 2
+};
+
+/* Masks for opcodes.  */
+enum cris_opcode_masks
+{
+  BRANCH_SIGNED_SHORT_OFFSET_MASK = 0x1,
+  SIGNED_EXTEND_BIT_MASK          = 0x2,
+  SIGNED_BYTE_MASK                = 0x80,
+  SIGNED_BYTE_EXTEND_MASK         = 0xFFFFFF00,
+  SIGNED_WORD_MASK                = 0x8000,
+  SIGNED_WORD_EXTEND_MASK         = 0xFFFF0000,
+  SIGNED_DWORD_MASK               = 0x80000000,
+  SIGNED_QUICK_VALUE_MASK         = 0x20,
+  SIGNED_QUICK_VALUE_EXTEND_MASK  = 0xFFFFFFC0
+};
+
+/* Functions for opcodes.  The general form of the ETRAX 16-bit instruction:
+   Bit 15 - 12   Operand2
+       11 - 10   Mode
+        9 -  6   Opcode
+        5 -  4   Size
+        3 -  0   Operand1  */
+
+static int 
+cris_get_operand2 (unsigned short insn)
+{
+  return ((insn & 0xF000) >> 12);
+}
+
+static int
+cris_get_mode (unsigned short insn)
+{
+  return ((insn & 0x0C00) >> 10);
+}
+
+static int
+cris_get_opcode (unsigned short insn)
+{
+  return ((insn & 0x03C0) >> 6);
+}
+
+static int
+cris_get_size (unsigned short insn)
+{
+  return ((insn & 0x0030) >> 4);
+}
+
+static int
+cris_get_operand1 (unsigned short insn)
+{
+  return (insn & 0x000F);
+}
+
+/* Additional functions in order to handle opcodes.  */
+
+static int
+cris_get_wide_opcode (unsigned short insn)
+{
+  return ((insn & 0x03E0) >> 5);
+}
+
+static int
+cris_get_short_size (unsigned short insn)
+{
+  return ((insn & 0x0010) >> 4);
+}
+
+static int
+cris_get_quick_value (unsigned short insn)
+{
+  return (insn & 0x003F);
+}
+
+static int
+cris_get_bdap_quick_offset (unsigned short insn)
+{
+  return (insn & 0x00FF);
+}
+
+static int
+cris_get_branch_short_offset (unsigned short insn)
+{
+  return (insn & 0x00FF);
+}
+
+static int
+cris_get_asr_shift_steps (unsigned long value)
+{
+  return (value & 0x3F);
+}
+
+static int
+cris_get_asr_quick_shift_steps (unsigned short insn)
+{
+  return (insn & 0x1F);
+}
+
+static int
+cris_get_clear_size (unsigned short insn)
+{
+  return ((insn) & 0xC000);
+}
+
+static int
+cris_is_signed_extend_bit_on (unsigned short insn)
+{
+  return (((insn) & 0x20) == 0x20);
+}
+
+static int
+cris_is_xflag_bit_on (unsigned short insn)
+{
+  return (((insn) & 0x1000) == 0x1000);
+}
+
+static void
+cris_set_size_to_dword (unsigned short *insn)
+{
+  *insn &= 0xFFCF; 
+  *insn |= 0x20; 
+}
+
+static signed char
+cris_get_signed_offset (unsigned short insn)
+{
+  return ((signed char) (insn & 0x00FF));
+}
+
+/* Calls an op function given the op-type, working on the insn and the
+   inst_env.  */
+static void cris_gdb_func (enum cris_op_type, unsigned short, inst_env_type *);
+
+static CORE_ADDR cris_skip_prologue_main (CORE_ADDR pc, int frameless_p);
+
+static struct gdbarch *cris_gdbarch_init (struct gdbarch_info,
+                                          struct gdbarch_list *);
+
+static int cris_delayed_get_disassembler (bfd_vma, disassemble_info *);
+
+static void cris_dump_tdep (struct gdbarch *, struct ui_file *);
+
+static void cris_version_update (char *ignore_args, int from_tty, 
+                                 struct cmd_list_element *c);
+
+static void cris_mode_update (char *ignore_args, int from_tty, 
+                              struct cmd_list_element *c);
+
+static void cris_abi_update (char *ignore_args, int from_tty, 
+                             struct cmd_list_element *c);
+
+static CORE_ADDR bfd_lookup_symbol (bfd *, const char *);
+
+/* Frames information. The definition of the struct frame_info is
+
+   CORE_ADDR frame
+   CORE_ADDR pc
+   int signal_handler_caller
+   CORE_ADDR return_pc
+   int leaf_function
+
+   If the compilation option -fno-omit-frame-pointer is present the
+   variable frame will be set to the content of R8 which is the frame
+   pointer register.
+
+   The variable pc contains the address where execution is performed
+   in the present frame.  The innermost frame contains the current content
+   of the register PC.  All other frames contain the content of the
+   register PC in the next frame.
+
+   The variable signal_handler_caller is non-zero when the frame is
+   associated with the call of a signal handler.
+
+   The variable return_pc contains the address where execution should be
+   resumed when the present frame has finished, the return address.
+
+   The variable leaf_function is 1 if the return address is in the register
+   SRP, and 0 if it is on the stack.
+
+   Prologue instructions C-code.
+   The prologue may consist of (-fno-omit-frame-pointer)
+   1)                2)
+   push   srp
+   push   r8         push   r8
+   move.d sp,r8      move.d sp,r8
+   subq   X,sp       subq   X,sp
+   movem  rY,[sp]    movem  rY,[sp]
+   move.S rZ,[r8-U]  move.S rZ,[r8-U]
+
+   where 1 is a non-terminal function, and 2 is a leaf-function.
+
+   Note that this assumption is extremely brittle, and will break at the
+   slightest change in GCC's prologue.
+
+   If local variables are declared or register contents are saved on stack
+   the subq-instruction will be present with X as the number of bytes
+   needed for storage.  The reshuffle with respect to r8 may be performed
+   with any size S (b, w, d) and any of the general registers Z={0..13}. 
+   The offset U should be representable by a signed 8-bit value in all cases. 
+   Thus, the prefix word is assumed to be immediate byte offset mode followed
+   by another word containing the instruction.
+
+   Degenerate cases:
+   3)
+   push   r8
+   move.d sp,r8
+   move.d r8,sp
+   pop    r8   
+
+   Prologue instructions C++-code.
+   Case 1) and 2) in the C-code may be followed by
+
+   move.d r10,rS    ; this
+   move.d r11,rT    ; P1
+   move.d r12,rU    ; P2
+   move.d r13,rV    ; P3
+   move.S [r8+U],rZ ; P4
+
+   if any of the call parameters are stored. The host expects these 
+   instructions to be executed in order to get the call parameters right.  */
+
+/* Examine the prologue of a function.  The variable ip is the address of 
+   the first instruction of the prologue.  The variable limit is the address 
+   of the first instruction after the prologue.  The variable fi contains the 
+   information in struct frame_info.  The variable frameless_p controls whether
+   the entire prologue is examined (0) or just enough instructions to 
+   determine that it is a prologue (1).  */
+
+CORE_ADDR 
+cris_examine (CORE_ADDR ip, CORE_ADDR limit, struct frame_info *fi, 
+              int frameless_p)
+{
+  /* Present instruction.  */
+  unsigned short insn;
+
+  /* Next instruction, lookahead.  */
+  unsigned short insn_next; 
+  int regno;
+
+  /* Is there a push fp?  */
+  int have_fp; 
+
+  /* Number of byte on stack used for local variables and movem.  */
+  int val; 
+
+  /* Highest register number in a movem.  */
+  int regsave;
+
+  /* move.d r<source_register>,rS */
+  short source_register; 
+
+  /* This frame is with respect to a leaf until a push srp is found.  */
+  fi->extra_info->leaf_function = 1;
+
+  /* This frame is without the FP until a push fp is found.  */
+  have_fp = 0;
+
+  /* Assume nothing on stack.  */
+  val = 0;
+  regsave = -1;
+
+  /* No information about register contents so far.  */
+
+  /* We only want to know the end of the prologue when fi->saved_regs == 0.
+     When the saved registers are allocated full information is required.  */
+  if (fi->saved_regs)
+    {
+      for (regno = 0; regno < NUM_REGS; regno++)
+        fi->saved_regs[regno] = 0;
+    }
+  /* Find the prologue instructions.  */
+  do
+    {
+      insn = read_memory_unsigned_integer (ip, sizeof (short));
+      ip += sizeof (short);
+      if (insn == 0xE1FC)
+        {
+          /* push <reg> 32 bit instruction */
+          insn_next = read_memory_unsigned_integer (ip, sizeof (short));
+          ip += sizeof (short);
+          regno = cris_get_operand2 (insn_next);
+
+          /* This check, meant to recognize srp, used to be regno == 
+             (SRP_REGNUM - NUM_GENREGS), but that covers r11 also.  */
+          if (insn_next == 0xBE7E)
+            {
+              if (frameless_p)
+                {
+                  return ip;
+                }
+              fi->extra_info->leaf_function = 0;
+            }
+          else if (regno == FP_REGNUM)
+            {
+              have_fp = 1;
+            }
+        }
+      else if (insn == 0x866E)
+        {
+          /* move.d sp,r8 */
+          if (frameless_p)
+            {
+              return ip;
+            }
+          continue;
+        }
+      else if (cris_get_operand2 (insn) == SP_REGNUM 
+               && cris_get_mode (insn) == 0x0000
+               && cris_get_opcode (insn) == 0x000A)
+        {
+          /* subq <val>,sp */
+          val = cris_get_quick_value (insn);
+        }
+      else if (cris_get_mode (insn) == 0x0002 
+               && cris_get_opcode (insn) == 0x000F
+               && cris_get_size (insn) == 0x0003
+               && cris_get_operand1 (insn) == SP_REGNUM)
+        {
+          /* movem r<regsave>,[sp] */
+          if (frameless_p)
+            {
+              return ip;
+            }
+          regsave = cris_get_operand2 (insn);
+        }
+      else if (cris_get_operand2 (insn) == SP_REGNUM
+               && ((insn & 0x0F00) >> 8) == 0x0001
+               && (cris_get_signed_offset (insn) < 0))
+        {
+          /* Immediate byte offset addressing prefix word with sp as base 
+             register.  Used for CRIS v8 i.e. ETRAX 100 and newer if <val> 
+             is between 64 and 128. 
+             movem r<regsave>,[sp=sp-<val>] */
+          val = -cris_get_signed_offset (insn);
+          insn_next = read_memory_unsigned_integer (ip, sizeof (short));
+          ip += sizeof (short);
+          if (cris_get_mode (insn_next) == PREFIX_ASSIGN_MODE
+              && cris_get_opcode (insn_next) == 0x000F
+              && cris_get_size (insn_next) == 0x0003
+              && cris_get_operand1 (insn_next) == SP_REGNUM)
+            {
+              if (frameless_p)
+                {
+                  return ip;
+                }
+              regsave = cris_get_operand2 (insn_next);
+            }
+          else
+            {
+              /* The prologue ended before the limit was reached.  */
+              ip -= 2 * sizeof (short);
+              break;
+            }
+        }
+      else if (cris_get_mode (insn) == 0x0001
+               && cris_get_opcode (insn) == 0x0009
+               && cris_get_size (insn) == 0x0002)
+        {
+          /* move.d r<10..13>,r<0..15> */
+          if (frameless_p)
+            {
+              return ip;
+            }
+          source_register = cris_get_operand1 (insn);
+
+          /* FIXME?  In the glibc solibs, the prologue might contain something
+             like (this example taken from relocate_doit):
+             move.d $pc,$r0
+             sub.d 0xfffef426,$r0
+             which isn't covered by the source_register check below.  Question
+             is whether to add a check for this combo, or make better use of
+             the limit variable instead.  */
+          if (source_register < ARG1_REGNUM || source_register > ARG4_REGNUM)
+            {
+              /* The prologue ended before the limit was reached.  */
+              ip -= sizeof (short);
+              break;
+            }
+        }
+      else if (cris_get_operand2 (insn) == FP_REGNUM 
+               /* The size is a fixed-size.  */
+               && ((insn & 0x0F00) >> 8) == 0x0001 
+               /* A negative offset.  */
+               && (cris_get_signed_offset (insn) < 0))  
+        {
+          /* move.S rZ,[r8-U] (?) */
+          insn_next = read_memory_unsigned_integer (ip, sizeof (short));
+          ip += sizeof (short);
+          regno = cris_get_operand2 (insn_next);
+          if ((regno >= 0 && regno < SP_REGNUM)
+              && cris_get_mode (insn_next) == PREFIX_OFFSET_MODE
+              && cris_get_opcode (insn_next) == 0x000F)
+            {
+              /* move.S rZ,[r8-U] */
+              continue;
+            }
+          else
+            {
+              /* The prologue ended before the limit was reached.  */
+              ip -= 2 * sizeof (short);
+              break;
+            }
+        }
+      else if (cris_get_operand2 (insn) == FP_REGNUM 
+               /* The size is a fixed-size.  */
+               && ((insn & 0x0F00) >> 8) == 0x0001 
+               /* A positive offset.  */
+               && (cris_get_signed_offset (insn) > 0))  
+        {
+          /* move.S [r8+U],rZ (?) */
+          insn_next = read_memory_unsigned_integer (ip, sizeof (short));
+          ip += sizeof (short);
+          regno = cris_get_operand2 (insn_next);
+          if ((regno >= 0 && regno < SP_REGNUM)
+              && cris_get_mode (insn_next) == PREFIX_OFFSET_MODE
+              && cris_get_opcode (insn_next) == 0x0009
+              && cris_get_operand1 (insn_next) == regno)
+            {
+              /* move.S [r8+U],rZ */
+              continue;
+            }
+          else
+            {
+              /* The prologue ended before the limit was reached.  */
+              ip -= 2 * sizeof (short);
+              break;
+            }
+        }
+      else
+        {
+          /* The prologue ended before the limit was reached.  */
+          ip -= sizeof (short);
+          break;
+        }
+    }
+  while (ip < limit);
+
+  /* We only want to know the end of the prologue when
+     fi->saved_regs == 0.  */ 
+  if (!fi->saved_regs)
+    return ip;
+
+  if (have_fp)
+    {
+      fi->saved_regs[FP_REGNUM] = FRAME_FP (fi);
+      
+      /* Calculate the addresses.  */
+      for (regno = regsave; regno >= 0; regno--)
+        {
+          fi->saved_regs[regno] = FRAME_FP (fi) - val;
+          val -= 4;
+        }
+      if (fi->extra_info->leaf_function)
+        {
+          /* Set the register SP to contain the stack pointer of 
+             the caller.  */
+          fi->saved_regs[SP_REGNUM] = FRAME_FP (fi) + 4;
+        }
+      else
+        {
+          /* Set the register SP to contain the stack pointer of 
+             the caller.  */
+          fi->saved_regs[SP_REGNUM] = FRAME_FP (fi) + 8;
+      
+          /* Set the register SRP to contain the return address of 
+             the caller.  */
+          fi->saved_regs[SRP_REGNUM] = FRAME_FP (fi) + 4;
+        }
+    }
+  return ip;
+}
+
+/* Advance pc beyond any function entry prologue instructions at pc
+   to reach some "real" code.  */
+
+CORE_ADDR
+cris_skip_prologue (CORE_ADDR pc)
+{
+  return cris_skip_prologue_main (pc, 0);
+}
+
+/* As cris_skip_prologue, but stops as soon as it knows that the function 
+   has a frame.  Its result is equal to its input pc if the function is 
+   frameless, unequal otherwise.  */
+
+CORE_ADDR
+cris_skip_prologue_frameless_p (CORE_ADDR pc)
+{
+  return cris_skip_prologue_main (pc, 1);
+}
+
+/* Given a PC value corresponding to the start of a function, return the PC
+   of the first instruction after the function prologue.  */
+
+CORE_ADDR
+cris_skip_prologue_main (CORE_ADDR pc, int frameless_p)
+{
+  struct frame_info fi;
+  static struct frame_extra_info fei;
+  struct symtab_and_line sal = find_pc_line (pc, 0);
+  int best_limit;
+  CORE_ADDR pc_after_prologue;
+  
+  /* frame_info now contains dynamic memory.  Since fi is a dummy here,
+     I use static memory for extra_info, and don't bother allocating
+     memory for saved_regs.  */
+  fi.saved_regs = 0;
+  fi.extra_info = &fei;
+
+  /* If there is no symbol information then sal.end == 0, and we end up
+     examining only the first instruction in the function prologue. 
+     Exaggerating the limit seems to be harmless.  */
+  if (sal.end > 0)
+    best_limit = sal.end;
+  else
+    best_limit = pc + 100; 
+
+  pc_after_prologue = cris_examine (pc, best_limit, &fi, frameless_p);
+  return pc_after_prologue;
+}
+
+/* Use the program counter to determine the contents and size of a breakpoint
+   instruction.  It returns a pointer to a string of bytes that encode a
+   breakpoint instruction, stores the length of the string to *lenptr, and
+   adjusts pcptr (if necessary) to point to the actual memory location where
+   the breakpoint should be inserted.  */
+
+const unsigned char *
+cris_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+{
+  static unsigned char break_insn[] = {0x38, 0xe9};
+  *lenptr = 2;
+
+  return break_insn;
+}
+
+/* Returns the register SRP (subroutine return pointer) which must contain 
+   the content of the register PC after a function call.  */
+
+static CORE_ADDR
+cris_saved_pc_after_call (struct frame_info *frame)
+{
+  return read_register (SRP_REGNUM);
+}
+
+/* Returns 1 if spec_reg is applicable to the current gdbarch's CRIS version,
+   0 otherwise.  */
+
+int
+cris_spec_reg_applicable (struct cris_spec_reg spec_reg)
+{
+  int version = cris_version ();
+  
+  switch (spec_reg.applicable_version)
+    {
+    case cris_ver_version_all:
+      return 1;
+    case cris_ver_warning:
+      /* Indeterminate/obsolete.  */
+      return 0;
+    case cris_ver_sim:
+      /* Simulator only.  */
+      return 0;
+    case cris_ver_v0_3:
+      return (version >= 0 && version <= 3);
+    case cris_ver_v3p:
+      return (version >= 3);
+    case cris_ver_v8:
+      return (version == 8 || version == 9);
+    case cris_ver_v8p:
+      return (version >= 8);
+    case cris_ver_v10p:
+      return (version >= 10);
+    default:
+      /* Invalid cris version.  */
+      return 0;
+    }
+}
+
+/* Returns the register size in unit byte.  Returns 0 for an unimplemented
+   register, -1 for an invalid register.  */
+
+int
+cris_register_size (int regno)
+{
+  int i;
+  int spec_regno;
+  
+  if (regno >= 0 && regno < NUM_GENREGS)
+    {
+      /* General registers (R0 - R15) are 32 bits.  */
+      return 4;
+    }
+  else if (regno >= NUM_GENREGS && regno < NUM_REGS)
+    {
+      /* Special register (R16 - R31).  cris_spec_regs is zero-based. 
+         Adjust regno accordingly.  */
+      spec_regno = regno - NUM_GENREGS;
+      
+      /* The entries in cris_spec_regs are stored in register number order,
+         which means we can shortcut into the array when searching it.  */
+      for (i = spec_regno; cris_spec_regs[i].name != NULL; i++)
+        {
+          if (cris_spec_regs[i].number == spec_regno 
+              && cris_spec_reg_applicable (cris_spec_regs[i]))
+            /* Go with the first applicable register.  */
+            return cris_spec_regs[i].reg_size;
+        }
+      /* Special register not applicable to this CRIS version.  */
+      return 0;
+    }
+  else
+    {
+      /* Invalid register.  */
+      return -1;
+    }
+}
+
+/* Nonzero if regno should not be fetched from the target.  This is the case
+   for unimplemented (size 0) and non-existant registers.  */
+
+int
+cris_cannot_fetch_register (int regno)
+{
+  return ((regno < 0 || regno >= NUM_REGS) 
+          || (cris_register_size (regno) == 0));
+}
+
+/* Nonzero if regno should not be written to the target, for various 
+   reasons.  */
+
+int
+cris_cannot_store_register (int regno)
+{
+  /* There are three kinds of registers we refuse to write to.
+     1. Those that not implemented.
+     2. Those that are read-only (depends on the processor mode).
+     3. Those registers to which a write has no effect.
+  */
+
+  if (regno < 0 || regno >= NUM_REGS || cris_register_size (regno) == 0)
+    /* Not implemented.  */
+    return 1;
+
+  else if  (regno == VR_REGNUM)
+    /* Read-only.  */
+    return 1;
+
+  else if  (regno == P0_REGNUM || regno == P4_REGNUM || regno == P8_REGNUM)
+    /* Writing has no effect.  */
+    return 1;
+
+  else if (cris_mode () == CRIS_MODE_USER)
+    {
+      if (regno == IBR_REGNUM || regno == BAR_REGNUM || regno == BRP_REGNUM 
+          || regno == IRP_REGNUM)
+        /* Read-only in user mode.  */
+        return 1;
+    }
+  
+  return 0;
+}
+
+/* Returns the register offset for the first byte of register regno's space 
+   in the saved register state.  Returns -1 for an invalid or unimplemented
+   register.  */
+
+int
+cris_register_offset (int regno)
+{
+  int i;
+  int reg_size;
+  int offset = 0;
+  
+  if (regno >= 0 && regno < NUM_REGS)
+    {
+      /* FIXME: The offsets should be cached and calculated only once,
+         when the architecture being debugged has changed.  */
+      for (i = 0; i < regno; i++)
+        offset += cris_register_size (i);
+      
+      return offset;
+    }
+  else
+    {
+      /* Invalid register. */
+      return -1;
+    }
+}
+
+/* Return the GDB type (defined in gdbtypes.c) for the "standard" data type
+   of data in register regno.  */
+
+struct type *
+cris_register_virtual_type (int regno)
+{
+  if (regno == SP_REGNUM || regno == PC_REGNUM
+      || (regno > P8_REGNUM && regno < USP_REGNUM))
+    {
+      /* SP, PC, IBR, IRP, SRP, BAR, DCCR, BRP */
+      return lookup_pointer_type (builtin_type_void);
+    }
+  else if (regno == P8_REGNUM || regno == USP_REGNUM
+           || (regno >= 0 && regno < SP_REGNUM))
+    {
+      /* R0 - R13, P8, P15 */
+      return builtin_type_unsigned_long;
+    }
+  else if (regno > P3_REGNUM && regno < P8_REGNUM)
+    {
+      /* P4, CCR, DCR0, DCR1 */
+      return builtin_type_unsigned_short;
+    }
+  else if (regno > PC_REGNUM && regno < P4_REGNUM)
+    {
+      /* P0, P1, P2, P3 */
+      return builtin_type_unsigned_char;
+    }
+  else
+    {
+      /* Invalid register.  */
+      return builtin_type_void;
+    }
+}
+
+/* Stores a function return value of type type, where valbuf is the address 
+   of the value to be stored.  */
+
+/* In the original CRIS ABI, R10 is used to store return values.  */
+
+void
+cris_abi_original_store_return_value (struct type *type, char *valbuf)
+{
+  int len = TYPE_LENGTH (type);
+  
+  if (len <= REGISTER_SIZE) 
+    write_register_bytes (REGISTER_BYTE (RET_REGNUM), valbuf, len);
+  else
+    internal_error (__FILE__, __LINE__, "cris_abi_original_store_return_value: type length too large.");
+}
+
+/* In the CRIS ABI V2, R10 and R11 are used to store return values.  */
+
+void
+cris_abi_v2_store_return_value (struct type *type, char *valbuf)
+{
+  int len = TYPE_LENGTH (type);
+  
+  if (len <= 2 * REGISTER_SIZE)
+    {
+      /* Note that this works since R10 and R11 are consecutive registers.  */
+      write_register_bytes (REGISTER_BYTE (RET_REGNUM), valbuf, len);
+    }
+  else
+    internal_error (__FILE__, __LINE__, "cris_abi_v2_store_return_value: type length too large.");
+}
+
+/* Return the name of register regno as a string. Return NULL for an invalid or
+   unimplemented register.  */
+
+const char *
+cris_register_name (int regno)
+{
+  static char *cris_genreg_names[] =
+  { "r0",  "r1",  "r2",  "r3", \
+    "r4",  "r5",  "r6",  "r7", \
+    "r8",  "r9",  "r10", "r11", \
+    "r12", "r13", "sp",  "pc" };
+
+  int i;
+  int spec_regno;
+
+  if (regno >= 0 && regno < NUM_GENREGS)
+    {
+      /* General register.  */
+      return cris_genreg_names[regno];
+    }
+  else if (regno >= NUM_GENREGS && regno < NUM_REGS)
+    {
+      /* Special register (R16 - R31).  cris_spec_regs is zero-based. 
+         Adjust regno accordingly.  */
+      spec_regno = regno - NUM_GENREGS;
+      
+      /* The entries in cris_spec_regs are stored in register number order,
+         which means we can shortcut into the array when searching it.  */
+      for (i = spec_regno; cris_spec_regs[i].name != NULL; i++)
+        {
+          if (cris_spec_regs[i].number == spec_regno 
+              && cris_spec_reg_applicable (cris_spec_regs[i]))
+            /* Go with the first applicable register.  */
+            return cris_spec_regs[i].name;
+        }
+      /* Special register not applicable to this CRIS version.  */
+      return NULL;
+    }
+  else
+    {
+      /* Invalid register.  */
+      return NULL;
+    }
+}
+
+int
+cris_register_bytes_ok (long bytes)
+{
+  return (bytes == REGISTER_BYTES);
+}
+
+/* Extract from an array regbuf containing the raw register state a function
+   return value of type type, and copy that, in virtual format, into 
+   valbuf.  */
+
+/* In the original CRIS ABI, R10 is used to return values.  */
+
+void
+cris_abi_original_extract_return_value (struct type *type, char *regbuf, 
+                                        char *valbuf)
+{
+  int len = TYPE_LENGTH (type);
+  
+  if (len <= REGISTER_SIZE)
+    memcpy (valbuf, regbuf + REGISTER_BYTE (RET_REGNUM), len);
+  else
+    internal_error (__FILE__, __LINE__, "cris_abi_original_extract_return_value: type length too large");
+}
+
+/* In the CRIS ABI V2, R10 and R11 are used to store return values.  */
+
+void
+cris_abi_v2_extract_return_value (struct type *type, char *regbuf, 
+                                  char *valbuf)
+{
+  int len = TYPE_LENGTH (type);
+  
+  if (len <= 2 * REGISTER_SIZE)
+    memcpy (valbuf, regbuf + REGISTER_BYTE (RET_REGNUM), len);
+  else
+    internal_error (__FILE__, __LINE__, "cris_abi_v2_extract_return_value: type length too large");
+}
+
+/* Store the address of the place in which to copy the structure the
+   subroutine will return.  In the CRIS ABI, R9 is used in order to pass 
+   the address of the allocated area where a structure return value must 
+   be stored.  R9 is call-clobbered, which means we must save it here for
+   later use.  */
+
+void
+cris_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+{
+  write_register (STR_REGNUM, addr);
+  struct_return_address = addr;
+}
+
+/* Extract from regbuf the address where a function should return a 
+   structure value.  It's not there in the CRIS ABI, so we must do it another
+   way.  */
+
+CORE_ADDR
+cris_extract_struct_value_address (char *regbuf)
+{
+  return struct_return_address;
+}
+
+/* Returns 1 if a value of the given type being returned from a function 
+   must have space allocated for it on the stack.  gcc_p is true if the 
+   function being considered is known to have been compiled by GCC. 
+   In the CRIS ABI, structure return values are passed to the called 
+   function by reference in register R9 to a caller-allocated area, so
+   this is always true.  */
+
+int
+cris_use_struct_convention (int gcc_p, struct type *type)
+{
+  return 1;
+}
+
+/* Returns 1 if the given type will be passed by pointer rather than 
+   directly.  */
+
+/* In the original CRIS ABI, arguments shorter than or equal to 32 bits are 
+   passed by value.  */
+
+int 
+cris_abi_original_reg_struct_has_addr (int gcc_p, struct type *type)
+{ 
+  return (TYPE_LENGTH (type) > 4);
+}
+
+/* In the CRIS ABI V2, arguments shorter than or equal to 64 bits are passed
+   by value.  */
+
+int 
+cris_abi_v2_reg_struct_has_addr (int gcc_p, struct type *type)
+{ 
+  return (TYPE_LENGTH (type) > 8);
+}
+
+/* Returns 1 if the function invocation represented by fi does not have a 
+   stack frame associated with it.  Otherwise return 0.  */
+
+int
+cris_frameless_function_invocation (struct frame_info *fi)
+{
+  if (fi->signal_handler_caller)
+    return 0;
+  else
+    return frameless_look_for_prologue (fi);
+}
+
+/* See frame.h.  Determines the address of all registers in the current stack
+   frame storing each in frame->saved_regs.  Space for frame->saved_regs shall
+   be allocated by FRAME_INIT_SAVED_REGS using either frame_saved_regs_zalloc
+   or frame_obstack_alloc.  */
+
+void
+cris_frame_init_saved_regs (struct frame_info *fi)
+{
+  CORE_ADDR ip;
+  struct symtab_and_line sal;
+  int best_limit;
+  char *dummy_regs = deprecated_generic_find_dummy_frame (fi->pc, fi->frame);
+  
+  /* Examine the entire prologue.  */
+  register int frameless_p = 0; 
+
+  /* Has this frame's registers already been initialized?  */
+  if (fi->saved_regs)
+    return;
+
+  frame_saved_regs_zalloc (fi);
+  
+  if (dummy_regs)
+    {
+      /* I don't see this ever happening, considering the context in which
+         cris_frame_init_saved_regs is called (always when we're not in
+         a dummy frame).  */
+      memcpy (&fi->saved_regs, dummy_regs, sizeof (fi->saved_regs));
+    }
+  else
+    {    
+      ip = get_pc_function_start (fi->pc);
+      sal = find_pc_line (ip, 0);
+
+      /* If there is no symbol information then sal.end == 0, and we end up
+         examining only the first instruction in the function prologue. 
+         Exaggerating the limit seems to be harmless.  */
+      if (sal.end > 0)
+        best_limit = sal.end;
+      else
+        best_limit = ip + 100;
+
+      cris_examine (ip, best_limit, fi, frameless_p);
+    }
+}
+
+/* Initialises the extra frame information at the creation of a new frame. 
+   The inparameter fromleaf is 0 when the call is from create_new_frame. 
+   When the call is from get_prev_frame_info, fromleaf is determined by
+   cris_frameless_function_invocation.  */
+
+void
+cris_init_extra_frame_info (int fromleaf, struct frame_info *fi)
+{
+  if (fi->next)
+    {
+      /* Called from get_prev_frame.  */
+      fi->pc = FRAME_SAVED_PC (fi->next);
+    }
+  fi->extra_info = (struct frame_extra_info *)
+    frame_obstack_alloc (sizeof (struct frame_extra_info));
+  fi->extra_info->return_pc = 0;
+  fi->extra_info->leaf_function = 0;
+
+  if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+    {    
+      /* We need to setup fi->frame here because run_stack_dummy gets it wrong
+         by assuming it's always FP.  */
+      fi->frame = deprecated_read_register_dummy (fi->pc, fi->frame,
+                                                 SP_REGNUM);
+      fi->extra_info->return_pc = 
+        deprecated_read_register_dummy (fi->pc, fi->frame, PC_REGNUM);
+
+      /* FIXME: Is this necessarily true?  */
+      fi->extra_info->leaf_function = 0;
+    }
+  else
+    {
+      cris_frame_init_saved_regs (fi);
+
+      /* Check fromleaf/frameless_function_invocation.  (FIXME)  */
+
+      if (fi->saved_regs[SRP_REGNUM] != 0)
+        {
+          /* SRP was saved on the stack; non-leaf function.  */
+          fi->extra_info->return_pc =
+            read_memory_integer (fi->saved_regs[SRP_REGNUM], 
+                                 REGISTER_RAW_SIZE (SRP_REGNUM));
+        }
+      else
+        {
+          /* SRP is still in a register; leaf function.  */
+          fi->extra_info->return_pc = read_register (SRP_REGNUM);
+          /* FIXME: Should leaf_function be set to 1 here?  */
+          fi->extra_info->leaf_function = 1;
+        }
+    }
+}
+
+/* Return the content of the frame pointer in the present frame.  In other
+   words, determine the address of the calling function's frame.  */
+
+CORE_ADDR
+cris_frame_chain (struct frame_info *fi)
+{
+  if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+    {
+      return fi->frame;
+    }
+  else if (!inside_entry_file (fi->pc))
+    {
+      return read_memory_unsigned_integer (FRAME_FP (fi), 4);
+    }
+  else
+    {
+      return 0;
+    }
+}
+
+/* Return the saved PC (which equals the return address) of this frame.  */
+
+CORE_ADDR
+cris_frame_saved_pc (struct frame_info *fi)
+{
+  return fi->extra_info->return_pc;
+}
+
+/* Return the address of the argument block for the frame described 
+   by struct frame_info.  */
+
+CORE_ADDR
+cris_frame_args_address (struct frame_info *fi)
+{
+  return FRAME_FP (fi);
+}
+
+/* Return the address of the locals block for the frame
+   described by struct frame_info.  */
+
+CORE_ADDR
+cris_frame_locals_address (struct frame_info *fi)
+{
+  return FRAME_FP (fi);
+}
+
+/* Setup the function arguments for calling a function in the inferior.  */
+
+CORE_ADDR 
+cris_abi_original_push_arguments (int nargs, struct value **args, 
+                                  CORE_ADDR sp, int struct_return, 
+                                  CORE_ADDR struct_addr)
+{
+  int stack_alloc;
+  int stack_offset;
+  int argreg;
+  int argnum;
+  struct type *type;
+  int len;
+  CORE_ADDR regval;
+  char *val;
+
+  /* Data and parameters reside in different areas on the stack. 
+     Both frame pointers grow toward higher addresses.  */  
+  CORE_ADDR fp_params;
+  CORE_ADDR fp_data;
+  
+  /* Are we returning a value using a structure return or a normal value 
+     return?  struct_addr is the address of the reserved space for the return 
+     structure to be written on the stack.  */
+  if (struct_return)
+    {
+      write_register (STR_REGNUM, struct_addr);
+    }
+
+  /* Make sure there's space on the stack.  Allocate space for data and a 
+     parameter to refer to that data.  */
+  for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
+    stack_alloc += (TYPE_LENGTH (VALUE_TYPE (args[argnum])) + REGISTER_SIZE);
+  sp -= stack_alloc;
+  /* We may over-allocate a little here, but that won't hurt anything.  */
+
+  /* Initialize stack frame pointers.  */
+  fp_params = sp;
+  fp_data = sp + (nargs * REGISTER_SIZE);
+
+  /* Now load as many as possible of the first arguments into
+     registers, and push the rest onto the stack.  */
+  argreg = ARG1_REGNUM; 
+  stack_offset = 0;
+
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      type = VALUE_TYPE (args[argnum]);
+      len = TYPE_LENGTH (type);
+      val = (char *) VALUE_CONTENTS (args[argnum]);
+    
+      if (len <= REGISTER_SIZE && argreg <= ARG4_REGNUM)
+        {
+          /* Data fits in a register; put it in the first available 
+             register.  */
+          write_register (argreg, *(unsigned long *) val);
+          argreg++;
+        }
+      else if (len > REGISTER_SIZE && argreg <= ARG4_REGNUM)
+        {
+          /* Data does not fit in register; pass it on the stack and
+             put its address in the first available register.  */
+          write_memory (fp_data, val, len);
+          write_register (argreg, fp_data);
+          fp_data += len;
+          argreg++;      
+        }
+      else if (len > REGISTER_SIZE)
+        {
+          /* Data does not fit in register; put both data and 
+             parameter on the stack.  */
+          write_memory (fp_data, val, len);
+          write_memory (fp_params, (char *) (&fp_data), REGISTER_SIZE);
+          fp_data += len;
+          fp_params += REGISTER_SIZE;
+        }
+      else
+        {
+          /* Data fits in a register, but we are out of registers;
+             put the parameter on the stack.  */
+          write_memory (fp_params, val, REGISTER_SIZE);
+          fp_params += REGISTER_SIZE;
+        }
+    }
+
+  return sp;
+}
+
+CORE_ADDR 
+cris_abi_v2_push_arguments (int nargs, struct value **args, CORE_ADDR sp, 
+                     int struct_return, CORE_ADDR struct_addr)
+{
+  int stack_alloc;
+  int stack_offset;
+  int argreg;
+  int argnum;
+
+  CORE_ADDR regval;
+
+  /* The function's arguments and memory allocated by gdb for the arguments to
+     point at reside in separate areas on the stack.
+     Both frame pointers grow toward higher addresses.  */
+  CORE_ADDR fp_arg;
+  CORE_ADDR fp_mem;
+  
+  /* Are we returning a value using a structure return or a normal value 
+     return?  struct_addr is the address of the reserved space for the return 
+     structure to be written on the stack.  */
+  if (struct_return)
+    {
+      write_register (STR_REGNUM, struct_addr);
+    }
+
+  /* Allocate enough to keep things word-aligned on both parts of the 
+     stack.  */
+  stack_alloc = 0;
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      int len;
+      int reg_demand;
+      
+      len = TYPE_LENGTH (VALUE_TYPE (args[argnum]));
+      reg_demand = (len / REGISTER_SIZE) + (len % REGISTER_SIZE != 0 ? 1 : 0);
+
+      /* reg_demand * REGISTER_SIZE is the amount of memory we might need to
+         allocate for this argument.  2 * REGISTER_SIZE is the amount of stack
+         space we might need to pass the argument itself (either by value or by
+         reference).  */
+      stack_alloc += (reg_demand * REGISTER_SIZE + 2 * REGISTER_SIZE);
+    }
+  sp -= stack_alloc;
+  /* We may over-allocate a little here, but that won't hurt anything.  */
+
+  /* Initialize frame pointers.  */
+  fp_arg = sp;
+  fp_mem = sp + (nargs * (2 * REGISTER_SIZE));
+
+  /* Now load as many as possible of the first arguments into registers,
+     and push the rest onto the stack.  */
+  argreg = ARG1_REGNUM; 
+  stack_offset = 0;
+
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      int len;
+      char *val;
+      int reg_demand;
+      int i;
+      
+      len = TYPE_LENGTH (VALUE_TYPE (args[argnum]));
+      val = (char *) VALUE_CONTENTS (args[argnum]);
+      
+      /* How may registers worth of storage do we need for this argument?  */
+      reg_demand = (len / REGISTER_SIZE) + (len % REGISTER_SIZE != 0 ? 1 : 0);
+        
+      if (len <= (2 * REGISTER_SIZE)
+          && (argreg + reg_demand - 1 <= ARG4_REGNUM)) 
+        {
+          /* Data passed by value.  Fits in available register(s).  */
+          for (i = 0; i < reg_demand; i++)
+            {
+              write_register (argreg, *(unsigned long *) val);
+              argreg++;
+              val += REGISTER_SIZE;
+            }
+        }
+      else if (len <= (2 * REGISTER_SIZE) && argreg <= ARG4_REGNUM)
+        {
+          /* Data passed by value. Does not fit in available register(s).  
+             Use the register(s) first, then the stack.  */
+          for (i = 0; i < reg_demand; i++)
+            {
+              if (argreg <= ARG4_REGNUM)
+                {
+                  write_register (argreg, *(unsigned long *) val);
+                  argreg++;
+                  val += REGISTER_SIZE;
+                }
+              else
+                {
+                  /* I guess this memory write could write the remaining data
+                     all at once instead of in REGISTER_SIZE chunks.  */
+                  write_memory (fp_arg, val, REGISTER_SIZE);
+                  fp_arg += REGISTER_SIZE;
+                  val += REGISTER_SIZE;              
+                }
+            }    
+        }
+      else if (len > (2 * REGISTER_SIZE))
+        {
+          /* Data passed by reference.  Put it on the stack.  */
+          write_memory (fp_mem, val, len);
+          write_memory (fp_arg, (char *) (&fp_mem), REGISTER_SIZE);
+
+          /* fp_mem need not be word-aligned since it's just a chunk of
+             memory being pointed at.  That is, += len would do.  */
+          fp_mem += reg_demand * REGISTER_SIZE;
+          fp_arg += REGISTER_SIZE;
+        }
+      else
+        {
+          /* Data passed by value.  No available registers.  Put it on 
+             the stack.  */
+          write_memory (fp_arg, val, len);
+
+          /* fp_arg must be word-aligned (i.e., don't += len) to match
+             the function prologue.  */
+          fp_arg += reg_demand * REGISTER_SIZE;
+        }
+    }
+
+  return sp;
+}
+
+/* Never put the return address on the stack.  The register SRP is pushed
+   by the called function unless it is a leaf-function.  Due to the BRP
+   register the PC will change when continue is sent.  */
+
+CORE_ADDR
+cris_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
+{
+  write_register (SRP_REGNUM, CALL_DUMMY_ADDRESS ());
+  return sp;
+}
+
+/* Restore the machine to the state it had before the current frame 
+   was created.  Discard the innermost frame from the stack and restore 
+   all saved registers.  */
+
+void 
+cris_pop_frame (void)
+{
+  register struct frame_info *fi = get_current_frame ();
+  register int regno;
+  register int stack_offset = 0;
+  
+  if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+    {
+      /* This happens when we hit a breakpoint set at the entry point,
+         when returning from a dummy frame.  */
+      generic_pop_dummy_frame ();
+    }
+  else
+    {
+      cris_frame_init_saved_regs (fi);
+
+      /* For each register, the address of where it was saved on entry to
+         the frame now lies in fi->saved_regs[regno], or zero if it was not 
+         saved.  This includes special registers such as PC and FP saved in
+         special ways in the stack frame.  The SP_REGNUM is even more
+         special, the address here is the SP for the next frame, not the
+         address where the SP was saved.  */
+                                                     
+      /* Restore general registers R0 - R7.  They were pushed on the stack 
+         after SP was saved.  */
+      for (regno = 0; regno < FP_REGNUM; regno++)
+        {
+          if (fi->saved_regs[regno])
+            {
+              write_register (regno, 
+                              read_memory_integer (fi->saved_regs[regno], 4));
+            }
+        }
+     
+      if (fi->saved_regs[FP_REGNUM])
+        {
+          /* Pop the frame pointer (R8).  It was pushed before SP 
+             was saved.  */
+          write_register (FP_REGNUM, 
+                          read_memory_integer (fi->saved_regs[FP_REGNUM], 4));
+          stack_offset += 4;
+
+          /* Not a leaf function.  */
+          if (fi->saved_regs[SRP_REGNUM])
+            {     
+              /* SRP was pushed before SP was saved.  */
+              stack_offset += 4;
+            }
+      
+          /* Restore the SP and adjust for R8 and (possibly) SRP.  */
+          write_register (SP_REGNUM, fi->saved_regs[FP_REGNUM] + stack_offset);
+        } 
+      else
+        {
+          /* Currently, we can't get the correct info into fi->saved_regs 
+             without a frame pointer.  */
+        }
+    
+      /* Restore the PC.  */
+      write_register (PC_REGNUM, fi->extra_info->return_pc);
+    }
+  flush_cached_frames ();
+}
+
+/* Calculates a value that measures how good inst_args constraints an 
+   instruction.  It stems from cris_constraint, found in cris-dis.c.  */
+
+static int
+constraint (unsigned int insn, const signed char *inst_args, 
+            inst_env_type *inst_env)
+{
+  int retval = 0;
+  int tmp, i;
+
+  const char *s = inst_args;
+
+  for (; *s; s++)
+    switch (*s) 
+      {
+      case 'm':
+        if ((insn & 0x30) == 0x30)
+          return -1;
+        break;
+        
+      case 'S':
+        /* A prefix operand.  */
+        if (inst_env->prefix_found)
+          break;
+        else
+          return -1;
+
+      case 'B':
+        /* A "push" prefix.  (This check was REMOVED by san 970921.)  Check for
+           valid "push" size.  In case of special register, it may be != 4.  */
+        if (inst_env->prefix_found)
+          break;
+        else
+          return -1;
+
+      case 'D':
+        retval = (((insn >> 0xC) & 0xF) == (insn & 0xF));
+        if (!retval)
+          return -1;
+        else 
+          retval += 4;
+        break;
+
+      case 'P':
+        tmp = (insn >> 0xC) & 0xF;
+
+        for (i = 0; cris_spec_regs[i].name != NULL; i++)
+          {
+            /* Since we match four bits, we will give a value of
+               4 - 1 = 3 in a match.  If there is a corresponding
+               exact match of a special register in another pattern, it
+               will get a value of 4, which will be higher.  This should
+               be correct in that an exact pattern would match better that
+               a general pattern.
+               Note that there is a reason for not returning zero; the
+               pattern for "clear" is partly  matched in the bit-pattern
+               (the two lower bits must be zero), while the bit-pattern
+               for a move from a special register is matched in the
+               register constraint.
+               This also means we will will have a race condition if
+               there is a partly match in three bits in the bit pattern.  */
+            if (tmp == cris_spec_regs[i].number)
+              {
+                retval += 3;
+                break;
+              }
+          }
+        
+        if (cris_spec_regs[i].name == NULL)
+          return -1;
+        break;
+      }
+  return retval;
+}
+
+/* Returns the number of bits set in the variable value.  */
+
+static int
+number_of_bits (unsigned int value)
+{
+  int number_of_bits = 0;
+  
+  while (value != 0)
+    {
+      number_of_bits += 1;
+      value &= (value - 1);
+    }
+  return number_of_bits;
+}
+
+/* Finds the address that should contain the single step breakpoint(s). 
+   It stems from code in cris-dis.c.  */
+
+static int
+find_cris_op (unsigned short insn, inst_env_type *inst_env)
+{
+  int i;
+  int max_level_of_match = -1;
+  int max_matched = -1;
+  int level_of_match;
+
+  for (i = 0; cris_opcodes[i].name != NULL; i++)
+    {
+      if (((cris_opcodes[i].match & insn) == cris_opcodes[i].match) 
+          && ((cris_opcodes[i].lose & insn) == 0))
+        {
+          level_of_match = constraint (insn, cris_opcodes[i].args, inst_env);
+          if (level_of_match >= 0)
+            {
+              level_of_match +=
+                number_of_bits (cris_opcodes[i].match | cris_opcodes[i].lose);
+              if (level_of_match > max_level_of_match)
+                {
+                  max_matched = i;
+                  max_level_of_match = level_of_match;
+                  if (level_of_match == 16)
+                    {
+                      /* All bits matched, cannot find better.  */
+                      break;
+                    }
+                }
+            }
+        }
+    }
+  return max_matched;
+}
+
+/* Attempts to find single-step breakpoints.  Returns -1 on failure which is
+   actually an internal error.  */
+
+static int
+find_step_target (inst_env_type *inst_env)
+{
+  int i;
+  int offset;
+  unsigned short insn;
+
+  /* Create a local register image and set the initial state.  */
+  for (i = 0; i < NUM_GENREGS; i++)
+    {
+      inst_env->reg[i] = (unsigned long) read_register (i);
+    }
+  offset = NUM_GENREGS;
+  for (i = 0; i < NUM_SPECREGS; i++)
+    {
+      inst_env->preg[i] = (unsigned long) read_register (offset + i);
+    }
+  inst_env->branch_found = 0;
+  inst_env->slot_needed = 0;
+  inst_env->delay_slot_pc_active = 0;
+  inst_env->prefix_found = 0;
+  inst_env->invalid = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+
+  /* Look for a step target.  */
+  do
+    {
+      /* Read an instruction from the client.  */
+      insn = read_memory_unsigned_integer (inst_env->reg[PC_REGNUM], 2);
+
+      /* If the instruction is not in a delay slot the new content of the
+         PC is [PC] + 2.  If the instruction is in a delay slot it is not
+         that simple.  Since a instruction in a delay slot cannot change 
+         the content of the PC, it does not matter what value PC will have. 
+         Just make sure it is a valid instruction.  */
+      if (!inst_env->delay_slot_pc_active)
+        {
+          inst_env->reg[PC_REGNUM] += 2;
+        }
+      else
+        {
+          inst_env->delay_slot_pc_active = 0;
+          inst_env->reg[PC_REGNUM] = inst_env->delay_slot_pc;
+        }
+      /* Analyse the present instruction.  */
+      i = find_cris_op (insn, inst_env);
+      if (i == -1)
+        {
+          inst_env->invalid = 1;
+        }
+      else
+        {
+          cris_gdb_func (cris_opcodes[i].op, insn, inst_env);
+        }
+    } while (!inst_env->invalid 
+             && (inst_env->prefix_found || inst_env->xflag_found 
+                 || inst_env->slot_needed));
+  return i;
+}
+
+/* There is no hardware single-step support.  The function find_step_target
+   digs through the opcodes in order to find all possible targets. 
+   Either one ordinary target or two targets for branches may be found.  */
+
+void
+cris_software_single_step (enum target_signal ignore, int insert_breakpoints)
+{
+  inst_env_type inst_env;
+  
+  if (insert_breakpoints)
+    {
+      /* Analyse the present instruction environment and insert 
+         breakpoints.  */
+      int status = find_step_target (&inst_env);
+      if (status == -1)
+        {
+          /* Could not find a target.  FIXME: Should do something.  */
+        }
+      else
+        {
+          /* Insert at most two breakpoints.  One for the next PC content
+             and possibly another one for a branch, jump, etc.  */
+          next_pc = (CORE_ADDR) inst_env.reg[PC_REGNUM];
+          target_insert_breakpoint (next_pc, break_mem[0]);
+          if (inst_env.branch_found 
+              && (CORE_ADDR) inst_env.branch_break_address != next_pc)
+            {
+              branch_target_address = 
+                (CORE_ADDR) inst_env.branch_break_address;
+              target_insert_breakpoint (branch_target_address, break_mem[1]);
+              branch_break_inserted = 1;
+            }
+        }
+    }
+  else
+    {
+      /* Remove breakpoints.  */
+      target_remove_breakpoint (next_pc, break_mem[0]);
+      if (branch_break_inserted)
+        {
+          target_remove_breakpoint (branch_target_address, break_mem[1]);
+          branch_break_inserted = 0;
+        }
+    }
+}
+
+/* Calculates the prefix value for quick offset addressing mode.  */
+
+void
+quick_mode_bdap_prefix (unsigned short inst, inst_env_type *inst_env)
+{
+  /* It's invalid to be in a delay slot.  You can't have a prefix to this
+     instruction (not 100% sure).  */
+  if (inst_env->slot_needed || inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return; 
+    }
+  inst_env->prefix_value = inst_env->reg[cris_get_operand2 (inst)];
+  inst_env->prefix_value += cris_get_bdap_quick_offset (inst);
+
+  /* A prefix doesn't change the xflag_found.  But the rest of the flags
+     need updating.  */
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 1;
+}
+
+/* Updates the autoincrement register.  The size of the increment is derived 
+   from the size of the operation.  The PC is always kept aligned on even
+   word addresses.  */
+
+void 
+process_autoincrement (int size, unsigned short inst, inst_env_type *inst_env)
+{
+  if (size == INST_BYTE_SIZE)
+    {
+      inst_env->reg[cris_get_operand1 (inst)] += 1;
+
+      /* The PC must be word aligned, so increase the PC with one
+         word even if the size is byte.  */
+      if (cris_get_operand1 (inst) == REG_PC)
+        {
+          inst_env->reg[REG_PC] += 1;
+        }
+    }
+  else if (size == INST_WORD_SIZE)
+    {
+      inst_env->reg[cris_get_operand1 (inst)] += 2;
+    }
+  else if (size == INST_DWORD_SIZE)
+    {
+      inst_env->reg[cris_get_operand1 (inst)] += 4;
+    }
+  else
+    {
+      /* Invalid size.  */
+      inst_env->invalid = 1;
+    }
+}
+
+/* Just a forward declaration.  */
+
+unsigned long
+get_data_from_address (unsigned short *inst, CORE_ADDR address);
+
+/* Calculates the prefix value for the general case of offset addressing 
+   mode.  */
+
+void
+bdap_prefix (unsigned short inst, inst_env_type *inst_env)
+{
+
+  long offset;
+
+  /* It's invalid to be in a delay slot.  */
+  if (inst_env->slot_needed || inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return; 
+    }
+
+  /* The calculation of prefix_value used to be after process_autoincrement,
+     but that fails for an instruction such as jsr [$r0+12] which is encoded
+     as 5f0d 0c00 30b9 when compiled with -fpic.  Since PC is operand1 it
+     mustn't be incremented until we have read it and what it points at.  */
+  inst_env->prefix_value = inst_env->reg[cris_get_operand2 (inst)];
+
+  /* The offset is an indirection of the contents of the operand1 register.  */
+  inst_env->prefix_value += 
+    get_data_from_address (&inst, inst_env->reg[cris_get_operand1 (inst)]);
+  
+  if (cris_get_mode (inst) == AUTOINC_MODE)
+    {
+      process_autoincrement (cris_get_size (inst), inst, inst_env); 
+    }
+   
+  /* A prefix doesn't change the xflag_found.  But the rest of the flags
+     need updating.  */
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 1;
+}
+
+/* Calculates the prefix value for the index addressing mode.  */
+
+void
+biap_prefix (unsigned short inst, inst_env_type *inst_env)
+{
+  /* It's invalid to be in a delay slot.  I can't see that it's possible to
+     have a prefix to this instruction.  So I will treat this as invalid.  */
+  if (inst_env->slot_needed || inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+  
+  inst_env->prefix_value = inst_env->reg[cris_get_operand1 (inst)];
+
+  /* The offset is the operand2 value shifted the size of the instruction 
+     to the left.  */
+  inst_env->prefix_value += 
+    inst_env->reg[cris_get_operand2 (inst)] << cris_get_size (inst);
+  
+  /* If the PC is operand1 (base) the address used is the address after 
+     the main instruction, i.e. address + 2 (the PC is already compensated
+     for the prefix operation).  */
+  if (cris_get_operand1 (inst) == REG_PC)
+    {
+      inst_env->prefix_value += 2;
+    }
+
+  /* A prefix doesn't change the xflag_found.  But the rest of the flags
+     need updating.  */
+  inst_env->slot_needed = 0;
+  inst_env->xflag_found = 0;
+  inst_env->prefix_found = 1;
+}
+
+/* Calculates the prefix value for the double indirect addressing mode.  */
+
+void 
+dip_prefix (unsigned short inst, inst_env_type *inst_env)
+{
+
+  CORE_ADDR address;
+
+  /* It's invalid to be in a delay slot.  */
+  if (inst_env->slot_needed || inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+  
+  /* The prefix value is one dereference of the contents of the operand1
+     register.  */
+  address = (CORE_ADDR) inst_env->reg[cris_get_operand1 (inst)];
+  inst_env->prefix_value = read_memory_unsigned_integer (address, 4);
+    
+  /* Check if the mode is autoincrement.  */
+  if (cris_get_mode (inst) == AUTOINC_MODE)
+    {
+      inst_env->reg[cris_get_operand1 (inst)] += 4;
+    }
+
+  /* A prefix doesn't change the xflag_found.  But the rest of the flags
+     need updating.  */
+  inst_env->slot_needed = 0;
+  inst_env->xflag_found = 0;
+  inst_env->prefix_found = 1;
+}
+
+/* Finds the destination for a branch with 8-bits offset.  */
+
+void
+eight_bit_offset_branch_op (unsigned short inst, inst_env_type *inst_env)
+{
+
+  short offset;
+
+  /* If we have a prefix or are in a delay slot it's bad.  */
+  if (inst_env->slot_needed || inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+  
+  /* We have a branch, find out where the branch will land.  */
+  offset = cris_get_branch_short_offset (inst);
+
+  /* Check if the offset is signed.  */
+  if (offset & BRANCH_SIGNED_SHORT_OFFSET_MASK)
+    {
+      offset |= 0xFF00;
+    }
+  
+  /* The offset ends with the sign bit, set it to zero.  The address
+     should always be word aligned.  */
+  offset &= ~BRANCH_SIGNED_SHORT_OFFSET_MASK;
+  
+  inst_env->branch_found = 1;
+  inst_env->branch_break_address = inst_env->reg[REG_PC] + offset;
+
+  inst_env->slot_needed = 1;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 1;
+}
+
+/* Finds the destination for a branch with 16-bits offset.  */
+
+void 
+sixteen_bit_offset_branch_op (unsigned short inst, inst_env_type *inst_env)
+{
+  short offset;
+
+  /* If we have a prefix or is in a delay slot it's bad.  */
+  if (inst_env->slot_needed || inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  /* We have a branch, find out the offset for the branch.  */
+  offset = read_memory_integer (inst_env->reg[REG_PC], 2);
+
+  /* The instruction is one word longer than normal, so add one word
+     to the PC.  */
+  inst_env->reg[REG_PC] += 2;
+
+  inst_env->branch_found = 1;
+  inst_env->branch_break_address = inst_env->reg[REG_PC] + offset;
+
+
+  inst_env->slot_needed = 1;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 1;
+}
+
+/* Handles the ABS instruction.  */
+
+void 
+abs_op (unsigned short inst, inst_env_type *inst_env)
+{
+
+  long value;
+  
+  /* ABS can't have a prefix, so it's bad if it does.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  /* Check if the operation affects the PC.  */
+  if (cris_get_operand2 (inst) == REG_PC)
+    {
+    
+      /* It's invalid to change to the PC if we are in a delay slot.  */
+      if (inst_env->slot_needed)
+        {
+          inst_env->invalid = 1;
+          return;
+        }
+
+      value = (long) inst_env->reg[REG_PC];
+
+      /* The value of abs (SIGNED_DWORD_MASK) is SIGNED_DWORD_MASK.  */
+      if (value != SIGNED_DWORD_MASK)
+        {
+          value = -value;
+          inst_env->reg[REG_PC] = (long) value;
+        }
+    }
+
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the ADDI instruction.  */
+
+void 
+addi_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* It's invalid to have the PC as base register.  And ADDI can't have
+     a prefix.  */
+  if (inst_env->prefix_found || (cris_get_operand1 (inst) == REG_PC))
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the ASR instruction.  */
+
+void 
+asr_op (unsigned short inst, inst_env_type *inst_env)
+{
+  int shift_steps;
+  unsigned long value;
+  unsigned long signed_extend_mask = 0;
+
+  /* ASR can't have a prefix, so check that it doesn't.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  /* Check if the PC is the target register.  */
+  if (cris_get_operand2 (inst) == REG_PC)
+    {
+      /* It's invalid to change the PC in a delay slot.  */
+      if (inst_env->slot_needed)
+        {
+          inst_env->invalid = 1;
+          return;
+        }
+      /* Get the number of bits to shift.  */
+      shift_steps = cris_get_asr_shift_steps (inst_env->reg[cris_get_operand1 (inst)]);
+      value = inst_env->reg[REG_PC];
+
+      /* Find out how many bits the operation should apply to.  */
+      if (cris_get_size (inst) == INST_BYTE_SIZE)
+        {
+          if (value & SIGNED_BYTE_MASK)
+            {
+              signed_extend_mask = 0xFF;
+              signed_extend_mask = signed_extend_mask >> shift_steps;
+              signed_extend_mask = ~signed_extend_mask;
+            }
+          value = value >> shift_steps;
+          value |= signed_extend_mask;
+          value &= 0xFF;
+          inst_env->reg[REG_PC] &= 0xFFFFFF00;
+          inst_env->reg[REG_PC] |= value;
+        }
+      else if (cris_get_size (inst) == INST_WORD_SIZE)
+        {
+          if (value & SIGNED_WORD_MASK)
+            {
+              signed_extend_mask = 0xFFFF;
+              signed_extend_mask = signed_extend_mask >> shift_steps;
+              signed_extend_mask = ~signed_extend_mask;
+            }
+          value = value >> shift_steps;
+          value |= signed_extend_mask;
+          value &= 0xFFFF;
+          inst_env->reg[REG_PC] &= 0xFFFF0000;
+          inst_env->reg[REG_PC] |= value;
+        }
+      else if (cris_get_size (inst) == INST_DWORD_SIZE)
+        {
+          if (value & SIGNED_DWORD_MASK)
+            {
+              signed_extend_mask = 0xFFFFFFFF;
+              signed_extend_mask = signed_extend_mask >> shift_steps;
+              signed_extend_mask = ~signed_extend_mask;
+            }
+          value = value >> shift_steps;
+          value |= signed_extend_mask;
+          inst_env->reg[REG_PC]  = value;
+        }
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the ASRQ instruction.  */
+
+void 
+asrq_op (unsigned short inst, inst_env_type *inst_env)
+{
+
+  int shift_steps;
+  unsigned long value;
+  unsigned long signed_extend_mask = 0;
+  
+  /* ASRQ can't have a prefix, so check that it doesn't.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  /* Check if the PC is the target register.  */
+  if (cris_get_operand2 (inst) == REG_PC)
+    {
+
+      /* It's invalid to change the PC in a delay slot.  */
+      if (inst_env->slot_needed)
+        {
+          inst_env->invalid = 1;
+          return;
+        }
+      /* The shift size is given as a 5 bit quick value, i.e. we don't
+         want the the sign bit of the quick value.  */
+      shift_steps = cris_get_asr_shift_steps (inst);
+      value = inst_env->reg[REG_PC];
+      if (value & SIGNED_DWORD_MASK)
+        {
+          signed_extend_mask = 0xFFFFFFFF;
+          signed_extend_mask = signed_extend_mask >> shift_steps;
+          signed_extend_mask = ~signed_extend_mask;
+        }
+      value = value >> shift_steps;
+      value |= signed_extend_mask;
+      inst_env->reg[REG_PC]  = value;
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the AX, EI and SETF instruction.  */
+
+void 
+ax_ei_setf_op (unsigned short inst, inst_env_type *inst_env)
+{
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+  /* Check if the instruction is setting the X flag.  */
+  if (cris_is_xflag_bit_on (inst))
+    {
+      inst_env->xflag_found = 1;
+    }
+  else
+    {
+      inst_env->xflag_found = 0;
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->disable_interrupt = 1;
+}
+
+/* Checks if the instruction is in assign mode.  If so, it updates the assign 
+   register.  Note that check_assign assumes that the caller has checked that
+   there is a prefix to this instruction.  The mode check depends on this.  */
+
+void 
+check_assign (unsigned short inst, inst_env_type *inst_env)
+{
+  /* Check if it's an assign addressing mode.  */
+  if (cris_get_mode (inst) == PREFIX_ASSIGN_MODE)
+    {
+      /* Assign the prefix value to operand 1.  */
+      inst_env->reg[cris_get_operand1 (inst)] = inst_env->prefix_value;
+    }
+}
+
+/* Handles the 2-operand BOUND instruction.  */
+
+void 
+two_operand_bound_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* It's invalid to have the PC as the index operand.  */
+  if (cris_get_operand2 (inst) == REG_PC)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+  /* Check if we have a prefix.  */
+  if (inst_env->prefix_found)
+    {
+      check_assign (inst, inst_env);
+    }
+  /* Check if this is an autoincrement mode.  */
+  else if (cris_get_mode (inst) == AUTOINC_MODE)
+    {
+      /* It's invalid to change the PC in a delay slot.  */
+      if (inst_env->slot_needed)
+        {
+          inst_env->invalid = 1;
+          return;
+        }
+      process_autoincrement (cris_get_size (inst), inst, inst_env);
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the 3-operand BOUND instruction.  */
+
+void 
+three_operand_bound_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* It's an error if we haven't got a prefix.  And it's also an error
+     if the PC is the destination register.  */
+  if ((!inst_env->prefix_found) || (cris_get_operand1 (inst) == REG_PC))
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Clears the status flags in inst_env.  */
+
+void 
+btst_nop_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* It's an error if we have got a prefix.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Clears the status flags in inst_env.  */
+
+void 
+clearf_di_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* It's an error if we have got a prefix.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 1;
+}
+
+/* Handles the CLEAR instruction if it's in register mode.  */
+
+void 
+reg_mode_clear_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* Check if the target is the PC.  */
+  if (cris_get_operand2 (inst) == REG_PC)
+    {
+      /* The instruction will clear the instruction's size bits.  */
+      int clear_size = cris_get_clear_size (inst);
+      if (clear_size == INST_BYTE_SIZE)
+        {
+          inst_env->delay_slot_pc = inst_env->reg[REG_PC] & 0xFFFFFF00;
+        }
+      if (clear_size == INST_WORD_SIZE)
+        {
+          inst_env->delay_slot_pc = inst_env->reg[REG_PC] & 0xFFFF0000;
+        }
+      if (clear_size == INST_DWORD_SIZE)
+        {
+          inst_env->delay_slot_pc = 0x0;
+        }
+      /* The jump will be delayed with one delay slot.  So we need a delay 
+         slot.  */
+      inst_env->slot_needed = 1;
+      inst_env->delay_slot_pc_active = 1;
+    }
+  else
+    {
+      /* The PC will not change => no delay slot.  */
+      inst_env->slot_needed = 0;
+    }
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the TEST instruction if it's in register mode.  */
+
+void
+reg_mode_test_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* It's an error if we have got a prefix.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+
+}
+
+/* Handles the CLEAR and TEST instruction if the instruction isn't 
+   in register mode.  */
+
+void 
+none_reg_mode_clear_test_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* Check if we are in a prefix mode.  */
+  if (inst_env->prefix_found)
+    {
+      /* The only way the PC can change is if this instruction is in
+         assign addressing mode.  */
+      check_assign (inst, inst_env);
+    }
+  /* Indirect mode can't change the PC so just check if the mode is
+     autoincrement.  */
+  else if (cris_get_mode (inst) == AUTOINC_MODE)
+    {
+      process_autoincrement (cris_get_size (inst), inst, inst_env);
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Checks that the PC isn't the destination register or the instructions has
+   a prefix.  */
+
+void 
+dstep_logshift_mstep_neg_not_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* It's invalid to have the PC as the destination.  The instruction can't
+     have a prefix.  */
+  if ((cris_get_operand2 (inst) == REG_PC) || inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Checks that the instruction doesn't have a prefix.  */
+
+void
+break_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* The instruction can't have a prefix.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 1;
+}
+
+/* Checks that the PC isn't the destination register and that the instruction
+   doesn't have a prefix.  */
+
+void
+scc_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* It's invalid to have the PC as the destination.  The instruction can't
+     have a prefix.  */
+  if ((cris_get_operand2 (inst) == REG_PC) || inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 1;
+}
+
+/* Handles the register mode JUMP instruction.  */
+
+void 
+reg_mode_jump_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* It's invalid to do a JUMP in a delay slot.  The mode is register, so 
+     you can't have a prefix.  */
+  if ((inst_env->slot_needed) || (inst_env->prefix_found))
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+  
+  /* Just change the PC.  */
+  inst_env->reg[REG_PC] = inst_env->reg[cris_get_operand1 (inst)];
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 1;
+}
+
+/* Handles the JUMP instruction for all modes except register.  */
+
+void none_reg_mode_jump_op (unsigned short inst, inst_env_type *inst_env)
+{
+  unsigned long newpc;
+  CORE_ADDR address;
+
+  /* It's invalid to do a JUMP in a delay slot.  */
+  if (inst_env->slot_needed)
+    {
+      inst_env->invalid = 1;
+    }
+  else
+    {
+      /* Check if we have a prefix.  */
+      if (inst_env->prefix_found)
+        {
+          check_assign (inst, inst_env);
+
+          /* Get the new value for the the PC.  */
+          newpc = 
+            read_memory_unsigned_integer ((CORE_ADDR) inst_env->prefix_value,
+                                          4);
+        }
+      else
+        {
+          /* Get the new value for the PC.  */
+          address = (CORE_ADDR) inst_env->reg[cris_get_operand1 (inst)];
+          newpc = read_memory_unsigned_integer (address, 4);
+
+          /* Check if we should increment a register.  */
+          if (cris_get_mode (inst) == AUTOINC_MODE)
+            {
+              inst_env->reg[cris_get_operand1 (inst)] += 4;
+            }
+        }
+      inst_env->reg[REG_PC] = newpc;
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 1;
+}
+
+/* Handles moves to special registers (aka P-register) for all modes.  */
+
+void 
+move_to_preg_op (unsigned short inst, inst_env_type *inst_env)
+{
+  if (inst_env->prefix_found)
+    {
+      /* The instruction has a prefix that means we are only interested if
+         the instruction is in assign mode.  */
+      if (cris_get_mode (inst) == PREFIX_ASSIGN_MODE)
+        {
+          /* The prefix handles the problem if we are in a delay slot.  */
+          if (cris_get_operand1 (inst) == REG_PC)
+            {
+              /* Just take care of the assign.  */
+              check_assign (inst, inst_env);
+            }
+        }
+    }
+  else if (cris_get_mode (inst) == AUTOINC_MODE)
+    {
+      /* The instruction doesn't have a prefix, the only case left that we
+         are interested in is the autoincrement mode.  */
+      if (cris_get_operand1 (inst) == REG_PC)
+        {
+          /* If the PC is to be incremented it's invalid to be in a 
+             delay slot.  */
+          if (inst_env->slot_needed)
+            {
+              inst_env->invalid = 1;
+              return;
+            }
+
+          /* The increment depends on the size of the special register.  */
+          if (cris_register_size (cris_get_operand2 (inst)) == 1)
+            {
+              process_autoincrement (INST_BYTE_SIZE, inst, inst_env);
+            }
+          else if (cris_register_size (cris_get_operand2 (inst)) == 2)
+            {
+              process_autoincrement (INST_WORD_SIZE, inst, inst_env);
+            }
+          else
+            {
+              process_autoincrement (INST_DWORD_SIZE, inst, inst_env);
+            }
+        }
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 1;
+}
+
+/* Handles moves from special registers (aka P-register) for all modes
+   except register.  */
+
+void 
+none_reg_mode_move_from_preg_op (unsigned short inst, inst_env_type *inst_env)
+{
+  if (inst_env->prefix_found)
+    {
+      /* The instruction has a prefix that means we are only interested if
+         the instruction is in assign mode.  */
+      if (cris_get_mode (inst) == PREFIX_ASSIGN_MODE)
+        {
+          /* The prefix handles the problem if we are in a delay slot.  */
+          if (cris_get_operand1 (inst) == REG_PC)
+            {
+              /* Just take care of the assign.  */
+              check_assign (inst, inst_env);
+            }
+        }
+    }    
+  /* The instruction doesn't have a prefix, the only case left that we
+     are interested in is the autoincrement mode.  */
+  else if (cris_get_mode (inst) == AUTOINC_MODE)
+    {
+      if (cris_get_operand1 (inst) == REG_PC)
+        {
+          /* If the PC is to be incremented it's invalid to be in a 
+             delay slot.  */
+          if (inst_env->slot_needed)
+            {
+              inst_env->invalid = 1;
+              return;
+            }
+          
+          /* The increment depends on the size of the special register.  */
+          if (cris_register_size (cris_get_operand2 (inst)) == 1)
+            {
+              process_autoincrement (INST_BYTE_SIZE, inst, inst_env);
+            }
+          else if (cris_register_size (cris_get_operand2 (inst)) == 2)
+            {
+              process_autoincrement (INST_WORD_SIZE, inst, inst_env);
+            }
+          else
+            {
+              process_autoincrement (INST_DWORD_SIZE, inst, inst_env);
+            }
+        }
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 1;
+}
+
+/* Handles moves from special registers (aka P-register) when the mode
+   is register.  */
+
+void 
+reg_mode_move_from_preg_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* Register mode move from special register can't have a prefix.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  if (cris_get_operand1 (inst) == REG_PC)
+    {
+      /* It's invalid to change the PC in a delay slot.  */
+      if (inst_env->slot_needed)
+        {
+          inst_env->invalid = 1;
+          return;
+        }
+      /* The destination is the PC, the jump will have a delay slot.  */
+      inst_env->delay_slot_pc = inst_env->preg[cris_get_operand2 (inst)];
+      inst_env->slot_needed = 1;
+      inst_env->delay_slot_pc_active = 1;
+    }
+  else
+    {
+      /* If the destination isn't PC, there will be no jump.  */
+      inst_env->slot_needed = 0;
+    }
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 1;
+}
+
+/* Handles the MOVEM from memory to general register instruction.  */
+
+void 
+move_mem_to_reg_movem_op (unsigned short inst, inst_env_type *inst_env)
+{
+  if (inst_env->prefix_found)
+    {
+      /* The prefix handles the problem if we are in a delay slot.  Is the
+         MOVEM instruction going to change the PC?  */
+      if (cris_get_operand2 (inst) >= REG_PC)
+        {
+          inst_env->reg[REG_PC] = 
+            read_memory_unsigned_integer (inst_env->prefix_value, 4);
+        }
+      /* The assign value is the value after the increment.  Normally, the   
+         assign value is the value before the increment.  */
+      if ((cris_get_operand1 (inst) == REG_PC) 
+          && (cris_get_mode (inst) == PREFIX_ASSIGN_MODE))
+        {
+          inst_env->reg[REG_PC] = inst_env->prefix_value;
+          inst_env->reg[REG_PC] += 4 * (cris_get_operand2 (inst) + 1);
+        }
+    }
+  else
+    {
+      /* Is the MOVEM instruction going to change the PC?  */
+      if (cris_get_operand2 (inst) == REG_PC)
+        {
+          /* It's invalid to change the PC in a delay slot.  */
+          if (inst_env->slot_needed)
+            {
+              inst_env->invalid = 1;
+              return;
+            }
+          inst_env->reg[REG_PC] =
+            read_memory_unsigned_integer (inst_env->reg[cris_get_operand1 (inst)], 
+                                          4);
+        }
+      /* The increment is not depending on the size, instead it's depending
+         on the number of registers loaded from memory.  */
+      if ((cris_get_operand1 (inst) == REG_PC) && (cris_get_mode (inst) == AUTOINC_MODE))
+        {
+          /* It's invalid to change the PC in a delay slot.  */
+          if (inst_env->slot_needed)
+            {
+              inst_env->invalid = 1;
+              return;
+            }
+          inst_env->reg[REG_PC] += 4 * (cris_get_operand2 (inst) + 1); 
+        }
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the MOVEM to memory from general register instruction.  */
+
+void 
+move_reg_to_mem_movem_op (unsigned short inst, inst_env_type *inst_env)
+{
+  if (inst_env->prefix_found)
+    {
+      /* The assign value is the value after the increment.  Normally, the
+         assign value is the value before the increment.  */
+      if ((cris_get_operand1 (inst) == REG_PC) &&
+          (cris_get_mode (inst) == PREFIX_ASSIGN_MODE))
+        {
+          /* The prefix handles the problem if we are in a delay slot.  */
+          inst_env->reg[REG_PC] = inst_env->prefix_value;
+          inst_env->reg[REG_PC] += 4 * (cris_get_operand2 (inst) + 1);
+        }
+    }
+  else
+    {
+      /* The increment is not depending on the size, instead it's depending
+         on the number of registers loaded to memory.  */
+      if ((cris_get_operand1 (inst) == REG_PC) && (cris_get_mode (inst) == AUTOINC_MODE))
+        {
+          /* It's invalid to change the PC in a delay slot.  */
+          if (inst_env->slot_needed)
+            {
+              inst_env->invalid = 1;
+              return;
+            }
+          inst_env->reg[REG_PC] += 4 * (cris_get_operand2 (inst) + 1);
+        }
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the pop instruction to a general register. 
+   POP is a assembler macro for MOVE.D [SP+], Rd.  */
+
+void 
+reg_pop_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* POP can't have a prefix.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+  if (cris_get_operand2 (inst) == REG_PC)
+    {
+      /* It's invalid to change the PC in a delay slot.  */
+      if (inst_env->slot_needed)
+        {
+          inst_env->invalid = 1;
+          return;
+        }
+      inst_env->reg[REG_PC] = 
+        read_memory_unsigned_integer (inst_env->reg[REG_SP], 4);
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles moves from register to memory.  */
+
+void 
+move_reg_to_mem_index_inc_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* Check if we have a prefix.  */
+  if (inst_env->prefix_found)
+    {
+      /* The only thing that can change the PC is an assign.  */
+      check_assign (inst, inst_env);
+    }
+  else if ((cris_get_operand1 (inst) == REG_PC) 
+           && (cris_get_mode (inst) == AUTOINC_MODE))
+    {
+      /* It's invalid to change the PC in a delay slot.  */
+      if (inst_env->slot_needed)
+        {
+          inst_env->invalid = 1;
+          return;
+        }
+      process_autoincrement (cris_get_size (inst), inst, inst_env);
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the intructions that's not yet implemented, by setting 
+   inst_env->invalid to true.  */
+
+void 
+not_implemented_op (unsigned short inst, inst_env_type *inst_env)
+{
+  inst_env->invalid = 1;
+}
+
+/* Handles the XOR instruction.  */
+
+void 
+xor_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* XOR can't have a prefix.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  /* Check if the PC is the target.  */
+  if (cris_get_operand2 (inst) == REG_PC)
+    {
+      /* It's invalid to change the PC in a delay slot.  */
+      if (inst_env->slot_needed)
+        {
+          inst_env->invalid = 1;
+          return;
+        }
+      inst_env->reg[REG_PC] ^= inst_env->reg[cris_get_operand1 (inst)];
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the MULS instruction.  */
+
+void 
+muls_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* MULS/U can't have a prefix.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  /* Consider it invalid if the PC is the target.  */
+  if (cris_get_operand2 (inst) == REG_PC)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the MULU instruction.  */
+
+void 
+mulu_op (unsigned short inst, inst_env_type *inst_env)
+{
+  /* MULS/U can't have a prefix.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  /* Consider it invalid if the PC is the target.  */
+  if (cris_get_operand2 (inst) == REG_PC)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Calculate the result of the instruction for ADD, SUB, CMP AND, OR and MOVE. 
+   The MOVE instruction is the move from source to register.  */
+
+void 
+add_sub_cmp_and_or_move_action (unsigned short inst, inst_env_type *inst_env, 
+                                unsigned long source1, unsigned long source2)
+{
+  unsigned long pc_mask;
+  unsigned long operation_mask;
+  
+  /* Find out how many bits the operation should apply to.  */
+  if (cris_get_size (inst) == INST_BYTE_SIZE)
+    {
+      pc_mask = 0xFFFFFF00; 
+      operation_mask = 0xFF;
+    }
+  else if (cris_get_size (inst) == INST_WORD_SIZE)
+    {
+      pc_mask = 0xFFFF0000;
+      operation_mask = 0xFFFF;
+    }
+  else if (cris_get_size (inst) == INST_DWORD_SIZE)
+    {
+      pc_mask = 0x0;
+      operation_mask = 0xFFFFFFFF;
+    }
+  else
+    {
+      /* The size is out of range.  */
+      inst_env->invalid = 1;
+      return;
+    }
+
+  /* The instruction just works on uw_operation_mask bits.  */
+  source2 &= operation_mask;
+  source1 &= operation_mask;
+
+  /* Now calculate the result.  The opcode's 3 first bits separates
+     the different actions.  */
+  switch (cris_get_opcode (inst) & 7)
+    {
+    case 0:  /* add */
+      source1 += source2;
+      break;
+
+    case 1:  /* move */
+      source1 = source2;
+      break;
+
+    case 2:  /* subtract */
+      source1 -= source2;
+      break;
+
+    case 3:  /* compare */
+      break;
+
+    case 4:  /* and */
+      source1 &= source2;
+      break;
+
+    case 5:  /* or */
+      source1 |= source2;
+      break;
+
+    default:
+      inst_env->invalid = 1;
+      return;
+
+      break;
+    }
+
+  /* Make sure that the result doesn't contain more than the instruction
+     size bits.  */
+  source2 &= operation_mask;
+
+  /* Calculate the new breakpoint address.  */
+  inst_env->reg[REG_PC] &= pc_mask;
+  inst_env->reg[REG_PC] |= source1;
+
+}
+
+/* Extends the value from either byte or word size to a dword.  If the mode
+   is zero extend then the value is extended with zero.  If instead the mode
+   is signed extend the sign bit of the value is taken into consideration.  */
+
+unsigned long 
+do_sign_or_zero_extend (unsigned long value, unsigned short *inst)
+{
+  /* The size can be either byte or word, check which one it is. 
+     Don't check the highest bit, it's indicating if it's a zero
+     or sign extend.  */
+  if (cris_get_size (*inst) & INST_WORD_SIZE)
+    {
+      /* Word size.  */
+      value &= 0xFFFF;
+
+      /* Check if the instruction is signed extend.  If so, check if value has
+         the sign bit on.  */
+      if (cris_is_signed_extend_bit_on (*inst) && (value & SIGNED_WORD_MASK))
+        {
+          value |= SIGNED_WORD_EXTEND_MASK;
+        } 
+    }
+  else
+    {
+      /* Byte size.  */
+      value &= 0xFF;
+
+      /* Check if the instruction is signed extend.  If so, check if value has
+         the sign bit on.  */
+      if (cris_is_signed_extend_bit_on (*inst) && (value & SIGNED_BYTE_MASK))
+        {
+          value |= SIGNED_BYTE_EXTEND_MASK;
+        }
+    }
+  /* The size should now be dword.  */
+  cris_set_size_to_dword (inst);
+  return value;
+}
+
+/* Handles the register mode for the ADD, SUB, CMP, AND, OR and MOVE
+   instruction.  The MOVE instruction is the move from source to register.  */
+
+void 
+reg_mode_add_sub_cmp_and_or_move_op (unsigned short inst,
+                                     inst_env_type *inst_env)
+{
+  unsigned long operand1;
+  unsigned long operand2;
+
+  /* It's invalid to have a prefix to the instruction.  This is a register 
+     mode instruction and can't have a prefix.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+  /* Check if the instruction has PC as its target.  */
+  if (cris_get_operand2 (inst) == REG_PC)
+    {
+      if (inst_env->slot_needed)
+        {
+          inst_env->invalid = 1;
+          return;
+        }
+      /* The instruction has the PC as its target register.  */
+      operand1 = inst_env->reg[cris_get_operand1 (inst)]; 
+      operand2 = inst_env->reg[REG_PC];
+
+      /* Check if it's a extend, signed or zero instruction.  */
+      if (cris_get_opcode (inst) < 4)
+        {
+          operand1 = do_sign_or_zero_extend (operand1, &inst);
+        }
+      /* Calculate the PC value after the instruction, i.e. where the
+         breakpoint should be.  The order of the udw_operands is vital.  */
+      add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand1); 
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Returns the data contained at address.  The size of the data is derived from
+   the size of the operation.  If the instruction is a zero or signed
+   extend instruction, the size field is changed in instruction.  */
+
+unsigned long 
+get_data_from_address (unsigned short *inst, CORE_ADDR address)
+{
+  int size = cris_get_size (*inst);
+  unsigned long value;
+
+  /* If it's an extend instruction we don't want the signed extend bit,
+     because it influences the size.  */
+  if (cris_get_opcode (*inst) < 4)
+    {
+      size &= ~SIGNED_EXTEND_BIT_MASK;
+    }
+  /* Is there a need for checking the size?  Size should contain the number of
+     bytes to read.  */
+  size = 1 << size;
+  value = read_memory_unsigned_integer (address, size);
+
+  /* Check if it's an extend, signed or zero instruction.  */
+  if (cris_get_opcode (*inst) < 4)
+    {
+      value = do_sign_or_zero_extend (value, inst);
+    }
+  return value;
+}
+
+/* Handles the assign addresing mode for the ADD, SUB, CMP, AND, OR and MOVE 
+   instructions.  The MOVE instruction is the move from source to register.  */
+
+void 
+handle_prefix_assign_mode_for_aritm_op (unsigned short inst, 
+                                        inst_env_type *inst_env)
+{
+  unsigned long operand2;
+  unsigned long operand3;
+
+  check_assign (inst, inst_env);
+  if (cris_get_operand2 (inst) == REG_PC)
+    {
+      operand2 = inst_env->reg[REG_PC];
+
+      /* Get the value of the third operand.  */
+      operand3 = get_data_from_address (&inst, inst_env->prefix_value);
+
+      /* Calculate the PC value after the instruction, i.e. where the
+         breakpoint should be.  The order of the udw_operands is vital.  */
+      add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand3);
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the three-operand addressing mode for the ADD, SUB, CMP, AND and
+   OR instructions.  Note that for this to work as expected, the calling
+   function must have made sure that there is a prefix to this instruction.  */
+
+void 
+three_operand_add_sub_cmp_and_or_op (unsigned short inst, 
+                                     inst_env_type *inst_env)
+{
+  unsigned long operand2;
+  unsigned long operand3;
+
+  if (cris_get_operand1 (inst) == REG_PC)
+    {
+      /* The PC will be changed by the instruction.  */
+      operand2 = inst_env->reg[cris_get_operand2 (inst)];
+
+      /* Get the value of the third operand.  */
+      operand3 = get_data_from_address (&inst, inst_env->prefix_value);
+
+      /* Calculate the PC value after the instruction, i.e. where the
+         breakpoint should be.  */
+      add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand3);
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the index addresing mode for the ADD, SUB, CMP, AND, OR and MOVE
+   instructions.  The MOVE instruction is the move from source to register.  */
+
+void 
+handle_prefix_index_mode_for_aritm_op (unsigned short inst, 
+                                       inst_env_type *inst_env)
+{
+  if (cris_get_operand1 (inst) != cris_get_operand2 (inst))
+    {
+      /* If the instruction is MOVE it's invalid.  If the instruction is ADD,
+         SUB, AND or OR something weird is going on (if everything works these
+         instructions should end up in the three operand version).  */
+      inst_env->invalid = 1;
+      return;
+    }
+  else
+    {
+      /* three_operand_add_sub_cmp_and_or does the same as we should do here
+         so use it.  */
+      three_operand_add_sub_cmp_and_or_op (inst, inst_env);
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the autoincrement and indirect addresing mode for the ADD, SUB,
+   CMP, AND OR and MOVE instruction.  The MOVE instruction is the move from
+   source to register.  */
+
+void 
+handle_inc_and_index_mode_for_aritm_op (unsigned short inst, 
+                                        inst_env_type *inst_env)
+{
+  unsigned long operand1;
+  unsigned long operand2;
+  unsigned long operand3;
+  int size;
+
+  /* The instruction is either an indirect or autoincrement addressing mode. 
+     Check if the destination register is the PC.  */
+  if (cris_get_operand2 (inst) == REG_PC)
+    {
+      /* Must be done here, get_data_from_address may change the size 
+         field.  */
+      size = cris_get_size (inst);
+      operand2 = inst_env->reg[REG_PC];
+
+      /* Get the value of the third operand, i.e. the indirect operand.  */
+      operand1 = inst_env->reg[cris_get_operand1 (inst)];
+      operand3 = get_data_from_address (&inst, operand1);
+
+      /* Calculate the PC value after the instruction, i.e. where the
+         breakpoint should be.  The order of the udw_operands is vital.  */
+      add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand3); 
+    }
+  /* If this is an autoincrement addressing mode, check if the increment
+     changes the PC.  */
+  if ((cris_get_operand1 (inst) == REG_PC) && (cris_get_mode (inst) == AUTOINC_MODE))
+    {
+      /* Get the size field.  */
+      size = cris_get_size (inst);
+
+      /* If it's an extend instruction we don't want the signed extend bit,
+         because it influences the size.  */
+      if (cris_get_opcode (inst) < 4)
+        {
+          size &= ~SIGNED_EXTEND_BIT_MASK;
+        }
+      process_autoincrement (size, inst, inst_env);
+    } 
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the two-operand addressing mode, all modes except register, for
+   the ADD, SUB CMP, AND and OR instruction.  */
+
+void 
+none_reg_mode_add_sub_cmp_and_or_move_op (unsigned short inst, 
+                                          inst_env_type *inst_env)
+{
+  if (inst_env->prefix_found)
+    {
+      if (cris_get_mode (inst) == PREFIX_INDEX_MODE)
+        {
+          handle_prefix_index_mode_for_aritm_op (inst, inst_env);
+        }
+      else if (cris_get_mode (inst) == PREFIX_ASSIGN_MODE)
+        {
+          handle_prefix_assign_mode_for_aritm_op (inst, inst_env);
+        }
+      else
+        {
+          /* The mode is invalid for a prefixed base instruction.  */
+          inst_env->invalid = 1;
+          return;
+        }
+    }
+  else
+    {
+      handle_inc_and_index_mode_for_aritm_op (inst, inst_env);
+    }
+}
+
+/* Handles the quick addressing mode for the ADD and SUB instruction.  */
+
+void 
+quick_mode_add_sub_op (unsigned short inst, inst_env_type *inst_env)
+{
+  unsigned long operand1;
+  unsigned long operand2;
+
+  /* It's a bad idea to be in a prefix instruction now.  This is a quick mode
+     instruction and can't have a prefix.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+
+  /* Check if the instruction has PC as its target.  */
+  if (cris_get_operand2 (inst) == REG_PC)
+    {
+      if (inst_env->slot_needed)
+        {
+          inst_env->invalid = 1;
+          return;
+        }
+      operand1 = cris_get_quick_value (inst);
+      operand2 = inst_env->reg[REG_PC];
+
+      /* The size should now be dword.  */
+      cris_set_size_to_dword (&inst);
+
+      /* Calculate the PC value after the instruction, i.e. where the
+         breakpoint should be.  */
+      add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand1);
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Handles the quick addressing mode for the CMP, AND and OR instruction.  */
+
+void 
+quick_mode_and_cmp_move_or_op (unsigned short inst, inst_env_type *inst_env)
+{
+  unsigned long operand1;
+  unsigned long operand2;
+
+  /* It's a bad idea to be in a prefix instruction now.  This is a quick mode
+     instruction and can't have a prefix.  */
+  if (inst_env->prefix_found)
+    {
+      inst_env->invalid = 1;
+      return;
+    }
+  /* Check if the instruction has PC as its target.  */
+  if (cris_get_operand2 (inst) == REG_PC)
+    {
+      if (inst_env->slot_needed)
+        {
+          inst_env->invalid = 1;
+          return;
+        }
+      /* The instruction has the PC as its target register.  */
+      operand1 = cris_get_quick_value (inst);
+      operand2 = inst_env->reg[REG_PC];
+
+      /* The quick value is signed, so check if we must do a signed extend.  */
+      if (operand1 & SIGNED_QUICK_VALUE_MASK)
+        {
+          /* sign extend  */
+          operand1 |= SIGNED_QUICK_VALUE_EXTEND_MASK;
+        }
+      /* The size should now be dword.  */
+      cris_set_size_to_dword (&inst);
+
+      /* Calculate the PC value after the instruction, i.e. where the
+         breakpoint should be.  */
+      add_sub_cmp_and_or_move_action (inst, inst_env, operand2, operand1);
+    }
+  inst_env->slot_needed = 0;
+  inst_env->prefix_found = 0;
+  inst_env->xflag_found = 0;
+  inst_env->disable_interrupt = 0;
+}
+
+/* Translate op_type to a function and call it.  */
+
+static void cris_gdb_func (enum cris_op_type op_type, unsigned short inst, 
+                           inst_env_type *inst_env)
+{
+  switch (op_type)
+    {
+    case cris_not_implemented_op:
+      not_implemented_op (inst, inst_env);
+      break;
+
+    case cris_abs_op:
+      abs_op (inst, inst_env);
+      break;
+
+    case cris_addi_op:
+      addi_op (inst, inst_env);
+      break;
+
+    case cris_asr_op:
+      asr_op (inst, inst_env);
+      break;
+
+    case cris_asrq_op:
+      asrq_op (inst, inst_env);
+      break;
+
+    case cris_ax_ei_setf_op:
+      ax_ei_setf_op (inst, inst_env);
+      break;
+
+    case cris_bdap_prefix:
+      bdap_prefix (inst, inst_env);
+      break;
+
+    case cris_biap_prefix:
+      biap_prefix (inst, inst_env);
+      break;
+
+    case cris_break_op:
+      break_op (inst, inst_env);
+      break;
+
+    case cris_btst_nop_op:
+      btst_nop_op (inst, inst_env);
+      break;
+
+    case cris_clearf_di_op:
+      clearf_di_op (inst, inst_env);
+      break;
+
+    case cris_dip_prefix:
+      dip_prefix (inst, inst_env);
+      break;
+
+    case cris_dstep_logshift_mstep_neg_not_op:
+      dstep_logshift_mstep_neg_not_op (inst, inst_env);
+      break;
+
+    case cris_eight_bit_offset_branch_op:
+      eight_bit_offset_branch_op (inst, inst_env);
+      break;
+
+    case cris_move_mem_to_reg_movem_op:
+      move_mem_to_reg_movem_op (inst, inst_env);
+      break;
+
+    case cris_move_reg_to_mem_movem_op:
+      move_reg_to_mem_movem_op (inst, inst_env);
+      break;
+
+    case cris_move_to_preg_op:
+      move_to_preg_op (inst, inst_env);
+      break;
+
+    case cris_muls_op:
+      muls_op (inst, inst_env);
+      break;
+
+    case cris_mulu_op:
+      mulu_op (inst, inst_env);
+      break;
+
+    case cris_none_reg_mode_add_sub_cmp_and_or_move_op:
+      none_reg_mode_add_sub_cmp_and_or_move_op (inst, inst_env);
+      break;
+
+    case cris_none_reg_mode_clear_test_op:
+      none_reg_mode_clear_test_op (inst, inst_env);
+      break;
+
+    case cris_none_reg_mode_jump_op:
+      none_reg_mode_jump_op (inst, inst_env);
+      break;
+
+    case cris_none_reg_mode_move_from_preg_op:
+      none_reg_mode_move_from_preg_op (inst, inst_env);
+      break;
+
+    case cris_quick_mode_add_sub_op:
+      quick_mode_add_sub_op (inst, inst_env);
+      break;
+
+    case cris_quick_mode_and_cmp_move_or_op:
+      quick_mode_and_cmp_move_or_op (inst, inst_env);
+      break;
+
+    case cris_quick_mode_bdap_prefix:
+      quick_mode_bdap_prefix (inst, inst_env);
+      break;
+
+    case cris_reg_mode_add_sub_cmp_and_or_move_op:
+      reg_mode_add_sub_cmp_and_or_move_op (inst, inst_env);
+      break;
+
+    case cris_reg_mode_clear_op:
+      reg_mode_clear_op (inst, inst_env);
+      break;
+
+    case cris_reg_mode_jump_op:
+      reg_mode_jump_op (inst, inst_env);
+      break;
+
+    case cris_reg_mode_move_from_preg_op:
+      reg_mode_move_from_preg_op (inst, inst_env);
+      break;
+
+    case cris_reg_mode_test_op:
+      reg_mode_test_op (inst, inst_env);
+      break;
+
+    case cris_scc_op:
+      scc_op (inst, inst_env);
+      break;
+
+    case cris_sixteen_bit_offset_branch_op:
+      sixteen_bit_offset_branch_op (inst, inst_env);
+      break;
+
+    case cris_three_operand_add_sub_cmp_and_or_op:
+      three_operand_add_sub_cmp_and_or_op (inst, inst_env);
+      break;
+
+    case cris_three_operand_bound_op:
+      three_operand_bound_op (inst, inst_env);
+      break;
+
+    case cris_two_operand_bound_op:
+      two_operand_bound_op (inst, inst_env);
+      break;
+
+    case cris_xor_op:
+      xor_op (inst, inst_env);
+      break;
+    }
+}
+
+/* This wrapper is to avoid cris_get_assembler being called before 
+   exec_bfd has been set.  */
+
+static int
+cris_delayed_get_disassembler (bfd_vma addr, disassemble_info *info)
+{
+  tm_print_insn = cris_get_disassembler (exec_bfd);
+  return TARGET_PRINT_INSN (addr, info);
+}
+
+/* Copied from <asm/elf.h>.  */
+typedef unsigned long elf_greg_t;
+
+/* Same as user_regs_struct struct in <asm/user.h>.  */
+typedef elf_greg_t elf_gregset_t[35];
+
+/* Unpack an elf_gregset_t into GDB's register cache.  */
+
+void 
+supply_gregset (elf_gregset_t *gregsetp)
+{
+  int i;
+  elf_greg_t *regp = *gregsetp;
+  static char zerobuf[4] = {0};
+
+  /* The kernel dumps all 32 registers as unsigned longs, but supply_register
+     knows about the actual size of each register so that's no problem.  */
+  for (i = 0; i < NUM_GENREGS + NUM_SPECREGS; i++)
+    {
+      supply_register (i, (char *)&regp[i]);
+    }
+}
+
+/*  Use a local version of this function to get the correct types for
+    regsets, until multi-arch core support is ready.  */
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
+                      int which, CORE_ADDR reg_addr)
+{
+  elf_gregset_t gregset;
+
+  switch (which)
+    {
+    case 0:
+      if (core_reg_size != sizeof (gregset))
+        {
+          warning ("wrong size gregset struct in core file");
+        }
+      else
+        {
+          memcpy (&gregset, core_reg_sect, sizeof (gregset));
+          supply_gregset (&gregset);
+        }
+
+    default:
+      /* We've covered all the kinds of registers we know about here,
+         so this must be something we wouldn't know what to do with
+         anyway.  Just ignore it.  */
+      break;
+    }
+}
+
+static struct core_fns cris_elf_core_fns =
+{
+  bfd_target_elf_flavour,               /* core_flavour */
+  default_check_format,                 /* check_format */
+  default_core_sniffer,                 /* core_sniffer */
+  fetch_core_registers,                 /* core_read_registers */
+  NULL                                  /* next */
+};
+
+/* Fetch (and possibly build) an appropriate link_map_offsets
+   structure for native GNU/Linux CRIS targets using the struct
+   offsets defined in link.h (but without actual reference to that
+   file).
+
+   This makes it possible to access GNU/Linux CRIS shared libraries
+   from a GDB that was not built on an GNU/Linux CRIS host (for cross
+   debugging).
+
+   See gdb/solib-svr4.h for an explanation of these fields.  */
+
+struct link_map_offsets *
+cris_linux_svr4_fetch_link_map_offsets (void)
+{ 
+  static struct link_map_offsets lmo;
+  static struct link_map_offsets *lmp = NULL;
+
+  if (lmp == NULL)
+    { 
+      lmp = &lmo;
+
+      lmo.r_debug_size = 8;    /* The actual size is 20 bytes, but
+                                  this is all we need.  */
+      lmo.r_map_offset = 4;
+      lmo.r_map_size   = 4;
+
+      lmo.link_map_size = 20;
+
+      lmo.l_addr_offset = 0;
+      lmo.l_addr_size   = 4;
+
+      lmo.l_name_offset = 4;
+      lmo.l_name_size   = 4;
+
+      lmo.l_next_offset = 12;
+      lmo.l_next_size   = 4;
+
+      lmo.l_prev_offset = 16;
+      lmo.l_prev_size   = 4;
+    }
+
+  return lmp;
+}
+
+static void
+cris_fpless_backtrace (char *noargs, int from_tty)
+{
+  /* Points at the instruction after the jsr (except when in innermost frame
+     where it points at the original pc).  */
+  CORE_ADDR pc = 0;
+
+  /* Temporary variable, used for parsing from the start of the function that
+     the pc is in, up to the pc.  */
+  CORE_ADDR tmp_pc = 0;
+  CORE_ADDR sp = 0;
+
+  /* Information about current frame.  */
+  struct symtab_and_line sal;
+  char* func_name;
+
+  /* Present instruction.  */
+  unsigned short insn;
+  
+  /* Next instruction, lookahead.  */
+  unsigned short insn_next; 
+
+  /* This is to store the offset between sp at start of function and until we
+     reach push srp (if any).  */
+  int sp_add_later = 0;
+  int push_srp_found = 0;
+
+  int val = 0;
+
+  /* Frame counter.  */
+  int frame = 0;
+
+  /* For the innermost frame, we want to look at srp in case it's a leaf
+     function (since there's no push srp in that case).  */
+  int innermost_frame = 1;
+  
+  read_register_gen (PC_REGNUM, (char *) &pc);
+  read_register_gen (SP_REGNUM, (char *) &sp);
+  
+  /* We make an explicit return when we can't find an outer frame.  */
+  while (1)
+    {
+      /* Get file name and line number.  */
+      sal = find_pc_line (pc, 0);
+
+      /* Get function name.  */
+      find_pc_partial_function (pc, &func_name, (CORE_ADDR *) NULL,
+                                (CORE_ADDR *) NULL);
+
+      /* Print information about current frame.  */
+      printf_unfiltered ("#%i  0x%08lx in %s", frame++, pc, func_name);
+      if (sal.symtab)
+        {    
+          printf_unfiltered (" at %s:%i", sal.symtab->filename, sal.line);
+        }
+      printf_unfiltered ("\n");
+      
+      /* Get the start address of this function.  */
+      tmp_pc = get_pc_function_start (pc);
+  
+      /* Mini parser, only meant to find push sp and sub ...,sp from the start
+         of the function, up to the pc.  */
+      while (tmp_pc < pc)
+        {
+          insn = read_memory_unsigned_integer (tmp_pc, sizeof (short));
+          tmp_pc += sizeof (short);
+          if (insn == 0xE1FC)
+            {
+              /* push <reg> 32 bit instruction */
+              insn_next = read_memory_unsigned_integer (tmp_pc, 
+                                                        sizeof (short));
+              tmp_pc += sizeof (short);
+
+              /* Recognize srp.  */
+              if (insn_next == 0xBE7E)
+                {
+                  /* For subsequent (not this one though) push or sub which
+                     affects sp, adjust sp immediately.  */
+                  push_srp_found = 1;
+
+                  /* Note: this will break if we ever encounter a 
+                     push vr (1 byte) or push ccr (2 bytes).  */
+                  sp_add_later += 4;
+                }
+              else
+                {
+                  /* Some other register was pushed.  */
+                  if (push_srp_found)
+                    {    
+                      sp += 4;
+                    }
+                  else
+                    {
+                      sp_add_later += 4;
+                    }
+                }
+            }
+          else if (cris_get_operand2 (insn) == SP_REGNUM 
+                   && cris_get_mode (insn) == 0x0000
+                   && cris_get_opcode (insn) == 0x000A)
+            {
+              /* subq <val>,sp */
+              val = cris_get_quick_value (insn);
+
+              if (push_srp_found)
+                {
+                  sp += val;
+                }
+              else
+                {
+                  sp_add_later += val;
+                }
+              
+            }
+          else if (cris_get_operand2 (insn) == SP_REGNUM
+                   /* Autoincrement addressing mode.  */
+                   && cris_get_mode (insn) == 0x0003
+                   /* Opcode.  */
+                   && ((insn) & 0x03E0) >> 5 == 0x0004)
+            {
+              /* subu <val>,sp */
+              val = get_data_from_address (&insn, tmp_pc);
+
+              if (push_srp_found)
+                {
+                  sp += val;
+                }
+              else
+                {
+                  sp_add_later += val;
+                }
+            }
+          else if (cris_get_operand2 (insn) == SP_REGNUM
+                   && ((insn & 0x0F00) >> 8) == 0x0001
+                   && (cris_get_signed_offset (insn) < 0))
+            {
+              /* Immediate byte offset addressing prefix word with sp as base 
+                 register.  Used for CRIS v8 i.e. ETRAX 100 and newer if <val> 
+                 is between 64 and 128. 
+                 movem r<regsave>,[sp=sp-<val>] */
+              val = -cris_get_signed_offset (insn);
+              insn_next = read_memory_unsigned_integer (tmp_pc, 
+                                                        sizeof (short));
+              tmp_pc += sizeof (short);
+              
+              if (cris_get_mode (insn_next) == PREFIX_ASSIGN_MODE
+                  && cris_get_opcode (insn_next) == 0x000F
+                  && cris_get_size (insn_next) == 0x0003
+                  && cris_get_operand1 (insn_next) == SP_REGNUM)
+                {             
+                  if (push_srp_found)
+                    {
+                      sp += val;
+                    }
+                  else
+                    {
+                      sp_add_later += val;
+                    }
+                }
+            }
+        }
+      
+      if (push_srp_found)
+        {
+          /* Reset flag.  */
+          push_srp_found = 0;
+
+          /* sp should now point at where srp is stored on the stack.  Update
+             the pc to the srp.  */
+          pc = read_memory_unsigned_integer (sp, 4);
+        }
+      else if (innermost_frame)
+        {
+          /* We couldn't find a push srp in the prologue, so this must be
+             a leaf function, and thus we use the srp register directly.
+             This should happen at most once, for the innermost function.  */
+          read_register_gen (SRP_REGNUM, (char *) &pc);
+        }
+      else
+        {
+          /* Couldn't find an outer frame.  */
+          return;
+        }
+
+      /* Reset flag.  (In case the innermost frame wasn't a leaf, we don't
+         want to look at the srp register later either).  */
+      innermost_frame = 0;
+
+      /* Now, add the offset for everything up to, and including push srp,
+         that was held back during the prologue parsing.  */ 
+      sp += sp_add_later;
+      sp_add_later = 0;
+    }
+}
+
+void
+_initialize_cris_tdep (void)
+{
+  struct cmd_list_element *c;
+
+  gdbarch_register (bfd_arch_cris, cris_gdbarch_init, cris_dump_tdep);
+  
+  /* Used in disassembly.  */
+  tm_print_insn = cris_delayed_get_disassembler;
+
+  /* CRIS-specific user-commands.  */
+  c = add_set_cmd ("cris-version", class_support, var_integer, 
+                   (char *) &usr_cmd_cris_version, 
+                   "Set the current CRIS version.", &setlist);
+  set_cmd_sfunc (c, cris_version_update);
+  add_show_from_set (c, &showlist);
+  
+  c = add_set_enum_cmd ("cris-mode", class_support, cris_mode_enums, 
+                        &usr_cmd_cris_mode, 
+                        "Set the current CRIS mode.", &setlist);
+  set_cmd_sfunc (c, cris_mode_update);
+  add_show_from_set (c, &showlist);
+
+  c = add_set_enum_cmd ("cris-abi", class_support, cris_abi_enums, 
+                        &usr_cmd_cris_abi, 
+                        "Set the current CRIS ABI version.", &setlist);
+  set_cmd_sfunc (c, cris_abi_update);
+  add_show_from_set (c, &showlist);
+
+  c = add_cmd ("cris-fpless-backtrace", class_support, cris_fpless_backtrace, 
+               "Display call chain using the subroutine return pointer.\n"
+               "Note that this displays the address after the jump to the "
+               "subroutine.", &cmdlist);
+  
+  add_core_fns (&cris_elf_core_fns);
+  
+}
+
+/* Prints out all target specific values.  */
+
+static void
+cris_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  if (tdep != NULL)
+    {
+      fprintf_unfiltered (file, "cris_dump_tdep: tdep->cris_version = %i\n",
+                          tdep->cris_version);
+      fprintf_unfiltered (file, "cris_dump_tdep: tdep->cris_mode = %s\n",
+                          tdep->cris_mode);
+      fprintf_unfiltered (file, "cris_dump_tdep: tdep->cris_abi = %s\n",
+                          tdep->cris_abi);
+
+    }
+}
+
+static void
+cris_version_update (char *ignore_args, int from_tty, 
+                     struct cmd_list_element *c)
+{
+  struct gdbarch_info info;
+
+  /* NOTE: cagney/2002-03-17: The add_show_from_set() function clones
+     the set command passed as a parameter.  The clone operation will
+     include (BUG?) any ``set'' command callback, if present.
+     Commands like ``info set'' call all the ``show'' command
+     callbacks.  Unfortunatly, for ``show'' commands cloned from
+     ``set'', this includes callbacks belonging to ``set'' commands.
+     Making this worse, this only occures if add_show_from_set() is
+     called after add_cmd_sfunc() (BUG?).  */
+
+  /* From here on, trust the user's CRIS version setting.  */
+  if (cmd_type (c) == set_cmd)
+    {
+      usr_cmd_cris_version_valid = 1;
+  
+      /* Update the current architecture, if needed.  */
+      gdbarch_info_init (&info);
+      if (!gdbarch_update_p (info))
+        internal_error (__FILE__, __LINE__, "cris_gdbarch_update: failed to update architecture.");
+    }  
+}
+
+static void
+cris_mode_update (char *ignore_args, int from_tty, 
+                 struct cmd_list_element *c)
+{
+  struct gdbarch_info info;
+  
+  /* NOTE: cagney/2002-03-17: The add_show_from_set() function clones
+     the set command passed as a parameter.  The clone operation will
+     include (BUG?) any ``set'' command callback, if present.
+     Commands like ``info set'' call all the ``show'' command
+     callbacks.  Unfortunatly, for ``show'' commands cloned from
+     ``set'', this includes callbacks belonging to ``set'' commands.
+     Making this worse, this only occures if add_show_from_set() is
+     called after add_cmd_sfunc() (BUG?).  */
+
+  /* From here on, trust the user's CRIS mode setting.  */
+  if (cmd_type (c) == set_cmd)
+    {
+      usr_cmd_cris_mode_valid = 1;
+  
+      /* Update the current architecture, if needed.  */
+      gdbarch_info_init (&info);
+      if (!gdbarch_update_p (info))
+        internal_error (__FILE__, __LINE__, "cris_gdbarch_update: failed to update architecture.");
+    }
+}
+
+static void
+cris_abi_update (char *ignore_args, int from_tty, 
+                 struct cmd_list_element *c)
+{
+  struct gdbarch_info info;
+  
+  /* NOTE: cagney/2002-03-17: The add_show_from_set() function clones
+     the set command passed as a parameter.  The clone operation will
+     include (BUG?) any ``set'' command callback, if present.
+     Commands like ``info set'' call all the ``show'' command
+     callbacks.  Unfortunatly, for ``show'' commands cloned from
+     ``set'', this includes callbacks belonging to ``set'' commands.
+     Making this worse, this only occures if add_show_from_set() is
+     called after add_cmd_sfunc() (BUG?).  */
+
+  /* From here on, trust the user's CRIS ABI setting.  */
+  if (cmd_type (c) == set_cmd)
+    {
+      usr_cmd_cris_abi_valid = 1;
+  
+      /* Update the current architecture, if needed.  */
+      gdbarch_info_init (&info);
+      if (!gdbarch_update_p (info))
+        internal_error (__FILE__, __LINE__, "cris_gdbarch_update: failed to update architecture.");
+    }
+}
+
+/* Copied from pa64solib.c, with a couple of minor changes.  */
+
+static CORE_ADDR
+bfd_lookup_symbol (bfd *abfd, const char *symname)
+{
+  unsigned int storage_needed;
+  asymbol *sym;
+  asymbol **symbol_table;
+  unsigned int number_of_symbols;
+  unsigned int i;
+  struct cleanup *back_to;
+  CORE_ADDR symaddr = 0;
+
+  storage_needed = bfd_get_symtab_upper_bound (abfd);
+
+  if (storage_needed > 0)
+    {
+      symbol_table = (asymbol **) xmalloc (storage_needed);
+      back_to = make_cleanup (free, (PTR) symbol_table);
+      number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+
+      for (i = 0; i < number_of_symbols; i++)
+       {
+         sym = *symbol_table++;
+         if (!strcmp (sym->name, symname))
+           {
+             /* Bfd symbols are section relative.  */
+             symaddr = sym->value + sym->section->vma;
+             break;
+           }
+       }
+      do_cleanups (back_to);
+    }
+  return (symaddr);
+}
+
+static struct gdbarch *
+cris_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int cris_version;
+  const char *cris_mode;
+  const char *cris_abi;
+  CORE_ADDR cris_abi_sym = 0;
+  int register_bytes;
+
+  if (usr_cmd_cris_version_valid)
+    {
+      /* Trust the user's CRIS version setting.  */ 
+      cris_version = usr_cmd_cris_version;
+    }
+  else
+    {
+      /* Assume it's CRIS version 10.  */
+      cris_version = 10;
+    }
+
+  if (usr_cmd_cris_mode_valid)
+    {
+      /* Trust the user's CRIS mode setting.  */ 
+      cris_mode = usr_cmd_cris_mode;
+    }
+  else if (cris_version == 10)
+    {
+      /* Assume CRIS version 10 is in user mode.  */
+      cris_mode = CRIS_MODE_USER;
+    }
+  else
+    {
+      /* Strictly speaking, older CRIS version don't have a supervisor mode,
+         but we regard its only mode as supervisor mode.  */
+      cris_mode = CRIS_MODE_SUPERVISOR;
+    }
+
+  if (usr_cmd_cris_abi_valid)
+    {
+      /* Trust the user's ABI setting.  */
+      cris_abi = usr_cmd_cris_abi;
+    }
+  else if (info.abfd)
+    {
+      if (bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+        {
+          /* An elf target uses the new ABI.  */
+          cris_abi = CRIS_ABI_V2;
+        }
+      else if (bfd_get_flavour (info.abfd) == bfd_target_aout_flavour)
+        {
+          /* An a.out target may use either ABI.  Look for hints in the
+             symbol table.  */
+          cris_abi_sym = bfd_lookup_symbol (info.abfd, CRIS_ABI_SYMBOL);
+          cris_abi = cris_abi_sym ? CRIS_ABI_V2 : CRIS_ABI_ORIGINAL;
+        }
+      else
+        {
+          /* Unknown bfd flavour.  Assume it's the new ABI.  */
+          cris_abi = CRIS_ABI_V2;
+        }
+    }
+  else if (arches != NULL)
+    {
+      /* No bfd available.  Stick with the ABI from the most recently
+         selected architecture of this same family (the head of arches
+         always points to this).  (This is to avoid changing the ABI
+         when the user updates the architecture with the 'set
+         cris-version' command.)  */
+      cris_abi = gdbarch_tdep (arches->gdbarch)->cris_abi;
+    }
+  else
+    {
+      /* No bfd, and no previously selected architecture available.
+         Assume it's the new ABI.  */
+      cris_abi = CRIS_ABI_V2;
+    }
+
+  /* Make the current settings visible to the user.  */
+  usr_cmd_cris_version = cris_version;
+  usr_cmd_cris_mode = cris_mode;
+  usr_cmd_cris_abi = cris_abi;
+  
+  /* Find a candidate among the list of pre-declared architectures.  Both
+     CRIS version and ABI must match.  */
+  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)->cris_version == cris_version)
+          && (gdbarch_tdep (arches->gdbarch)->cris_mode == cris_mode)
+          && (gdbarch_tdep (arches->gdbarch)->cris_abi == cris_abi))
+        return arches->gdbarch;
+    }
+
+  /* No matching architecture was found.  Create a new one.  */
+  tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  tdep->cris_version = cris_version;
+  tdep->cris_mode = cris_mode;
+  tdep->cris_abi = cris_abi;
+
+  /* INIT shall ensure that the INFO.BYTE_ORDER is non-zero.  */
+  switch (info.byte_order)
+    {
+    case BFD_ENDIAN_LITTLE:
+      /* Ok.  */
+      break;
+
+    case BFD_ENDIAN_BIG:
+      internal_error (__FILE__, __LINE__, "cris_gdbarch_init: big endian byte order in info");
+      break;
+    
+    default:
+      internal_error (__FILE__, __LINE__, "cris_gdbarch_init: unknown byte order in info");
+    }
+
+  /* Initialize the ABI dependent things.  */
+  if (tdep->cris_abi == CRIS_ABI_ORIGINAL)
+    {
+      set_gdbarch_double_bit (gdbarch, 32);
+      set_gdbarch_push_arguments (gdbarch, cris_abi_original_push_arguments);
+      set_gdbarch_deprecated_store_return_value (gdbarch, 
+                                      cris_abi_original_store_return_value);
+      set_gdbarch_deprecated_extract_return_value 
+        (gdbarch, cris_abi_original_extract_return_value);
+      set_gdbarch_reg_struct_has_addr 
+        (gdbarch, cris_abi_original_reg_struct_has_addr);
+    }
+  else if (tdep->cris_abi == CRIS_ABI_V2)
+    {
+      set_gdbarch_double_bit (gdbarch, 64);
+      set_gdbarch_push_arguments (gdbarch, cris_abi_v2_push_arguments);
+      set_gdbarch_deprecated_store_return_value (gdbarch, cris_abi_v2_store_return_value);
+      set_gdbarch_deprecated_extract_return_value
+       (gdbarch, cris_abi_v2_extract_return_value);
+      set_gdbarch_reg_struct_has_addr (gdbarch, 
+                                       cris_abi_v2_reg_struct_has_addr);
+    }
+  else
+    internal_error (__FILE__, __LINE__, "cris_gdbarch_init: unknown CRIS ABI");
+
+  /* The default definition of a long double is 2 * TARGET_DOUBLE_BIT,
+     which means we have to set this explicitly.  */
+  set_gdbarch_long_double_bit (gdbarch, 64);
+    
+  /* There are 32 registers (some of which may not be implemented).  */
+  set_gdbarch_num_regs (gdbarch, 32);
+  set_gdbarch_sp_regnum (gdbarch, 14);
+  set_gdbarch_fp_regnum (gdbarch, 8);
+  set_gdbarch_pc_regnum (gdbarch, 15);
+
+  set_gdbarch_register_name (gdbarch, cris_register_name);
+  
+  /* Length of ordinary registers used in push_word and a few other places. 
+     REGISTER_RAW_SIZE is the real way to know how big a register is.  */
+  set_gdbarch_register_size (gdbarch, 4);
+  
+  /* NEW */
+  set_gdbarch_register_bytes_ok (gdbarch, cris_register_bytes_ok);
+  set_gdbarch_software_single_step (gdbarch, cris_software_single_step);
+
+  
+  set_gdbarch_cannot_store_register (gdbarch, cris_cannot_store_register);
+  set_gdbarch_cannot_fetch_register (gdbarch, cris_cannot_fetch_register);
+
+
+  /* The total amount of space needed to store (in an array called registers)
+     GDB's copy of the machine's register state.  Note: We can not use
+     cris_register_size at this point, since it relies on current_gdbarch
+     being set.  */
+  switch (tdep->cris_version)
+    {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+      /* Support for these may be added later.  */
+      internal_error (__FILE__, __LINE__, "cris_gdbarch_init: unsupported CRIS version");
+      break;
+      
+    case 8:
+    case 9:
+      /* CRIS v8 and v9, a.k.a. ETRAX 100.  General registers R0 - R15 
+         (32 bits), special registers P0 - P1 (8 bits), P4 - P5 (16 bits), 
+         and P8 - P14 (32 bits).  */
+      register_bytes = (16 * 4) + (2 * 1) + (2 * 2) + (7 * 4);
+      break;
+
+    case 10:
+    case 11: 
+      /* CRIS v10 and v11, a.k.a. ETRAX 100LX.  In addition to ETRAX 100, 
+         P7 (32 bits), and P15 (32 bits) have been implemented.  */
+      register_bytes = (16 * 4) + (2 * 1) + (2 * 2) + (9 * 4);
+      break;
+
+    default:
+      internal_error (__FILE__, __LINE__, "cris_gdbarch_init: unknown CRIS version");
+    }
+
+  set_gdbarch_register_bytes (gdbarch, register_bytes);
+
+  /* Returns the register offset for the first byte of register regno's space 
+     in the saved register state.  */
+  set_gdbarch_register_byte (gdbarch, cris_register_offset);
+  
+  /* The length of the registers in the actual machine representation.  */
+  set_gdbarch_register_raw_size (gdbarch, cris_register_size);
+  
+  /* The largest value REGISTER_RAW_SIZE can have.  */
+  set_gdbarch_max_register_raw_size (gdbarch, 32);
+  
+  /* The length of the registers in the program's representation.  */
+  set_gdbarch_register_virtual_size (gdbarch, cris_register_size);
+  
+  /* The largest value REGISTER_VIRTUAL_SIZE can have.  */
+  set_gdbarch_max_register_virtual_size (gdbarch, 32);
+
+  set_gdbarch_register_virtual_type (gdbarch, cris_register_virtual_type);
+  
+  /* Use generic dummy frames.  */
+  set_gdbarch_use_generic_dummy_frames (gdbarch, 1);
+  
+  /* Where to execute the call in the memory segments.  */
+  set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+  set_gdbarch_call_dummy_address (gdbarch, entry_point_address);
+  
+  /* Start execution at the beginning of dummy.  */
+  set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+  set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
+  
+  /* Set to 1 since call_dummy_breakpoint_offset was defined.  */
+  set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+  
+  /* Read all about dummy frames in blockframe.c.  */
+  set_gdbarch_call_dummy_length (gdbarch, 0);
+  set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_at_entry_point);
+  
+  /* Defined to 1 to indicate that the target supports inferior function 
+     calls.  */
+  set_gdbarch_call_dummy_p (gdbarch, 1);
+  set_gdbarch_call_dummy_words (gdbarch, 0);
+  set_gdbarch_sizeof_call_dummy_words (gdbarch, 0);
+  
+  /* No stack adjustment needed when peforming an inferior function call.  */
+  set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+  set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy);
+
+  set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register);
+  
+  /* No register requires conversion from raw format to virtual format.  */
+  set_gdbarch_register_convertible (gdbarch, generic_register_convertible_not);
+
+  set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
+  set_gdbarch_push_return_address (gdbarch, cris_push_return_address);
+  set_gdbarch_pop_frame (gdbarch, cris_pop_frame);
+
+  set_gdbarch_store_struct_return (gdbarch, cris_store_struct_return);
+  set_gdbarch_deprecated_extract_struct_value_address
+    (gdbarch, cris_extract_struct_value_address);
+  set_gdbarch_use_struct_convention (gdbarch, cris_use_struct_convention);
+
+  set_gdbarch_frame_init_saved_regs (gdbarch, cris_frame_init_saved_regs);
+  set_gdbarch_init_extra_frame_info (gdbarch, cris_init_extra_frame_info);
+  set_gdbarch_skip_prologue (gdbarch, cris_skip_prologue);
+  set_gdbarch_prologue_frameless_p (gdbarch, generic_prologue_frameless_p);
+  
+  /* The stack grows downward.  */
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+  set_gdbarch_breakpoint_from_pc (gdbarch, cris_breakpoint_from_pc);
+  
+  /* The PC must not be decremented after a breakpoint.  (The breakpoint
+     handler takes care of that.)  */
+  set_gdbarch_decr_pc_after_break (gdbarch, 0);
+  
+  /* Offset from address of function to start of its code.  */
+  set_gdbarch_function_start_offset (gdbarch, 0);  
+  
+  /* The number of bytes at the start of arglist that are not really args,
+     0 in the CRIS ABI.  */
+  set_gdbarch_frame_args_skip (gdbarch, 0);
+  set_gdbarch_frameless_function_invocation 
+    (gdbarch, cris_frameless_function_invocation);
+  set_gdbarch_frame_chain (gdbarch, cris_frame_chain);
+  set_gdbarch_frame_chain_valid (gdbarch, generic_file_frame_chain_valid);
+
+  set_gdbarch_frame_saved_pc (gdbarch, cris_frame_saved_pc);
+  set_gdbarch_frame_args_address (gdbarch, cris_frame_args_address);
+  set_gdbarch_frame_locals_address (gdbarch, cris_frame_locals_address);
+  set_gdbarch_saved_pc_after_call (gdbarch, cris_saved_pc_after_call);
+
+  set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
+  
+  /* No extra stack alignment needed.  Set to 1 by default.  */
+  set_gdbarch_extra_stack_alignment_needed (gdbarch, 0);
+  
+  /* Helpful for backtracing and returning in a call dummy.  */
+  set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
+
+  /* Use target_specific function to define link map offsets.  */
+  set_solib_svr4_fetch_link_map_offsets 
+    (gdbarch, cris_linux_svr4_fetch_link_map_offsets);
+  
+  return gdbarch;
+}
diff --git a/gdb/mcore-tdep.c b/gdb/mcore-tdep.c
new file mode 100644 (file)
index 0000000..395bb44
--- /dev/null
@@ -0,0 +1,1180 @@
+/* Target-machine dependent code for Motorola MCore for GDB, the GNU debugger
+   Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "regcache.h"
+#include "symfile.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "arch-utils.h"
+
+/* Functions declared and used only in this file */
+
+static CORE_ADDR mcore_analyze_prologue (struct frame_info *fi, CORE_ADDR pc, int skip_prologue);
+
+static struct frame_info *analyze_dummy_frame (CORE_ADDR pc, CORE_ADDR frame);
+
+static int get_insn (CORE_ADDR pc);
+
+/* Functions exported from this file */
+
+int mcore_use_struct_convention (int gcc_p, struct type *type);
+
+void _initialize_mcore (void);
+
+void mcore_init_extra_frame_info (int fromleaf, struct frame_info *fi);
+
+CORE_ADDR mcore_frame_saved_pc (struct frame_info *fi);
+
+CORE_ADDR mcore_find_callers_reg (struct frame_info *fi, int regnum);
+
+CORE_ADDR mcore_frame_args_address (struct frame_info *fi);
+
+CORE_ADDR mcore_frame_locals_address (struct frame_info *fi);
+
+CORE_ADDR mcore_push_return_address (CORE_ADDR pc, CORE_ADDR sp);
+
+CORE_ADDR mcore_push_arguments (int nargs, struct value ** args, CORE_ADDR sp,
+                       int struct_return, CORE_ADDR struct_addr);
+
+void mcore_pop_frame ();
+
+CORE_ADDR mcore_skip_prologue (CORE_ADDR pc);
+
+CORE_ADDR mcore_frame_chain (struct frame_info *fi);
+
+const unsigned char *mcore_breakpoint_from_pc (CORE_ADDR * bp_addr, int *bp_size);
+
+int mcore_use_struct_convention (int gcc_p, struct type *type);
+
+void mcore_store_return_value (struct type *type, char *valbuf);
+
+CORE_ADDR mcore_extract_struct_value_address (char *regbuf);
+
+void mcore_extract_return_value (struct type *type, char *regbuf, char *valbuf);
+
+#ifdef MCORE_DEBUG
+int mcore_debug = 0;
+#endif
+
+
+/* All registers are 4 bytes long.  */
+#define MCORE_REG_SIZE 4
+#define MCORE_NUM_REGS 65
+
+/* Some useful register numbers.  */
+#define PR_REGNUM 15
+#define FIRST_ARGREG 2
+#define LAST_ARGREG 7
+#define RETVAL_REGNUM 2
+
+  
+/* Additional info that we use for managing frames */
+struct frame_extra_info
+  {
+    /* A generic status word */
+    int status;
+
+    /* Size of this frame */
+    int framesize;
+
+    /* The register that is acting as a frame pointer, if
+       it is being used.  This is undefined if status
+       does not contain the flag MY_FRAME_IN_FP. */
+    int fp_regnum;
+  };
+
+/* frame_extra_info status flags */
+
+/* The base of the current frame is actually in the stack pointer.
+   This happens when there is no frame pointer (MCore ABI does not
+   require a frame pointer) or when we're stopped in the prologue or
+   epilogue itself.  In these cases, mcore_analyze_prologue will need
+   to update fi->frame before returning or analyzing the register
+   save instructions. */
+#define MY_FRAME_IN_SP 0x1
+
+/* The base of the current frame is in a frame pointer register.
+   This register is noted in frame_extra_info->fp_regnum.
+
+   Note that the existence of an FP might also indicate that the
+   function has called alloca. */
+#define MY_FRAME_IN_FP 0x2
+
+/* This flag is set to indicate that this frame is the top-most
+   frame. This tells frame chain not to bother trying to unwind
+   beyond this frame. */
+#define NO_MORE_FRAMES 0x4
+
+/* Instruction macros used for analyzing the prologue */
+#define IS_SUBI0(x)   (((x) & 0xfe0f) == 0x2400)       /* subi r0,oimm5    */
+#define IS_STM(x)     (((x) & 0xfff0) == 0x0070)       /* stm rf-r15,r0    */
+#define IS_STWx0(x)   (((x) & 0xf00f) == 0x9000)       /* stw rz,(r0,disp) */
+#define IS_STWxy(x)   (((x) & 0xf000) == 0x9000)       /* stw rx,(ry,disp) */
+#define IS_MOVx0(x)   (((x) & 0xfff0) == 0x1200)       /* mov rn,r0        */
+#define IS_LRW1(x)    (((x) & 0xff00) == 0x7100)       /* lrw r1,literal   */
+#define IS_MOVI1(x)   (((x) & 0xf80f) == 0x6001)       /* movi r1,imm7     */
+#define IS_BGENI1(x)  (((x) & 0xfe0f) == 0x3201)       /* bgeni r1,imm5    */
+#define IS_BMASKI1(x) (((x) & 0xfe0f) == 0x2C01)       /* bmaski r1,imm5   */
+#define IS_ADDI1(x)   (((x) & 0xfe0f) == 0x2001)       /* addi r1,oimm5    */
+#define IS_SUBI1(x)   (((x) & 0xfe0f) == 0x2401)       /* subi r1,oimm5    */
+#define IS_RSUBI1(x)  (((x) & 0xfe0f) == 0x2801)       /* rsubi r1,imm5    */
+#define IS_NOT1(x)    (((x) & 0xffff) == 0x01f1)       /* not r1           */
+#define IS_ROTLI1(x)  (((x) & 0xfe0f) == 0x3801)       /* rotli r1,imm5    */
+#define IS_BSETI1(x)  (((x) & 0xfe0f) == 0x3401)       /* bseti r1,imm5    */
+#define IS_BCLRI1(x)  (((x) & 0xfe0f) == 0x3001)       /* bclri r1,imm5    */
+#define IS_IXH1(x)    (((x) & 0xffff) == 0x1d11)       /* ixh r1,r1        */
+#define IS_IXW1(x)    (((x) & 0xffff) == 0x1511)       /* ixw r1,r1        */
+#define IS_SUB01(x)   (((x) & 0xffff) == 0x0510)       /* subu r0,r1       */
+#define IS_RTS(x)     (((x) & 0xffff) == 0x00cf)       /* jmp r15          */
+
+#define IS_R1_ADJUSTER(x) \
+    (IS_ADDI1(x) || IS_SUBI1(x) || IS_ROTLI1(x) || IS_BSETI1(x) \
+     || IS_BCLRI1(x) || IS_RSUBI1(x) || IS_NOT1(x) \
+     || IS_IXH1(x) || IS_IXW1(x))
+\f
+
+#ifdef MCORE_DEBUG
+static void
+mcore_dump_insn (char *commnt, CORE_ADDR pc, int insn)
+{
+  if (mcore_debug)
+    {
+      printf_filtered ("MCORE:  %s %08x %08x ",
+                      commnt, (unsigned int) pc, (unsigned int) insn);
+      TARGET_PRINT_INSN (pc, &tm_print_insn_info);
+      printf_filtered ("\n");
+    }
+}
+#define mcore_insn_debug(args) { if (mcore_debug) printf_filtered args; }
+#else /* !MCORE_DEBUG */
+#define mcore_dump_insn(a,b,c) {}
+#define mcore_insn_debug(args) {}
+#endif
+
+
+static struct type *
+mcore_register_virtual_type (int regnum)
+{
+  if (regnum < 0 || regnum >= MCORE_NUM_REGS)
+    internal_error (__FILE__, __LINE__,
+                   "mcore_register_virtual_type: illegal register number %d",
+                   regnum);
+  else
+    return builtin_type_int;
+}
+
+static int
+mcore_register_byte (int regnum)
+{
+  if (regnum < 0 || regnum >= MCORE_NUM_REGS)
+    internal_error (__FILE__, __LINE__,
+                   "mcore_register_byte: illegal register number %d",
+                   regnum);
+  else 
+    return (regnum * MCORE_REG_SIZE);
+}
+
+static int
+mcore_register_size (int regnum)
+{
+  
+  if (regnum < 0 || regnum >= MCORE_NUM_REGS)
+    internal_error (__FILE__, __LINE__,
+                   "mcore_register_size: illegal register number %d",
+                   regnum);
+  else
+    return MCORE_REG_SIZE;
+}
+
+/* The registers of the Motorola MCore processors */
+
+static const char *
+mcore_register_name (int regnum)
+{
+
+  static char *register_names[] = { 
+    "r0",   "r1",  "r2",    "r3",   "r4",   "r5",   "r6",   "r7",
+    "r8",   "r9",  "r10",   "r11",  "r12",  "r13",  "r14",  "r15",
+    "ar0",  "ar1", "ar2",   "ar3",  "ar4",  "ar5",  "ar6",  "ar7",
+    "ar8",  "ar9", "ar10", "ar11",  "ar12", "ar13", "ar14", "ar15",
+    "psr",  "vbr", "epsr",  "fpsr", "epc",  "fpc",  "ss0",  "ss1",
+    "ss2",  "ss3", "ss4",   "gcr",  "gsr",  "cr13", "cr14", "cr15",
+    "cr16", "cr17", "cr18", "cr19", "cr20", "cr21", "cr22", "cr23",
+    "cr24", "cr25", "cr26", "cr27", "cr28", "cr29", "cr30", "cr31",
+    "pc" 
+  };
+
+  if (regnum < 0 ||
+      regnum >= sizeof (register_names) / sizeof (register_names[0]))
+    internal_error (__FILE__, __LINE__,
+                   "mcore_register_name: illegal register number %d",
+                   regnum);
+  else
+    return register_names[regnum];
+}
+
+/* Given the address at which to insert a breakpoint (BP_ADDR),
+   what will that breakpoint be?
+
+   For MCore, we have a breakpoint instruction. Since all MCore
+   instructions are 16 bits, this is all we need, regardless of
+   address. bpkt = 0x0000 */
+
+const unsigned char *
+mcore_breakpoint_from_pc (CORE_ADDR * bp_addr, int *bp_size)
+{
+  static char breakpoint[] =
+  {0x00, 0x00};
+  *bp_size = 2;
+  return breakpoint;
+}
+
+static CORE_ADDR
+mcore_saved_pc_after_call (struct frame_info *frame)
+{
+  return read_register (PR_REGNUM);
+}
+
+/* This is currently handled by init_extra_frame_info.  */
+static void
+mcore_frame_init_saved_regs (struct frame_info *frame)
+{
+
+}
+
+/* This is currently handled by mcore_push_arguments  */
+static void
+mcore_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+{
+
+}
+
+static int
+mcore_reg_struct_has_addr (int gcc_p, struct type *type)
+{
+  return 0;
+}
+
+
+/* Helper function for several routines below.  This funtion simply
+   sets up a fake, aka dummy, frame (not a _call_ dummy frame) that
+   we can analyze with mcore_analyze_prologue. */
+
+static struct frame_info *
+analyze_dummy_frame (CORE_ADDR pc, CORE_ADDR frame)
+{
+  static struct frame_info *dummy = NULL;
+
+  if (dummy == NULL)
+    {
+      dummy = (struct frame_info *) xmalloc (sizeof (struct frame_info));
+      dummy->saved_regs = (CORE_ADDR *) xmalloc (SIZEOF_FRAME_SAVED_REGS);
+      dummy->extra_info =
+       (struct frame_extra_info *) xmalloc (sizeof (struct frame_extra_info));
+    }
+
+  dummy->next = NULL;
+  dummy->prev = NULL;
+  dummy->pc = pc;
+  dummy->frame = frame;
+  dummy->extra_info->status = 0;
+  dummy->extra_info->framesize = 0;
+  memset (dummy->saved_regs, '\000', SIZEOF_FRAME_SAVED_REGS);
+  mcore_analyze_prologue (dummy, 0, 0);
+  return dummy;
+}
+
+/* Function prologues on the Motorola MCore processors consist of:
+
+   - adjustments to the stack pointer (r1 used as scratch register)
+   - store word/multiples that use r0 as the base address
+   - making a copy of r0 into another register (a "frame" pointer)
+
+   Note that the MCore really doesn't have a real frame pointer.
+   Instead, the compiler may copy the SP into a register (usually
+   r8) to act as an arg pointer.  For our target-dependent purposes,
+   the frame info's "frame" member will be the beginning of the
+   frame. The SP could, in fact, point below this.
+
+   The prologue ends when an instruction fails to meet either of
+   the first two criteria or when an FP is made.  We make a special
+   exception for gcc. When compiling unoptimized code, gcc will
+   setup stack slots. We need to make sure that we skip the filling
+   of these stack slots as much as possible. This is only done
+   when SKIP_PROLOGUE is set, so that it does not mess up
+   backtraces. */
+
+/* Analyze the prologue of frame FI to determine where registers are saved,
+   the end of the prologue, etc. Return the address of the first line
+   of "real" code (i.e., the end of the prologue). */
+
+static CORE_ADDR
+mcore_analyze_prologue (struct frame_info *fi, CORE_ADDR pc, int skip_prologue)
+{
+  CORE_ADDR func_addr, func_end, addr, stop;
+  CORE_ADDR stack_size;
+  int insn, rn;
+  int status;
+  int fp_regnum = 0; /* dummy, valid when (flags & MY_FRAME_IN_FP) */
+  int flags;
+  int framesize;
+  int register_offsets[NUM_REGS];
+  char *name;
+
+  /* If provided, use the PC in the frame to look up the
+     start of this function. */
+  pc = (fi == NULL ? pc : fi->pc);
+
+  /* Find the start of this function. */
+  status = find_pc_partial_function (pc, &name, &func_addr, &func_end);
+
+  /* If the start of this function could not be found or if the debbuger
+     is stopped at the first instruction of the prologue, do nothing. */
+  if (status == 0)
+    return pc;
+
+  /* If the debugger is entry function, give up. */
+  if (func_addr == entry_point_address ())
+    {
+      if (fi != NULL)
+       fi->extra_info->status |= NO_MORE_FRAMES;
+      return pc;
+    }
+
+  /* At the start of a function, our frame is in the stack pointer. */
+  flags = MY_FRAME_IN_SP;
+
+  /* Start decoding the prologue.  We start by checking two special cases:
+
+     1. We're about to return
+     2. We're at the first insn of the prologue.
+
+     If we're about to return, our frame has already been deallocated.
+     If we are stopped at the first instruction of a prologue,
+     then our frame has not yet been set up. */
+
+  /* Get the first insn from memory (all MCore instructions are 16 bits) */
+  mcore_insn_debug (("MCORE: starting prologue decoding\n"));
+  insn = get_insn (pc);
+  mcore_dump_insn ("got 1: ", pc, insn);
+
+  /* Check for return. */
+  if (fi != NULL && IS_RTS (insn))
+    {
+      mcore_insn_debug (("MCORE: got jmp r15"));
+      if (fi->next == NULL)
+       fi->frame = read_sp ();
+      return fi->pc;
+    }
+
+  /* Check for first insn of prologue */
+  if (fi != NULL && fi->pc == func_addr)
+    {
+      if (fi->next == NULL)
+       fi->frame = read_sp ();
+      return fi->pc;
+    }
+
+  /* Figure out where to stop scanning */
+  stop = (fi ? fi->pc : func_end);
+
+  /* Don't walk off the end of the function */
+  stop = (stop > func_end ? func_end : stop);
+
+  /* REGISTER_OFFSETS will contain offsets, from the top of the frame
+     (NOT the frame pointer), for the various saved registers or -1
+     if the register is not saved. */
+  for (rn = 0; rn < NUM_REGS; rn++)
+    register_offsets[rn] = -1;
+
+  /* Analyze the prologue. Things we determine from analyzing the
+     prologue include:
+     * the size of the frame
+     * where saved registers are located (and which are saved)
+     * FP used? */
+  mcore_insn_debug (("MCORE: Scanning prologue: func_addr=0x%x, stop=0x%x\n",
+                    (unsigned int) func_addr, (unsigned int) stop));
+
+  framesize = 0;
+  for (addr = func_addr; addr < stop; addr += 2)
+    {
+      /* Get next insn */
+      insn = get_insn (addr);
+      mcore_dump_insn ("got 2: ", addr, insn);
+
+      if (IS_SUBI0 (insn))
+       {
+         int offset = 1 + ((insn >> 4) & 0x1f);
+         mcore_insn_debug (("MCORE: got subi r0,%d; continuing\n", offset));
+         framesize += offset;
+         continue;
+       }
+      else if (IS_STM (insn))
+       {
+         /* Spill register(s) */
+         int offset;
+         int start_register;
+
+         /* BIG WARNING! The MCore ABI does not restrict functions
+            to taking only one stack allocation. Therefore, when
+            we save a register, we record the offset of where it was
+            saved relative to the current framesize. This will
+            then give an offset from the SP upon entry to our
+            function. Remember, framesize is NOT constant until
+            we're done scanning the prologue. */
+         start_register = (insn & 0xf);
+         mcore_insn_debug (("MCORE: got stm r%d-r15,(r0)\n", start_register));
+
+         for (rn = start_register, offset = 0; rn <= 15; rn++, offset += 4)
+           {
+             register_offsets[rn] = framesize - offset;
+             mcore_insn_debug (("MCORE: r%d saved at 0x%x (offset %d)\n", rn,
+                                register_offsets[rn], offset));
+           }
+         mcore_insn_debug (("MCORE: continuing\n"));
+         continue;
+       }
+      else if (IS_STWx0 (insn))
+       {
+         /* Spill register: see note for IS_STM above. */
+         int imm;
+
+         rn = (insn >> 8) & 0xf;
+         imm = (insn >> 4) & 0xf;
+         register_offsets[rn] = framesize - (imm << 2);
+         mcore_insn_debug (("MCORE: r%d saved at offset 0x%x\n", rn, register_offsets[rn]));
+         mcore_insn_debug (("MCORE: continuing\n"));
+         continue;
+       }
+      else if (IS_MOVx0 (insn))
+       {
+         /* We have a frame pointer, so this prologue is over.  Note
+            the register which is acting as the frame pointer. */
+         flags |= MY_FRAME_IN_FP;
+         flags &= ~MY_FRAME_IN_SP;
+         fp_regnum = insn & 0xf;
+         mcore_insn_debug (("MCORE: Found a frame pointer: r%d\n", fp_regnum));
+
+         /* If we found an FP, we're at the end of the prologue. */
+         mcore_insn_debug (("MCORE: end of prologue\n"));
+         if (skip_prologue)
+           continue;
+
+         /* If we're decoding prologue, stop here. */
+         addr += 2;
+         break;
+       }
+      else if (IS_STWxy (insn) && (flags & MY_FRAME_IN_FP) && ((insn & 0xf) == fp_regnum))
+       {
+         /* Special case. Skip over stack slot allocs, too. */
+         mcore_insn_debug (("MCORE: push arg onto stack.\n"));
+         continue;
+       }
+      else if (IS_LRW1 (insn) || IS_MOVI1 (insn)
+              || IS_BGENI1 (insn) || IS_BMASKI1 (insn))
+       {
+         int adjust = 0;
+         int offset = 0;
+         int insn2;
+
+         mcore_insn_debug (("MCORE: looking at large frame\n"));
+         if (IS_LRW1 (insn))
+           {
+             adjust =
+               read_memory_integer ((addr + 2 + ((insn & 0xff) << 2)) & 0xfffffffc, 4);
+           }
+         else if (IS_MOVI1 (insn))
+           adjust = (insn >> 4) & 0x7f;
+         else if (IS_BGENI1 (insn))
+           adjust = 1 << ((insn >> 4) & 0x1f);
+         else                  /* IS_BMASKI (insn) */
+           adjust = (1 << (adjust >> 4) & 0x1f) - 1;
+
+         mcore_insn_debug (("MCORE: base framesize=0x%x\n", adjust));
+
+         /* May have zero or more insns which modify r1 */
+         mcore_insn_debug (("MCORE: looking for r1 adjusters...\n"));
+         offset = 2;
+         insn2 = get_insn (addr + offset);
+         while (IS_R1_ADJUSTER (insn2))
+           {
+             int imm;
+
+             imm = (insn2 >> 4) & 0x1f;
+             mcore_dump_insn ("got 3: ", addr + offset, insn);
+             if (IS_ADDI1 (insn2))
+               {
+                 adjust += (imm + 1);
+                 mcore_insn_debug (("MCORE: addi r1,%d\n", imm + 1));
+               }
+             else if (IS_SUBI1 (insn2))
+               {
+                 adjust -= (imm + 1);
+                 mcore_insn_debug (("MCORE: subi r1,%d\n", imm + 1));
+               }
+             else if (IS_RSUBI1 (insn2))
+               {
+                 adjust = imm - adjust;
+                 mcore_insn_debug (("MCORE: rsubi r1,%d\n", imm + 1));
+               }
+             else if (IS_NOT1 (insn2))
+               {
+                 adjust = ~adjust;
+                 mcore_insn_debug (("MCORE: not r1\n"));
+               }
+             else if (IS_ROTLI1 (insn2))
+               {
+                 adjust <<= imm;
+                 mcore_insn_debug (("MCORE: rotli r1,%d\n", imm + 1));
+               }
+             else if (IS_BSETI1 (insn2))
+               {
+                 adjust |= (1 << imm);
+                 mcore_insn_debug (("MCORE: bseti r1,%d\n", imm));
+               }
+             else if (IS_BCLRI1 (insn2))
+               {
+                 adjust &= ~(1 << imm);
+                 mcore_insn_debug (("MCORE: bclri r1,%d\n", imm));
+               }
+             else if (IS_IXH1 (insn2))
+               {
+                 adjust *= 3;
+                 mcore_insn_debug (("MCORE: ix.h r1,r1\n"));
+               }
+             else if (IS_IXW1 (insn2))
+               {
+                 adjust *= 5;
+                 mcore_insn_debug (("MCORE: ix.w r1,r1\n"));
+               }
+
+             offset += 2;
+             insn2 = get_insn (addr + offset);
+           };
+
+         mcore_insn_debug (("MCORE: done looking for r1 adjusters\n"));
+
+         /* If the next insn adjusts the stack pointer, we keep everything;
+            if not, we scrap it and we've found the end of the prologue. */
+         if (IS_SUB01 (insn2))
+           {
+             addr += offset;
+             framesize += adjust;
+             mcore_insn_debug (("MCORE: found stack adjustment of 0x%x bytes.\n", adjust));
+             mcore_insn_debug (("MCORE: skipping to new address 0x%x\n", addr));
+             mcore_insn_debug (("MCORE: continuing\n"));
+             continue;
+           }
+
+         /* None of these instructions are prologue, so don't touch
+            anything. */
+         mcore_insn_debug (("MCORE: no subu r1,r0, NOT altering framesize.\n"));
+         break;
+       }
+
+      /* This is not a prologue insn, so stop here. */
+      mcore_insn_debug (("MCORE: insn is not a prologue insn -- ending scan\n"));
+      break;
+    }
+
+  mcore_insn_debug (("MCORE: done analyzing prologue\n"));
+  mcore_insn_debug (("MCORE: prologue end = 0x%x\n", addr));
+
+  /* Save everything we have learned about this frame into FI. */
+  if (fi != NULL)
+    {
+      fi->extra_info->framesize = framesize;
+      fi->extra_info->fp_regnum = fp_regnum;
+      fi->extra_info->status = flags;
+
+      /* Fix the frame pointer. When gcc uses r8 as a frame pointer,
+         it is really an arg ptr. We adjust fi->frame to be a "real"
+         frame pointer. */
+      if (fi->next == NULL)
+       {
+         if (fi->extra_info->status & MY_FRAME_IN_SP)
+           fi->frame = read_sp () + framesize;
+         else
+           fi->frame = read_register (fp_regnum) + framesize;
+       }
+
+      /* Note where saved registers are stored. The offsets in REGISTER_OFFSETS
+         are computed relative to the top of the frame. */
+      for (rn = 0; rn < NUM_REGS; rn++)
+       {
+         if (register_offsets[rn] >= 0)
+           {
+             fi->saved_regs[rn] = fi->frame - register_offsets[rn];
+             mcore_insn_debug (("Saved register %s stored at 0x%08x, value=0x%08x\n",
+                              mcore_register_names[rn], fi->saved_regs[rn],
+                             read_memory_integer (fi->saved_regs[rn], 4)));
+           }
+       }
+    }
+
+  /* Return addr of first non-prologue insn. */
+  return addr;
+}
+
+/* Given a GDB frame, determine the address of the calling function's frame.
+   This will be used to create a new GDB frame struct, and then
+   INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame. */
+
+CORE_ADDR
+mcore_frame_chain (struct frame_info * fi)
+{
+  struct frame_info *dummy;
+  CORE_ADDR callers_addr;
+
+  /* Analyze the prologue of this function. */
+  if (fi->extra_info->status == 0)
+    mcore_analyze_prologue (fi, 0, 0);
+
+  /* If mcore_analyze_prologue set NO_MORE_FRAMES, quit now. */
+  if (fi->extra_info->status & NO_MORE_FRAMES)
+    return 0;
+
+  /* Now that we've analyzed our prologue, we can start to ask
+     for information about our caller. The easiest way to do
+     this is to analyze our caller's prologue. 
+
+     If our caller has a frame pointer, then we need to find
+     the value of that register upon entry to our frame.
+     This value is either in fi->saved_regs[rn] if it's saved,
+     or it's still in a register.
+
+     If our caller does not have a frame pointer, then his frame base
+     is <our base> + -<caller's frame size>. */
+  dummy = analyze_dummy_frame (FRAME_SAVED_PC (fi), fi->frame);
+
+  if (dummy->extra_info->status & MY_FRAME_IN_FP)
+    {
+      int fp = dummy->extra_info->fp_regnum;
+
+      /* Our caller has a frame pointer. */
+      if (fi->saved_regs[fp] != 0)
+       {
+         /* The "FP" was saved on the stack.  Don't forget to adjust
+            the "FP" with the framesize to get a real FP. */
+         callers_addr = read_memory_integer (fi->saved_regs[fp], REGISTER_SIZE)
+           + dummy->extra_info->framesize;
+       }
+      else
+       {
+         /* It's still in the register.  Don't forget to adjust
+            the "FP" with the framesize to get a real FP. */
+         callers_addr = read_register (fp) + dummy->extra_info->framesize;
+       }
+    }
+  else
+    {
+      /* Our caller does not have a frame pointer. */
+      callers_addr = fi->frame + dummy->extra_info->framesize;
+    }
+
+  return callers_addr;
+}
+
+/* Skip the prologue of the function at PC. */
+
+CORE_ADDR
+mcore_skip_prologue (CORE_ADDR pc)
+{
+  CORE_ADDR func_addr, func_end;
+  struct symtab_and_line sal;
+
+  /* If we have line debugging information, then the end of the
+     prologue should be the first assembly instruction of the first
+     source line */
+  if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+    {
+      sal = find_pc_line (func_addr, 0);
+      if (sal.end && sal.end < func_end)
+       return sal.end;
+    }
+
+  return mcore_analyze_prologue (NULL, pc, 1);
+}
+
+/* Return the address at which function arguments are offset. */
+CORE_ADDR
+mcore_frame_args_address (struct frame_info * fi)
+{
+  return fi->frame - fi->extra_info->framesize;
+}
+
+CORE_ADDR
+mcore_frame_locals_address (struct frame_info * fi)
+{
+  return fi->frame - fi->extra_info->framesize;
+}
+
+/* Return the frame pointer in use at address PC. */
+
+void
+mcore_virtual_frame_pointer (CORE_ADDR pc, int *reg, LONGEST *offset)
+{
+  struct frame_info *dummy = analyze_dummy_frame (pc, 0);
+  if (dummy->extra_info->status & MY_FRAME_IN_SP)
+    {
+      *reg = SP_REGNUM;
+      *offset = 0;
+    }
+  else
+    {
+      *reg = dummy->extra_info->fp_regnum;
+      *offset = 0;
+    }
+}
+
+/* Find the value of register REGNUM in frame FI. */
+
+CORE_ADDR
+mcore_find_callers_reg (struct frame_info *fi, int regnum)
+{
+  for (; fi != NULL; fi = fi->next)
+    {
+      if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+       return deprecated_read_register_dummy (fi->pc, fi->frame, regnum);
+      else if (fi->saved_regs[regnum] != 0)
+       return read_memory_integer (fi->saved_regs[regnum],
+                                   REGISTER_SIZE);
+    }
+
+  return read_register (regnum);
+}
+
+/* Find the saved pc in frame FI. */
+
+CORE_ADDR
+mcore_frame_saved_pc (struct frame_info * fi)
+{
+
+  if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+    return deprecated_read_register_dummy (fi->pc, fi->frame, PC_REGNUM);
+  else
+    return mcore_find_callers_reg (fi, PR_REGNUM);
+}
+\f
+/* INFERIOR FUNCTION CALLS */
+
+/* This routine gets called when either the user uses the "return"
+   command, or the call dummy breakpoint gets hit. */
+
+void
+mcore_pop_frame (void)
+{
+  int rn;
+  struct frame_info *fi = get_current_frame ();
+
+  if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+    generic_pop_dummy_frame ();
+  else
+    {
+      /* Write out the PC we saved. */
+      write_register (PC_REGNUM, FRAME_SAVED_PC (fi));
+
+      /* Restore any saved registers. */
+      for (rn = 0; rn < NUM_REGS; rn++)
+       {
+         if (fi->saved_regs[rn] != 0)
+           {
+             ULONGEST value;
+
+             value = read_memory_unsigned_integer (fi->saved_regs[rn],
+                                                   REGISTER_SIZE);
+             write_register (rn, value);
+           }
+       }
+
+      /* Actually cut back the stack. */
+      write_register (SP_REGNUM, FRAME_FP (fi));
+    }
+
+  /* Finally, throw away any cached frame information. */
+  flush_cached_frames ();
+}
+
+/* Setup arguments and PR for a call to the target. First six arguments
+   go in FIRST_ARGREG -> LAST_ARGREG, subsequent args go on to the stack.
+
+   * Types with lengths greater than REGISTER_SIZE may not be split
+   between registers and the stack, and they must start in an even-numbered
+   register. Subsequent args will go onto the stack.
+
+   * Structs may be split between registers and stack, left-aligned.
+
+   * If the function returns a struct which will not fit into registers (it's
+   more than eight bytes), we must allocate for that, too. Gdb will tell
+   us where this buffer is (STRUCT_ADDR), and we simply place it into
+   FIRST_ARGREG, since the MCORE treats struct returns (of less than eight
+   bytes) as hidden first arguments. */
+
+CORE_ADDR
+mcore_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+                     int struct_return, CORE_ADDR struct_addr)
+{
+  int argreg;
+  int argnum;
+  struct stack_arg
+    {
+      int len;
+      char *val;
+    }
+   *stack_args;
+  int nstack_args = 0;
+
+  stack_args = (struct stack_arg *) alloca (nargs * sizeof (struct stack_arg));
+
+  argreg = FIRST_ARGREG;
+
+  /* Align the stack. This is mostly a nop, but not always. It will be needed
+     if we call a function which has argument overflow. */
+  sp &= ~3;
+
+  /* If this function returns a struct which does not fit in the
+     return registers, we must pass a buffer to the function
+     which it can use to save the return value. */
+  if (struct_return)
+    write_register (argreg++, struct_addr);
+
+  /* FIXME: what about unions? */
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      char *val = (char *) VALUE_CONTENTS (args[argnum]);
+      int len = TYPE_LENGTH (VALUE_TYPE (args[argnum]));
+      struct type *type = VALUE_TYPE (args[argnum]);
+      int olen;
+
+      mcore_insn_debug (("MCORE PUSH: argreg=%d; len=%d; %s\n",
+                        argreg, len, TYPE_CODE (type) == TYPE_CODE_STRUCT ? "struct" : "not struct"));
+      /* Arguments larger than a register must start in an even
+         numbered register. */
+      olen = len;
+
+      if (TYPE_CODE (type) != TYPE_CODE_STRUCT && len > REGISTER_SIZE && argreg % 2)
+       {
+         mcore_insn_debug (("MCORE PUSH: %d > REGISTER_SIZE: and %s is not even\n",
+                            len, mcore_register_names[argreg]));
+         argreg++;
+       }
+
+      if ((argreg <= LAST_ARGREG && len <= (LAST_ARGREG - argreg + 1) * REGISTER_SIZE)
+         || (TYPE_CODE (type) == TYPE_CODE_STRUCT))
+       {
+         /* Something that will fit entirely into registers (or a struct
+            which may be split between registers and stack). */
+         mcore_insn_debug (("MCORE PUSH: arg %d going into regs\n", argnum));
+
+         if (TYPE_CODE (type) == TYPE_CODE_STRUCT && olen < REGISTER_SIZE)
+           {
+             /* Small structs must be right aligned within the register,
+                the most significant bits are undefined. */
+             write_register (argreg, extract_unsigned_integer (val, len));
+             argreg++;
+             len = 0;
+           }
+
+         while (len > 0 && argreg <= LAST_ARGREG)
+           {
+             write_register (argreg, extract_unsigned_integer (val, REGISTER_SIZE));
+             argreg++;
+             val += REGISTER_SIZE;
+             len -= REGISTER_SIZE;
+           }
+
+         /* Any remainder for the stack is noted below... */
+       }
+      else if (TYPE_CODE (VALUE_TYPE (args[argnum])) != TYPE_CODE_STRUCT
+              && len > REGISTER_SIZE)
+       {
+         /* All subsequent args go onto the stack. */
+         mcore_insn_debug (("MCORE PUSH: does not fit into regs, going onto stack\n"));
+         argnum = LAST_ARGREG + 1;
+       }
+
+      if (len > 0)
+       {
+         /* Note that this must be saved onto the stack */
+         mcore_insn_debug (("MCORE PUSH: adding arg %d to stack\n", argnum));
+         stack_args[nstack_args].val = val;
+         stack_args[nstack_args].len = len;
+         nstack_args++;
+       }
+
+    }
+
+  /* We're done with registers and stack allocation. Now do the actual
+     stack pushes. */
+  while (nstack_args--)
+    {
+      sp -= stack_args[nstack_args].len;
+      write_memory (sp, stack_args[nstack_args].val, stack_args[nstack_args].len);
+    }
+
+  /* Return adjusted stack pointer.  */
+  return sp;
+}
+
+/* Store the return address for the call dummy. For MCore, we've
+   opted to use generic call dummies, so we simply store the
+   CALL_DUMMY_ADDRESS into the PR register (r15). */
+
+CORE_ADDR
+mcore_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
+{
+  write_register (PR_REGNUM, CALL_DUMMY_ADDRESS ());
+  return sp;
+}
+
+/* Setting/getting return values from functions.
+
+   The Motorola MCore processors use r2/r3 to return anything
+   not larger than 32 bits. Everything else goes into a caller-
+   supplied buffer, which is passed in via a hidden first
+   argument.
+
+   For gdb, this leaves us two routes, based on what
+   USE_STRUCT_CONVENTION (mcore_use_struct_convention) returns.
+   If this macro returns 1, gdb will call STORE_STRUCT_RETURN and
+   EXTRACT_STRUCT_VALUE_ADDRESS.
+
+   If USE_STRUCT_CONVENTION retruns 0, then gdb uses STORE_RETURN_VALUE
+   and EXTRACT_RETURN_VALUE to store/fetch the functions return value. */
+
+/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
+   EXTRACT_RETURN_VALUE?  GCC_P is true if compiled with gcc
+   and TYPE is the type (which is known to be struct, union or array). */
+
+int
+mcore_use_struct_convention (int gcc_p, struct type *type)
+{
+  return (TYPE_LENGTH (type) > 8);
+}
+
+/* Where is the return value saved? For MCore, a pointer to 
+   this buffer was passed as a hidden first argument, so
+   just return that address. */
+
+CORE_ADDR
+mcore_extract_struct_value_address (char *regbuf)
+{
+  return extract_address (regbuf + REGISTER_BYTE (FIRST_ARGREG), REGISTER_SIZE);
+}
+
+/* Given a function which returns a value of type TYPE, extract the
+   the function's return value and place the result into VALBUF.
+   REGBUF is the register contents of the target. */
+
+void
+mcore_extract_return_value (struct type *type, char *regbuf, char *valbuf)
+{
+  /* Copy the return value (starting) in RETVAL_REGNUM to VALBUF. */
+  /* Only getting the first byte! if len = 1, we need the last byte of
+     the register, not the first. */
+  memcpy (valbuf, regbuf + REGISTER_BYTE (RETVAL_REGNUM) +
+  (TYPE_LENGTH (type) < 4 ? 4 - TYPE_LENGTH (type) : 0), TYPE_LENGTH (type));
+}
+
+/* Store the return value in VALBUF (of type TYPE) where the caller
+   expects to see it.
+
+   Values less than 32 bits are stored in r2, right justified and
+   sign or zero extended.
+
+   Values between 32 and 64 bits are stored in r2 (most
+   significant word) and r3 (least significant word, left justified).
+   Note that this includes structures of less than eight bytes, too. */
+
+void
+mcore_store_return_value (struct type *type, char *valbuf)
+{
+  int value_size;
+  int return_size;
+  int offset;
+  char *zeros;
+
+  value_size = TYPE_LENGTH (type);
+
+  /* Return value fits into registers. */
+  return_size = (value_size + REGISTER_SIZE - 1) & ~(REGISTER_SIZE - 1);
+  offset = REGISTER_BYTE (RETVAL_REGNUM) + (return_size - value_size);
+  zeros = alloca (return_size);
+  memset (zeros, 0, return_size);
+
+  write_register_bytes (REGISTER_BYTE (RETVAL_REGNUM), zeros, return_size);
+  write_register_bytes (offset, valbuf, value_size);
+}
+
+/* Initialize our target-dependent "stuff" for this newly created frame.
+
+   This includes allocating space for saved registers and analyzing
+   the prologue of this frame. */
+
+void
+mcore_init_extra_frame_info (int fromleaf, struct frame_info *fi)
+{
+  if (fi && fi->next)
+    fi->pc = FRAME_SAVED_PC (fi->next);
+
+  frame_saved_regs_zalloc (fi);
+
+  fi->extra_info = (struct frame_extra_info *)
+    frame_obstack_alloc (sizeof (struct frame_extra_info));
+  fi->extra_info->status = 0;
+  fi->extra_info->framesize = 0;
+
+  if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+    {
+      /* We need to setup fi->frame here because run_stack_dummy gets it wrong
+         by assuming it's always FP.  */
+      fi->frame = deprecated_read_register_dummy (fi->pc, fi->frame, SP_REGNUM);
+    }
+  else
+    mcore_analyze_prologue (fi, 0, 0);
+}
+
+/* Get an insturction from memory. */
+
+static int
+get_insn (CORE_ADDR pc)
+{
+  char buf[4];
+  int status = read_memory_nobpt (pc, buf, 2);
+  if (status != 0)
+    return 0;
+
+  return extract_unsigned_integer (buf, 2);
+}
+
+static struct gdbarch *
+mcore_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  static LONGEST call_dummy_words[7] = { };
+  struct gdbarch_tdep *tdep = NULL;
+  struct gdbarch *gdbarch;
+
+  /* find a candidate among the list of pre-declared architectures. */
+  arches = gdbarch_list_lookup_by_info (arches, &info);
+  if (arches != NULL)
+    return (arches->gdbarch);
+
+  gdbarch = gdbarch_alloc (&info, 0);
+
+  /* Registers: */
+
+  /* All registers are 32 bits */
+  set_gdbarch_register_size (gdbarch, MCORE_REG_SIZE);
+  set_gdbarch_max_register_raw_size (gdbarch, MCORE_REG_SIZE);
+  set_gdbarch_max_register_virtual_size (gdbarch, MCORE_REG_SIZE);
+  set_gdbarch_register_name (gdbarch, mcore_register_name);
+  set_gdbarch_register_virtual_type (gdbarch, mcore_register_virtual_type);
+  set_gdbarch_register_virtual_size (gdbarch, mcore_register_size);
+  set_gdbarch_register_raw_size (gdbarch, mcore_register_size);
+  set_gdbarch_register_byte (gdbarch, mcore_register_byte);
+  set_gdbarch_register_bytes (gdbarch, MCORE_REG_SIZE * MCORE_NUM_REGS);
+  set_gdbarch_num_regs (gdbarch, MCORE_NUM_REGS);
+  set_gdbarch_pc_regnum (gdbarch, 64);
+  set_gdbarch_sp_regnum (gdbarch, 0);
+  set_gdbarch_fp_regnum (gdbarch, 0);
+  set_gdbarch_get_saved_register (gdbarch, generic_unwind_get_saved_register);
+
+  /* Call Dummies:  */
+
+  set_gdbarch_call_dummy_p (gdbarch, 1);
+  set_gdbarch_use_generic_dummy_frames (gdbarch, 1);
+  set_gdbarch_call_dummy_words (gdbarch, call_dummy_words);
+  set_gdbarch_sizeof_call_dummy_words (gdbarch, 0);
+  set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+  set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+  set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
+  set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+  set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy);
+  set_gdbarch_call_dummy_address (gdbarch, entry_point_address);
+  set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
+  set_gdbarch_pc_in_call_dummy (gdbarch, generic_pc_in_call_dummy);
+  set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+  set_gdbarch_saved_pc_after_call (gdbarch, mcore_saved_pc_after_call);
+  set_gdbarch_function_start_offset (gdbarch, 0);
+  set_gdbarch_decr_pc_after_break (gdbarch, 0);
+  set_gdbarch_breakpoint_from_pc (gdbarch, mcore_breakpoint_from_pc);
+  set_gdbarch_push_return_address (gdbarch, mcore_push_return_address);
+  set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
+  set_gdbarch_push_arguments (gdbarch, mcore_push_arguments);
+  set_gdbarch_call_dummy_length (gdbarch, 0);
+
+  /* Frames:  */
+
+  set_gdbarch_init_extra_frame_info (gdbarch, mcore_init_extra_frame_info);
+  set_gdbarch_frame_chain (gdbarch, mcore_frame_chain);
+  set_gdbarch_frame_chain_valid (gdbarch, generic_func_frame_chain_valid);
+  set_gdbarch_frame_init_saved_regs (gdbarch, mcore_frame_init_saved_regs);
+  set_gdbarch_frame_saved_pc (gdbarch, mcore_frame_saved_pc);
+  set_gdbarch_deprecated_store_return_value (gdbarch, mcore_store_return_value);
+  set_gdbarch_deprecated_extract_return_value (gdbarch, 
+                                              mcore_extract_return_value);
+  set_gdbarch_store_struct_return (gdbarch, mcore_store_struct_return);
+  set_gdbarch_deprecated_extract_struct_value_address (gdbarch, 
+                                                      mcore_extract_struct_value_address);
+  set_gdbarch_skip_prologue (gdbarch, mcore_skip_prologue);
+  set_gdbarch_frame_args_skip (gdbarch, 0);
+  set_gdbarch_frame_args_address (gdbarch, mcore_frame_args_address);
+  set_gdbarch_frame_locals_address (gdbarch, mcore_frame_locals_address);
+  set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
+  set_gdbarch_pop_frame (gdbarch, mcore_pop_frame);
+  set_gdbarch_virtual_frame_pointer (gdbarch, mcore_virtual_frame_pointer);
+
+  /* Misc.:  */
+
+  /* Stack grows down.  */
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_use_struct_convention (gdbarch, mcore_use_struct_convention);
+  set_gdbarch_believe_pcc_promotion (gdbarch, 1);
+  /* MCore will never pass a sturcture by reference. It will always be split
+     between registers and stack.  */
+  set_gdbarch_reg_struct_has_addr (gdbarch, mcore_reg_struct_has_addr);
+
+  return gdbarch;
+}
+
+static void
+mcore_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+
+}
+
+void
+_initialize_mcore_tdep (void)
+{
+  extern int print_insn_mcore (bfd_vma, disassemble_info *);
+  gdbarch_register (bfd_arch_mcore, mcore_gdbarch_init, mcore_dump_tdep);
+  tm_print_insn = print_insn_mcore;
+
+#ifdef MCORE_DEBUG
+  add_show_from_set (add_set_cmd ("mcoredebug", no_class,
+                                 var_boolean, (char *) &mcore_debug,
+                                 "Set mcore debugging.\n", &setlist),
+                    &showlist);
+#endif
+}
diff --git a/gdb/ns32k-tdep.c b/gdb/ns32k-tdep.c
new file mode 100644 (file)
index 0000000..58c2e13
--- /dev/null
@@ -0,0 +1,626 @@
+/* Target dependent code for the NS32000, for GDB.
+   Copyright 1986, 1988, 1991, 1992, 1994, 1995, 1998, 1999, 2000, 2001,
+   2002 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "target.h"
+
+#include "arch-utils.h"
+
+#include "ns32k-tdep.h"
+
+static int sign_extend (int value, int bits);
+static CORE_ADDR ns32k_get_enter_addr (CORE_ADDR);
+static int ns32k_localcount (CORE_ADDR enter_pc);
+static void flip_bytes (void *, int);
+
+static const char *
+ns32k_register_name_32082 (int regno)
+{
+  static char *register_names[] =
+  {
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+    "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+    "sp", "fp", "pc", "ps",
+    "l0", "l1", "l2", "l3", "xx",
+  };
+
+  if (regno < 0)
+    return NULL;
+  if (regno >= sizeof (register_names) / sizeof (*register_names))
+    return NULL;
+
+  return (register_names[regno]);
+}
+
+static const char *
+ns32k_register_name_32382 (int regno)
+{
+  static char *register_names[] =
+  {
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+    "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+    "sp", "fp", "pc", "ps",
+    "fsr",
+    "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", "xx",
+  };
+
+  if (regno < 0)
+    return NULL;
+  if (regno >= sizeof (register_names) / sizeof (*register_names))
+    return NULL;
+
+  return (register_names[regno]);
+}
+
+static int
+ns32k_register_byte_32082 (int regno)
+{
+  if (regno >= NS32K_LP0_REGNUM)
+    return (NS32K_LP0_REGNUM * 4) + ((regno - NS32K_LP0_REGNUM) * 8);
+
+  return (regno * 4);
+}
+
+static int
+ns32k_register_byte_32382 (int regno)
+{
+  /* This is a bit yuk.  The even numbered double precision floating
+     point long registers occupy the same space as the even:odd numbered
+     single precision floating point registers, but the extra 32381 FPU
+     registers are at the end.  Doing it this way is compatible for both
+     32081 and 32381 equipped machines.  */
+
+  return ((regno < NS32K_LP0_REGNUM ? regno
+           : (regno - NS32K_LP0_REGNUM) & 1 ? regno - 1
+           : (regno - NS32K_LP0_REGNUM + FP0_REGNUM)) * 4);
+}
+
+static int
+ns32k_register_raw_size (int regno)
+{
+  /* All registers are 4 bytes, except for the doubled floating
+     registers.  */
+
+  return ((regno >= NS32K_LP0_REGNUM) ? 8 : 4);
+}
+
+static int
+ns32k_register_virtual_size (int regno)
+{
+  return ((regno >= NS32K_LP0_REGNUM) ? 8 : 4);
+}
+
+static struct type *
+ns32k_register_virtual_type (int regno)
+{
+  if (regno < FP0_REGNUM)
+    return (builtin_type_int);
+
+  if (regno < FP0_REGNUM + 8)
+    return (builtin_type_float);
+
+  if (regno < NS32K_LP0_REGNUM)
+    return (builtin_type_int); 
+
+  return (builtin_type_double);
+}
+
+/* Immediately after a function call, return the saved PC.  Can't
+   always go through the frames for this because on some systems,
+   the new frame is not set up until the new function executes some
+   instructions.  */
+
+static CORE_ADDR
+ns32k_saved_pc_after_call (struct frame_info *frame)
+{
+  return (read_memory_integer (read_register (SP_REGNUM), 4));
+}
+
+/* Advance PC across any function entry prologue instructions
+   to reach some "real" code.  */
+
+static CORE_ADDR
+umax_skip_prologue (CORE_ADDR pc)
+{
+  register unsigned char op = read_memory_integer (pc, 1);
+  if (op == 0x82)
+    {
+      op = read_memory_integer (pc + 2, 1);
+      if ((op & 0x80) == 0)
+       pc += 3;
+      else if ((op & 0xc0) == 0x80)
+       pc += 4;
+      else
+       pc += 6;
+    }
+  return pc;
+}
+\f
+static const unsigned char *
+ns32k_breakpoint_from_pc (CORE_ADDR *pcp, int *lenp)
+{
+  static const unsigned char breakpoint_insn[] = { 0xf2 };
+
+  *lenp = sizeof (breakpoint_insn);
+  return breakpoint_insn;
+}
+
+/* Return number of args passed to a frame.
+   Can return -1, meaning no way to tell.
+   Encore's C compiler often reuses same area on stack for args,
+   so this will often not work properly.  If the arg names
+   are known, it's likely most of them will be printed. */
+
+static int
+umax_frame_num_args (struct frame_info *fi)
+{
+  int numargs;
+  CORE_ADDR pc;
+  CORE_ADDR enter_addr;
+  unsigned int insn;
+  unsigned int addr_mode;
+  int width;
+
+  numargs = -1;
+  enter_addr = ns32k_get_enter_addr ((fi)->pc);
+  if (enter_addr > 0)
+    {
+      pc = ((enter_addr == 1)
+           ? SAVED_PC_AFTER_CALL (fi)
+           : FRAME_SAVED_PC (fi));
+      insn = read_memory_integer (pc, 2);
+      addr_mode = (insn >> 11) & 0x1f;
+      insn = insn & 0x7ff;
+      if ((insn & 0x7fc) == 0x57c
+         && addr_mode == 0x14) /* immediate */
+       {
+         if (insn == 0x57c)    /* adjspb */
+           width = 1;
+         else if (insn == 0x57d)       /* adjspw */
+           width = 2;
+         else if (insn == 0x57f)       /* adjspd */
+           width = 4;
+         else
+           internal_error (__FILE__, __LINE__, "bad else");
+         numargs = read_memory_integer (pc + 2, width);
+         if (width > 1)
+           flip_bytes (&numargs, width);
+         numargs = -sign_extend (numargs, width * 8) / 4;
+       }
+    }
+  return numargs;
+}
+
+static int
+sign_extend (int value, int bits)
+{
+  value = value & ((1 << bits) - 1);
+  return (value & (1 << (bits - 1))
+         ? value | (~((1 << bits) - 1))
+         : value);
+}
+
+static void
+flip_bytes (void *p, int count)
+{
+  char tmp;
+  char *ptr = 0;
+
+  while (count > 0)
+    {
+      tmp = *ptr;
+      ptr[0] = ptr[count - 1];
+      ptr[count - 1] = tmp;
+      ptr++;
+      count -= 2;
+    }
+}
+
+/* Return the number of locals in the current frame given a
+   pc pointing to the enter instruction.  This is used by
+   ns32k_frame_init_saved_regs.  */
+
+static int
+ns32k_localcount (CORE_ADDR enter_pc)
+{
+  unsigned char localtype;
+  int localcount;
+
+  localtype = read_memory_integer (enter_pc + 2, 1);
+  if ((localtype & 0x80) == 0)
+    localcount = localtype;
+  else if ((localtype & 0xc0) == 0x80)
+    localcount = (((localtype & 0x3f) << 8)
+                 | (read_memory_integer (enter_pc + 3, 1) & 0xff));
+  else
+    localcount = (((localtype & 0x3f) << 24)
+                 | ((read_memory_integer (enter_pc + 3, 1) & 0xff) << 16)
+                 | ((read_memory_integer (enter_pc + 4, 1) & 0xff) << 8)
+                 | (read_memory_integer (enter_pc + 5, 1) & 0xff));
+  return localcount;
+}
+
+
+/* Nonzero if instruction at PC is a return instruction.  */
+
+static int
+ns32k_about_to_return (CORE_ADDR pc)
+{
+  return (read_memory_integer (pc, 1) == 0x12);
+}
+
+/* Get the address of the enter opcode for this function, if it is active.
+   Returns positive address > 1 if pc is between enter/exit, 
+   1 if pc before enter or after exit, 0 otherwise. */
+static CORE_ADDR
+ns32k_get_enter_addr (CORE_ADDR pc)
+{
+  CORE_ADDR enter_addr;
+  unsigned char op;
+
+  if (pc == 0)
+    return 0;
+
+  if (ns32k_about_to_return (pc))
+    return 1;                  /* after exit */
+
+  enter_addr = get_pc_function_start (pc);
+
+  if (pc == enter_addr)
+    return 1;                  /* before enter */
+
+  op = read_memory_integer (enter_addr, 1);
+
+  if (op != 0x82)
+    return 0;                  /* function has no enter/exit */
+
+  return enter_addr;           /* pc is between enter and exit */
+}
+
+static CORE_ADDR
+ns32k_frame_chain (struct frame_info *frame)
+{
+  /* In the case of the NS32000 series, the frame's nominal address is the
+     FP value, and that address is saved at the previous FP value as a
+     4-byte word.  */
+
+  if (inside_entry_file (frame->pc))
+    return 0;
+
+  return (read_memory_integer (frame->frame, 4));
+}
+
+static CORE_ADDR
+ns32k_frame_saved_pc (struct frame_info *frame)
+{
+  if (frame->signal_handler_caller)
+    return (sigtramp_saved_pc (frame)); /* XXXJRT */
+
+  return (read_memory_integer (frame->frame + 4, 4));
+}
+
+static CORE_ADDR
+ns32k_frame_args_address (struct frame_info *frame)
+{
+  if (ns32k_get_enter_addr (frame->pc) > 1)
+    return (frame->frame);
+
+  return (read_register (SP_REGNUM) - 4);
+}
+
+static CORE_ADDR
+ns32k_frame_locals_address (struct frame_info *frame)
+{
+  return (frame->frame);
+}
+
+/* Code to initialize the addresses of the saved registers of frame described
+   by FRAME_INFO.  This includes special registers such as pc and fp saved in
+   special ways in the stack frame.  sp is even more special: the address we
+   return for it IS the sp for the next frame.  */
+
+static void
+ns32k_frame_init_saved_regs (struct frame_info *frame)
+{
+  int regmask, regnum;
+  int localcount;
+  CORE_ADDR enter_addr, next_addr;
+
+  if (frame->saved_regs)
+    return;
+
+  frame_saved_regs_zalloc (frame);
+
+  enter_addr = ns32k_get_enter_addr (frame->pc);
+  if (enter_addr > 1)
+    {
+      regmask = read_memory_integer (enter_addr + 1, 1) & 0xff;
+      localcount = ns32k_localcount (enter_addr);
+      next_addr = frame->frame + localcount;
+
+      for (regnum = 0; regnum < 8; regnum++)
+       {
+          if (regmask & (1 << regnum))
+           frame->saved_regs[regnum] = next_addr -= 4;
+       }
+
+      frame->saved_regs[SP_REGNUM] = frame->frame + 4;
+      frame->saved_regs[PC_REGNUM] = frame->frame + 4;
+      frame->saved_regs[FP_REGNUM] = read_memory_integer (frame->frame, 4);
+    }
+  else if (enter_addr == 1)
+    {
+      CORE_ADDR sp = read_register (SP_REGNUM);
+      frame->saved_regs[PC_REGNUM] = sp;
+      frame->saved_regs[SP_REGNUM] = sp + 4;
+    }
+}
+
+static void
+ns32k_push_dummy_frame (void)
+{
+  CORE_ADDR sp = read_register (SP_REGNUM);
+  int regnum;
+
+  sp = push_word (sp, read_register (PC_REGNUM));
+  sp = push_word (sp, read_register (FP_REGNUM));
+  write_register (FP_REGNUM, sp);
+
+  for (regnum = 0; regnum < 8; regnum++)
+    sp = push_word (sp, read_register (regnum));
+
+  write_register (SP_REGNUM, sp);
+}
+
+static void
+ns32k_pop_frame (void)
+{
+  struct frame_info *frame = get_current_frame ();
+  CORE_ADDR fp;
+  int regnum;
+
+  fp = frame->frame;
+  FRAME_INIT_SAVED_REGS (frame);
+
+  for (regnum = 0; regnum < 8; regnum++)
+    if (frame->saved_regs[regnum])
+      write_register (regnum,
+                     read_memory_integer (frame->saved_regs[regnum], 4));
+
+  write_register (FP_REGNUM, read_memory_integer (fp, 4));
+  write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
+  write_register (SP_REGNUM, fp + 8);
+  flush_cached_frames ();
+}
+\f
+/* The NS32000 call dummy sequence:
+
+       enter   0xff,0                  82 ff 00
+       jsr     @0x00010203             7f ae c0 01 02 03
+       adjspd  0x69696969              7f a5 01 02 03 04
+       bpt                             f2
+
+   It is 16 bytes long.  */
+
+static LONGEST ns32k_call_dummy_words[] =
+{
+  0x7f00ff82,
+  0x0201c0ae,
+  0x01a57f03,
+  0xf2040302
+};
+static int sizeof_ns32k_call_dummy_words = sizeof (ns32k_call_dummy_words);
+
+#define NS32K_CALL_DUMMY_ADDR         5
+#define NS32K_CALL_DUMMY_NARGS        11
+
+static void
+ns32k_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
+                      struct value **args, struct type *type, int gcc_p)
+{
+  int flipped;
+
+  flipped = fun | 0xc0000000;
+  flip_bytes (&flipped, 4);
+  store_unsigned_integer (dummy + NS32K_CALL_DUMMY_ADDR, 4, flipped);
+
+  flipped = - nargs * 4;
+  flip_bytes (&flipped, 4);
+  store_unsigned_integer (dummy + NS32K_CALL_DUMMY_NARGS, 4, flipped);
+}
+\f
+static void
+ns32k_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+{
+  /* On this machine, this is a no-op (Encore Umax didn't use GCC).  */
+}
+
+static void
+ns32k_extract_return_value (struct type *valtype, char *regbuf, char *valbuf)
+{
+  memcpy (valbuf,
+          regbuf + REGISTER_BYTE (TYPE_CODE (valtype) == TYPE_CODE_FLT ?
+                                 FP0_REGNUM : 0), TYPE_LENGTH (valtype));
+}
+
+static void
+ns32k_store_return_value (struct type *valtype, char *valbuf)
+{
+  write_register_bytes (TYPE_CODE (valtype) == TYPE_CODE_FLT ?
+                       FP0_REGNUM : 0, valbuf, TYPE_LENGTH (valtype));
+}
+
+static CORE_ADDR
+ns32k_extract_struct_value_address (char *regbuf)
+{
+  return (extract_address (regbuf + REGISTER_BYTE (0), REGISTER_RAW_SIZE (0)));
+}
+\f
+void
+ns32k_gdbarch_init_32082 (struct gdbarch *gdbarch)
+{
+  set_gdbarch_num_regs (gdbarch, NS32K_NUM_REGS_32082);
+
+  set_gdbarch_register_name (gdbarch, ns32k_register_name_32082);
+  set_gdbarch_register_bytes (gdbarch, NS32K_REGISTER_BYTES_32082);
+  set_gdbarch_register_byte (gdbarch, ns32k_register_byte_32082);
+}
+
+void
+ns32k_gdbarch_init_32382 (struct gdbarch *gdbarch)
+{
+  set_gdbarch_num_regs (gdbarch, NS32K_NUM_REGS_32382);
+
+  set_gdbarch_register_name (gdbarch, ns32k_register_name_32382);
+  set_gdbarch_register_bytes (gdbarch, NS32K_REGISTER_BYTES_32382);
+  set_gdbarch_register_byte (gdbarch, ns32k_register_byte_32382);
+}
+
+/* Initialize the current architecture based on INFO.  If possible, re-use an
+   architecture from ARCHES, which is a list of architectures already created
+   during this debugging session.
+
+   Called e.g. at program startup, when reading a core file, and when reading
+   a binary file.  */
+
+static struct gdbarch *
+ns32k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch_tdep *tdep;
+  struct gdbarch *gdbarch;
+  enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
+
+  /* Try to determine the OS ABI of the object we are loading.  */
+  if (info.abfd != NULL)
+    {
+      osabi = gdbarch_lookup_osabi (info.abfd);
+    }
+
+  /* Find a candidate among extant architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      /* Make sure the OS ABI selection matches.  */
+      tdep = gdbarch_tdep (arches->gdbarch);
+      if (tdep && tdep->osabi == osabi)
+       return arches->gdbarch;
+    }
+
+  tdep = xmalloc (sizeof (struct gdbarch_tdep));
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  tdep->osabi = osabi;
+
+  /* Register info */
+  ns32k_gdbarch_init_32082 (gdbarch);
+  set_gdbarch_num_regs (gdbarch, NS32K_SP_REGNUM);
+  set_gdbarch_num_regs (gdbarch, NS32K_FP_REGNUM);
+  set_gdbarch_num_regs (gdbarch, NS32K_PC_REGNUM);
+  set_gdbarch_num_regs (gdbarch, NS32K_PS_REGNUM);
+
+  set_gdbarch_register_size (gdbarch, NS32K_REGISTER_SIZE);
+  set_gdbarch_register_raw_size (gdbarch, ns32k_register_raw_size);
+  set_gdbarch_max_register_raw_size (gdbarch, NS32K_MAX_REGISTER_RAW_SIZE);
+  set_gdbarch_register_virtual_size (gdbarch, ns32k_register_virtual_size);
+  set_gdbarch_max_register_virtual_size (gdbarch,
+                                         NS32K_MAX_REGISTER_VIRTUAL_SIZE);
+  set_gdbarch_register_virtual_type (gdbarch, ns32k_register_virtual_type);
+
+  /* Frame and stack info */
+  set_gdbarch_skip_prologue (gdbarch, umax_skip_prologue);
+  set_gdbarch_saved_pc_after_call (gdbarch, ns32k_saved_pc_after_call);
+
+  set_gdbarch_frame_num_args (gdbarch, umax_frame_num_args);
+  set_gdbarch_frameless_function_invocation (gdbarch,
+                                   generic_frameless_function_invocation_not);
+  
+  set_gdbarch_frame_chain (gdbarch, ns32k_frame_chain);
+  set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid);
+  set_gdbarch_frame_saved_pc (gdbarch, ns32k_frame_saved_pc);
+
+  set_gdbarch_frame_args_address (gdbarch, ns32k_frame_args_address);
+  set_gdbarch_frame_locals_address (gdbarch, ns32k_frame_locals_address);
+
+  set_gdbarch_frame_init_saved_regs (gdbarch, ns32k_frame_init_saved_regs);
+
+  set_gdbarch_frame_args_skip (gdbarch, 8);
+
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+  /* Return value info */
+  set_gdbarch_store_struct_return (gdbarch, ns32k_store_struct_return);
+  set_gdbarch_deprecated_extract_return_value (gdbarch, ns32k_extract_return_value);
+  set_gdbarch_deprecated_store_return_value (gdbarch, ns32k_store_return_value);
+  set_gdbarch_deprecated_extract_struct_value_address (gdbarch,
+                                            ns32k_extract_struct_value_address);
+
+  /* Call dummy info */
+  set_gdbarch_push_dummy_frame (gdbarch, ns32k_push_dummy_frame);
+  set_gdbarch_pop_frame (gdbarch, ns32k_pop_frame);
+  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+  set_gdbarch_call_dummy_p (gdbarch, 1);
+  set_gdbarch_call_dummy_words (gdbarch, ns32k_call_dummy_words);
+  set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof_ns32k_call_dummy_words);
+  set_gdbarch_fix_call_dummy (gdbarch, ns32k_fix_call_dummy);
+  set_gdbarch_call_dummy_start_offset (gdbarch, 3);
+  set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 0);
+  set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
+  set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_on_stack);
+  set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+
+  /* Breakpoint info */
+  set_gdbarch_decr_pc_after_break (gdbarch, 0);
+  set_gdbarch_breakpoint_from_pc (gdbarch, ns32k_breakpoint_from_pc);
+
+  /* Misc info */
+  set_gdbarch_function_start_offset (gdbarch, 0);
+
+  /* Hook in OS ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch, osabi);
+
+  return (gdbarch);
+}
+
+static void
+ns32k_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+  if (tdep == NULL)
+    return;
+
+  fprintf_unfiltered (file, "ns32k_dump_tdep: OS ABI = %s\n",
+                     gdbarch_osabi_name (tdep->osabi));
+}
+
+void
+_initialize_ns32k_tdep (void)
+{
+  gdbarch_register (bfd_arch_ns32k, ns32k_gdbarch_init, ns32k_dump_tdep);
+
+  tm_print_insn = print_insn_ns32k;
+}
diff --git a/gdb/sh3-rom.c b/gdb/sh3-rom.c
new file mode 100644 (file)
index 0000000..f450ac9
--- /dev/null
@@ -0,0 +1,384 @@
+/* Remote target glue for the Hitachi SH-3 ROM monitor.
+   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "monitor.h"
+#include "serial.h"
+#include "srec.h"
+#include "arch-utils.h"
+#include "regcache.h"
+
+#include "sh-tdep.h"
+
+static struct serial *parallel;
+static int parallel_in_use;
+
+static void sh3_open (char *args, int from_tty);
+
+static void
+sh3_supply_register (char *regname, int regnamelen, char *val, int vallen)
+{
+  int numregs;
+  int regno;
+
+  numregs = 1;
+  regno = -1;
+
+  if (regnamelen == 2)
+    {
+      switch (regname[0])
+       {
+       case 'S':
+         if (regname[1] == 'R')
+           regno = SR_REGNUM;
+         break;
+       case 'P':
+         if (regname[1] == 'C')
+           regno = PC_REGNUM;
+         else if (regname[1] == 'R')
+           regno = PR_REGNUM;
+         break;
+       }
+    }
+  else if (regnamelen == 3)
+    {
+      switch (regname[0])
+       {
+       case 'G':
+       case 'V':
+         if (regname[1] == 'B' && regname[2] == 'R')
+           {
+             if (regname[0] == 'G')
+               regno = VBR_REGNUM;
+             else
+               regno = GBR_REGNUM;
+           }
+         break;
+       case 'S':
+         if (regname[1] == 'S' && regname[2] == 'R')
+           regno = gdbarch_tdep (current_gdbarch)->SSR_REGNUM;
+         else if (regname[1] == 'P' && regname[2] == 'C')
+           regno = gdbarch_tdep (current_gdbarch)->SPC_REGNUM;
+         break;
+       }
+    }
+  else if (regnamelen == 4)
+    {
+      switch (regname[0])
+       {
+       case 'M':
+         if (regname[1] == 'A' && regname[2] == 'C')
+           {
+             if (regname[3] == 'H')
+               regno = MACH_REGNUM;
+             else if (regname[3] == 'L')
+               regno = MACL_REGNUM;
+           }
+         break;
+       case 'R':
+         if (regname[1] == '0' && regname[2] == '-' && regname[3] == '7')
+           {
+             regno = R0_REGNUM;
+             numregs = 8;
+           }
+       }
+    }
+  else if (regnamelen == 5)
+    {
+      if (regname[1] == '8' && regname[2] == '-' && regname[3] == '1'
+         && regname[4] == '5')
+       {
+         regno = R0_REGNUM + 8;
+         numregs = 8;
+       }
+    }
+  else if (regnamelen == 17)
+    {
+    }
+
+  if (regno >= 0)
+    while (numregs-- > 0)
+      val = monitor_supply_register (regno++, val);
+}
+
+static void
+sh3_load (struct serial *desc, char *file, int hashmark)
+{
+  if (parallel_in_use)
+    {
+      monitor_printf ("pl;s\r");
+      load_srec (parallel, file, 0, 80, SREC_ALL, hashmark, NULL);
+      monitor_expect_prompt (NULL, 0);
+    }
+  else
+    {
+      monitor_printf ("il;s:x\r");
+      monitor_expect ("\005", NULL, 0);                /* Look for ENQ */
+      serial_write (desc, "\006", 1);  /* Send ACK */
+      monitor_expect ("LO x\r", NULL, 0);      /* Look for filename */
+
+      load_srec (desc, file, 0, 80, SREC_ALL, hashmark, NULL);
+
+      monitor_expect ("\005", NULL, 0);                /* Look for ENQ */
+      serial_write (desc, "\006", 1);  /* Send ACK */
+      monitor_expect_prompt (NULL, 0);
+    }
+}
+
+/* This array of registers need to match the indexes used by GDB.
+   This exists because the various ROM monitors use different strings
+   than does GDB, and don't necessarily support all the registers
+   either. So, typing "info reg sp" becomes a "r30".  */
+
+static char *sh3_regnames[] =
+{
+  "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+  "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
+  "PC", "PR", "GBR", "VBR", "MACH", "MACL", "SR",
+  NULL, NULL,
+  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+  "SSR", "SPC",
+  "R0_BANK0", "R1_BANK0", "R2_BANK0", "R3_BANK0",
+  "R4_BANK0", "R5_BANK0", "R6_BANK0", "R7_BANK0",
+  "R0_BANK1", "R1_BANK1", "R2_BANK1", "R3_BANK1",
+  "R4_BANK1", "R5_BANK1", "R6_BANK1", "R7_BANK1"
+};
+
+static char *sh3e_regnames[] =
+{
+  "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+  "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
+  "PC", "PR", "GBR", "VBR", "MACH", "MACL", "SR",
+  "FPUL", "FPSCR",
+  "FR0", "FR1", "FR2", "FR3", "FR4", "FR5", "FR6", "FR7",
+  "FR8", "FR9", "FR10", "FR11", "FR12", "FR13", "FR14", "FR15",
+  "SSR", "SPC",
+  "R0_BANK0", "R1_BANK0", "R2_BANK0", "R3_BANK0",
+  "R4_BANK0", "R5_BANK0", "R6_BANK0", "R7_BANK0",
+  "R0_BANK1", "R1_BANK1", "R2_BANK1", "R3_BANK1",
+  "R4_BANK1", "R5_BANK1", "R6_BANK1", "R7_BANK1"
+};
+
+/* Define the monitor command strings. Since these are passed directly
+   through to a printf style function, we may include formatting
+   strings. We also need a CR or LF on the end.  */
+
+static struct target_ops sh3_ops, sh3e_ops;
+
+static char *sh3_inits[] =
+{"\003", NULL};                        /* Exits sub-command mode & download cmds */
+
+static struct monitor_ops sh3_cmds;
+
+static void
+init_sh3_cmds (void)
+{
+  sh3_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_GETMEM_READ_SINGLE;     /* flags */
+  sh3_cmds.init = sh3_inits;   /* monitor init string */
+  sh3_cmds.cont = "g\r";       /* continue command */
+  sh3_cmds.step = "s\r";       /* single step */
+  sh3_cmds.stop = "\003";      /* Interrupt program */
+  sh3_cmds.set_break = "b %x\r";       /* set a breakpoint */
+  sh3_cmds.clr_break = "b -%x\r";      /* clear a breakpoint */
+  sh3_cmds.clr_all_break = "b -\r";    /* clear all breakpoints */
+  sh3_cmds.fill = "f %x @%x %x\r";     /* fill (start len val) */
+  sh3_cmds.setmem.cmdb = "m %x %x\r";  /* setmem.cmdb (addr, value) */
+  sh3_cmds.setmem.cmdw = "m %x %x;w\r";                /* setmem.cmdw (addr, value) */
+  sh3_cmds.setmem.cmdl = "m %x %x;l\r";                /* setmem.cmdl (addr, value) */
+  sh3_cmds.setmem.cmdll = NULL;        /* setmem.cmdll (addr, value) */
+  sh3_cmds.setmem.resp_delim = NULL;   /* setreg.resp_delim */
+  sh3_cmds.setmem.term = NULL; /* setreg.term */
+  sh3_cmds.setmem.term_cmd = NULL;     /* setreg.term_cmd */
+  sh3_cmds.getmem.cmdb = "m %x\r";     /* getmem.cmdb (addr, len) */
+  sh3_cmds.getmem.cmdw = "m %x;w\r";   /* getmem.cmdw (addr, len) */
+  sh3_cmds.getmem.cmdl = "m %x;l\r";   /* getmem.cmdl (addr, len) */
+  sh3_cmds.getmem.cmdll = NULL;        /* getmem.cmdll (addr, len) */
+  sh3_cmds.getmem.resp_delim = "^ [0-9A-F]+ "; /* getmem.resp_delim */
+  sh3_cmds.getmem.term = "? "; /* getmem.term */
+  sh3_cmds.getmem.term_cmd = ".\r";    /* getmem.term_cmd */
+  sh3_cmds.setreg.cmd = ".%s %x\r";    /* setreg.cmd (name, value) */
+  sh3_cmds.setreg.resp_delim = NULL;   /* setreg.resp_delim */
+  sh3_cmds.setreg.term = NULL; /* setreg.term */
+  sh3_cmds.setreg.term_cmd = NULL;     /* setreg.term_cmd */
+  sh3_cmds.getreg.cmd = ".%s\r";       /* getreg.cmd (name) */
+  sh3_cmds.getreg.resp_delim = "=";    /* getreg.resp_delim */
+  sh3_cmds.getreg.term = "? "; /* getreg.term */
+  sh3_cmds.getreg.term_cmd = ".\r";    /* getreg.term_cmd */
+  sh3_cmds.dump_registers = "r\r";     /* dump_registers */
+  sh3_cmds.register_pattern = "\\(\\w+\\)=\\([0-9a-fA-F]+\\( +[0-9a-fA-F]+\\b\\)*\\)";
+  sh3_cmds.supply_register = sh3_supply_register;      /* supply_register */
+  sh3_cmds.load_routine = sh3_load;    /* load_routine */
+  sh3_cmds.load = NULL;                /* download command */
+  sh3_cmds.loadresp = NULL;    /* Load response */
+  sh3_cmds.prompt = "\n:";     /* monitor command prompt */
+  sh3_cmds.line_term = "\r";   /* end-of-line terminator */
+  sh3_cmds.cmd_end = ".\r";    /* optional command terminator */
+  sh3_cmds.target = &sh3_ops;  /* target operations */
+  sh3_cmds.stopbits = SERIAL_1_STOPBITS;       /* number of stop bits */
+  sh3_cmds.regnames = sh3_regnames;    /* registers names */
+  sh3_cmds.magic = MONITOR_OPS_MAGIC;  /* magic */
+}                              /* init_sh3_cmds */
+
+/* This monitor structure is identical except for a couple slots, so
+   we will fill it in from the base structure when needed.  */
+
+static struct monitor_ops sh3e_cmds;
+
+static void
+sh3_open (char *args, int from_tty)
+{
+  char *serial_port_name = args;
+  char *parallel_port_name = 0;
+
+  if (args)
+    {
+      char *cursor = serial_port_name = xstrdup (args);
+
+      while (*cursor && *cursor != ' ')
+       cursor++;
+
+      if (*cursor)
+       *cursor++ = 0;
+
+      while (*cursor == ' ')
+       cursor++;
+
+      if (*cursor)
+       parallel_port_name = cursor;
+    }
+
+  monitor_open (serial_port_name, &sh3_cmds, from_tty);
+
+  if (parallel_port_name)
+    {
+      parallel = serial_open (parallel_port_name);
+
+      if (!parallel)
+       perror_with_name ("Unable to open parallel port.");
+
+      parallel_in_use = 1;
+    }
+
+  /* If we connected successfully, we know the processor is an SH3.  */
+  set_architecture_from_arch_mach (bfd_arch_sh, bfd_mach_sh3);
+}
+
+
+static void
+sh3e_open (char *args, int from_tty)
+{
+  char *serial_port_name = args;
+  char *parallel_port_name = 0;
+
+  if (args)
+    {
+      char *cursor = serial_port_name = xstrdup (args);
+
+      while (*cursor && *cursor != ' ')
+       cursor++;
+
+      if (*cursor)
+       *cursor++ = 0;
+
+      while (*cursor == ' ')
+       cursor++;
+
+      if (*cursor)
+       parallel_port_name = cursor;
+    }
+
+  /* Set up the SH-3E monitor commands structure.  */
+
+  memcpy (&sh3e_cmds, &sh3_cmds, sizeof (struct monitor_ops));
+
+  sh3e_cmds.target = &sh3e_ops;
+  sh3e_cmds.regnames = sh3e_regnames;
+
+  monitor_open (serial_port_name, &sh3e_cmds, from_tty);
+
+  if (parallel_port_name)
+    {
+      parallel = serial_open (parallel_port_name);
+
+      if (!parallel)
+       perror_with_name ("Unable to open parallel port.");
+
+      parallel_in_use = 1;
+    }
+
+  /* If we connected successfully, we know the processor is an SH3E.  */
+  set_architecture_from_arch_mach (bfd_arch_sh, bfd_mach_sh3);
+}
+
+static void
+sh3_close (int quitting)
+{
+  monitor_close (quitting);
+  if (parallel_in_use)
+    {
+      serial_close (parallel);
+      parallel_in_use = 0;
+    }
+}
+
+void
+_initialize_sh3_rom (void)
+{
+  init_sh3_cmds ();
+  init_monitor_ops (&sh3_ops);
+
+  sh3_ops.to_shortname = "sh3";
+  sh3_ops.to_longname = "Hitachi SH-3 rom monitor";
+
+  sh3_ops.to_doc =
+  /* We can download through the parallel port too. */
+    "Debug on a Hitachi eval board running the SH-3E rom monitor.\n"
+    "Specify the serial device it is connected to.\n"
+    "If you want to use the parallel port to download to it, specify that\n"
+    "as an additional second argument.";
+
+  sh3_ops.to_open = sh3_open;
+  sh3_ops.to_close = sh3_close;
+
+  add_target (&sh3_ops);
+
+  /* Setup the SH3e, which has float registers.  */
+
+  init_monitor_ops (&sh3e_ops);
+
+  sh3e_ops.to_shortname = "sh3e";
+  sh3e_ops.to_longname = "Hitachi SH-3E rom monitor";
+
+  sh3e_ops.to_doc =
+  /* We can download through the parallel port too. */
+    "Debug on a Hitachi eval board running the SH-3E rom monitor.\n"
+    "Specify the serial device it is connected to.\n"
+    "If you want to use the parallel port to download to it, specify that\n"
+    "as an additional second argument.";
+
+  sh3e_ops.to_open = sh3e_open;
+  sh3e_ops.to_close = sh3_close;
+
+  add_target (&sh3e_ops);
+}
diff --git a/gdb/vax-tdep.c b/gdb/vax-tdep.c
new file mode 100644 (file)
index 0000000..709ef38
--- /dev/null
@@ -0,0 +1,702 @@
+/* Print VAX instructions for GDB, the GNU debugger.
+   Copyright 1986, 1989, 1991, 1992, 1995, 1996, 1998, 1999, 2000, 2002
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "symtab.h"
+#include "opcode/vax.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "frame.h"
+#include "value.h"
+#include "arch-utils.h"
+
+#include "vax-tdep.h"
+
+static gdbarch_register_name_ftype vax_register_name;
+static gdbarch_register_byte_ftype vax_register_byte;
+static gdbarch_register_raw_size_ftype vax_register_raw_size;
+static gdbarch_register_virtual_size_ftype vax_register_virtual_size;
+static gdbarch_register_virtual_type_ftype vax_register_virtual_type;
+
+static gdbarch_skip_prologue_ftype vax_skip_prologue;
+static gdbarch_saved_pc_after_call_ftype vax_saved_pc_after_call;
+static gdbarch_frame_num_args_ftype vax_frame_num_args;
+static gdbarch_frame_chain_ftype vax_frame_chain;
+static gdbarch_frame_saved_pc_ftype vax_frame_saved_pc;
+static gdbarch_frame_args_address_ftype vax_frame_args_address;
+static gdbarch_frame_locals_address_ftype vax_frame_locals_address;
+static gdbarch_frame_init_saved_regs_ftype vax_frame_init_saved_regs;
+
+static gdbarch_store_struct_return_ftype vax_store_struct_return;
+static gdbarch_deprecated_extract_return_value_ftype vax_extract_return_value;
+static gdbarch_deprecated_extract_struct_value_address_ftype
+    vax_extract_struct_value_address;
+
+static gdbarch_push_dummy_frame_ftype vax_push_dummy_frame;
+static gdbarch_pop_frame_ftype vax_pop_frame;
+static gdbarch_fix_call_dummy_ftype vax_fix_call_dummy;
+
+/* Return 1 if P points to an invalid floating point value.
+   LEN is the length in bytes -- not relevant on the Vax.  */
+
+/* FIXME: cagney/2002-01-19: The macro below was originally defined in
+   tm-vax.h and used in values.c.  Two problems.  Firstly this is a
+   very non-portable and secondly it is wrong.  The VAX should be
+   using floatformat and associated methods to identify and handle
+   invalid floating-point values.  Adding to the poor target's woes
+   there is no floatformat_vax_{f,d} and no TARGET_FLOAT_FORMAT
+   et.al..  */
+
+/* FIXME: cagney/2002-01-19: It turns out that the only thing that
+   uses this macro is the vax disassembler code (so how old is this
+   target?).  This target should instead be using the opcodes
+   disassembler.  That allowing the macro to be eliminated.  */
+
+#define INVALID_FLOAT(p, len) ((*(short *) p & 0xff80) == 0x8000)
+
+/* Vax instructions are never longer than this.  */
+#define MAXLEN 62
+
+/* Number of elements in the opcode table.  */
+#define NOPCODES (sizeof votstrs / sizeof votstrs[0])
+
+static unsigned char *print_insn_arg ();
+\f
+static const char *
+vax_register_name (int regno)
+{
+  static char *register_names[] =
+  {
+    "r0",  "r1",  "r2",  "r3", "r4", "r5", "r6", "r7",
+    "r8",  "r9", "r10", "r11", "ap", "fp", "sp", "pc",
+    "ps",
+  };
+
+  if (regno < 0)
+    return (NULL);
+  if (regno >= (sizeof(register_names) / sizeof(*register_names)))
+    return (NULL);
+  return (register_names[regno]);
+}
+
+static int
+vax_register_byte (int regno)
+{
+  return (regno * 4);
+}
+
+static int
+vax_register_raw_size (int regno)
+{
+  return (4);
+}
+
+static int
+vax_register_virtual_size (int regno)
+{
+  return (4);
+}
+
+static struct type *
+vax_register_virtual_type (int regno)
+{
+  return (builtin_type_int);
+}
+\f
+static void
+vax_frame_init_saved_regs (struct frame_info *frame)
+{
+  int regnum, regmask;
+  CORE_ADDR next_addr;
+
+  if (frame->saved_regs)
+    return;
+
+  frame_saved_regs_zalloc (frame);
+
+  regmask = read_memory_integer (frame->frame + 4, 4) >> 16;
+
+  next_addr = frame->frame + 16;
+
+  /* regmask's low bit is for register 0, which is the first one
+     what would be pushed.  */
+  for (regnum = 0; regnum < VAX_AP_REGNUM; regnum++)
+    {
+      if (regmask & (1 << regnum))
+        frame->saved_regs[regnum] = next_addr += 4;
+    }
+
+  frame->saved_regs[SP_REGNUM] = next_addr + 4;
+  if (regmask & (1 << FP_REGNUM))
+    frame->saved_regs[SP_REGNUM] +=
+      4 + (4 * read_memory_integer (next_addr + 4, 4));
+
+  frame->saved_regs[PC_REGNUM] = frame->frame + 16;
+  frame->saved_regs[FP_REGNUM] = frame->frame + 12;
+  frame->saved_regs[VAX_AP_REGNUM] = frame->frame + 8;
+  frame->saved_regs[PS_REGNUM] = frame->frame + 4;
+}
+
+static CORE_ADDR
+vax_frame_saved_pc (struct frame_info *frame)
+{
+  if (frame->signal_handler_caller)
+    return (sigtramp_saved_pc (frame)); /* XXXJRT */
+
+  return (read_memory_integer (frame->frame + 16, 4));
+}
+
+CORE_ADDR
+vax_frame_args_address_correct (struct frame_info *frame)
+{
+  /* Cannot find the AP register value directly from the FP value.  Must
+     find it saved in the frame called by this one, or in the AP register
+     for the innermost frame.  However, there is no way to tell the
+     difference between the innermost frame and a frame for which we
+     just don't know the frame that it called (e.g. "info frame 0x7ffec789").
+     For the sake of argument, suppose that the stack is somewhat trashed
+     (which is one reason that "info frame" exists).  So, return 0 (indicating
+     we don't know the address of the arglist) if we don't know what frame
+     this frame calls.  */
+  if (frame->next)
+    return (read_memory_integer (frame->next->frame + 8, 4));
+
+  return (0);
+}
+
+static CORE_ADDR
+vax_frame_args_address (struct frame_info *frame)
+{
+  /* In most of GDB, getting the args address is too important to
+     just say "I don't know".  This is sometimes wrong for functions
+     that aren't on top of the stack, but c'est la vie.  */
+  if (frame->next)
+    return (read_memory_integer (frame->next->frame + 8, 4));
+
+  return (read_register (VAX_AP_REGNUM));
+}
+
+static CORE_ADDR
+vax_frame_locals_address (struct frame_info *frame)
+{
+  return (frame->frame);
+}
+
+static int
+vax_frame_num_args (struct frame_info *fi)
+{
+  return (0xff & read_memory_integer (FRAME_ARGS_ADDRESS (fi), 1));
+}
+
+static CORE_ADDR
+vax_frame_chain (struct frame_info *frame)
+{
+  /* In the case of the VAX, the frame's nominal address is the FP value,
+     and 12 bytes later comes the saved previous FP value as a 4-byte word.  */
+  if (inside_entry_file (frame->pc))
+    return (0);
+
+  return (read_memory_integer (frame->frame + 12, 4));
+}
+\f
+static void
+vax_push_dummy_frame (void)
+{
+  CORE_ADDR sp = read_register (SP_REGNUM);
+  int regnum;
+
+  sp = push_word (sp, 0);      /* arglist */
+  for (regnum = 11; regnum >= 0; regnum--)
+    sp = push_word (sp, read_register (regnum));
+  sp = push_word (sp, read_register (PC_REGNUM));
+  sp = push_word (sp, read_register (FP_REGNUM));
+  sp = push_word (sp, read_register (VAX_AP_REGNUM));
+  sp = push_word (sp, (read_register (PS_REGNUM) & 0xffef) + 0x2fff0000);
+  sp = push_word (sp, 0);
+  write_register (SP_REGNUM, sp);
+  write_register (FP_REGNUM, sp);
+  write_register (VAX_AP_REGNUM, sp + (17 * 4));
+}
+
+static void
+vax_pop_frame (void)
+{
+  CORE_ADDR fp = read_register (FP_REGNUM);
+  int regnum;
+  int regmask = read_memory_integer (fp + 4, 4);
+
+  write_register (PS_REGNUM,
+                 (regmask & 0xffff)
+                 | (read_register (PS_REGNUM) & 0xffff0000));
+  write_register (PC_REGNUM, read_memory_integer (fp + 16, 4));
+  write_register (FP_REGNUM, read_memory_integer (fp + 12, 4));
+  write_register (VAX_AP_REGNUM, read_memory_integer (fp + 8, 4));
+  fp += 16;
+  for (regnum = 0; regnum < 12; regnum++)
+    if (regmask & (0x10000 << regnum))
+      write_register (regnum, read_memory_integer (fp += 4, 4));
+  fp = fp + 4 + ((regmask >> 30) & 3);
+  if (regmask & 0x20000000)
+    {
+      regnum = read_memory_integer (fp, 4);
+      fp += (regnum + 1) * 4;
+    }
+  write_register (SP_REGNUM, fp);
+  flush_cached_frames ();
+}
+
+/* The VAX call dummy sequence:
+
+       calls #69, @#32323232
+       bpt
+
+   It is 8 bytes long.  The address and argc are patched by
+   vax_fix_call_dummy().  */
+static LONGEST vax_call_dummy_words[] = { 0x329f69fb, 0x03323232 };
+static int sizeof_vax_call_dummy_words = sizeof(vax_call_dummy_words);
+
+static void
+vax_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
+                    struct value **args, struct type *type, int gcc_p)
+{
+  dummy[1] = nargs;
+  store_unsigned_integer (dummy + 3, 4, fun);
+}
+\f
+static void
+vax_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+{
+  write_register (1, addr);
+}
+
+static void
+vax_extract_return_value (struct type *valtype, char *regbuf, char *valbuf)
+{
+  memcpy (valbuf, regbuf + REGISTER_BYTE (0), TYPE_LENGTH (valtype));
+}
+
+static void
+vax_store_return_value (struct type *valtype, char *valbuf)
+{
+  write_register_bytes (0, valbuf, TYPE_LENGTH (valtype));
+}
+
+static CORE_ADDR
+vax_extract_struct_value_address (char *regbuf)
+{
+  return (extract_address (regbuf + REGISTER_BYTE (0), REGISTER_RAW_SIZE (0)));
+}
+\f
+static const unsigned char *
+vax_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+{
+  static const unsigned char vax_breakpoint[] = { 3 };
+
+  *lenptr = sizeof(vax_breakpoint);
+  return (vax_breakpoint);
+}
+\f
+/* Advance PC across any function entry prologue instructions
+   to reach some "real" code.  */
+
+static CORE_ADDR
+vax_skip_prologue (CORE_ADDR pc)
+{
+  register int op = (unsigned char) read_memory_integer (pc, 1);
+  if (op == 0x11)
+    pc += 2;                   /* skip brb */
+  if (op == 0x31)
+    pc += 3;                   /* skip brw */
+  if (op == 0xC2
+      && ((unsigned char) read_memory_integer (pc + 2, 1)) == 0x5E)
+    pc += 3;                   /* skip subl2 */
+  if (op == 0x9E
+      && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xAE
+      && ((unsigned char) read_memory_integer (pc + 3, 1)) == 0x5E)
+    pc += 4;                   /* skip movab */
+  if (op == 0x9E
+      && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xCE
+      && ((unsigned char) read_memory_integer (pc + 4, 1)) == 0x5E)
+    pc += 5;                   /* skip movab */
+  if (op == 0x9E
+      && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xEE
+      && ((unsigned char) read_memory_integer (pc + 6, 1)) == 0x5E)
+    pc += 7;                   /* skip movab */
+  return pc;
+}
+
+static CORE_ADDR
+vax_saved_pc_after_call (struct frame_info *frame)
+{
+  return (FRAME_SAVED_PC(frame));
+}
+\f
+/* Print the vax instruction at address MEMADDR in debugged memory,
+   from disassembler info INFO.
+   Returns length of the instruction, in bytes.  */
+
+static int
+vax_print_insn (CORE_ADDR memaddr, disassemble_info *info)
+{
+  unsigned char buffer[MAXLEN];
+  register int i;
+  register unsigned char *p;
+  const char *d;
+
+  int status = (*info->read_memory_func) (memaddr, buffer, MAXLEN, info);
+  if (status != 0)
+    {
+      (*info->memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+
+  for (i = 0; i < NOPCODES; i++)
+    if (votstrs[i].detail.code == buffer[0]
+       || votstrs[i].detail.code == *(unsigned short *) buffer)
+      break;
+
+  /* Handle undefined instructions.  */
+  if (i == NOPCODES)
+    {
+      (*info->fprintf_func) (info->stream, "0%o", buffer[0]);
+      return 1;
+    }
+
+  (*info->fprintf_func) (info->stream, "%s", votstrs[i].name);
+
+  /* Point at first byte of argument data,
+     and at descriptor for first argument.  */
+  p = buffer + 1 + (votstrs[i].detail.code >= 0x100);
+  d = votstrs[i].detail.args;
+
+  if (*d)
+    (*info->fprintf_func) (info->stream, " ");
+
+  while (*d)
+    {
+      p = print_insn_arg (d, p, memaddr + (p - buffer), info);
+      d += 2;
+      if (*d)
+       (*info->fprintf_func) (info->stream, ",");
+    }
+  return p - buffer;
+}
+\f
+static unsigned char *
+print_insn_arg (char *d, register char *p, CORE_ADDR addr,
+               disassemble_info *info)
+{
+  register int regnum = *p & 0xf;
+  float floatlitbuf;
+
+  if (*d == 'b')
+    {
+      if (d[1] == 'b')
+       (*info->fprintf_func) (info->stream, "0x%x", addr + *p++ + 1);
+      else
+       {
+         (*info->fprintf_func) (info->stream, "0x%x", addr + *(short *) p + 2);
+         p += 2;
+       }
+    }
+  else
+    switch ((*p++ >> 4) & 0xf)
+      {
+      case 0:
+      case 1:
+      case 2:
+      case 3:                  /* Literal mode */
+       if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h')
+         {
+           *(int *) &floatlitbuf = 0x4000 + ((p[-1] & 0x3f) << 4);
+           (*info->fprintf_func) (info->stream, "$%f", floatlitbuf);
+         }
+       else
+         (*info->fprintf_func) (info->stream, "$%d", p[-1] & 0x3f);
+       break;
+
+      case 4:                  /* Indexed */
+       p = (char *) print_insn_arg (d, p, addr + 1, info);
+       (*info->fprintf_func) (info->stream, "[%s]", REGISTER_NAME (regnum));
+       break;
+
+      case 5:                  /* Register */
+       (*info->fprintf_func) (info->stream, REGISTER_NAME (regnum));
+       break;
+
+      case 7:                  /* Autodecrement */
+       (*info->fprintf_func) (info->stream, "-");
+      case 6:                  /* Register deferred */
+       (*info->fprintf_func) (info->stream, "(%s)", REGISTER_NAME (regnum));
+       break;
+
+      case 9:                  /* Autoincrement deferred */
+       (*info->fprintf_func) (info->stream, "@");
+       if (regnum == PC_REGNUM)
+         {
+           (*info->fprintf_func) (info->stream, "#");
+           info->target = *(long *) p;
+           (*info->print_address_func) (info->target, info);
+           p += 4;
+           break;
+         }
+      case 8:                  /* Autoincrement */
+       if (regnum == PC_REGNUM)
+         {
+           (*info->fprintf_func) (info->stream, "#");
+           switch (d[1])
+             {
+             case 'b':
+               (*info->fprintf_func) (info->stream, "%d", *p++);
+               break;
+
+             case 'w':
+               (*info->fprintf_func) (info->stream, "%d", *(short *) p);
+               p += 2;
+               break;
+
+             case 'l':
+               (*info->fprintf_func) (info->stream, "%d", *(long *) p);
+               p += 4;
+               break;
+
+             case 'q':
+               (*info->fprintf_func) (info->stream, "0x%x%08x",
+                                      ((long *) p)[1], ((long *) p)[0]);
+               p += 8;
+               break;
+
+             case 'o':
+               (*info->fprintf_func) (info->stream, "0x%x%08x%08x%08x",
+                                      ((long *) p)[3], ((long *) p)[2],
+                                      ((long *) p)[1], ((long *) p)[0]);
+               p += 16;
+               break;
+
+             case 'f':
+               if (INVALID_FLOAT (p, 4))
+                 (*info->fprintf_func) (info->stream,
+                                        "<<invalid float 0x%x>>",
+                                        *(int *) p);
+               else
+                 (*info->fprintf_func) (info->stream, "%f", *(float *) p);
+               p += 4;
+               break;
+
+             case 'd':
+               if (INVALID_FLOAT (p, 8))
+                 (*info->fprintf_func) (info->stream,
+                                        "<<invalid float 0x%x%08x>>",
+                                        ((long *) p)[1], ((long *) p)[0]);
+               else
+                 (*info->fprintf_func) (info->stream, "%f", *(double *) p);
+               p += 8;
+               break;
+
+             case 'g':
+               (*info->fprintf_func) (info->stream, "g-float");
+               p += 8;
+               break;
+
+             case 'h':
+               (*info->fprintf_func) (info->stream, "h-float");
+               p += 16;
+               break;
+
+             }
+         }
+       else
+         (*info->fprintf_func) (info->stream, "(%s)+", REGISTER_NAME (regnum));
+       break;
+
+      case 11:                 /* Byte displacement deferred */
+       (*info->fprintf_func) (info->stream, "@");
+      case 10:                 /* Byte displacement */
+       if (regnum == PC_REGNUM)
+         {
+           info->target = addr + *p + 2;
+           (*info->print_address_func) (info->target, info);
+         }
+       else
+         (*info->fprintf_func) (info->stream, "%d(%s)", *p, REGISTER_NAME (regnum));
+       p += 1;
+       break;
+
+      case 13:                 /* Word displacement deferred */
+       (*info->fprintf_func) (info->stream, "@");
+      case 12:                 /* Word displacement */
+       if (regnum == PC_REGNUM)
+         {
+           info->target = addr + *(short *) p + 3;
+           (*info->print_address_func) (info->target, info);
+         }
+       else
+         (*info->fprintf_func) (info->stream, "%d(%s)",
+                                *(short *) p, REGISTER_NAME (regnum));
+       p += 2;
+       break;
+
+      case 15:                 /* Long displacement deferred */
+       (*info->fprintf_func) (info->stream, "@");
+      case 14:                 /* Long displacement */
+       if (regnum == PC_REGNUM)
+         {
+           info->target = addr + *(short *) p + 5;
+           (*info->print_address_func) (info->target, info);
+         }
+       else
+         (*info->fprintf_func) (info->stream, "%d(%s)",
+                                *(long *) p, REGISTER_NAME (regnum));
+       p += 4;
+      }
+
+  return (unsigned char *) p;
+}
+\f
+/* Initialize the current architecture based on INFO.  If possible, re-use an
+   architecture from ARCHES, which is a list of architectures already created
+   during this debugging session.
+
+   Called e.g. at program startup, when reading a core file, and when reading
+   a binary file.  */
+
+static struct gdbarch *
+vax_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch_tdep *tdep;
+  struct gdbarch *gdbarch;
+  enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
+
+  /* Try to determine the ABI of the object we are loading.  */
+
+  if (info.abfd != NULL)
+    osabi = gdbarch_lookup_osabi (info.abfd);
+
+  /* Find a candidate among extant architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      /* Make sure the ABI selection matches.  */
+      tdep = gdbarch_tdep (arches->gdbarch);
+      if (tdep && tdep->osabi == osabi)
+       return arches->gdbarch;
+    }
+
+  tdep = xmalloc (sizeof (struct gdbarch_tdep));
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  tdep->osabi = osabi;
+
+  /* Register info */
+  set_gdbarch_num_regs (gdbarch, VAX_NUM_REGS);
+  set_gdbarch_sp_regnum (gdbarch, VAX_SP_REGNUM);
+  set_gdbarch_fp_regnum (gdbarch, VAX_FP_REGNUM);
+  set_gdbarch_pc_regnum (gdbarch, VAX_PC_REGNUM);
+  set_gdbarch_ps_regnum (gdbarch, VAX_PS_REGNUM);
+
+  set_gdbarch_register_name (gdbarch, vax_register_name);
+  set_gdbarch_register_size (gdbarch, VAX_REGISTER_SIZE);
+  set_gdbarch_register_bytes (gdbarch, VAX_REGISTER_BYTES);
+  set_gdbarch_register_byte (gdbarch, vax_register_byte);
+  set_gdbarch_register_raw_size (gdbarch, vax_register_raw_size);
+  set_gdbarch_max_register_raw_size (gdbarch, VAX_MAX_REGISTER_RAW_SIZE);
+  set_gdbarch_register_virtual_size (gdbarch, vax_register_virtual_size);
+  set_gdbarch_max_register_virtual_size (gdbarch,
+                                         VAX_MAX_REGISTER_VIRTUAL_SIZE);
+  set_gdbarch_register_virtual_type (gdbarch, vax_register_virtual_type);
+
+  /* Frame and stack info */
+  set_gdbarch_skip_prologue (gdbarch, vax_skip_prologue);
+  set_gdbarch_saved_pc_after_call (gdbarch, vax_saved_pc_after_call);
+
+  set_gdbarch_frame_num_args (gdbarch, vax_frame_num_args);
+  set_gdbarch_frameless_function_invocation (gdbarch,
+                                  generic_frameless_function_invocation_not);
+
+  set_gdbarch_frame_chain (gdbarch, vax_frame_chain);
+  set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid);
+  set_gdbarch_frame_saved_pc (gdbarch, vax_frame_saved_pc);
+
+  set_gdbarch_frame_args_address (gdbarch, vax_frame_args_address);
+  set_gdbarch_frame_locals_address (gdbarch, vax_frame_locals_address);
+
+  set_gdbarch_frame_init_saved_regs (gdbarch, vax_frame_init_saved_regs);
+
+  set_gdbarch_frame_args_skip (gdbarch, 4);
+
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+  /* Return value info */
+  set_gdbarch_store_struct_return (gdbarch, vax_store_struct_return);
+  set_gdbarch_deprecated_extract_return_value (gdbarch, vax_extract_return_value);
+  set_gdbarch_deprecated_store_return_value (gdbarch, vax_store_return_value);
+  set_gdbarch_deprecated_extract_struct_value_address (gdbarch, vax_extract_struct_value_address);
+
+  /* Call dummy info */
+  set_gdbarch_push_dummy_frame (gdbarch, vax_push_dummy_frame);
+  set_gdbarch_pop_frame (gdbarch, vax_pop_frame);
+  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+  set_gdbarch_call_dummy_p (gdbarch, 1);
+  set_gdbarch_call_dummy_words (gdbarch, vax_call_dummy_words);
+  set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof_vax_call_dummy_words);
+  set_gdbarch_fix_call_dummy (gdbarch, vax_fix_call_dummy);
+  set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+  set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+  set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 7);
+  set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
+  set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_on_stack);
+  set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+
+  /* Breakpoint info */
+  set_gdbarch_breakpoint_from_pc (gdbarch, vax_breakpoint_from_pc);
+  set_gdbarch_decr_pc_after_break (gdbarch, 0);
+
+  /* Misc info */
+  set_gdbarch_function_start_offset (gdbarch, 2);
+  set_gdbarch_believe_pcc_promotion (gdbarch, 1);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch, osabi);
+
+  return (gdbarch);
+}
+
+static void
+vax_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+  if (tdep == NULL)
+    return;
+
+  fprintf_unfiltered (file, "vax_dump_tdep: OS ABI = %s\n",
+                     gdbarch_osabi_name (tdep->osabi));
+}
+
+void
+_initialize_vax_tdep (void)
+{
+  gdbarch_register (bfd_arch_vax, vax_gdbarch_init, vax_dump_tdep);
+
+  tm_print_insn = vax_print_insn;
+}