* arc-tdep.c: #include "gdbcmd.h".
authorDavid Edelsohn <dje.gcc@gmail.com>
Wed, 12 Apr 1995 15:47:39 +0000 (15:47 +0000)
committerDavid Edelsohn <dje.gcc@gmail.com>
Wed, 12 Apr 1995 15:47:39 +0000 (15:47 +0000)
(codestream_seek): Pass CORE_ADDR.
(arc_cpu_type, tmp_arc_cpu_type, arc_cpu_type_table): New globals.
(debug_pipeline_p): Likewise.
(X_...): Instruction field access macros.
(BUILD_INSN): Define.
(codestream_tell): Allow for stream elements > 1 byte.
(codestream_fill): Likewise.
(setup_prologue_scan): New function.
(arc_get_frame_setup): Call it.  Update to current spec
regarding prologues.  Use BUILD_INSN.
(skip_prologue): New argument `frameless_p'.  Use BUILD_INSN.
(arc_frame_saved_pc): New function.
(frame_find_saved_regs): Use BUILD_INSN.
(get_insn_type, single_step): New functions.
(one_stepped): New global.
(arc_set_cpu_type_command, arc_show_cpu_type_command): New functions.
(arc_set_cpu_type): New function.
(_initialize_arc_tdep): Define new `set' commands `cpu',
`displaypipeline', and `debugpipeline'.
* remote-arc.c (break_insn): Add bi-endian support.
(arc_insert_breakpoint): Likewise.
(arc_remove_breakpoint): Likewise.
(switch_command): Delete.
* arc/tm-arc.h (TARGET_BYTE_ORDER): Delete.
(TARGET_BYTE_ORDER_SELECTABLE): Define.
(DEFAULT_ARC_CPU_TYPE): Define.
(SKIP_PROLOGUE_FRAMELESS_P): Define.
(BREAKPOINT): Delete.
(BIG_BREAKPOINT, LITTLE_BREAKPOINT): Define.
(DECR_PC_AFTER_BREAK): Change to 8.
(NO_SINGLE_STEP): Define.
(ARC_PC_TO_REAL_ADDRESS): Define.
(SAVED_PC_AFTER_CALL): Use it.
(NUM_REGS, REGISTER_BYTES): Fix.
(FRAME_SAVED_PC): Call arc_frame_saved_pc.
(FRAME_LOCALS_ADDRESS): Fix.

gdb/arc-tdep.c
gdb/config/arc/tm-arc.h
gdb/remote-arc.c

index 14b9fcb..e76aa93 100644 (file)
@@ -24,9 +24,62 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "target.h"
 #include "floatformat.h"
 #include "symtab.h"
+#include "gdbcmd.h"
+
+/* Current CPU, set with the "set cpu" command.  */
+char *arc_cpu_type;
+char *tmp_arc_cpu_type;
+
+/* Table of cpu names.  */
+struct {
+  char *name;
+  int value;
+} arc_cpu_type_table[] = {
+  { "base", bfd_mach_arc_base },
+  { "host", bfd_mach_arc_host },
+  { "graphics", bfd_mach_arc_graphics },
+  { "audio", bfd_mach_arc_audio },
+  { NULL, 0 }
+};
+
+/* Used by simulator.  */
+int display_pipeline_p;
+int cpu_timer;
+/* This one must have the same type as used in the emulator.
+   It's currently an enum so this should be ok for now.  */
+int debug_pipeline_p;
+
+#define ARC_CALL_SAVED_REG(r) ((r) >= 16 && (r) < 24)
 
+#define OPMASK 0xf8000000
+
+/* Instruction field accessor macros.  */
+#define X_OP(i) (((i) >> 27) & 0x1f)
+#define X_A(i) (((i) >> 21) & 0x3f)
+#define X_B(i) (((i) >> 15) & 0x3f)
+#define X_C(i) (((i) >> 9) & 0x3f)
+#define X_D(i) ((((i) & 0x1ff) ^ 0x100) - 0x100)
+#define X_L(i) (((((i) >> 5) & 0x3ffffc) ^ 0x200000) - 0x200000)
+#define X_N(i) (((i) >> 5) & 3)
+#define X_Q(i) ((i) & 0x1f)
+
+/* Return non-zero if X is a short immediate data indicator.  */
+#define SHIMM_P(x) ((x) == 61 || (x) == 63)
+
+/* Return non-zero if X is a "long" (32 bit) immediate data indicator.  */
+#define LIMM_P(x) ((x) == 62)
+
+/* Build a simple instruction.  */
+#define BUILD_INSN(op, a, b, c, d) \
+  ((((op) & 31) << 27) \
+   | (((a) & 63) << 21) \
+   | (((b) & 63) << 15) \
+   | (((c) & 63) << 9) \
+   | ((d) & 511))
+\f
+/* Codestream stuff.  */
 static void codestream_read PARAMS ((unsigned int *, int));
-static void codestream_seek PARAMS ((int));
+static void codestream_seek PARAMS ((CORE_ADDR));
 static unsigned int codestream_fill PARAMS ((int));
 
 #define CODESTREAM_BUFSIZ 16 
