summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog26
-rw-r--r--gdb/doc/ChangeLog6
-rw-r--r--gdb/doc/gdb.texinfo38
-rw-r--r--gdb/spu-linux-nat.c3
-rw-r--r--gdb/spu-tdep.c619
-rw-r--r--gdb/spu-tdep.h9
-rw-r--r--gdb/target.h2
-rw-r--r--gdb/testsuite/ChangeLog6
-rw-r--r--gdb/testsuite/gdb.arch/spu-info.c236
-rw-r--r--gdb/testsuite/gdb.arch/spu-info.exp243
10 files changed, 1185 insertions, 3 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ddd98adebf8..0d16e47cdaa 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,31 @@
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
accessing non-seekable spufs files.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 38c3b856e6c..7a73f3bf031 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -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
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 7c04b2b28ee..0641386870c 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -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}
diff --git a/gdb/spu-linux-nat.c b/gdb/spu-linux-nat.c
index 21a7c5d00d7..3a03f225336 100644
--- a/gdb/spu-linux-nat.c
+++ b/gdb/spu-linux-nat.c
@@ -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;
diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
index 305201a930f..88720846b0b 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -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");
}
@@ -108,10 +126,29 @@ 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);
}
diff --git a/gdb/spu-tdep.h b/gdb/spu-tdep.h
index 7d0df185391..d573608393d 100644
--- a/gdb/spu-tdep.h
+++ b/gdb/spu-tdep.h
@@ -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. */
diff --git a/gdb/target.h b/gdb/target.h
index 24db1361965..7cde49b6450 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -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.
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 80d31af48cd..c953e57f334 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -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
index 00000000000..1fc83ec076c
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/spu-info.c
@@ -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
index 00000000000..61e997aa97b
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/spu-info.exp
@@ -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