aboutsummaryrefslogtreecommitdiff
path: root/gdb/sparc-tdep.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@redhat.com>2012-04-21 19:03:52 +0000
committerDavid S. Miller <davem@redhat.com>2012-04-21 19:03:52 +0000
commit8d1b3521dbd074e72764e19fb7c9b430a968e664 (patch)
tree7a1c8c8feff2ada052d1a0049e91b612b069264b /gdb/sparc-tdep.c
parent4272ccafddc93f492a2c8b3c4a0ffa64a96e94f4 (diff)
downloadgdb-8d1b3521dbd074e72764e19fb7c9b430a968e664.zip
gdb-8d1b3521dbd074e72764e19fb7c9b430a968e664.tar.gz
gdb-8d1b3521dbd074e72764e19fb7c9b430a968e664.tar.bz2
Handle sparc compare-and-branch
SPARC-T4 adds a "compare and branch" instruction which fuses a compare and a branch instruction into one. The branch is non-delayed, there are no anulling facilities, and the displacement is 10-bits. This also corrects the existing bit test for Branch on Integer Register. The distinguising characteristic between Branch on Integer Register and Compare-and-Branch is bit 28. The existing code was checking bit 24 for zero, but that's pointless because bit 24 is already covered by the "X_OP2 (insn) == 3" test. gdb/ * sparc-tdep.c (X_DISP10): Define. (sparc_analyze_control_transfer): Handle compare-and-branch.
Diffstat (limited to 'gdb/sparc-tdep.c')
-rw-r--r--gdb/sparc-tdep.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c
index 24d54b7..00bca01 100644
--- a/gdb/sparc-tdep.c
+++ b/gdb/sparc-tdep.c
@@ -85,6 +85,7 @@ struct regset;
/* Sign extension macros. */
#define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000)
#define X_DISP19(i) ((((i) & 0x7ffff) ^ 0x40000) - 0x40000)
+#define X_DISP10(i) ((((((i) >> 11) && 0x300) | (((i) >> 5) & 0xff)) ^ 0x200) - 0x200)
#define X_SIMM13(i) ((((i) & 0x1fff) ^ 0x1000) - 0x1000)
/* Fetch the instruction at PC. Instructions are always big-endian
@@ -1451,14 +1452,24 @@ sparc_analyze_control_transfer (struct frame_info *frame,
{
unsigned long insn = sparc_fetch_instruction (pc);
int conditional_p = X_COND (insn) & 0x7;
- int branch_p = 0;
+ int branch_p = 0, fused_p = 0;
long offset = 0; /* Must be signed for sign-extend. */
- if (X_OP (insn) == 0 && X_OP2 (insn) == 3 && (insn & 0x1000000) == 0)
+ if (X_OP (insn) == 0 && X_OP2 (insn) == 3)
{
- /* Branch on Integer Register with Prediction (BPr). */
- branch_p = 1;
- conditional_p = 1;
+ if ((insn & 0x10000000) == 0)
+ {
+ /* Branch on Integer Register with Prediction (BPr). */
+ branch_p = 1;
+ conditional_p = 1;
+ }
+ else
+ {
+ /* Compare and Branch */
+ branch_p = 1;
+ fused_p = 1;
+ offset = 4 * X_DISP10 (insn);
+ }
}
else if (X_OP (insn) == 0 && X_OP2 (insn) == 6)
{
@@ -1495,7 +1506,16 @@ sparc_analyze_control_transfer (struct frame_info *frame,
if (branch_p)
{
- if (conditional_p)
+ if (fused_p)
+ {
+ /* Fused compare-and-branch instructions are non-delayed,
+ and do not have an annuling capability. So we need to
+ always set a breakpoint on both the NPC and the branch
+ target address. */
+ gdb_assert (offset != 0);
+ return pc + offset;
+ }
+ else if (conditional_p)
{
/* For conditional branches, return nPC + 4 iff the annul
bit is 1. */