[committed, spu] Handle interrupt enable bit in PC
Ulrich Weigand
uweigand@de.ibm.com
Thu Mar 8 21:19:00 GMT 2007
Hello,
the SPU supports a form of "interrupts". If these are enabled, the
low bit of the PC is read as 1 (even though all instructions must be
4-aligned).
Current spu-tdep.c code ignored this special meaning of the low bit,
which caused in particular some confusion when single-stepping through
interrupt-enabled code.
Fixed by the following patch.
Tested on spu-elf, committed to mainline.
Bye,
Ulrich
ChangeLog:
* spu-tdep.c (spu_unwind_pc): Mask off interrupt enable bit.
(spu_software_single_step): Likewise.
(spu_read_pc, spu_write_pc): New functions.
(spu_gdbarch_init): Install them.
Index: gdb/spu-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/spu-tdep.c,v
retrieving revision 1.7
diff -u -p -r1.7 spu-tdep.c
--- gdb/spu-tdep.c 27 Feb 2007 20:17:19 -0000 1.7
+++ gdb/spu-tdep.c 8 Mar 2007 21:07:23 -0000
@@ -726,7 +726,9 @@ static const struct frame_base spu_frame
static CORE_ADDR
spu_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- return frame_unwind_register_unsigned (next_frame, SPU_PC_REGNUM);
+ CORE_ADDR pc = frame_unwind_register_unsigned (next_frame, SPU_PC_REGNUM);
+ /* Mask off interrupt enable bit. */
+ return pc & -4;
}
static CORE_ADDR
@@ -735,6 +737,22 @@ spu_unwind_sp (struct gdbarch *gdbarch,
return frame_unwind_register_unsigned (next_frame, SPU_SP_REGNUM);
}
+static CORE_ADDR
+spu_read_pc (ptid_t ptid)
+{
+ CORE_ADDR pc = read_register_pid (SPU_PC_REGNUM, ptid);
+ /* Mask off interrupt enable bit. */
+ return pc & -4;
+}
+
+static void
+spu_write_pc (CORE_ADDR pc, ptid_t ptid)
+{
+ /* 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);
+}
+
/* Function calling convention. */
@@ -970,7 +988,8 @@ spu_software_single_step (enum target_si
gdb_byte buf[4];
regcache_cooked_read (current_regcache, SPU_PC_REGNUM, buf);
- pc = extract_unsigned_integer (buf, 4);
+ /* Mask off interrupt enable bit. */
+ pc = extract_unsigned_integer (buf, 4) & -4;
if (target_read_memory (pc, buf, 4))
return;
@@ -980,9 +999,9 @@ spu_software_single_step (enum target_si
instruction is a PPE-assisted call, in which case it is at PC + 8.
Wrap around LS limit to be on the safe side. */
if ((insn & 0xffffff00) == 0x00002100)
- next_pc = (pc + 8) & (SPU_LS_SIZE - 1) & -4;
+ next_pc = (pc + 8) & (SPU_LS_SIZE - 1);
else
- next_pc = (pc + 4) & (SPU_LS_SIZE - 1) & -4;
+ next_pc = (pc + 4) & (SPU_LS_SIZE - 1);
insert_single_step_breakpoint (next_pc);
@@ -995,10 +1014,10 @@ spu_software_single_step (enum target_si
else if (reg != -1)
{
regcache_cooked_read_part (current_regcache, reg, 0, 4, buf);
- target += extract_unsigned_integer (buf, 4);
+ target += extract_unsigned_integer (buf, 4) & -4;
}
- target = target & (SPU_LS_SIZE - 1) & -4;
+ target = target & (SPU_LS_SIZE - 1);
if (target != next_pc)
insert_single_step_breakpoint (target);
}
@@ -1035,6 +1054,8 @@ spu_gdbarch_init (struct gdbarch_info in
set_gdbarch_num_pseudo_regs (gdbarch, SPU_NUM_PSEUDO_REGS);
set_gdbarch_sp_regnum (gdbarch, SPU_SP_REGNUM);
set_gdbarch_pc_regnum (gdbarch, SPU_PC_REGNUM);
+ set_gdbarch_read_pc (gdbarch, spu_read_pc);
+ set_gdbarch_write_pc (gdbarch, spu_write_pc);
set_gdbarch_register_name (gdbarch, spu_register_name);
set_gdbarch_register_type (gdbarch, spu_register_type);
set_gdbarch_pseudo_register_read (gdbarch, spu_pseudo_register_read);
--
Dr. Ulrich Weigand
GNU Toolchain for Linux on System z and Cell BE
Ulrich.Weigand@de.ibm.com
More information about the Gdb-patches
mailing list