diff options
author | David S. Miller <davem@redhat.com> | 2012-04-21 19:03:52 +0000 |
---|---|---|
committer | David S. Miller <davem@redhat.com> | 2012-04-21 19:03:52 +0000 |
commit | 8d1b3521dbd074e72764e19fb7c9b430a968e664 (patch) | |
tree | 7a1c8c8feff2ada052d1a0049e91b612b069264b /gdb/sparc-tdep.c | |
parent | 4272ccafddc93f492a2c8b3c4a0ffa64a96e94f4 (diff) | |
download | gdb-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.c | 32 |
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. */ |