/* SPU target-dependent code for GDB, the GNU debugger.
- Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
Contributed by Ulrich Weigand <uweigand@de.ibm.com>.
Based on a port by Sid Manning <sid@us.ibm.com>.
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
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "arch-utils.h"
#include "spu-tdep.h"
+
+/* The tdep structure. */
+struct gdbarch_tdep
+{
+ /* SPU-specific vector type. */
+ struct type *spu_builtin_type_vec128;
+};
+
+
/* SPU-specific vector type. */
-struct type *spu_builtin_type_vec128;
+static struct type *
+spu_builtin_type_vec128 (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (!tdep->spu_builtin_type_vec128)
+ {
+ struct type *t;
+
+ t = init_composite_type ("__spu_builtin_type_vec128", TYPE_CODE_UNION);
+ append_composite_type_field (t, "uint128", builtin_type_int128);
+ append_composite_type_field (t, "v2_int64",
+ init_vector_type (builtin_type_int64, 2));
+ append_composite_type_field (t, "v4_int32",
+ init_vector_type (builtin_type_int32, 4));
+ append_composite_type_field (t, "v8_int16",
+ init_vector_type (builtin_type_int16, 8));
+ append_composite_type_field (t, "v16_int8",
+ init_vector_type (builtin_type_int8, 16));
+ append_composite_type_field (t, "v2_double",
+ init_vector_type (builtin_type_double, 2));
+ append_composite_type_field (t, "v4_float",
+ init_vector_type (builtin_type_float, 4));
+
+ TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
+ TYPE_NAME (t) = "spu_builtin_type_vec128";
+
+ tdep->spu_builtin_type_vec128 = t;
+ }
+
+ return tdep->spu_builtin_type_vec128;
+}
+
+
+/* The list of available "info spu " commands. */
+static struct cmd_list_element *infospucmdlist = NULL;
/* Registers. */
static const char *
-spu_register_name (int reg_nr)
+spu_register_name (struct gdbarch *gdbarch, int reg_nr)
{
static char *register_names[] =
{
"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)
spu_register_type (struct gdbarch *gdbarch, int reg_nr)
{
if (reg_nr < SPU_NUM_GPRS)
- return spu_builtin_type_vec128;
+ return spu_builtin_type_vec128 (gdbarch);
switch (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");
}
/* 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 (¤t_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)
{
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 (¤t_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 (¤t_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)
{
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 (¤t_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"));
}
return default_register_reggroup_p (gdbarch, regnum, group);
}
+/* Address conversion. */
+
+static CORE_ADDR
+spu_pointer_to_address (struct type *type, const gdb_byte *buf)
+{
+ ULONGEST addr = extract_unsigned_integer (buf, TYPE_LENGTH (type));
+ ULONGEST lslr = SPU_LS_SIZE - 1; /* Hard-wired LS size. */
+
+ if (target_has_registers && target_has_stack && target_has_memory)
+ lslr = get_frame_register_unsigned (get_selected_frame (NULL),
+ SPU_LSLR_REGNUM);
+
+ return addr & lslr;
+}
+
+static CORE_ADDR
+spu_integer_to_address (struct gdbarch *gdbarch,
+ struct type *type, const gdb_byte *buf)
+{
+ ULONGEST addr = unpack_long (type, buf);
+ ULONGEST lslr = SPU_LS_SIZE - 1; /* Hard-wired LS size. */
+
+ if (target_has_registers && target_has_stack && target_has_memory)
+ lslr = get_frame_register_unsigned (get_selected_frame (NULL),
+ SPU_LSLR_REGNUM);
+
+ return addr & lslr;
+}
+
/* Decoding SPU instructions. */
/* Return the first instruction after the prologue starting at PC. */
static CORE_ADDR
-spu_skip_prologue (CORE_ADDR pc)
+spu_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
struct spu_prologue_data data;
return spu_analyze_prologue (pc, (CORE_ADDR)-1, &data);
/* Return the frame pointer in use at address PC. */
static void
-spu_virtual_frame_pointer (CORE_ADDR pc, int *reg, LONGEST *offset)
+spu_virtual_frame_pointer (struct gdbarch *gdbarch, CORE_ADDR pc,
+ int *reg, LONGEST *offset)
{
struct spu_prologue_data data;
spu_analyze_prologue (pc, (CORE_ADDR)-1, &data);
}
static CORE_ADDR
-spu_read_pc (ptid_t ptid)
+spu_read_pc (struct regcache *regcache)
{
- CORE_ADDR pc = read_register_pid (SPU_PC_REGNUM, ptid);
+ ULONGEST pc;
+ regcache_cooked_read_unsigned (regcache, SPU_PC_REGNUM, &pc);
/* Mask off interrupt enable bit. */
return pc & -4;
}
static void
-spu_write_pc (CORE_ADDR pc, ptid_t ptid)
+spu_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
/* Keep interrupt enabled state unchanged. */
- CORE_ADDR old_pc = read_register_pid (SPU_PC_REGNUM, ptid);
- write_register_pid (SPU_PC_REGNUM, (pc & -4) | (old_pc & 3), ptid);
+ ULONGEST old_pc;
+ regcache_cooked_read_unsigned (regcache, SPU_PC_REGNUM, &old_pc);
+ regcache_cooked_write_unsigned (regcache, SPU_PC_REGNUM,
+ (pc & -4) | (old_pc & 3));
}
/* Allocate stack frame header. */
sp -= 32;
+ /* Store stack back chain. */
+ regcache_cooked_read (regcache, SPU_RAW_SP_REGNUM, buf);
+ target_write_memory (sp, buf, 16);
+
/* Finally, update the SP register. */
regcache_cooked_write_unsigned (regcache, SPU_SP_REGNUM, sp);
/* Breakpoints. */
static const gdb_byte *
-spu_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr)
+spu_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr, int *lenptr)
{
static const gdb_byte breakpoint[] = { 0x00, 0x00, 0x3f, 0xff };
/* Software single-stepping support. */
int
-spu_software_single_step (struct regcache *regcache)
+spu_software_single_step (struct frame_info *frame)
{
CORE_ADDR pc, next_pc;
unsigned int insn;
int offset, reg;
gdb_byte buf[4];
- regcache_cooked_read (regcache, SPU_PC_REGNUM, buf);
- /* Mask off interrupt enable bit. */
- pc = extract_unsigned_integer (buf, 4) & -4;
+ pc = get_frame_pc (frame);
if (target_read_memory (pc, buf, 4))
return 1;
target += pc;
else if (reg != -1)
{
- regcache_cooked_read_part (regcache, reg, 0, 4, buf);
+ get_frame_register_bytes (frame, reg, 0, 4, buf);
target += extract_unsigned_integer (buf, 4) & -4;
}
}
+/* "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 (¤t_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 (¤t_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 (¤t_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 (¤t_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 (¤t_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 (¤t_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 Or)\n"));
+ else
+ printf_filtered (_("(Type Overwrite)\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 Or)\n"));
+ else
+ printf_filtered (_("(Type Overwrite)\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 (¤t_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 (¤t_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 (¤t_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 (¤t_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 (¤t_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 *
spu_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
/* Find a candidate among the list of pre-declared architectures. */
arches = gdbarch_list_lookup_by_info (arches, &info);
return NULL;
/* Yes, create a new architecture. */
- gdbarch = gdbarch_alloc (&info, NULL);
+ tdep = XCALLOC (1, struct gdbarch_tdep);
+ gdbarch = gdbarch_alloc (&info, tdep);
/* Disassembler. */
set_gdbarch_print_insn (gdbarch, print_insn_spu);
set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+ /* Address conversion. */
+ set_gdbarch_pointer_to_address (gdbarch, spu_pointer_to_address);
+ set_gdbarch_integer_to_address (gdbarch, spu_integer_to_address);
+
/* Inferior function calls. */
set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
set_gdbarch_frame_align (gdbarch, spu_frame_align);
return gdbarch;
}
-/* Implement a SPU-specific vector type as replacement
- for __gdb_builtin_type_vec128. */
-static void
-spu_init_vector_type (void)
-{
- struct type *type;
-
- type = init_composite_type ("__spu_builtin_type_vec128", TYPE_CODE_UNION);
- append_composite_type_field (type, "uint128", builtin_type_int128);
- append_composite_type_field (type, "v2_int64", builtin_type_v2_int64);
- append_composite_type_field (type, "v4_int32", builtin_type_v4_int32);
- append_composite_type_field (type, "v8_int16", builtin_type_v8_int16);
- append_composite_type_field (type, "v16_int8", builtin_type_v16_int8);
- append_composite_type_field (type, "v2_double", builtin_type_v2_double);
- append_composite_type_field (type, "v4_float", builtin_type_v4_float);
-
- TYPE_FLAGS (type) |= TYPE_FLAG_VECTOR;
- TYPE_NAME (type) = "spu_builtin_type_vec128";
- spu_builtin_type_vec128 = type;
-}
-
void
_initialize_spu_tdep (void)
{
register_gdbarch_init (bfd_arch_spu, spu_gdbarch_init);
- spu_init_vector_type ();
-
/* 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);
}