@@ -36,22 +89,28 @@ static unsigned int codestream_buf[CODESTREAM_BUFSIZ];
 static int codestream_off;
 static int codestream_cnt;
 
-#define codestream_tell() (codestream_addr + codestream_off)
-#define codestream_peek() (codestream_cnt == 0 ? \
-                          codestream_fill(1): codestream_buf[codestream_off])
-#define codestream_get() (codestream_cnt-- == 0 ? \
-                        codestream_fill(0) : codestream_buf[codestream_off++])
-#define OPMASK 0xf8000000
+#define codestream_tell() \
+  (codestream_addr + codestream_off * sizeof (codestream_buf[0]))
+#define codestream_peek() \
+  (codestream_cnt == 0 \
+   ? codestream_fill (1) \
+   : codestream_buf[codestream_off])
+#define codestream_get() \
+  (codestream_cnt-- == 0 \
+   ? codestream_fill (0) \
+   : codestream_buf[codestream_off++])
 
 static unsigned int 
 codestream_fill (peek_flag)
     int peek_flag;
 {
   codestream_addr = codestream_next_addr;
-  codestream_next_addr += CODESTREAM_BUFSIZ;
+  codestream_next_addr += CODESTREAM_BUFSIZ * sizeof (codestream_buf[0]);
   codestream_off = 0;
   codestream_cnt = CODESTREAM_BUFSIZ;
-  read_memory (codestream_addr, (char *) codestream_buf, CODESTREAM_BUFSIZ);
+  /* FIXME: need to handle byte order differences.  */
+  read_memory (codestream_addr, (char *) codestream_buf,
+              CODESTREAM_BUFSIZ * sizeof (codestream_buf[0]));
   
   if (peek_flag)
     return (codestream_peek());
@@ -61,7 +120,7 @@ codestream_fill (peek_flag)
 
 static void
 codestream_seek (place)
-    int place;
+    CORE_ADDR place;
 {
   codestream_next_addr = place / CODESTREAM_BUFSIZ;
   codestream_next_addr *= CODESTREAM_BUFSIZ;
@@ -82,145 +141,171 @@ codestream_read (buf, count)
   for (i = 0; i < count; i++)
     *p++ = codestream_get ();
 }
+\f
+/* Set up prologue scanning and return the first insn,
+   not including the "sub sp,sp,32" of a stdarg function.  */
+
+static unsigned int
+setup_prologue_scan (pc)
+     CORE_ADDR pc;
+{
+  unsigned int insn;
+
+  codestream_seek (pc);
+  insn = codestream_get ();
+
+  /* The authority for what appears here is the home-grown ABI.  */
+
+  /* First insn may be "sub sp,sp,32" if stdarg fn.  */
+  if (insn == BUILD_INSN (10, SP_REGNUM, SP_REGNUM, SHIMM_REGNUM, 32))
+    insn = codestream_get ();
+
+  return insn;
+}
 
 /*
- * find & return amound a local space allocated, and advance codestream to
- * first register push (if any)
- * if entry sequence doesn't make sense, return -1, and leave 
- * codestream pointer random
+ * Find & return amount a local space allocated, and advance codestream to
+ * first register push (if any).
+ * If entry sequence doesn't make sense, return -1, and leave 
+ * codestream pointer random.
  */
 
 static long
 arc_get_frame_setup (pc)
-     int pc;
+     CORE_ADDR pc;
 {
-  unsigned int insn, n;
+  unsigned int insn;
+  /* Size of frame or -1 if unrecognizable prologue.  */
+  int n = -1;
 
-  codestream_seek (pc);
-  insn = codestream_get ();
+  insn = setup_prologue_scan (pc);
 
-  if (insn & OPMASK == 0x10000000)             /* st fp,[sp] */
+  if ((insn & BUILD_INSN (-1, 0, -1, -1, -1))  /* st blink,[sp,4] */
+      == BUILD_INSN (2, 0, SP_REGNUM, BLINK_REGNUM, 4))
+    {
+      insn = codestream_get ();
+      /* Frame may not be necessary, even though blink is saved.
+        At least this is something we recognize.  */
+      n = 0;
+    }
+
+  if ((insn & BUILD_INSN (-1, 0, -1, -1, -1))          /* st fp,[sp] */
+      == BUILD_INSN (2, 0, SP_REGNUM, FP_REGNUM, 0))
     {  
       insn = codestream_get ();
-      if (insn & OPMASK != 0x10000000)         /* st blink,[sp,4] */
-       {
-         if (insn & OPMASK != 0x60000000)      /* for leaf, no st blink */
-           return -1;
-       }
-      else if (codestream_get () & OPMASK != 0x60000000)    /* mov fp,sp */
-       return (-1);
+      if ((insn & BUILD_INSN (-1, -1, -1, -1, 0))
+              != BUILD_INSN (12, FP_REGNUM, SP_REGNUM, SP_REGNUM, 0))
+       return -1;
 
-      /* check for stack adjustment sub sp,nnn,sp */
+      /* Check for stack adjustment sub sp,sp,nnn.  */
       insn = codestream_peek ();
-      if (insn & OPMASK == 0x50000000)
+      if ((insn & BUILD_INSN (-1, -1, -1, 0, 0))
+         == BUILD_INSN (10, SP_REGNUM, SP_REGNUM, 0, 0))
        {
-         n = (insn & 0x000001ff ); 
+         if (LIMM_P (X_C (insn)))
+           n = codestream_get ();
+         else if (SHIMM_P (X_C (insn)))
+           n = X_D (insn);
+         else
+           return -1;
+         if (n < 0)
+           return -1;
+
           codestream_get ();
 
-         /* this sequence is used to get the address of the return
-          * buffer for a function that returns a structure
-          */
+         /* This sequence is used to get the address of the return
+            buffer for a function that returns a structure.  */
          insn = codestream_peek ();
          if (insn & OPMASK == 0x60000000)
            codestream_get ();
-
-         return n;
        }
+      /* Frameless fn.  */
       else
        {
-         return (0);
+         n = 0;
        }
     }
-  return (-1);
+
+  return n;
 }
 
-/* return pc of first real instruction */
+/* Given a pc value, skip it forward past the function prologue by
+   disassembling instructions that appear to be a prologue.
+
+   If FRAMELESS_P is set, we are only testing to see if the function
+   is frameless.  If it is a frameless function, return PC unchanged.
+   This allows a quicker answer.  */
+
 CORE_ADDR
-skip_prologue (pc)
-     int pc;
+skip_prologue (pc, frameless_p)
+     CORE_ADDR pc;
+     int frameless_p;
 {
   unsigned int insn;
-  int i;
-  CORE_ADDR pos;
-  
-  if (arc_get_frame_setup (pc) < 0)
+  int i, frame_size;
+
+  if ((frame_size = arc_get_frame_setup (pc)) < 0)
     return (pc);
-  
-  /* skip over register saves */
-  for (i = 0; i < 10; i++)
+
+  if (frameless_p)
+    return frame_size == 0 ? pc : codestream_tell ();
+
+  /* Skip over register saves.  */
+  for (i = 0; i < 8; i++)
     {
       insn = codestream_peek ();
-      if (insn & OPMASK != 0x10000000)       /* break if not st inst */
+      if ((insn & BUILD_INSN (-1, 0, -1, 0, 0))
+         != BUILD_INSN (2, 0, SP_REGNUM, 0, 0))
+       break; /* not st insn */
+      if (! ARC_CALL_SAVED_REG (X_C (insn)))
        break;
       codestream_get ();
     }
-     
-  codestream_seek (pos);
-  return (codestream_tell ());
+
+  return codestream_tell ();
 }
 
-/* Return number of args passed to a frame.
-   Can return -1, meaning no way to tell.  */
-int
-frame_num_args (fi)
-     struct frame_info *fi;
+/* Return the return address for a frame.
+   This is used to implement FRAME_SAVED_PC.
+   This is taken from frameless_look_for_prologue.  */
+
+CORE_ADDR
+arc_frame_saved_pc (frame)
+     struct frame_info *frame;
 {
-#if 1
-  return -1;
-#else
-  /* This loses because not only might the compiler not be popping the
-     args right after the function call, it might be popping args from both
-     this call and a previous one, and we would say there are more args
-     than there really are.  Is it true for ARC */
-
-  int retpc;                                           
-  unsigned char op;                                    
-  struct frame_info *pfi;
-
-  int frameless;
-
-  FRAMELESS_FUNCTION_INVOCATION (fi, frameless);
-  if (frameless)
-    /* In the absence of a frame pointer, GDB doesn't get correct values
-       for nameless arguments.  Return -1, so it doesn't print any
-       nameless arguments.  */
-    return -1;
-
-  pfi = get_prev_frame_info (fi);                      
-  if (pfi == 0)
+  CORE_ADDR func_start;
+  unsigned int insn;
+
+  func_start = get_pc_function_start (frame->pc) + FUNCTION_START_OFFSET;
+  if (func_start == 0)
     {
-      /* Note:  this can happen if we are looking at the frame for
-        main, because FRAME_CHAIN_VALID won't let us go into
-        start.  If we have debugging symbols, that's not really
-        a big deal; it just means it will only show as many arguments
-        to main as are declared.  */
-      return -1;
+      /* Best guess.  */
+      return ARC_PC_TO_REAL_ADDRESS (read_memory_integer (FRAME_FP (frame) + 4, 4));
     }
+
+  /* If the first insn is "st blink,[sp,4]" we can get blink from there.
+     Otherwise this is a leaf function and we can use blink.  Note that
+     this still allows for the case where a leaf function saves/clobbers/
+     restores blink.  */
+
+  insn = setup_prologue_scan (func_start);
+
+  if ((insn & BUILD_INSN (-1, 0, -1, -1, -1))  /* st blink,[sp,4] */
+      != BUILD_INSN (2, 0, SP_REGNUM, BLINK_REGNUM, 4))
+    return ARC_PC_TO_REAL_ADDRESS (read_register (BLINK_REGNUM));
   else
-    {
-      retpc = pfi->pc;                                 
-      op = read_memory_integer (retpc, 1);                     
-      if (op == 0x59)                                  
-       /* pop %ecx */                         
-       return 1;                               
-       }
-      else
-       {
-         return 0;
-       }
-    }
-#endif
+    return ARC_PC_TO_REAL_ADDRESS (read_memory_integer (FRAME_FP (frame) + 4, 4));
 }
 
 /*
- * parse the first few instructions of the function to see
+ * Parse the first few instructions of the function to see
  * what registers were stored.
  *
  * The startup sequence can be at the start of the function.
- * 'st fp,[sp], st blink,[sp+4], mov fp,sp' 
+ * 'st blink,[sp+4], st fp,[sp], mov fp,sp' 
  *
- * Local space is allocated just below by sub sp,nnn,sp
- * Next, the registers used by this function are stored.
+ * Local space is allocated just below by sub sp,sp,nnn.
+ * Next, the registers used by this function are stored (as offsets from sp).
  */
 
 void
