* target.h (enum target_object): Add TARGET_OBJECT_SPU.
authorUlrich Weigand <uweigand@de.ibm.com>
Tue, 12 Jun 2007 14:35:26 +0000 (14:35 +0000)
committerUlrich Weigand <uweigand@de.ibm.com>
Tue, 12 Jun 2007 14:35:26 +0000 (14:35 +0000)
* spu-linux-nat.c (spu_xfer_partial): Handle TARGET_OBJECT_SPU.

* spu-tdep.h (SPU_NUM_PSEUDO_REGS): Add 5 pseudo registers.
(enum spu_regnum): Add SPU_FPSCR_REGNUM, SPU_SRR0_REGNUM,
SPU_LSLR_REGNUM, SPU_DECR_REGNUM, SPU_DECR_STATUS_REGNUM.
* spu-tdep.c (infospucmdlist): New variable.
(spu_register_name): Handle additional pseudo registers.
(spu_register_type): Likewise.
(spu_pseudo_register_read): Likewise.
(spu_pseudo_register_write): Likewise.
(spu_pseudo_register_read_spu): New function.
(spu_pseudo_register_write_spu): Likewise.
(info_spu_event_command): New function.
(info_spu_signal_command): Likewise.
(info_spu_mailbox_list): Likewise.
(info_spu_mailbox_command): Likewise.
(spu_mfc_get_bitfield): Likewise.
(info_spu_dma_cmdlist): Likewise.
(info_spu_dma_command): Likewise.
(info_spu_proxydma_command): Likewise.
(info_spu_command): Likewise.
(_initialize_spu_tdep): Install "info spu" commands.

testsuite/ChangeLog:

* gdb.arch/spu-info.exp: New testcase.
* gdb.arch/spu-info.c: New file.

doc/ChangeLog:

* gdb.texinfo (Architectures): Add new SPU section to document
Cell Broadband Engine SPU architecture specific commands.

gdb/ChangeLog
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/spu-linux-nat.c
gdb/spu-tdep.c
gdb/spu-tdep.h
gdb/target.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.arch/spu-info.c [new file with mode: 0644]
gdb/testsuite/gdb.arch/spu-info.exp [new file with mode: 0644]

index ddd98adebf86dba99559221ff45dc8f7b1c37c50..0d16e47cdaa4195bdb4800f1c28162a0eb896b81 100644 (file)
@@ -1,3 +1,29 @@
+2007-06-12  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * target.h (enum target_object): Add TARGET_OBJECT_SPU.
+       * spu-linux-nat.c (spu_xfer_partial): Handle TARGET_OBJECT_SPU.
+
+       * spu-tdep.h (SPU_NUM_PSEUDO_REGS): Add 5 pseudo registers.
+       (enum spu_regnum): Add SPU_FPSCR_REGNUM, SPU_SRR0_REGNUM,
+       SPU_LSLR_REGNUM, SPU_DECR_REGNUM, SPU_DECR_STATUS_REGNUM.
+       * spu-tdep.c (infospucmdlist): New variable.
+       (spu_register_name): Handle additional pseudo registers.
+       (spu_register_type): Likewise.
+       (spu_pseudo_register_read): Likewise.
+       (spu_pseudo_register_write): Likewise.
+       (spu_pseudo_register_read_spu): New function.
+       (spu_pseudo_register_write_spu): Likewise.
+       (info_spu_event_command): New function.
+       (info_spu_signal_command): Likewise.
+       (info_spu_mailbox_list): Likewise.
+       (info_spu_mailbox_command): Likewise.
+       (spu_mfc_get_bitfield): Likewise.
+       (info_spu_dma_cmdlist): Likewise.
+       (info_spu_dma_command): Likewise.
+       (info_spu_proxydma_command): Likewise.
+       (info_spu_command): Likewise.
+       (_initialize_spu_tdep): Install "info spu" commands.
+
 2007-06-12  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * spu-linux-nat.c (spu_proc_xfer_spu): Do not return failure when
index 38c3b856e6cbcf4a13080acbd4214ec74d4c3779..7a73f3bf03175ef07c26707e0bbdd0c1668b6f4d 100644 (file)
@@ -1,3 +1,9 @@
+2007-06-12  Ulrich Weigand  <uweigand@de.ibm.com>
+           Markus Deuling  <deuling@de.ibm.com>
+
+       * gdb.texinfo (Architectures): Add new SPU section to document
+       Cell Broadband Engine SPU architecture specific commands.
+
 2007-06-09  Vladimir Prus  <vladimir@codesourcery.com>
 
        * gdb.texinfo (GDB/MI Variable Objects): Editorial
index 7c04b2b28ee693ae6ce1196302dee1562f288758..0641386870cc4aa8dde1b7349654853addc7c7bd 100644 (file)
@@ -15100,6 +15100,7 @@ all uses of @value{GDBN} with the architecture, both native and cross.
 * Alpha::
 * MIPS::
 * HPPA::               HP PA architecture
+* SPU::                Cell Broadband Engine SPU architecture
 @end menu
 
 @node i386
@@ -15280,6 +15281,43 @@ given @var{address}.
 @end table
 
 
+@node SPU
+@subsection Cell Broadband Engine SPU architecture
+@cindex Cell Broadband Engine
+@cindex SPU
+
+When @value{GDBN} is debugging the Cell Broadband Engine SPU architecture,
+it provides the following special commands:
+
+@table @code
+@item info spu event
+@kindex info spu
+Display SPU event facility status.  Shows current event mask
+and pending event status.
+
+@item info spu signal
+Display SPU signal notification facility status.  Shows pending
+signal-control word and signal notification mode of both signal
+notification channels.
+
+@item info spu mailbox
+Display SPU mailbox facility status.  Shows all pending entries,
+in order of processing, in each of the SPU Write Outbound,
+SPU Write Outbound Interrupt, and SPU Read Inbound mailboxes.
+
+@item info spu dma
+Display MFC DMA status.  Shows all pending commands in the MFC
+DMA queue.  For each entry, opcode, tag, class IDs, effective
+and local store addresses and transfer size are shown.
+
+@item info spu proxydma
+Display MFC Proxy-DMA status.  Shows all pending commands in the MFC
+Proxy-DMA queue.  For each entry, opcode, tag, class IDs, effective
+and local store addresses and transfer size are shown.
+
+@end table
+
 @node Controlling GDB
 @chapter Controlling @value{GDBN}
 
