[rfc/rfa] [2/4] SPU enhancements: main part

Ulrich Weigand
2007-06-02T19:32:14Z

Hello,

this patch adds extended SPU query support for the spu-elf target.
The target currently uses only the "regs" and "mem" files present
in the Linux spufs directory associated with an SPU context.

However, those contexts actually provide a variety of different
files containing a number of additional information about the
SPU context which can be very helpful when debugging SPU programs.

This patch makes that information available. Some of the data
is presented in the form of additional pseudo registers, allowing
to both display and modify the status. Other data is read-only,
and is presented by a number of new "info spu" commands.

To get at the data, the spu-tdep file makes use of a new target
object type TARGET_OBJECT_SPU. The "annex" of that type describes
the spufs file that is to be accessed; the data contained in an
object of that type is simply the verbatim contents of the spufs
file.

This patch adds supports for TARGET_OBJECT_SPU only to the
spu-linux-nat.c native target. A follow-on patch will add
support for this object to for remote gdbserver debugging.

Thanks to Markus Deuling for providing the "info spu" test case.

Tested on spu-elf.

Eli, are the doc changes OK?

Bye,
Ulrich

ChangeLog:

* 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.

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.

diff -urNp gdb-orig/gdb/doc/gdb.texinfo gdb-head/gdb/doc/gdb.texinfo
--- gdb-orig/gdb/doc/gdb.texinfo 2007-05-31 18:54:31.000000000 +0200
+++ gdb-head/gdb/doc/gdb.texinfo 2007-06-01 22:29:18.089489327 +0200
@@ -15100,6 +15100,7 @@ all uses of @value{GDBN} with the archit
* Alpha::
* MIPS::
* HPPA:: HP PA architecture
+* SPU:: Cell Broadband Engine SPU architecture
@end menu

@node i386
@@ -15280,6 +15281,47 @@ 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 event
+Display SPU event facility status. Shows current event mask
+and pending event status.
+
+@item info spu signal
+@kindex 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
+@kindex 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
+@kindex 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
+@kindex 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 -urNp gdb-orig/gdb/spu-linux-nat.c gdb-head/gdb/spu-linux-nat.c
--- gdb-orig/gdb/spu-linux-nat.c 2007-06-01 22:01:18.838382108 +0200
+++ gdb-head/gdb/spu-linux-nat.c 2007-06-01 21:45:28.569989717 +0200
@@ -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 -urNp gdb-orig/gdb/spu-tdep.c gdb-head/gdb/spu-tdep.c
--- gdb-orig/gdb/spu-tdep.c 2007-06-01 21:33:30.149421000 +0200
+++ gdb-head/gdb/spu-tdep.c 2007-06-01 21:37:55.798457959 +0200
@@ -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 *gdbar
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 *gdbar
/* 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
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 gdbarc
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
}

+/* "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 -urNp gdb-orig/gdb/spu-tdep.h gdb-head/gdb/spu-tdep.h
--- gdb-orig/gdb/spu-tdep.h 2007-06-01 21:33:30.155420000 +0200
+++ gdb-head/gdb/spu-tdep.h 2007-06-01 21:37:55.842451624 +0200
@@ -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 -urNp gdb-orig/gdb/target.h gdb-head/gdb/target.h
--- gdb-orig/gdb/target.h 2007-06-01 21:33:30.163419000 +0200
+++ gdb-head/gdb/target.h 2007-06-01 21:37:55.848450760 +0200
@@ -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 -urNp gdb-orig/gdb/testsuite/gdb.arch/spu-info.c gdb-head/gdb/testsuite/gdb.arch/spu-info.c
--- gdb-orig/gdb/testsuite/gdb.arch/spu-info.c 1970-01-01 01:00:00.000000000 +0100
+++ gdb-head/gdb/testsuite/gdb.arch/spu-info.c 2007-06-01 21:38:38.271723189 +0200
@@ -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 -urNp gdb-orig/gdb/testsuite/gdb.arch/spu-info.exp gdb-head/gdb/testsuite/gdb.arch/spu-info.exp
--- gdb-orig/gdb/testsuite/gdb.arch/spu-info.exp 1970-01-01 01:00:00.000000000 +0100
+++ gdb-head/gdb/testsuite/gdb.arch/spu-info.exp 2007-06-01 21:38:38.277722325 +0200
@@ -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