@@ -233,15 +318,13 @@ frame_find_saved_regs (fip, fsrp)
   CORE_ADDR dummy_bottom;
   CORE_ADDR adr;
   int i, regnum, offset;
-  
+
   memset (fsrp, 0, sizeof *fsrp);
-  
-  /* if frame is the end of a dummy, compute where the
-   * beginning would be
-   */
+
+  /* If frame is the end of a dummy, compute where the beginning would be.  */
   dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH;
-  
-  /* check if the PC is in the stack, in a dummy frame */
+
+  /* Check if the PC is in the stack, in a dummy frame.  */
   if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) 
     {
       /* all regs were saved by push_call_dummy () */
@@ -253,23 +336,25 @@ frame_find_saved_regs (fip, fsrp)
        }
       return;
     }
-  
+
   locals = arc_get_frame_setup (get_pc_function_start (fip->pc));
-  
+
   if (locals >= 0) 
     {
+      /* Set `adr' to the value of `sp'.  */
       adr = fip->frame - locals;
-      for (i = 0; i < 10; i++) 
+      for (i = 0; i < 8; i++)
        {
          insn = codestream_get ();
-         if (insn & 0xffff8000 != 0x100d8000)
+         if ((insn & BUILD_INSN (-1, 0, -1, 0, 0))
+              != BUILD_INSN (2, 0, SP_REGNUM, 0, 0))
            break;
-          regnum = (insn & 0x00007c00) >> 9;
-         offset = (insn << 23) >> 23;
+          regnum = X_C (insn);
+         offset = X_D (insn);
          fsrp->regs[regnum] = adr + offset;
        }
     }