index 21a7c5d00d796afdfd4c4dfcce32ae18168d32d5..3a03f2253367c98422669ef1070ea6f694d79450 100644 (file)
@@ -535,6 +535,9 @@ spu_xfer_partial (struct target_ops *ops,
                  gdb_byte *readbuf, const gdb_byte *writebuf,
                  ULONGEST offset, LONGEST len)
 {
+  if (object == TARGET_OBJECT_SPU)
+    return spu_proc_xfer_spu (annex, readbuf, writebuf, offset, len);
+
   if (object == TARGET_OBJECT_MEMORY)
     {
       int fd;
index 305201a930fb4bf4973387f2765dc945d119b21d..88720846b0b39e2c4cdfd2a862b118633f764588 100644 (file)
@@ -49,6 +49,9 @@
 /* SPU-specific vector type.  */
 struct type *spu_builtin_type_vec128;
 
+/* The list of available "info spu " commands.  */
+static struct cmd_list_element *infospucmdlist = NULL;
+
 /* Registers.  */
 
 static const char *
@@ -72,7 +75,7 @@ spu_register_name (int reg_nr)
       "r104", "r105", "r106", "r107", "r108", "r109", "r110", "r111",
       "r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
       "r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127",
-      "id", "pc", "sp"
+      "id", "pc", "sp", "fpscr", "srr0", "lslr", "decr", "decr_status"
     };
 
   if (reg_nr < 0)
@@ -100,6 +103,21 @@ spu_register_type (struct gdbarch *gdbarch, int reg_nr)
     case SPU_SP_REGNUM:
       return builtin_type_void_data_ptr;
 
+    case SPU_FPSCR_REGNUM:
+      return builtin_type_uint128;
+
+    case SPU_SRR0_REGNUM:
+      return builtin_type_uint32;
+
+    case SPU_LSLR_REGNUM:
+      return builtin_type_uint32;
+
+    case SPU_DECR_REGNUM:
+      return builtin_type_uint32;
+
+    case SPU_DECR_STATUS_REGNUM:
+      return builtin_type_uint32;
+
     default:
       internal_error (__FILE__, __LINE__, "invalid regnum");
     }
@@ -107,11 +125,30 @@ spu_register_type (struct gdbarch *gdbarch, int reg_nr)
 
 /* Pseudo registers for preferred slots - stack pointer.  */
 
+static void
+spu_pseudo_register_read_spu (struct regcache *regcache, const char *regname,
+                             gdb_byte *buf)
+{
+  gdb_byte reg[32];
+  char annex[32];
+  ULONGEST id;
+
+  regcache_raw_read_unsigned (regcache, SPU_ID_REGNUM, &id);
+  xsnprintf (annex, sizeof annex, "%d/%s", (int) id, regname);
+  memset (reg, 0, sizeof reg);
+  target_read (&current_target, TARGET_OBJECT_SPU, annex,
+              reg, 0, sizeof reg);
+
+  store_unsigned_integer (buf, 4, strtoulst (reg, NULL, 16));
+}
+
 static void
 spu_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
                           int regnum, gdb_byte *buf)
 {
   gdb_byte reg[16];
+  char annex[32];
+  ULONGEST id;
 
   switch (regnum)
     {
@@ -120,16 +157,56 @@ spu_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
       memcpy (buf, reg, 4);
       break;
 
+    case SPU_FPSCR_REGNUM:
+      regcache_raw_read_unsigned (regcache, SPU_ID_REGNUM, &id);
+      xsnprintf (annex, sizeof annex, "%d/fpcr", (int) id);
+      target_read (&current_target, TARGET_OBJECT_SPU, annex, buf, 0, 16);
+      break;
+
+    case SPU_SRR0_REGNUM:
+      spu_pseudo_register_read_spu (regcache, "srr0", buf);
+      break;
+
+    case SPU_LSLR_REGNUM:
+      spu_pseudo_register_read_spu (regcache, "lslr", buf);
+      break;
+
+    case SPU_DECR_REGNUM:
+      spu_pseudo_register_read_spu (regcache, "decr", buf);
+      break;
+
+    case SPU_DECR_STATUS_REGNUM:
+      spu_pseudo_register_read_spu (regcache, "decr_status", buf);
+      break;
+
     default:
       internal_error (__FILE__, __LINE__, _("invalid regnum"));
     }
 }
 
+static void
+spu_pseudo_register_write_spu (struct regcache *regcache, const char *regname,
+                              const gdb_byte *buf)
+{
+  gdb_byte reg[32];
+  char annex[32];
+  ULONGEST id;
+
+  regcache_raw_read_unsigned (regcache, SPU_ID_REGNUM, &id);
+  xsnprintf (annex, sizeof annex, "%d/%s", (int) id, regname);
+  xsnprintf (reg, sizeof reg, "0x%s",
+            phex_nz (extract_unsigned_integer (buf, 4), 4));
+  target_write (&current_target, TARGET_OBJECT_SPU, annex,
+               reg, 0, strlen (reg));
+}
+
 static void
 spu_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
                            int regnum, const gdb_byte *buf)
 {
   gdb_byte reg[16];
+  char annex[32];
+  ULONGEST id;
 
   switch (regnum)
     {
@@ -139,6 +216,28 @@ spu_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
       regcache_raw_write (regcache, SPU_RAW_SP_REGNUM, reg);
       break;
 
+    case SPU_FPSCR_REGNUM:
+      regcache_raw_read_unsigned (regcache, SPU_ID_REGNUM, &id);
+      xsnprintf (annex, sizeof annex, "%d/fpcr", (int) id);
+      target_write (&current_target, TARGET_OBJECT_SPU, annex, buf, 0, 16);
+      break;
+
+    case SPU_SRR0_REGNUM:
+      spu_pseudo_register_write_spu (regcache, "srr0", buf);
+      break;
+
+    case SPU_LSLR_REGNUM:
+      spu_pseudo_register_write_spu (regcache, "lslr", buf);
+      break;
+
+    case SPU_DECR_REGNUM:
+      spu_pseudo_register_write_spu (regcache, "decr", buf);
+      break;
+
+    case SPU_DECR_STATUS_REGNUM:
+      spu_pseudo_register_write_spu (regcache, "decr_status", buf);
+      break;
+
     default:
       internal_error (__FILE__, __LINE__, _("invalid regnum"));
     }
@@ -1318,6 +1417,502 @@ spu_overlay_new_objfile (struct objfile *objfile)
 }
 
 
