This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

New port: CRIS architecture


Here is a set of patches that adds support for the CRIS architecture to
gdb.  The port has been updated to a 2000-10-27 snapshot of the CVS
source tree, and it's multi-arched.

Thanks in advance for reviewing this.

--
Orjan Friberg              E-mail: orjan.friberg@axis.com
Axis Communications AB     Phone:  +46 46 272 17 68
2000-12-04  Orjan Friberg  <orjanf@axis.com>

	* configure.tgt: Recognise the CRIS architecture.
	* cris-tdep.c: New file for CRIS target.
	* config/cris/tm-cris.h: New file for CRIS target.
	* config/cris/cris.mt: New file for CRIS target.


*** /home/orjanf/gdb-2000-10-27/gdb/gdb/configure.tgt   Tue Nov 14 09:35:39 2000
--- configure.tgt       Mon Nov 13 15:05:03 2000
*************** arm*-*-* | thumb*-*-* | strongarm*-*-*)
*** 61,66 ****
--- 61,67 ----
                          ;;
  # OBSOLETE c1-*-*)            gdb_target=convex ;;
  # OBSOLETE c2-*-*)            gdb_target=convex ;;
+ cris*)                  gdb_target=cris ;;
  
  d10v-*-*)             gdb_target=d10v ;;
  d30v-*-*)             gdb_target=d30v ;;