-  
+
   fsrp->regs[PC_REGNUM] = fip->frame + 4;
   fsrp->regs[FP_REGNUM] = fip->frame;
 }
@@ -322,7 +407,141 @@ pop_frame ()
   write_register (SP_REGNUM, fp + 8);
   flush_cached_frames ();
 }
+\f
+/* Simulate single-step.  */
+
+typedef enum
+{
+  NORMAL4, /* a normal 4 byte insn */
+  NORMAL8, /* a normal 8 byte insn */
+  BRANCH4, /* a 4 byte branch insn, including ones without delay slots */
+  BRANCH8, /* an 8 byte branch insn, including ones with delay slots */
+} insn_type;
+
+/* Return the type of INSN and store in TARGET the destination address of a
+   branch if this is one.  */
+/* ??? Need to verify all cases are properly handled.  */
+
+static insn_type
+get_insn_type (insn, pc, target)
+     unsigned long insn;
+     CORE_ADDR pc, *target;
+{
+  unsigned long limm;
+
+  switch (insn >> 27)
+    {
+    case 0 : case 1 : case 2 : /* load/store insns */
+      if (LIMM_P (X_A (insn))
+         || LIMM_P (X_B (insn))
+         || LIMM_P (X_C (insn)))
+       return NORMAL8;
+      return NORMAL4;
+    case 4 : case 5 : case 6 : /* branch insns */
+      *target = pc + 4 + X_L (insn);
+      /* ??? It isn't clear that this is always the right answer.
+        The problem occurs when the next insn is an 8 byte insn.  If the
+        branch is conditional there's no worry as there shouldn't be an 8
+        byte insn following.  The programmer may be cheating if s/he knows
+        the branch will never be taken, but we don't deal with that.
+        Note that the programmer is also allowed to play games by putting
+        an insn with long immediate data in the delay slot and then duplicate
+        the long immediate data at the branch target.  Ugh!  */
+      if (X_N (insn) == 0)
+       return BRANCH4;
+      return BRANCH8;
+    case 7 : /* jump insns */
+      if (LIMM_P (X_B (insn)))
+       {
+         limm = read_memory_integer (pc + 4, 4);
+         *target = ARC_PC_TO_REAL_ADDRESS (limm);
+         return BRANCH8;
+       }
+      if (SHIMM_P (X_B (insn)))
+       *target = ARC_PC_TO_REAL_ADDRESS (X_D (insn));
+      else
+       *target = ARC_PC_TO_REAL_ADDRESS (read_register (X_B (insn)));
+      if (X_Q (insn) == 0 && X_N (insn) == 0)
+       return BRANCH4;
+      return BRANCH8;
+    default : /* arithmetic insns, etc. */
+      if (LIMM_P (X_A (insn))
+         || LIMM_P (X_B (insn))
+         || LIMM_P (X_C (insn)))
+       return NORMAL8;
+      return NORMAL4;
+    }
+}
+
+/* Non-zero if we just simulated a single-step.  This is needed because we
+   cannot remove the breakpoints in the inferior process until after the
+   `wait' in `wait_for_inferior'.  */
+
+int one_stepped;
+
+/* single_step() is called just before we want to resume the inferior, if we
+   want to single-step it but there is no hardware or kernel single-step
+   support.  We find all the possible targets of the coming instruction and
+   breakpoint them.
+
+   single_step is also called just after the inferior stops.  If we had
+   set up a simulated single-step, we undo our damage.  */
 