+/* "info spu" commands.  */
+
+static void
+info_spu_event_command (char *args, int from_tty)
+{
+  struct frame_info *frame = get_selected_frame (NULL);
+  ULONGEST event_status = 0;
+  ULONGEST event_mask = 0;
+  struct cleanup *chain;
+  gdb_byte buf[100];
+  char annex[32];
+  LONGEST len;
+  int rc, id;
+
+  id = get_frame_register_unsigned (frame, SPU_ID_REGNUM);
+
+  xsnprintf (annex, sizeof annex, "%d/event_status", id);
+  len = target_read (&current_target, TARGET_OBJECT_SPU, annex,
+                    buf, 0, sizeof buf);
+  if (len <= 0)
+    error (_("Could not read event_status."));
+  event_status = strtoulst (buf, NULL, 16);
+  xsnprintf (annex, sizeof annex, "%d/event_mask", id);
+  len = target_read (&current_target, TARGET_OBJECT_SPU, annex,
+                    buf, 0, sizeof buf);
+  if (len <= 0)
+    error (_("Could not read event_mask."));
+  event_mask = strtoulst (buf, NULL, 16);
+  chain = make_cleanup_ui_out_tuple_begin_end (uiout, "SPUInfoEvent");
+
+  if (ui_out_is_mi_like_p (uiout))
+    {
+      ui_out_field_fmt (uiout, "event_status",
+                       "0x%s", phex_nz (event_status, 4));
+      ui_out_field_fmt (uiout, "event_mask",
+                       "0x%s", phex_nz (event_mask, 4));
+    }
+  else
+    {
+      printf_filtered (_("Event Status 0x%s\n"), phex (event_status, 4));
+      printf_filtered (_("Event Mask   0x%s\n"), phex (event_mask, 4));
+    }
+
+  do_cleanups (chain);
+}
+
+static void
+info_spu_signal_command (char *args, int from_tty)
+{
+  struct frame_info *frame = get_selected_frame (NULL);
+  ULONGEST signal1 = 0;
+  ULONGEST signal1_type = 0;
+  int signal1_pending = 0;
+  ULONGEST signal2 = 0;
+  ULONGEST signal2_type = 0;
+  int signal2_pending = 0;
+  struct cleanup *chain;
+  char annex[32];
+  gdb_byte buf[100];
+  LONGEST len;
+  int rc, id;
+
+  id = get_frame_register_unsigned (frame, SPU_ID_REGNUM);
+
+  xsnprintf (annex, sizeof annex, "%d/signal1", id);
+  len = target_read (&current_target, TARGET_OBJECT_SPU, annex, buf, 0, 4);
+  if (len < 0)
+    error (_("Could not read signal1."));
+  else if (len == 4)
+    {
+      signal1 = extract_unsigned_integer (buf, 4);
+      signal1_pending = 1;
+    }
+    
+  xsnprintf (annex, sizeof annex, "%d/signal1_type", id);
+  len = target_read (&current_target, TARGET_OBJECT_SPU, annex,
+                    buf, 0, sizeof buf);
+  if (len <= 0)
+    error (_("Could not read signal1_type."));
+  signal1_type = strtoulst (buf, NULL, 16);
+
+  xsnprintf (annex, sizeof annex, "%d/signal2", id);
+  len = target_read (&current_target, TARGET_OBJECT_SPU, annex, buf, 0, 4);
+  if (len < 0)
+    error (_("Could not read signal2."));
+  else if (len == 4)
+    {
+      signal2 = extract_unsigned_integer (buf, 4);
+      signal2_pending = 1;
+    }
+    
+  xsnprintf (annex, sizeof annex, "%d/signal2_type", id);
+  len = target_read (&current_target, TARGET_OBJECT_SPU, annex,
+                    buf, 0, sizeof buf);
+  if (len <= 0)
+    error (_("Could not read signal2_type."));
+  signal2_type = strtoulst (buf, NULL, 16);
+
+  chain = make_cleanup_ui_out_tuple_begin_end (uiout, "SPUInfoSignal");
+
+  if (ui_out_is_mi_like_p (uiout))
+    {
+      ui_out_field_int (uiout, "signal1_pending", signal1_pending);
+      ui_out_field_fmt (uiout, "signal1", "0x%s", phex_nz (signal1, 4));
+      ui_out_field_int (uiout, "signal1_type", signal1_type);
+      ui_out_field_int (uiout, "signal2_pending", signal2_pending);
+      ui_out_field_fmt (uiout, "signal2", "0x%s", phex_nz (signal2, 4));
+      ui_out_field_int (uiout, "signal2_type", signal2_type);
+    }
+  else
+    {
+      if (signal1_pending)
+       printf_filtered (_("Signal 1 control word 0x%s "), phex (signal1, 4));
+      else
+       printf_filtered (_("Signal 1 not pending "));
+
+      if (signal1_type)
+       printf_filtered (_("(Type Overwrite)\n"));
+      else
+       printf_filtered (_("(Type Or)\n"));
+
+      if (signal2_pending)
+       printf_filtered (_("Signal 2 control word 0x%s "), phex (signal2, 4));
+      else
+       printf_filtered (_("Signal 2 not pending "));
+
+      if (signal2_type)
+       printf_filtered (_("(Type Overwrite)\n"));
+      else
+       printf_filtered (_("(Type Or)\n"));
+    }
+
+  do_cleanups (chain);
+}
+
+static void
+info_spu_mailbox_list (gdb_byte *buf, int nr,
+                      const char *field, const char *msg)
+{
+  struct cleanup *chain;
+  int i;
+
+  if (nr <= 0)
+    return;
+
+  chain = make_cleanup_ui_out_table_begin_end (uiout, 1, nr, "mbox");
+
+  ui_out_table_header (uiout, 32, ui_left, field, msg);
+  ui_out_table_body (uiout);
+
+  for (i = 0; i < nr; i++)
+    {
+      struct cleanup *val_chain;
+      ULONGEST val;
+      val_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "mbox");
+      val = extract_unsigned_integer (buf + 4*i, 4);
+      ui_out_field_fmt (uiout, field, "0x%s", phex (val, 4));
+      do_cleanups (val_chain);
+
+      if (!ui_out_is_mi_like_p (uiout))
+       printf_filtered ("\n");
+    }
+
+  do_cleanups (chain);
+}
+
+static void
+info_spu_mailbox_command (char *args, int from_tty)
+{
+  struct frame_info *frame = get_selected_frame (NULL);
+  struct cleanup *chain;
+  char annex[32];
+  gdb_byte buf[1024];
+  LONGEST len;
+  int i, id;
+
+  id = get_frame_register_unsigned (frame, SPU_ID_REGNUM);
+
+  chain = make_cleanup_ui_out_tuple_begin_end (uiout, "SPUInfoMailbox");
+
+  xsnprintf (annex, sizeof annex, "%d/mbox_info", id);
+  len = target_read (&current_target, TARGET_OBJECT_SPU, annex,
+                    buf, 0, sizeof buf);
+  if (len < 0)
+    error (_("Could not read mbox_info."));
+
+  info_spu_mailbox_list (buf, len / 4, "mbox", "SPU Outbound Mailbox");
+
+  xsnprintf (annex, sizeof annex, "%d/ibox_info", id);
+  len = target_read (&current_target, TARGET_OBJECT_SPU, annex,
+                    buf, 0, sizeof buf);
+  if (len < 0)
+    error (_("Could not read ibox_info."));
+
+  info_spu_mailbox_list (buf, len / 4, "ibox", "SPU Outbound Interrupt Mailbox");
+
+  xsnprintf (annex, sizeof annex, "%d/wbox_info", id);
+  len = target_read (&current_target, TARGET_OBJECT_SPU, annex,
+                    buf, 0, sizeof buf);
+  if (len < 0)
+    error (_("Could not read wbox_info."));
+
+  info_spu_mailbox_list (buf, len / 4, "wbox", "SPU Inbound Mailbox");
+
+  do_cleanups (chain);
+}
+
+static ULONGEST
+spu_mfc_get_bitfield (ULONGEST word, int first, int last)
+{
+  ULONGEST mask = ~(~(ULONGEST)0 << (last - first + 1));
+  return (word >> (63 - last)) & mask;
+}
+
+static void
+info_spu_dma_cmdlist (gdb_byte *buf, int nr)
+{
+  static char *spu_mfc_opcode[256] =
+    {
+    /* 00 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    /* 10 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    /* 20 */ "put", "putb", "putf", NULL, "putl", "putlb", "putlf", NULL,
+             "puts", "putbs", "putfs", NULL, NULL, NULL, NULL, NULL,
+    /* 30 */ "putr", "putrb", "putrf", NULL, "putrl", "putrlb", "putrlf", NULL,
+             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    /* 40 */ "get", "getb", "getf", NULL, "getl", "getlb", "getlf", NULL,
+             "gets", "getbs", "getfs", NULL, NULL, NULL, NULL, NULL,
+    /* 50 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    /* 60 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    /* 70 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    /* 80 */ "sdcrt", "sdcrtst", NULL, NULL, NULL, NULL, NULL, NULL,
+             NULL, "sdcrz", NULL, NULL, NULL, "sdcrst", NULL, "sdcrf",
+    /* 90 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    /* a0 */ "sndsig", "sndsigb", "sndsigf", NULL, NULL, NULL, NULL, NULL,
+             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    /* b0 */ "putlluc", NULL, NULL, NULL, "putllc", NULL, NULL, NULL,
+             "putqlluc", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    /* c0 */ "barrier", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+             "mfceieio", NULL, NULL, NULL, "mfcsync", NULL, NULL, NULL,
+    /* d0 */ "getllar", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    /* e0 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    /* f0 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    };
+
+  struct cleanup *chain;
+  int i;
+
+  chain = make_cleanup_ui_out_table_begin_end (uiout, 10, nr, "dma_cmd");
+
+  ui_out_table_header (uiout, 7, ui_left, "opcode", "Opcode");
+  ui_out_table_header (uiout, 3, ui_left, "tag", "Tag");
+  ui_out_table_header (uiout, 3, ui_left, "tid", "TId");
+  ui_out_table_header (uiout, 3, ui_left, "rid", "RId");
+  ui_out_table_header (uiout, 18, ui_left, "ea", "EA");
+  ui_out_table_header (uiout, 7, ui_left, "lsa", "LSA");
+  ui_out_table_header (uiout, 7, ui_left, "size", "Size");
+  ui_out_table_header (uiout, 7, ui_left, "lstaddr", "LstAddr");
+  ui_out_table_header (uiout, 7, ui_left, "lstsize", "LstSize");
+  ui_out_table_header (uiout, 1, ui_left, "error_p", "E");
+
+  ui_out_table_body (uiout);
+
+  for (i = 0; i < nr; i++)
+    {
+      struct cleanup *cmd_chain;
+      ULONGEST mfc_cq_dw0;
+      ULONGEST mfc_cq_dw1;
+      ULONGEST mfc_cq_dw2;
+      ULONGEST mfc_cq_dw3;
+      int mfc_cmd_opcode, mfc_cmd_tag, rclass_id, tclass_id;
+      int lsa, size, list_lsa, list_size, mfc_lsa, mfc_size;
+      ULONGEST mfc_ea;
+      int list_valid_p, noop_valid_p, qw_valid_p, ea_valid_p, cmd_error_p;
+
+      /* Decode contents of MFC Command Queue Context Save/Restore Registers.
+        See "Cell Broadband Engine Registers V1.3", section 3.3.2.1.  */
+
+      mfc_cq_dw0 = extract_unsigned_integer (buf + 32*i, 8);
+      mfc_cq_dw1 = extract_unsigned_integer (buf + 32*i + 8, 8);
+      mfc_cq_dw2 = extract_unsigned_integer (buf + 32*i + 16, 8);
+      mfc_cq_dw3 = extract_unsigned_integer (buf + 32*i + 24, 8);
+
+      list_lsa = spu_mfc_get_bitfield (mfc_cq_dw0, 0, 14);
+      list_size = spu_mfc_get_bitfield (mfc_cq_dw0, 15, 26);
+      mfc_cmd_opcode = spu_mfc_get_bitfield (mfc_cq_dw0, 27, 34);
+      mfc_cmd_tag = spu_mfc_get_bitfield (mfc_cq_dw0, 35, 39);
+      list_valid_p = spu_mfc_get_bitfield (mfc_cq_dw0, 40, 40);
+      rclass_id = spu_mfc_get_bitfield (mfc_cq_dw0, 41, 43);
+      tclass_id = spu_mfc_get_bitfield (mfc_cq_dw0, 44, 46);
+
+      mfc_ea = spu_mfc_get_bitfield (mfc_cq_dw1, 0, 51) << 12
+               | spu_mfc_get_bitfield (mfc_cq_dw2, 25, 36);
+
+      mfc_lsa = spu_mfc_get_bitfield (mfc_cq_dw2, 0, 13);
+      mfc_size = spu_mfc_get_bitfield (mfc_cq_dw2, 14, 24);
+      noop_valid_p = spu_mfc_get_bitfield (mfc_cq_dw2, 37, 37);
+      qw_valid_p = spu_mfc_get_bitfield (mfc_cq_dw2, 38, 38);
+      ea_valid_p = spu_mfc_get_bitfield (mfc_cq_dw2, 39, 39);
+      cmd_error_p = spu_mfc_get_bitfield (mfc_cq_dw2, 40, 40);
+
+      cmd_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "cmd");
+
+      if (spu_mfc_opcode[mfc_cmd_opcode])
+       ui_out_field_string (uiout, "opcode", spu_mfc_opcode[mfc_cmd_opcode]);
+      else
+       ui_out_field_int (uiout, "opcode", mfc_cmd_opcode);
+
+      ui_out_field_int (uiout, "tag", mfc_cmd_tag);
+      ui_out_field_int (uiout, "tid", tclass_id);
+      ui_out_field_int (uiout, "rid", rclass_id);
+
+      if (ea_valid_p)
+       ui_out_field_fmt (uiout, "ea", "0x%s", phex (mfc_ea, 8));
+      else
+       ui_out_field_skip (uiout, "ea");
+
+      ui_out_field_fmt (uiout, "lsa", "0x%05x", mfc_lsa << 4);
+      if (qw_valid_p)
+       ui_out_field_fmt (uiout, "size", "0x%05x", mfc_size << 4);
+      else
+       ui_out_field_fmt (uiout, "size", "0x%05x", mfc_size);
+
+      if (list_valid_p)
+       {
+         ui_out_field_fmt (uiout, "lstaddr", "0x%05x", list_lsa << 3);
+         ui_out_field_fmt (uiout, "lstsize", "0x%05x", list_size << 3);
+       }
+      else
+       {
+         ui_out_field_skip (uiout, "lstaddr");
+         ui_out_field_skip (uiout, "lstsize");
+       }
+
+      if (cmd_error_p)
+       ui_out_field_string (uiout, "error_p", "*");
+      else
+       ui_out_field_skip (uiout, "error_p");
+
+      do_cleanups (cmd_chain);
+
+      if (!ui_out_is_mi_like_p (uiout))
+       printf_filtered ("\n");
+    }
+
+  do_cleanups (chain);
+}
+
+static void
+info_spu_dma_command (char *args, int from_tty)
+{
+  struct frame_info *frame = get_selected_frame (NULL);
+  ULONGEST dma_info_type;
+  ULONGEST dma_info_mask;
+  ULONGEST dma_info_status;
+  ULONGEST dma_info_stall_and_notify;
+  ULONGEST dma_info_atomic_command_status;
+  struct cleanup *chain;
+  char annex[32];
+  gdb_byte buf[1024];
+  LONGEST len;
+  int i, id;
+
+  id = get_frame_register_unsigned (frame, SPU_ID_REGNUM);
+
+  xsnprintf (annex, sizeof annex, "%d/dma_info", id);
+  len = target_read (&current_target, TARGET_OBJECT_SPU, annex,
+                    buf, 0, 40 + 16 * 32);
+  if (len <= 0)
+    error (_("Could not read dma_info."));
+
+  dma_info_type = extract_unsigned_integer (buf, 8);
+  dma_info_mask = extract_unsigned_integer (buf + 8, 8);
+  dma_info_status = extract_unsigned_integer (buf + 16, 8);
+  dma_info_stall_and_notify = extract_unsigned_integer (buf + 24, 8);
+  dma_info_atomic_command_status = extract_unsigned_integer (buf + 32, 8);
+  
+  chain = make_cleanup_ui_out_tuple_begin_end (uiout, "SPUInfoDMA");
+
+  if (ui_out_is_mi_like_p (uiout))
+    {
+      ui_out_field_fmt (uiout, "dma_info_type", "0x%s",
+                       phex_nz (dma_info_type, 4));
+      ui_out_field_fmt (uiout, "dma_info_mask", "0x%s",
+                       phex_nz (dma_info_mask, 4));
+      ui_out_field_fmt (uiout, "dma_info_status", "0x%s",
+                       phex_nz (dma_info_status, 4));
+      ui_out_field_fmt (uiout, "dma_info_stall_and_notify", "0x%s",
+                       phex_nz (dma_info_stall_and_notify, 4));
+      ui_out_field_fmt (uiout, "dma_info_atomic_command_status", "0x%s",
+                       phex_nz (dma_info_atomic_command_status, 4));
+    }
+  else
+    {
+      const char *query_msg;
+
+      switch (dma_info_type)
+       {
+       case 0: query_msg = _("no query pending"); break;
+       case 1: query_msg = _("'any' query pending"); break;
+       case 2: query_msg = _("'all' query pending"); break;
+       default: query_msg = _("undefined query type"); break;
+       }
+
+      printf_filtered (_("Tag-Group Status  0x%s\n"),
+                      phex (dma_info_status, 4));
+      printf_filtered (_("Tag-Group Mask    0x%s (%s)\n"),
+                      phex (dma_info_mask, 4), query_msg);
+      printf_filtered (_("Stall-and-Notify  0x%s\n"),
+                      phex (dma_info_stall_and_notify, 4));
+      printf_filtered (_("Atomic Cmd Status 0x%s\n"),
+                      phex (dma_info_atomic_command_status, 4));
+      printf_filtered ("\n");
+    }
+
+  info_spu_dma_cmdlist (buf + 40, 16);
+  do_cleanups (chain);
+}
+
+static void
+info_spu_proxydma_command (char *args, int from_tty)
+{
+  struct frame_info *frame = get_selected_frame (NULL);
+  ULONGEST dma_info_type;
+  ULONGEST dma_info_mask;
+  ULONGEST dma_info_status;
+  struct cleanup *chain;
+  char annex[32];
+  gdb_byte buf[1024];
+  LONGEST len;
+  int i, id;
+
+  id = get_frame_register_unsigned (frame, SPU_ID_REGNUM);
+
+  xsnprintf (annex, sizeof annex, "%d/proxydma_info", id);
+  len = target_read (&current_target, TARGET_OBJECT_SPU, annex,
+                    buf, 0, 24 + 8 * 32);
+  if (len <= 0)
+    error (_("Could not read proxydma_info."));
+
+  dma_info_type = extract_unsigned_integer (buf, 8);
+  dma_info_mask = extract_unsigned_integer (buf + 8, 8);
+  dma_info_status = extract_unsigned_integer (buf + 16, 8);
+  
+  chain = make_cleanup_ui_out_tuple_begin_end (uiout, "SPUInfoProxyDMA");
+
+  if (ui_out_is_mi_like_p (uiout))
+    {
+      ui_out_field_fmt (uiout, "proxydma_info_type", "0x%s",
+                       phex_nz (dma_info_type, 4));
+      ui_out_field_fmt (uiout, "proxydma_info_mask", "0x%s",
+                       phex_nz (dma_info_mask, 4));
+      ui_out_field_fmt (uiout, "proxydma_info_status", "0x%s",
+                       phex_nz (dma_info_status, 4));
+    }
+  else
+    {
+      const char *query_msg;
+
+      switch (dma_info_type)
+       {
+       case 0: query_msg = _("no query pending"); break;
+       case 1: query_msg = _("'any' query pending"); break;
+       case 2: query_msg = _("'all' query pending"); break;
+       default: query_msg = _("undefined query type"); break;
+       }
+
+      printf_filtered (_("Tag-Group Status  0x%s\n"),
+                      phex (dma_info_status, 4));
+      printf_filtered (_("Tag-Group Mask    0x%s (%s)\n"),
+                      phex (dma_info_mask, 4), query_msg);
+      printf_filtered ("\n");
+    }
+
+  info_spu_dma_cmdlist (buf + 24, 8);
+  do_cleanups (chain);
+}
+
+static void
+info_spu_command (char *args, int from_tty)
+{
+  printf_unfiltered (_("\"info spu\" must be followed by the name of an SPU facility.\n"));
+  help_list (infospucmdlist, "info spu ", -1, gdb_stdout);
+}
+
+
 /* Set up gdbarch struct.  */
 
 static struct gdbarch *