*** /home/orjanf/gdb-2000-10-27/gdb/gdb/cris-tdep.c	Mon Nov 20 13:15:27 2000
--- cris-tdep.c	Mon Dec  4 14:36:27 2000
***************
*** 0 ****
--- 1,3482 ----
+ /* Target dependent code for CRIS, for GDB, the GNU debugger.
+    Copyright (C) 2000 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"
+ 
+ /* To get entry_point_address.  */
+ #include "symfile.h"
+ 
+ extern const struct cris_spec_reg cris_spec_regs[];
+ 
+ /* CRIS version, set via the user command 'set cris-version'.  */
+ static int usr_cmd_cris_version;
+ 
+ /* Indicates whether to trust the above variable.  */
+ static int usr_cmd_cris_version_valid = 0;
+ 
+ /* CRIS ABI version.  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.  */
+ 
+ /* 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";
+ 
+ #define CRIS_ABI_SYMBOL ".$CRIS_ABI_V2"
+ 
+ /* CRIS ABI, set via the user command 'set cris-abi'.  */
+ static const char *usr_cmd_cris_abi;
+ 
+ /* Indicates whether to trust the above variable.  */
+ static int usr_cmd_cris_abi_valid = 0;
+ static const char *cris_abi_enums[] = 
+ {
+   CRIS_ABI_ORIGINAL,
+   CRIS_ABI_V2,
+   0
+ };
+ 
+ /* CRIS architecture specific information.  */
+ struct gdbarch_tdep
+ {
+   /* CRIS version.  Affects register names and sizes.  */
+   int cris_version;
+   const char *cris_abi;  
+ };
+ 
+ /* Macros for accessing target dependent data.  */
+ #define CRIS_VERSION (gdbarch_tdep (current_gdbarch)->cris_version)
+ #define CRIS_ABI (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;
+ 
+ 
+ /* The end of the prologue is the only information required when the fsr
+    register pointer is zero in cris_examine.  When fsr is allocated full
+    information is required.  */
+ #define END_OF_PROLOGUE_INFO_ONLY(fsr) ((fsr == 0) ? 1 : 0)
+ 
+ /* Machine-dependencies in CRIS for opcodes.  */
+ 
+ /* Instruction sizes.  */
+ #define INST_BYTE_SIZE       0
+ #define INST_WORD_SIZE       1
+ #define INST_DWORD_SIZE      2
+ 
+ /* Addressing modes.  */
+ #define REGISTER_MODE        1
+ #define INDIRECT_MODE        2
+ #define AUTOINC_MODE         3
+ 
+ /* Prefix-addressing modes.  */
+ #define PREFIX_INDEX_MODE    2
+ #define PREFIX_ASSIGN_MODE   3
+ 
+ /* Masks for opcodes.  */
+ #define BRANCH_SIGNED_SHORT_OFFSET_MASK 0x1
+ #define SIGNED_EXTEND_BIT_MASK          0x2
+ #define SIGNED_BYTE_MASK                0x80
+ #define SIGNED_BYTE_EXTEND_MASK         0xFFFFFF00
+ #define SIGNED_WORD_MASK                0x8000
+ #define SIGNED_WORD_EXTEND_MASK         0xFFFF0000
+ #define SIGNED_DWORD_MASK               0x80000000
+ #define SIGNED_QUICK_VALUE_MASK         0x20
+ #define SIGNED_QUICK_VALUE_EXTEND_MASK  0xFFFFFFC0
+ 
+ /* Macros 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  */
+ #define GET_OPERAND2(insn) ((insn & 0xF000) >> 12)
+ #define GET_MODE(insn) ((insn & 0x0C00) >> 10)
+ #define GET_OPCODE(insn) ((insn & 0x03C0) >> 6)
+ #define GET_SIZE(insn) ((insn & 0x0030) >> 4)
+ #define GET_OPERAND1(insn) (insn & 0x000F)
+ 
+ /* Additional macros in order to handle opcodes.  */
+ #define GET_WIDE_OPCODE(insn) ((insn & 0x03E0) >> 5)
+ #define GET_SHORT_SIZE(insn) ((insn & 0x0010) >> 4)
+ #define GET_QUICK_VALUE(insn) (insn & 0x003F)
+ #define GET_BDAP_QUICK_OFFSET(insn) (insn & 0x00FF)
+ #define GET_BRANCH_SHORT_OFFSET(insn) (insn & 0x00FF)
+ #define GET_ASR_SHIFT_STEPS(value) (value & 0x3F)
+ #define GET_ASR_QUICK_SHIFT_STEPS(insn) (insn & 0x1F)
+ #define GET_CLEAR_SIZE(insn) ((insn) & 0xC000)
+ #define IS_SIGNED_EXTEND_BIT_ON(insn) (((insn) & 0x20) == 0x20)
+ #define IS_XFLAG_BIT_ON(insn) (((insn) & 0x1000) == 0x1000)
+ #define SET_SIZE_TO_DWORD(insn) do {insn &= 0xFFCF; insn |= 0x20; } while (0)
+ 
+ /* Handle immediate byte offset addressing mode prefix format.  */
+ #define PREFIX_OFFSET_MODE   2
+ #define GET_SIGNED_OFFSET(insn) ((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_abi_update (char *ignore_args, int from_tty, 
+                              struct cmd_list_element *c);
+ 
+ static CORE_ADDR bfd_lookup_symbol (bfd *, 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.  */
+   if (!END_OF_PROLOGUE_INFO_ONLY (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 = GET_OPERAND2 (insn_next);
+           if (regno == (SRP_REGNUM - NUM_GENREGS))
+             {
+               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 (GET_OPERAND2 (insn) == SP_REGNUM 
+                && GET_MODE (insn) == 0x0000
+                && GET_OPCODE (insn) == 0x000A)
+         {
+           /* subq <val>,sp */
+           val = GET_QUICK_VALUE (insn);
+         }
+       else if (GET_MODE (insn) == 0x0002 
+                && GET_OPCODE (insn) == 0x000F
+                && GET_SIZE (insn) == 0x0003
+                && GET_OPERAND1 (insn) == SP_REGNUM)
+         {
+           /* movem r<regsave>,[sp] */
+           if (frameless_p)
+             {
+               return ip;
+             }
+           regsave = GET_OPERAND2 (insn);
+         }
+       else if (GET_OPERAND2 (insn) == SP_REGNUM
+                && ((insn & 0x0F00) >> 8) == 0x0001
+                && (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 = -GET_SIGNED_OFFSET (insn);
+           insn_next = read_memory_unsigned_integer (ip, sizeof (short));
+           ip += sizeof (short);
+           if (GET_MODE (insn_next) == PREFIX_ASSIGN_MODE
+               && GET_OPCODE (insn_next) == 0x000F
+               && GET_SIZE (insn_next) == 0x0003
+               && GET_OPERAND1 (insn_next) == SP_REGNUM)
+             {
+               if (frameless_p)
+                 {
+                   return ip;
+                 }
+               regsave = GET_OPERAND2 (insn_next);
+             }
+           else
+             {
+               /* The prologue ended before the limit was reached.  */
+               ip -= 2 * sizeof (short);
+               break;
+             }
+         }
+       else if (GET_MODE (insn) == 0x0001
+                && GET_OPCODE (insn) == 0x0009
+                && GET_SIZE (insn) == 0x0002)
+         {
+           /* move.d r<10..13>,r<0..15> */
+           if (frameless_p)
+             {
+               return ip;
+             }
+           source_register = GET_OPERAND1 (insn);
+           if (source_register < ARG1_REGNUM || source_register > ARG4_REGNUM)
+             {
+               /* The prologue ended before the limit was reached.  */
+               ip -= sizeof (short);
+               break;
+             }
+         }
+       else if (GET_OPERAND2 (insn) == FP_REGNUM 
+                /* The size is a fixed-size.  */
+                && ((insn & 0x0F00) >> 8) == 0x0001 
+                /* A negative offset.  */
+                && (GET_SIGNED_OFFSET (insn) < 0))  
+         {
+           /* move.S rZ,[r8-U] (?) */
+           insn_next = read_memory_unsigned_integer (ip, sizeof (short));
+           ip += sizeof (short);
+           regno = GET_OPERAND2 (insn_next);
+           if ((regno >= 0 && regno < SP_REGNUM)
+               && GET_MODE (insn_next) == PREFIX_OFFSET_MODE
+               && 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 (GET_OPERAND2 (insn) == FP_REGNUM 
+                /* The size is a fixed-size.  */
+                && ((insn & 0x0F00) >> 8) == 0x0001 
+                /* A positive offset.  */
+                && (GET_SIGNED_OFFSET (insn) > 0))  
+         {
+           /* move.S [r8+U],rZ (?) */
+           insn_next = read_memory_unsigned_integer (ip, sizeof (short));
+           ip += sizeof (short);
+           regno = GET_OPERAND2 (insn_next);
+           if ((regno >= 0 && regno < SP_REGNUM)
+               && GET_MODE (insn_next) == PREFIX_OFFSET_MODE
+               && GET_OPCODE (insn_next) == 0x0009
+               && 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);
+ 
+   /* Only want to know the end of the prologue.  */
+   if (END_OF_PROLOGUE_INFO_ONLY (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.  */
+ 
+ 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.  */
+ 
+ CORE_ADDR
+ cris_saved_pc_after_call ()
+ {
+   return read_register (SRP_REGNUM);
+ }
+ 
+ /* Returns 1 if spec_reg is applicable to CRIS_VERSION, 0 otherwise.  */
+ 
+ int
+ cris_spec_reg_applicable (struct cris_spec_reg spec_reg)
+ {
+   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 (CRIS_VERSION >= 0 && CRIS_VERSION <= 3);
+     case cris_ver_v3p:
+       return (CRIS_VERSION >= 3);
+     case cris_ver_v8:
+       return (CRIS_VERSION == 8 || CRIS_VERSION == 9);
+     case cris_ver_v8p:
+       return (CRIS_VERSION >= 8);
+     case cris_ver_v10p:
+       return (CRIS_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;
+     }
+ }
+ 
+ /* 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 < P15_REGNUM))
+     {
+       /* SP, PC, IBR, IRP, SRP, DTP0-BAR, DTP1-DCCR, BRP */
+       return lookup_pointer_type (builtin_type_void);
+     }
+   else if (regno == P8_REGNUM || regno == P15_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 CRIS ABI, R10 is always used in order 
+    to store return values.  */
+ 
+ void
+ cris_store_return_value (struct type *type, char *valbuf)
+ {
+   write_register_bytes (REGISTER_BYTE (RET_REGNUM), valbuf, 
+                         TYPE_LENGTH (type));
+ }
+ 
+ /* Return the name of register regno as a string. Return NULL for an invalid or
+    unimplemented register.  */
+ 
+ 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;
+     }
+ }
+ 
+ /* 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 CRIS ABI, R10 is always used in order to return values.  */
+ 
+ void
+ cris_extract_return_value (struct type *type, char *regbuf, char *valbuf)
+ {
+   memcpy (valbuf, regbuf + REGISTER_BYTE (RET_REGNUM), TYPE_LENGTH (type));
+ }
+ 
+ /* 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 CRIS ABI, arguments shorter than or equal to 32 or 64 bits are 
+    passed by value.  */
+ 
+ int 
+ cris_reg_struct_has_addr (int gcc_p, struct type *type)
+ { 
+   return ((CRIS_ABI == CRIS_ABI_ORIGINAL && TYPE_LENGTH (type) > 4) 
+           || (CRIS_ABI == CRIS_ABI_V2 && TYPE_LENGTH (type) > 8));
+ }
+ 
+ /* Returns 1 if the function invocation represented by fi does not have a 
+    stack fram 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 = 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)
+ {
+ 
+   fi->extra_info = (struct frame_extra_info *)
+     frame_obstack_alloc (sizeof (struct frame_extra_info));
+ 
+   if (fi->next)
+     {
+       /* Called from get_prev_frame.  */
+       fi->pc = FRAME_SAVED_PC (fi->next);
+     }
+   
+   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 = generic_read_register_dummy (fi->pc, fi->frame, SP_REGNUM);
+       fi->extra_info->return_pc = 
+         generic_read_register_dummy (fi->pc, fi->frame, PC_REGNUM);
+       fi->extra_info->leaf_function = 0;
+     }
+   else
+     {
+       cris_frame_init_saved_regs (fi);
+       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);
+         }
+     }
+ }
+ 
+ /* 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_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;
+ }
+ 
+ /* 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 (BRP_REGNUM, pc);
+   write_register (SRP_REGNUM, entry_point_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 ()
+ {
+   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 ();
+ }
+ 
+ /* 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 (*tm_print_insn) (addr, info);
+ }
+ 
+ void
+ _initialize_cris_tdep ()
+ {
+   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);
+   c->function.sfunc = cris_version_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);
+   c->function.sfunc = cris_abi_update;
+   add_show_from_set (c, &showlist);
+ }
+ 
+ /* 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_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;
+ 
+   /* From here on, trust the user's CRIS version setting.  */
+   if (c->type == set_cmd)
+     usr_cmd_cris_version_valid = 1;
+   
+   /* Update the current architecture, if needed.  */
+   memset (&info, 0, sizeof info);
+   if (!gdbarch_update_p (info))
+     internal_error ("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;
+   
+   /* From here on, trust the user's CRIS ABI setting.  */
+   if (c->type == set_cmd)
+     usr_cmd_cris_abi_valid = 1;
+   
+   /* Update the current architecture, if needed.  */
+   memset (&info, 0, sizeof info);
+   if (!gdbarch_update_p (info))
+     internal_error ("cris_gdbarch_update: failed to update architecture.");
+ 
+ }
+ 
+ /* Copied from pa64solib.c.  */
+ 
+ static CORE_ADDR
+ bfd_lookup_symbol (bfd *abfd, 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_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 8.  */
+       cris_version = 8;
+     }
+ 
+   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 (gdbarch_tdep (current_gdbarch))
+     {
+       /* No bfd available.  Stick with whatever ABI we're currently using.  
+          (This is to avoid changing the ABI when the user updates the 
+          architecture with the 'set cris-version' command.)  */
+       cris_abi = gdbarch_tdep (current_gdbarch)->cris_abi;
+     }
+   else
+     {
+       /* No bfd, and no current architecture available.  Assume it's the 
+          new ABI.  */
+       cris_abi = CRIS_ABI_V2;
+     }
+   
+   /* 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_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_abi = cris_abi;
+   
+   /* Make the current settings visible to the user.  */
+   usr_cmd_cris_version = cris_version;
+   usr_cmd_cris_abi = cris_abi;
+   
+   /* INIT shall ensure that the INFO.BYTE_ORDER is non-zero.  */
+   switch (info.byte_order)
+     {
+     case LITTLE_ENDIAN:
+       /* Ok.  */
+       break;
+ 
+     case BIG_ENDIAN:
+       internal_error ("cris_gdbarch_init: big endian byte order in info");
+       break;
+     
+     default:
+       internal_error ("cris_gdbarch_init: unknown byte order in info");
+     }
+ 
+   if (tdep->cris_abi == CRIS_ABI_ORIGINAL)
+     set_gdbarch_double_bit (gdbarch, 32);
+   else if (tdep->cris_abi == CRIS_ABI_V2)
+     set_gdbarch_double_bit (gdbarch, 64);
+   else
+     internal_error ("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);
+     
+   /* Floating point is IEEE compatible.  */
+   set_gdbarch_ieee_float (gdbarch, 1);
+ 
+   /* 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);
+   
+   /* 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 ("cris_gdbarch_init: unsupported CRIS version");
+       break;
+       
+     case 8:
+     case 9:
+       /* CRIS v8, 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:
+       /* CRIS v10, a.k.a. Etrax 100 LX.  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 ("cris_gdbarch_init: unsupported 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);
+   
+   /* Not sure about this one (not documented).  */
+   set_gdbarch_call_dummy_length (gdbarch, 0);
+   set_gdbarch_pc_in_call_dummy (gdbarch, generic_pc_in_call_dummy);
+   
+   /* Defined to 1 to indicate that the target supports inferior function 
+      calls.  */
+   set_gdbarch_call_dummy_p (gdbarch, 1);
+   
+   /* Defined to 0, and relying on magic (the recommended way).  */
+   set_gdbarch_call_dummy_words (gdbarch, 0);
+   
+   /* Defined to 0, and relying on magic (the recommended way).  */
+   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_extract_return_value (gdbarch, cris_extract_return_value);
+   set_gdbarch_push_arguments (gdbarch, cris_push_arguments);
+   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_store_return_value (gdbarch, cris_store_return_value);
+   set_gdbarch_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.  */
+   set_gdbarch_decr_pc_after_break (gdbarch, 0);
+   
+   /* Offset from address of function to start of its code. 
+      Zero on this unit.  */
+   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);
+   set_gdbarch_reg_struct_has_addr (gdbarch, cris_reg_struct_has_addr);
+   
+   /* Helpful for backtracing and returning in a call dummy.  */
+   set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
+ 
+   return gdbarch;
+ }
+ 
+ /* 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; i < NUM_SPECREGS; 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 (i == NUM_SPECREGS)
+           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
+ 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[GET_OPERAND2 (inst)];
+   inst_env->prefix_value += 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[GET_OPERAND1 (inst)] += 1;
+ 
+       /* The PC must be word aligned, so increase the PC with one
+          word even if the size is byte.  */
+       if (GET_OPERAND1 (inst) == REG_PC)
+         {
+           inst_env->reg[REG_PC] += 1;
+         }
+     }
+   else if (size == INST_WORD_SIZE)
+     {
+       inst_env->reg[GET_OPERAND1 (inst)] += 2;
+     }
+   else if (size == INST_DWORD_SIZE)
+     {
+       inst_env->reg[GET_OPERAND1 (inst)] += 4;
+     }
+   else
+     {
+       /* Invalid size.  */
+       inst_env->invalid = 1;
+     }
+ }
+ 
+ /* 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; 
+     }
+ 
+   if (GET_MODE (inst) == AUTOINC_MODE)
+     {
+       process_autoincrement (GET_SIZE (inst), inst, inst_env); 
+     }
+     
+   inst_env->prefix_value = inst_env->reg[GET_OPERAND2 (inst)];
+ 
+   /* The offset is an indirection of the contents of the operand1 register.  */
+   inst_env->prefix_value += 
+     read_memory_integer (inst_env->reg[GET_OPERAND1 (inst)], GET_SIZE (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;
+ }
+ 
+ /* 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[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[GET_OPERAND2 (inst)] << 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 (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[GET_OPERAND1 (inst)];
+   inst_env->prefix_value = read_memory_unsigned_integer (address, 4);
+     
+   /* Check if the mode is autoincrement.  */
+   if (GET_MODE (inst) == AUTOINC_MODE)
+     {
+       inst_env->reg[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 = 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 (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 || (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 (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 = GET_ASR_SHIFT_STEPS (inst_env->reg[GET_OPERAND1 (inst)]);
+       value = inst_env->reg[REG_PC];
+ 
+       /* Find out how many bits the operation should apply to.  */
+       if (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 (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 (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 (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 = GET_ASR_QUICK_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 (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 (GET_MODE (inst) == PREFIX_ASSIGN_MODE)
+     {
+       /* Assign the prefix value to operand 1.  */
+       inst_env->reg[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 (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 (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 (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) || (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 (GET_OPERAND2 (inst) == REG_PC)
+     {
+       /* The instruction will clear the instruction's size bits.  */
+       int clear_size = 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 (GET_MODE (inst) == AUTOINC_MODE)
+     {
+       process_autoincrement (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 ((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 ((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[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[GET_OPERAND1 (inst)];
+           newpc = read_memory_unsigned_integer (address, 4);
+ 
+           /* Check if we should increment a register.  */
+           if (GET_MODE (inst) == AUTOINC_MODE)
+             {
+               inst_env->reg[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 (GET_MODE (inst) == PREFIX_ASSIGN_MODE)
+         {
+           /* The prefix handles the problem if we are in a delay slot.  */
+           if (GET_OPERAND1 (inst) == REG_PC)
+             {
+               /* Just take care of the assign.  */
+               check_assign (inst, inst_env);
+             }
+         }
+     }
+   else if (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 (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. 
+              Register P0 to P3 has the size byte, register P4 to P7 has the 
+              size word and register P8 to P15 has the size dword.  */
+           if (GET_OPERAND2 (inst) < 4)
+             {
+               process_autoincrement (INST_BYTE_SIZE, inst, inst_env);
+             }
+           if (GET_OPERAND2 (inst) < 8)
+             {
+               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 (GET_MODE (inst) == PREFIX_ASSIGN_MODE)
+         {
+           /* The prefix handles the problem if we are in a delay slot.  */
+           if (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 (GET_MODE (inst) == AUTOINC_MODE)
+     {
+       if (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.  
+              Register P0 to P3 has the size byte, register P4 to P7 has 
+              the size word and register P8 to P15 has the size dword.  */
+           if (GET_OPERAND2 (inst) < 4)
+             {
+               process_autoincrement (INST_BYTE_SIZE, inst, inst_env);
+             }
+           if (GET_OPERAND2 (inst) < 8)
+             {
+               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 (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[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 (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 ((GET_OPERAND1 (inst) == REG_PC) 
+           && (GET_MODE (inst) == PREFIX_ASSIGN_MODE))
+         {
+           inst_env->reg[REG_PC] = inst_env->prefix_value;
+           inst_env->reg[REG_PC] += 4 * (GET_OPERAND2 (inst) + 1);
+         }
+     }
+   else
+     {
+       /* Is the MOVEM instruction going to change the PC?  */
+       if (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[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 ((GET_OPERAND1 (inst) == REG_PC) && (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 * (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 ((GET_OPERAND1 (inst) == REG_PC) &&
+           (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 * (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 ((GET_OPERAND1 (inst) == REG_PC) && (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 * (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 (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 ((GET_OPERAND1 (inst) == REG_PC) 
+            && (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 (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 (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[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 (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 (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 (GET_SIZE (inst) == INST_BYTE_SIZE)
+     {
+       pc_mask = 0xFFFFFF00; 
+       operation_mask = 0xFF;
+     }
+   else if (GET_SIZE (inst) == INST_WORD_SIZE)
+     {
+       pc_mask = 0xFFFF0000;
+       operation_mask = 0xFFFF;
+     }
+   else if (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 (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 (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 (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 (IS_SIGNED_EXTEND_BIT_ON (*inst) && (value & SIGNED_BYTE_MASK))
+         {
+           value |= SIGNED_BYTE_EXTEND_MASK;
+         }
+     }
+   /* The size should now be dword.  */
+   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 (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[operand1]; 
+       operand2 = inst_env->reg[REG_PC];
+ 
+       /* Check if it's a extend, signed or zero instruction.  */
+       if (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 = 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 (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 (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 (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 (GET_OPERAND1 (inst) == REG_PC)
+     {
+       /* The PC will be changed by the instruction.  */
+       operand2 = inst_env->reg[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 (GET_OPERAND1 (inst) != 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 (GET_OPERAND2 (inst) == REG_PC)
+     {
+       /* Must be done here, get_data_from_address may change the size 
+          field.  */
+       size = 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[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 ((GET_OPERAND1 (inst) == REG_PC) && (GET_MODE (inst) == AUTOINC_MODE))
+     {
+       /* Get the size field.  */
+       size = GET_SIZE (inst);
+ 
+       /* If it's an extend instruction we don't want the signed extend bit,
+          because it influences the size.  */
+       if (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 (GET_MODE (inst) == PREFIX_INDEX_MODE)
+         {
+           handle_prefix_index_mode_for_aritm_op (inst, inst_env);
+         }
+       else if (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 (GET_OPERAND2 (inst) == REG_PC)
+     {
+       if (inst_env->slot_needed)
+         {
+           inst_env->invalid = 1;
+           return;
+         }
+       operand1 = GET_QUICK_VALUE (inst);
+       operand2 = inst_env->reg[REG_PC];
+ 
+       /* The size should now be dword.  */
+       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 (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 = 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.  */
+       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;
+     }
+ }


*** /home/orjanf/gdb-2000-10-27/gdb/gdb/config/cris/tm-cris.h	Mon Nov 20 13:18:38 2000
--- config/cris/tm-cris.h	Thu Nov 30 15:28:48 2000
***************
*** 0 ****
--- 1,93 ----
+ /* Target machine sub-parameters for CRIS, for GDB, the GNU debugger.
+    Copyright (C) 2000 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.  */
+ 
+ #ifndef TM_CRIS_H
+ #define TM_CRIS_H
+ 
+ #define GDB_MULTI_ARCH 2
+ 
+ /* The target does not support single-stepping in hardware.  The file 
+    cris-tdep.c supplies the function single_step.  */
+ #define SOFTWARE_SINGLE_STEP_P 1
+ 
+ extern void single_step (unsigned int, int);
+ #define SOFTWARE_SINGLE_STEP(sig,bp_p) single_step (sig,bp_p)
+ 
+ /* In C++ code the line concept is messing with the result from SKIP_PROLOGUE. 
+    With this definition, the actual address returned is used as breakpoint.  */
+ #define PROLOGUE_FIRSTLINE_OVERLAP
+ 
+ /* Sequence of bytes for breakpoint instruction, break 8.  */
+ #define BPT_VECTOR 0x8
+ 
+ /* There are no floating point registers.  Used in gdbserver low-linux.c.  */
+ #define NUM_FREGS 0
+ 
+ /* There are 16 general registers.  */
+ #define NUM_GENREGS 16
+ 
+ /* There are 16 special registers.  */
+ #define NUM_SPECREGS 16
+ 
+ /* Sanity check of the size NUM_REGS * REGISTER_SIZE byte.  */
+ #define REGISTER_BYTES_OK(b) ((b) == REGISTER_BYTES)
+ 
+ /* Register numbers of various important registers in REGISTER_NAMES.
+    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, SP, and PC have been incorporated into the multi-arch framework, 
+    but are kept here for reference.  */
+ 
+ enum cris_regnums
+ {
+   /* Enums with respect to the general registers, valid for all 
+      CRIS versions.  */
+   FP_REGNUM   = 8,
+   STR_REGNUM  = 9,
+   RET_REGNUM  = 10,
+   ARG1_REGNUM = 10,
+   ARG2_REGNUM = 11,
+   ARG3_REGNUM = 12,
+   ARG4_REGNUM = 13,
+   SP_REGNUM   = 14,
+   PC_REGNUM   = 15,
+ 
+   /* Enums with respect to the special registers, some of which may not be
+      applicable to all CRIS versions.  */
+   P3_REGNUM   = 19,
+   P4_REGNUM   = 20,
+   P8_REGNUM   = 24,
+   SRP_REGNUM  = 27,
+   BRP_REGNUM  = 30,
+   P15_REGNUM  = 31
+ };
+ 
+ #endif


*** /home/orjanf/gdb-2000-10-27/gdb/gdb/config/cris/cris.mt	Mon Nov 20 13:19:15 2000
--- config/cris/cris.mt	Wed Nov  1 11:46:27 2000
***************
*** 0 ****
--- 1,4 ----
+ TDEPFILES= cris-tdep.o
+ TM_FILE= tm-cris.h
+ 
+ GDBSERVER_DEPFILES= low-cris.o

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]