+void
+single_step (ignore)
+     int ignore; /* sig, but we don't need it */
+{
+  static CORE_ADDR next_pc, target;
+  static int brktrg_p;
+  typedef char binsn_quantum[BREAKPOINT_MAX];
+  static binsn_quantum break_mem[2];
+
+  if (!one_stepped)
+    {
+      insn_type type;
+      CORE_ADDR pc;
+      unsigned long insn;
+
+      pc = read_register (PC_REGNUM);
+      insn = read_memory_integer (pc, 4);
+      type = get_insn_type (insn, pc, &target);
+
+      /* Always set a breakpoint for the insn after the branch.  */
+      next_pc = pc + ((type == NORMAL8 || type == BRANCH8) ? 8 : 4);
+      target_insert_breakpoint (next_pc, break_mem[0]);
+
+      brktrg_p = 0;
+
+      if ((type == BRANCH4 || type == BRANCH8)
+         /* Watch out for branches to the following location.
+            We just stored a breakpoint there and another call to
+            target_insert_breakpoint will think the real insn is the
+            breakpoint we just stored there.  */
+         && target != next_pc)
+       {
+         brktrg_p = 1;
+         target_insert_breakpoint (target, break_mem[1]);
+       }
+
+      /* We are ready to let it go.  */
+      one_stepped = 1;
+    }
+  else
+    {
+      /* Remove breakpoints.  */
+      target_remove_breakpoint (next_pc, break_mem[0]);
+
+      if (brktrg_p)
+       target_remove_breakpoint (target, break_mem[1]);
+
+      /* Fix the pc.  */
+      stop_pc -= DECR_PC_AFTER_BREAK;
+      write_pc (stop_pc);
+
+      one_stepped = 0;
+    }
+}
+\f
 #ifdef GET_LONGJMP_TARGET
 /* Figure out where the longjmp will land.  Slurp the args out of the stack.
    We expect the first arg to be a pointer to the jmp_buf structure from which
@@ -354,9 +573,113 @@ get_longjmp_target(pc)
   return 1;
 }
 #endif /* GET_LONGJMP_TARGET */
+\f
+/* Command to set cpu type.  */
 
 void