@@ -1430,4 +2025,26 @@ _initialize_spu_tdep (void)
   /* Add ourselves to objfile event chain.  */
   observer_attach_new_objfile (spu_overlay_new_objfile);
   spu_overlay_data = register_objfile_data ();
+
+  /* Add root prefix command for all "info spu" commands.  */
+  add_prefix_cmd ("spu", class_info, info_spu_command,
+                 _("Various SPU specific commands."),
+                 &infospucmdlist, "info spu ", 0, &infolist);
+
+  /* Add various "info spu" commands.  */
+  add_cmd ("event", class_info, info_spu_event_command,
+          _("Display SPU event facility status.\n"),
+          &infospucmdlist);
+  add_cmd ("signal", class_info, info_spu_signal_command,
+          _("Display SPU signal notification facility status.\n"),
+          &infospucmdlist);
+  add_cmd ("mailbox", class_info, info_spu_mailbox_command,
+          _("Display SPU mailbox facility status.\n"),
+          &infospucmdlist);
+  add_cmd ("dma", class_info, info_spu_dma_command,
+          _("Display MFC DMA status.\n"),
+          &infospucmdlist);
+  add_cmd ("proxydma", class_info, info_spu_proxydma_command,
+          _("Display MFC Proxy-DMA status.\n"),
+          &infospucmdlist);
 }
index 7d0df185391f5fda87e6a4d02fa61a872769babc..d573608393d23c90a25a9d2e5c29a5f18070dc20 100644 (file)
@@ -23,7 +23,7 @@
 
 /* Number of registers.  */
 #define SPU_NUM_REGS         130
-#define SPU_NUM_PSEUDO_REGS  1
+#define SPU_NUM_PSEUDO_REGS  6
 #define SPU_NUM_GPRS        128
 
 /* Register numbers of various important registers.  */
@@ -41,7 +41,12 @@ enum spu_regnum
   /* Special registers.  */
   SPU_ID_REGNUM = 128,         /* SPU ID register.  */
   SPU_PC_REGNUM = 129,         /* Next program counter.  */
-  SPU_SP_REGNUM = 130          /* Stack pointer (preferred slot).  */
+  SPU_SP_REGNUM = 130,         /* Stack pointer (preferred slot).  */
+  SPU_FPSCR_REGNUM = 131,      /* Floating point status/control register.  */
+  SPU_SRR0_REGNUM = 132,       /* SRR0 register.  */
+  SPU_LSLR_REGNUM = 133,       /* Local store limit register.  */
+  SPU_DECR_REGNUM = 134,       /* Decrementer value.  */
+  SPU_DECR_STATUS_REGNUM = 135 /* Decrementer status.  */
 };
 
 /* Local store.  */