+arc_set_cpu_type_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  int i;
+
+  if (tmp_arc_cpu_type == NULL || *tmp_arc_cpu_type == '\0')
+    {
+      printf_unfiltered ("The known ARC cpu types are as follows:\n");
+      for (i = 0; arc_cpu_type_table[i].name != NULL; ++i)
+       printf_unfiltered ("%s\n", arc_cpu_type_table[i].name);
+
+      /* Restore the value.  */
+      tmp_arc_cpu_type = strsave (arc_cpu_type);
+
+      return;
+    }
+  
+  if (!arc_set_cpu_type (tmp_arc_cpu_type))
+    {
+      error ("Unknown cpu type `%s'.", tmp_arc_cpu_type);
+      /* Restore its value.  */
+      tmp_arc_cpu_type = strsave (arc_cpu_type);
+    }
+}
+
+static void
+arc_show_cpu_type_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+}
+
+/* Modify the actual cpu type.
+   Result is a boolean indicating success.  */
+
+int
+arc_set_cpu_type (str)
+     char *str;
+{
+  int i, j;
+
+  if (str == NULL)
+    return 0;
+
+  for (i = 0; arc_cpu_type_table[i].name != NULL; ++i)
+    {
+      if (strcasecmp (str, arc_cpu_type_table[i].name) == 0)
+       {
+         arc_cpu_type = str;
+         tm_print_insn = arc_get_disassembler (arc_cpu_type_table[i].value,
+                                               TARGET_BYTE_ORDER == BIG_ENDIAN);
+         return 1;
+       }
+    }
+
+  return 0;
+}
+\f
+void
 _initialize_arc_tdep ()
 {
-  tm_print_insn = arc_get_disassembler (bfd_mach_arc_host);
+  struct cmd_list_element *c;
+
+  c = add_set_cmd ("cpu", class_support, var_string_noescape,
+                  (char *) &tmp_arc_cpu_type,
+                  "Set the type of ARC cpu in use.\n\
+This command has two purposes.  In a multi-cpu system it lets one\n\
+change the cpu being debugged.  It also gives one access to\n\
+cpu-type-specific registers and recognize cpu-type-specific instructions.\
+",
+                  &setlist);
+  c->function.cfunc = arc_set_cpu_type_command;
+  c = add_show_from_set (c, &showlist);
+  c->function.cfunc = arc_show_cpu_type_command;
+
+  /* We have to use strsave here because the `set' command frees it before
+     setting a new value.  */
+  tmp_arc_cpu_type = strsave (DEFAULT_ARC_CPU_TYPE);
+  arc_set_cpu_type (tmp_arc_cpu_type);
+
+  c = add_set_cmd ("displaypipeline", class_support, var_zinteger,
+                  (char *) &display_pipeline_p,
+                  "Set pipeline display (simulator only).\n\
+When enabled, the state of the pipeline after each cycle is displayed.",
+                  &setlist);
+  c = add_show_from_set (c, &showlist);
+
+  c = add_set_cmd ("debugpipeline", class_support, var_zinteger,
+                  (char *) &debug_pipeline_p,
+                  "Set pipeline debug display (simulator only).\n\
+When enabled, debugging information about the pipeline is displayed.",
+                  &setlist);
+  c = add_show_from_set (c, &showlist);
+
+  c = add_set_cmd ("cputimer", class_support, var_zinteger,
+                  (char *) &cpu_timer,
+                  "Set maximum cycle count (simulator only).\n\
+Control will return to gdb if the timer expires.\n\
+A negative value disables the timer.",
+                  &setlist);
+  c = add_show_from_set (c, &showlist);
+
+  /* FIXME: must be done after for now.  */
+  tm_print_insn = arc_get_disassembler (bfd_mach_arc_base, 1 /*FIXME*/);
 }
index a0285c5..83a197a 100644 (file)
@@ -1,6 +1,6 @@
 /* Parameters for target machine ARC, for GDB, the GNU debugger.
    Copyright (C) 1995 Free Software Foundation, Inc.
-   Contributed by Cygnus Support Corporation.
+   Contributed by Cygnus Support.
 
 This file is part of GDB.
 
@@ -18,8 +18,11 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
-/* Byte order is configurable, but this machine runs little-endian.  */
-#define        TARGET_BYTE_ORDER       LITTLE_ENDIAN
+/* Used by arc-tdep.c to set the default cpu type.  */
+#define DEFAULT_ARC_CPU_TYPE "base"
+
+/* Byte order is selectable.  */
+#define        TARGET_BYTE_ORDER_SELECTABLE
 
 /* We have IEEE floating point, if we have any float at all.  */
 #define IEEE_FLOAT
@@ -28,31 +31,61 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
    Zero on most machines.  */
 #define FUNCTION_START_OFFSET 0
 
-/* Advance pc across any function entry prologue instructions
-   to reach some "real" code.  */
-
-#define SKIP_PROLOGUE(pc)      { pc = skip_prologue (pc); }
-extern CORE_ADDR skip_prologue ();
-
-/* Sequence of bytes for breakpoint instruction.  */
-#define BREAKPOINT {0x01, 0x80, 0xbe, 0x1f}
-
-#define DECR_PC_AFTER_BREAK 4
+/* Advance PC across any function entry prologue instructions
+   to reach some "real" code.  SKIP_PROLOGUE_FRAMELESS_P advances
+   the PC past some of the 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.  */
+
+#define SKIP_PROLOGUE(pc) \
+  { pc = skip_prologue (pc, 0); }
+#define SKIP_PROLOGUE_FRAMELESS_P(pc) \
+  { pc = skip_prologue (pc, 1); }
+extern CORE_ADDR skip_prologue PARAMS ((CORE_ADDR, int));
+
+/* Sequence of bytes for breakpoint instruction.
+   ??? The current value is "sr -1,[-1]" and is for the simulator only.
+   The simulator watches for this and does the right thing.
+   The hardware version will have to associate with each breakpoint
+   the sequence "flag 1; nop; nop; nop".  IE: The breakpoint insn will not
+   be a fixed set of bits but instead will be a branch to a semi-random
+   address.  Presumably this will be cleaned up for "second silicon".  */
+#define BIG_BREAKPOINT { 0x12, 0x1f, 0xff, 0xff }
+#define LITTLE_BREAKPOINT { 0xff, 0xff, 0x1f, 0x12 }
+
+/* ??? This value may eventually be correct (if/when proper breakpoints
+   are added).  Until then no value is correct so leave as is and cope.  */
+#define DECR_PC_AFTER_BREAK 8
+
+/* We don't have a reliable single step facility.
+   ??? We do have a cycle single step facility, but that won't work.  */
+#define NO_SINGLE_STEP
+extern int one_stepped;
+extern void single_step PARAMS ((int));
+
+/* Given a pc value as defined by the hardware, return the real address.
+   Remember that on the ARC blink contains that status register which
+   includes PC + flags (so we have to mask out the flags).  */
+#define ARC_PC_TO_REAL_ADDRESS(pc) (((pc) & 0xffffff) << 2)
 
 /* Immediately after a function call, return the saved pc.
    Can't always go through the frames for this because on some machines
    the new frame is not set up until the new function
    executes some instructions.  */
 