index 24db1361965cd797b5d0fe7bde31430846b753d4..7cde49b64507a4c90b441f7ee22d6e6abbe83692 100644 (file)
@@ -189,6 +189,8 @@ enum target_object
 {
   /* AVR target specific transfer.  See "avr-tdep.c" and "remote.c".  */
   TARGET_OBJECT_AVR,
+  /* SPU target specific transfer.  See "spu-tdep.c".  */
+  TARGET_OBJECT_SPU,
   /* Transfer up-to LEN bytes of memory starting at OFFSET.  */
   TARGET_OBJECT_MEMORY,
   /* Memory, avoiding GDB's data cache and trusting the executable.
index 80d31af48cd6fb8907522b4763b2565bcd261544..c953e57f334820ddbc37d4433d5446d7c85ed618 100644 (file)
@@ -1,3 +1,9 @@
+2007-06-12  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
+           Markus Deuling  <deuling@de.ibm.com>
+
+       * gdb.arch/spu-info.exp: New testcase.
+       * gdb.arch/spu-info.c: New file.
+
 2007-06-05  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * gdb.arch/thumb-prologue.c: Record the breakpoint address in
diff --git a/gdb/testsuite/gdb.arch/spu-info.c b/gdb/testsuite/gdb.arch/spu-info.c
new file mode 100644 (file)
index 0000000..1fc83ec
--- /dev/null
@@ -0,0 +1,236 @@
+/* Copyright 2007 Free Software Foundation, Inc.
+
+   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.
+
+   This file is part of the gdb testsuite.
+
+   Contributed by Markus Deuling <deuling@de.ibm.com>.
+   Tests for 'info spu' commands.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <spu_mfcio.h>
+
+
+/* PPE-assisted call interface.  */
+void
+send_to_ppe (unsigned int signalcode, unsigned int opcode, void *data)
+{
+  __vector unsigned int stopfunc =
+    {
+      signalcode,     /* stop */
+      (opcode << 24) | (unsigned int) data,
+      0x4020007f,     /* nop */
+      0x35000000      /* bi $0 */
+    };
+
+  void (*f) (void) = (void *) &stopfunc;
+  asm ("sync");
+  f ();
+}
+
+/* PPE-assisted call to mmap from SPU.  */
+unsigned long long
+mmap_ea (unsigned long long start, size_t length,
+         int prot, int flags, int fd, off_t offset)
+{
+  struct mmap_args
+    {
+      unsigned long long start __attribute__ ((aligned (16)));
+      size_t length __attribute__ ((aligned (16)));
+      int prot __attribute__ ((aligned (16)));
+      int flags __attribute__ ((aligned (16)));
+      int fd __attribute__ ((aligned (16)));
+      off_t offset __attribute__ ((aligned (16)));
+    } args;
+
+  args.start = start;
+  args.length = length;
+  args.prot = prot;
+  args.flags = flags;
+  args.fd = fd;
+  args.offset = offset;
+
+  send_to_ppe (0x2101, 11, &args);
+  return args.start;
+}
+
+/* This works only in a Linux environment with <= 1024 open
+   file descriptors for one process. Result is the file
+   descriptor for the current context if available.  */
+int
+find_context_fd (void)
+{
+  int dir_fd = -1;
+  int i;
+
+  for (i = 0; i < 1024; i++)
+    {
+      struct stat stat;
+
+      if (fstat (i, &stat) < 0)
+        break;
+      if (S_ISDIR (stat.st_mode))
+        dir_fd = dir_fd == -1 ? i : -2;
+    }
+  return dir_fd < 0 ? -1 : dir_fd;
+}
+
+/* Open the context file and return the file handler.  */
+int
+open_context_file (int context_fd, char *name, int flags)
+{
+  char buf[128];
+
+  if (context_fd < 0)
+    return -1;
+
+  sprintf (buf, "/proc/self/fd/%d/%s", context_fd, name);
+  return open (buf, flags);
+}
+
+
+int
+do_event_test ()
+{
+  spu_write_event_mask (MFC_MULTI_SRC_SYNC_EVENT); /* 0x1000 */  /* Marker Event */
+  spu_write_event_mask (MFC_PRIV_ATTN_EVENT); /* 0x0800 */
+  spu_write_event_mask (MFC_LLR_LOST_EVENT); /* 0x0400 */
+  spu_write_event_mask (MFC_SIGNAL_NOTIFY_1_EVENT); /* 0x0200 */
+  spu_write_event_mask (MFC_SIGNAL_NOTIFY_2_EVENT); /* 0x0100 */
+  spu_write_event_mask (MFC_OUT_MBOX_AVAILABLE_EVENT); /* 0x0080 */
+  spu_write_event_mask (MFC_OUT_INTR_MBOX_AVAILABLE_EVENT); /* 0x0040 */
+  spu_write_event_mask (MFC_DECREMENTER_EVENT); /* 0x0020 */
+  spu_write_event_mask (MFC_IN_MBOX_AVAILABLE_EVENT); /* 0x0010 */
+  spu_write_event_mask (MFC_COMMAND_QUEUE_AVAILABLE_EVENT); /* 0x0008 */
+  spu_write_event_mask (MFC_LIST_STALL_NOTIFY_EVENT); /* 0x0002 */
+  spu_write_event_mask (MFC_TAG_STATUS_UPDATE_EVENT); /* 0x0001 */
+
+  return 0;
+}
+
+int
+do_dma_test ()
+{
+  #define MAP_FAILED      (-1ULL)
+  #define PROT_READ       0x1
+  #define MAP_PRIVATE     0x002
+  #define BSIZE 128
+  static char buf[BSIZE] __attribute__ ((aligned (128)));
+  char *file = "/var/tmp/tmp_buf";
+  struct stat fdstat;
+  int fd, cnt;
+  unsigned long long src;
+
+  /* Create a file and fill it with some bytes.  */
+  fd = open (file, O_CREAT | O_RDWR | O_TRUNC, 0777);
+  if (fd == -1)
+    return -1;
+  memset ((void *)buf, '1', BSIZE);
+  write (fd, buf, BSIZE);
+  write (fd, buf, BSIZE);
+  memset ((void *)buf, 0, BSIZE);
+
+  if (fstat (fd, &fdstat) != 0
+      || !fdstat.st_size)
+    return -2;
+
+  src = mmap_ea(0ULL, fdstat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+  if (src == MAP_FAILED)
+    return -3;
+
+  /* Copy some data via DMA.  */
+  mfc_get (&buf, src, BSIZE, 5, 0, 0);   /* Marker DMA */
+  mfc_write_tag_mask (1<<5);   /* Marker DMAWait */
+  spu_mfcstat (MFC_TAG_UPDATE_ALL);
+
+  /* Close the file.  */
+  close (fd);
+
+  return cnt;
+}
+
+int
+do_mailbox_test ()
+{
+  /* Write to SPU Outbound Mailbox.  */
+  if (spu_stat_out_mbox ())            /* Marker Mbox */
+    spu_write_out_mbox (0x12345678);
+
+  /* Write to SPU Outbound Interrupt Mailbox.  */
+  if (spu_stat_out_intr_mbox ())
+    spu_write_out_intr_mbox (0x12345678);
+
+  return 0;       /* Marker MboxEnd */
+}
+
+int
+do_signal_test ()
+{
+  struct stat fdstat;
+  int context_fd = find_context_fd ();
+  int ret, buf, fd;
+
+  buf = 23;    /* Marker Signal */
+  /* Write to signal1.  */
+  fd = open_context_file (context_fd, "signal1", O_RDWR);
+  if (fstat (fd, &fdstat) != 0)
+    return -1;
+  ret = write (fd, buf, sizeof (int));
+  close (fd);  /* Marker Signal1 */
+
+  /* Write to signal2.  */
+  fd = open_context_file (context_fd, "signal2", O_RDWR);
+  if (fstat (fd, &fdstat) != 0)
+    return -1;
+  ret = write (fd, buf, sizeof (int));
+  close (fd);  /* Marker Signal2 */
+
+  /* Read signal1.  */
+  if (spu_stat_signal1 ())
+    ret = spu_read_signal1 ();
+
+  /* Read signal2.  */
+  if (spu_stat_signal2 ())
+    ret = spu_read_signal2 ();   /* Marker SignalRead */
+
+  return 0;
+}
+
+int
+main (unsigned long long speid, unsigned long long argp, 
+      unsigned long long envp)
+{
+  int res;
+
+  /* info spu event  */
+  res = do_event_test ();
+
+  /* info spu dma  */
+  res = do_dma_test ();
+
+  /* info spu mailbox  */
+  res = do_mailbox_test ();
+
+  /* info spu signal  */
+  res = do_signal_test ();
+
+  return 0;
+}
+
diff --git a/gdb/testsuite/gdb.arch/spu-info.exp b/gdb/testsuite/gdb.arch/spu-info.exp
new file mode 100644 (file)
index 0000000..61e997a
--- /dev/null
@@ -0,0 +1,243 @@
+# Copyright 2007 Free Software Foundation, Inc.
+#
+# 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.  
+#
+# This file is part of the gdb testsuite.
+#
+# Contributed by Markus Deuling <deuling@de.ibm.com>.
+# Tests for 'info spu' commands.
+
+set prms_id 0
+set bug_id 0
+
+if { ![istarget "spu-*-elf"] } then {
+  verbose "Skipping SPU-only testcase"
+  return
+}
+
+set testfile "spu-info"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+set sources ${srcdir}/${subdir}/${srcfile}
+
+if { [gdb_compile $sources ${binfile} executable { debug }] != "" } {
+  return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# Continue to MARKER
+proc c_to { marker } {
+  global srcfile
+  set line [gdb_get_line_number $marker]
+  gdb_test "break $line" \
+          "Breakpoint.*at.*file.*$srcfile.*line $line.*" \
+          "break $line"
+  gdb_test "continue" \
+          "Continuing.*Breakpoint.*at.*$srcfile.*$line.*" \
+          "continue to $line"
+}
+
+
+
+if ![runto_main] then {
+  fail "Can't run to main"
+  return 0
+}
+
+# Check the help.
+gdb_test "info spu" \
+        ".*info spu.* must be followed by the name of an SPU facility.*" \
+        "info spu"
+gdb_test "help info spu" \
+        "Various SPU specific commands.*List of info spu subcommands.*" \
+        "help info spu"
+
+gdb_test "help info spu dma" \
+        "Display MFC DMA status." \
+        "help info spu dma"
+gdb_test "help info spu event" \
+        "Display SPU event facility status." \
+        "help info spu event"
+gdb_test "help info spu mailbox" \
+        "Display SPU mailbox facility status." \
+        "help info spu mailbox"
+gdb_test "help info spu proxydma" \
+        "Display MFC Proxy-DMA status." \
+        "help info spu proxydma"
+gdb_test "help info spu signal" \
+        "Display SPU signal notification facility status." \
+        "help info spu signal"
+
+
+# architecture should be spu:256K.
+gdb_test "show architecture" \
+        "The target architecture is set automatically.*currently spu:256K.*" \
+        "architecture = spu256K"
+
+# 'info spu event'.
+gdb_test "info spu event" \
+        "Event Status.*Event Mask.*" \
+        "info spu event"
+
+# 'info spu signal'.
+gdb_test "info spu signal" \
+        "Signal 1 not pending.*\(Type.*\).*Signal 2 not pending.*\(Type.*\).*" \
+        "info spu signal"
+
+# 'info spu mailbox'.
+gdb_test "info spu mailbox" \
+        "SPU Outbound Mailbox.*SPU Outbound Interrupt Mailbox.*" \
+        "info spu mailbox"
+
+# 'info spu dma'.
+gdb_test "info spu dma" \
+        "Tag-Group Status.*Tag-Group Mask.*Stall-and-Notify .*Atomic Cmd Status.*Opcode.*Tag.*TId.*RId.*EA.*LSA.*Size.*LstAddr.*LstSize.*E.*" \
+        "info spu dma"
+
+# 'info spu proxydma'.
+gdb_test "info spu proxydma" \
+        "Tag-Group Status.*Tag-Group Mask.*Opcode.*Tag.*TId.*RId.*EA.*LSA.*Size.*LstAddr.*LstSize.*E.*" \
+         "info spu proxydma"
+
+# Event tests.
+c_to "Marker Event"
+gdb_test "info spu event" \
+       "Event Status 0x00000000.*Event Mask   0x00000000.*" \
+       "empty event status"
+
+# MFC_MULTI_SRC_SYNC_EVENT.
+gdb_test "next" "" "next"
+gdb_test "info spu event" \
+       "Event Status 0x00000000.*Event Mask   0x00001000.*" \
+       "event mask 0x1000"
+# MFC_PRIV_ATTN_EVENT.
+gdb_test "next" "" "next"
+gdb_test "info spu event" \
+       "Event Status 0x00000000.*Event Mask   0x00000800.*" \
+       "event mask 0x0800"
+# MFC_LLR_LOST_EVENT.
+gdb_test "next" "" "next"
+gdb_test "info spu event" \
+       "Event Status 0x00000000.*Event Mask   0x00000400.*" \
+       "event mask 0x0400"
+# MFC_SIGNAL_NOTIFY_1_EVENT.
+gdb_test "next" "" "next"
+gdb_test "info spu event" \
+       "Event Status 0x00000000.*Event Mask   0x00000200.*" \
+       "event mask 0x0200"
+# MFC_SIGNAL_NOTIFY_2_EVENT.
+gdb_test "next" "" "next"
+gdb_test "info spu event" \
+       "Event Status 0x00000000.*Event Mask   0x00000100.*" \
+       "event mask 0x0100"
+# MFC_OUT_MBOX_AVAILABLE_EVENT.
+gdb_test "next" "" "next"
+gdb_test "info spu event" \
+       "Event Status 0x00000000.*Event Mask   0x00000080.*" \
+       "event mask 0x0080"
+# MFC_OUT_INTR_MBOX_AVAILABLE_EVENT.
+gdb_test "next" "" "next"
+gdb_test "info spu event" \
+       "Event Status 0x00000000.*Event Mask   0x00000040.*" \
+       "event mask 0x0040"
+# MFC_DECREMENTER_EVENT.
+gdb_test "next" "" "next"
+gdb_test "info spu event" \
+       "Event Status 0x00000000.*Event Mask   0x00000020.*" \
+       "event mask 0x0020"
+# MFC_IN_MBOX_AVAILABLE_EVENT.
+gdb_test "next" "" "next"
+gdb_test "info spu event" \
+       "Event Status 0x00000000.*Event Mask   0x00000010.*" \
+       "event mask 0x0010"
+# MFC_COMMAND_QUEUE_AVAILABLE_EVENT.
+gdb_test "next" "" "next"
+gdb_test "info spu event" \
+       "Event Status 0x00000000.*Event Mask   0x00000008.*" \
+       "event mask 0x0008"
+# MFC_LIST_STALL_NOTIFY_EVENT.
+gdb_test "next" "" "next"
+gdb_test "info spu event" \
+       "Event Status 0x00000000.*Event Mask   0x00000002.*" \
+       "event mask 0x0002"
+# MFC_TAG_STATUS_UPDATE_EVENT.
+gdb_test "next" "" "next"
+gdb_test "info spu event" \
+       "Event Status 0x00000000.*Event Mask   0x00000001.*" \
+       "event mask 0x0001"
+
+
+# DMA tests.
+# 'info spu dma' should be empty.
+c_to "Marker DMA"
+gdb_test "info spu dma" \
+        "Tag-Group Status.*0x00000000.*Tag-Group Mask.*0x00000000.*Stall-and-Notify.*0x00000000.*Atomic Cmd Status.*0x00000000.*Opcode.*Tag.*TId.*RId.*EA.*LSA.*Size.*LstAddr.*LstSize.*E.*0.*0.*0.*0.*0x00000 0x00000.*" \
+        "info spu dma (empty)"
+
+# 'info spu dma' should be filled with some data.
+c_to "Marker DMAWait"
+gdb_test "next" "" "next"
+gdb_test "info spu dma" \
+        "Tag-Group Status.*0x00000000.*Tag-Group Mask.*0x00000020.*Stall-and-Notify.*0x00000000.*Atomic Cmd Status.*0x00000000.*Opcode.*Tag.*TId.*RId.*EA.*LSA.*Size.*LstAddr.*LstSize.*E.*getl.*putllc.*get.*mfcsync.*get.*0.*0.*0.*0.*0x00000 0x00000.*" \
+        "info spu dma (non-empty)"
+gdb_test "finish" "" "finish"
+
+# Mailbox Test
+# 'info spu mailbox' should be empty.
+c_to "Marker Mbox"
+gdb_test "info spu mailbox" \
+        "SPU Outbound Mailbox.*0xc0000000.*SPU Outbound Interrupt Mailbox.*0xc0000000.*" \
+        "info spu mailbox"
+
+# 'info spu mailbox' should now contain data.
+c_to "Marker MboxEnd"
+gdb_test "info spu mailbox" \
+        "SPU Outbound Mailbox.*0x12345678.*SPU Outbound Interrupt Mailbox.*0x12345678.*" \
+        "info spu mailbox"
+
+# Signal Test
+# 'info spu signal'.
+c_to "Marker Signal"
+gdb_test "info spu signal" \
+        "Signal 1 not pending.*\(Type.*\).*Signal 2 not pending.*\(Type.*\).*" \
+        "info spu signal"
+
+# 'info spu signal' with signal1 pending.
+c_to "Marker Signal1"
+gdb_test "info spu signal" \
+        "Signal 1 control word 0x801c0800.*Signal 2 not pending.*\(Type.*\).*" \
+        "info spu signal"
+
+# 'info spu signal' with signal1 and signal2 pending.
+c_to "Marker Signal2"
+gdb_test "info spu signal" \
+        "Signal 1 control word 0x801c0800.*Signal 2 control word 0x801c0800.*" \
+        "info spu signal"
+
+# Read signal1. Only signal2 is pending.
+c_to "Marker SignalRead"
+gdb_test "info spu signal" \
+        "Signal 1 not pending.*Signal 2 control word 0x801c0800.*" \
+        "info spu signal"
+
+
+gdb_exit
+
+return 0