-#define SAVED_PC_AFTER_CALL(frame) (read_register (BLINK_REGNUM))
+#define SAVED_PC_AFTER_CALL(frame) \
+  (ARC_PC_TO_REAL_ADDRESS (read_register (BLINK_REGNUM)))
 
 /* Stack grows upward */
 
 #define INNER_THAN <
 
-/* Nonzero if instruction at pc is a return instruction.  */
+/* Nonzero if instruction at pc is a return instruction.
+   This is the "j [blink]" insn (with or without conditionals or delay
+   slots).  */
 
-#define ABOUT_TO_RETURN(pc) (read_memory_integer(pc,4) == 0x380f8000)
+#define ABOUT_TO_RETURN(pc) \
+  ((read_memory_integer(pc, 4) & 0xffffff80) == 0x380f8000)
 
 /* Say how long (ordinary) registers are.  This is a piece of bogosity
    used in push_word and a few other places; REGISTER_RAW_SIZE is the
@@ -60,7 +93,7 @@ extern CORE_ADDR skip_prologue ();
 #define REGISTER_SIZE 4
 
 /* Number of machine registers */
-#define NUM_REGS 91
+#define NUM_REGS 92
 
 /* Initializer for an array of names of registers.
    There should be NUM_REGS strings in this initializer.  */
@@ -97,6 +130,11 @@ extern CORE_ADDR skip_prologue ();
 #define AUX_BEG_REGNUM  61 /* aux reg begins */
 #define AUX_END_REGNUM  90 /* aux reg ends, pc not real aux reg */
 
+/* Fake registers used to mark immediate data.  */
+#define SHIMM_FLAG_REGNUM 61
+#define LIMM_REGNUM 62
+#define SHIMM_REGNUM 63
+
 #define AUX_REG_MAP \
 { \
    {  0,  1,  2,  3,  4,  5, \
@@ -129,7 +167,7 @@ extern CORE_ADDR skip_prologue ();
 
 /* Total amount of space needed to store our copies of the machine's
    register state, the array `registers'.  */
-#define REGISTER_BYTES (91*4)
+#define REGISTER_BYTES (NUM_REGS * 4)
 
 /* Index within `registers' of the first byte of the space for register N.  */
 #define REGISTER_BYTE(N) (4*(N))
@@ -165,7 +203,7 @@ extern CORE_ADDR skip_prologue ();
    this is also an argument.  This is used in call_function to build a
    stack, and in value_being_returned to print return values.
 
-   On arc, a structure is always retunred with pointer in r??. */
+   On arc, a structure is always retunred with pointer in r0. */
 
 #define USE_STRUCT_CONVENTION(gcc_p, type) 1
 
@@ -199,11 +237,6 @@ extern CORE_ADDR skip_prologue ();
 /* Describe the pointer in each stack frame to the previous stack frame
    (its caller).  */
 
-/* FRAME_CHAIN takes a frame's nominal address
-   and produces the frame's chain-pointer.
-   However, if FRAME_CHAIN_VALID returns zero,
-   it means the given frame is the outermost one and has no caller.  */
-
 /* We cache information about saved registers in the frame structure,
    to save us from having to re-scan function prologues every time
    a register in a non-current frame is accessed.  */
@@ -221,17 +254,20 @@ extern CORE_ADDR skip_prologue ();
 #define INIT_EXTRA_FRAME_INFO(fromleaf, fi) \
        ((fi)->fsr = 0, (fi)->arg_pointer = -1)
 
+/* FRAME_CHAIN takes a frame's nominal address
+   and produces the frame's chain-pointer.
+   However, if FRAME_CHAIN_VALID returns zero,
+   it means the given frame is the outermost one and has no caller.  */
 /* On the arc, we get the chain pointer by reading the PFP saved
    on the stack. */
-/* the PFP and RPC is in fp and fp+4. or it is in fp+4 and fp+8 ??? */
+/* The PFP and RPC is in fp and fp+4.  */
 
 #define FRAME_CHAIN(thisframe) \
-  (read_memory_integer (FRAME_FP(thisframe), 4))
+  (read_memory_integer (FRAME_FP (thisframe), 4))
 
 /* FRAME_CHAIN_VALID returns zero if the given frame is the outermost one
-   and has no caller.
-#define FRAME_CHAIN_VALID(thisframe) \
-   1
+   and has no caller.  */
+#define FRAME_CHAIN_VALID(chain, thisframe) ((chain) != 0)
 
 /* A macro that tells us whether the function invocation represented
    by FI does not have a frame on the stack associated with it.  If it
@@ -242,24 +278,28 @@ extern CORE_ADDR skip_prologue ();
     if ((FI)->signal_handler_caller) \
       (FRAMELESS) = 0; \
     else \
-      (FRAMELESS) = frameless_look_for_prologue(FI); \
+      (FRAMELESS) = frameless_look_for_prologue (FI); \
   } while (0)
 
-#define FRAME_SAVED_PC(frame) \
-  (read_memory_integer(FRAME_CHAIN(frame)+8,4))
+/* Where is the PC for a specific frame.
+   A leaf function may never save blink, so we have to check for that here.  */
+
+#define FRAME_SAVED_PC(frame) (arc_frame_saved_pc (frame))
+struct frame_info; /* in case frame.h not included yet */
+CORE_ADDR arc_frame_saved_pc PARAMS ((struct frame_info *));
 
-/* On the ARC, FRAME_ARGS_ADDRESS should return the value of
-   g14 as passed into the frame, if known.  We need a function for this.
+/* If the argument is on the stack, it will be here.
    We cache this value in the frame info if we've already looked it up.  */
+/* ??? Is the arg_pointer check necessary?  */
 
-#define FRAME_ARGS_ADDRESS(fi)         \
-  (((fi)->arg_pointer != -1)? (fi)->arg_pointer: (fi)->frame + 4)
+#define FRAME_ARGS_ADDRESS(fi) \
+  (((fi)->arg_pointer != -1) ? (fi)->arg_pointer : (fi)->frame)
 
 /* This is the same except it should return 0 when
    it does not really know where the args are, rather than guessing.
    This value is not cached since it is only used infrequently.  */
 
-#define FRAME_LOCALS_ADDRESS(fi)       (fi)->frame + 4
+#define FRAME_LOCALS_ADDRESS(fi)       ((fi)->frame)
 
 /* Set NUMARGS to the number of args passed to a frame.
    Can return -1, meaning no way to tell.  */
index 90ddf3c..7a97f3f 100644 (file)
@@ -894,20 +894,10 @@ arc_mourn ()
 }
 
 \f
-#ifdef REMOTE_BREAKPOINT
 
-/* On some machines, e.g. 68k, we may use a different breakpoint instruction
-   than other targets.  */
-static unsigned char break_insn[] = REMOTE_BREAKPOINT;
-
-/* Check that it fits in BREAKPOINT_MAX bytes.  */
-static unsigned char check_break_insn_size[BREAKPOINT_MAX] = REMOTE_BREAKPOINT;
-
-#else /* No REMOTE_BREAKPOINT.  */
-
-static unsigned char break_insn[] = BREAKPOINT;
-
-#endif /* No REMOTE_BREAKPOINT.  */
+static unsigned char big_break_insn[] = BIG_BREAKPOINT;
+static unsigned char little_break_insn[] = LITTLE_BREAKPOINT;
+#define BREAKPOINT_LEN (sizeof little_break_insn)
 
 /* Insert a breakpoint on targets that don't have any better breakpoint
    support.  We read the contents of the target location and stash it,
@@ -924,9 +914,16 @@ arc_insert_breakpoint (addr, contents_cache)
 {
   int val;
 
-  val = target_read_memory (addr, contents_cache, sizeof break_insn);
+  val = target_read_memory (addr, contents_cache, BREAKPOINT_LEN);
   if (val == 0)
-    val = target_write_memory (addr, (char *)break_insn, sizeof break_insn);
+    {
+      if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+       val = target_write_memory (addr, (char *) big_break_insn,
+                                  BREAKPOINT_LEN);
+      else
+       val = target_write_memory (addr, (char *) little_break_insn,
+                                  BREAKPOINT_LEN);
+    }
   return val;
 }
 
@@ -935,7 +932,7 @@ arc_remove_breakpoint (addr, contents_cache)
      CORE_ADDR addr;
      char *contents_cache;
 {
-  return target_write_memory (addr, contents_cache, sizeof break_insn);
+  return target_write_memory (addr, contents_cache, BREAKPOINT_LEN);
 }
 
 /* switch_command
@@ -961,13 +958,16 @@ switch_command (args, fromtty)
   switch (proc)
     {
     case 0:
-      tm_print_insn = arc_get_disassembler (bfd_mach_arc_audio);
+      tm_print_insn = arc_get_disassembler (bfd_mach_arc_audio,
+                                           TARGET_BYTE_ORDER == BIG_ENDIAN);
       break;
     case 1:
-      tm_print_insn = arc_get_disassembler (bfd_mach_arc_graphics);
+      tm_print_insn = arc_get_disassembler (bfd_mach_arc_graphics,
+                                           TARGET_BYTE_ORDER == BIG_ENDIAN);
       break;
     case 2:
-      tm_print_insn = arc_get_disassembler (bfd_mach_arc_host);
+      tm_print_insn = arc_get_disassembler (bfd_mach_arc_host,
+                                           TARGET_BYTE_ORDER == BIG_ENDIAN);
       break;
     }
 
@@ -1026,7 +1026,4 @@ void
 _initialize_remote_arc ()
 {
   add_target (&arc_ops);
-  add_com ("switch <processor>", class_obscure, switch_command,
-          "Switch to debug a different processor, can be one of 'host', \
-'graphic' and 'audio'.");
 }