aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorblueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>2008-05-15 19:44:09 +0000
committerblueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>2008-05-15 19:44:09 +0000
commitcf7c2ca5ff568d4a46674757b8ad545cfb9f6ab4 (patch)
treec8913d342f8a695825d3668690469c6ca26fe5e1
parentf02ca5cbeaf86038834c1953247a1579d7921927 (diff)
Implement brcond, ldst with large offset; fix direct jump, prologue
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4461 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r--tcg/sparc/tcg-target.c85
1 files changed, 71 insertions, 14 deletions
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index 58fe606ea3..ad5d42f570 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -169,14 +169,31 @@ static inline int tcg_target_const_match(tcg_target_long val,
#define INSN_OFF22(x) (((x) >> 2) & 0x3fffff)
#define INSN_COND(x, a) (((x) << 25) | ((a) << 29))
+#define COND_N 0x0
+#define COND_E 0x1
+#define COND_LE 0x2
+#define COND_L 0x3
+#define COND_LEU 0x4
+#define COND_CS 0x5
+#define COND_NEG 0x6
+#define COND_VS 0x7
#define COND_A 0x8
+#define COND_NE 0x9
+#define COND_G 0xa
+#define COND_GE 0xb
+#define COND_GU 0xc
+#define COND_CC 0xd
+#define COND_POS 0xe
+#define COND_VC 0xf
#define BA (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2))
#define ARITH_ADD (INSN_OP(2) | INSN_OP3(0x00))
#define ARITH_AND (INSN_OP(2) | INSN_OP3(0x01))
+#define ARITH_ANDCC (INSN_OP(2) | INSN_OP3(0x11))
#define ARITH_OR (INSN_OP(2) | INSN_OP3(0x02))
#define ARITH_XOR (INSN_OP(2) | INSN_OP3(0x03))
#define ARITH_SUB (INSN_OP(2) | INSN_OP3(0x08))
+#define ARITH_SUBCC (INSN_OP(2) | INSN_OP3(0x18))
#define ARITH_ADDX (INSN_OP(2) | INSN_OP3(0x10))
#define ARITH_SUBX (INSN_OP(2) | INSN_OP3(0x0c))
#define ARITH_UMUL (INSN_OP(2) | INSN_OP3(0x0a))
@@ -264,8 +281,11 @@ static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, int offset, in
if (check_fit(offset, 13))
tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(addr) |
INSN_IMM13(offset));
- else
- fprintf(stderr, "unimplemented %s with offset %d\n", __func__, offset);
+ else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset);
+ tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) |
+ INSN_RS2(addr));
+ }
}
static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
@@ -323,12 +343,52 @@ static inline void tcg_out_nop(TCGContext *s)
tcg_out32(s, SETHI | INSN_RD(TCG_REG_G0) | 0);
}
+static void tcg_out_branch(TCGContext *s, int opc, int label_index)
+{
+ int32_t val;
+ TCGLabel *l = &s->labels[label_index];
+
+ if (l->has_value) {
+ val = l->u.value - (tcg_target_long)s->code_ptr;
+ tcg_out32(s, (INSN_OP(0) | opc | INSN_OP2(0x2)
+ | INSN_OFF22(l->u.value - (unsigned long)s->code_ptr)));
+ } else
+ fprintf(stderr, "unimplemented branch\n");
+}
+
+static const uint8_t tcg_cond_to_bcond[10] = {
+ [TCG_COND_EQ] = COND_E,
+ [TCG_COND_NE] = COND_NE,
+ [TCG_COND_LT] = COND_L,
+ [TCG_COND_GE] = COND_GE,
+ [TCG_COND_LE] = COND_LE,
+ [TCG_COND_GT] = COND_G,
+ [TCG_COND_LTU] = COND_CS,
+ [TCG_COND_GEU] = COND_CC,
+ [TCG_COND_LEU] = COND_LEU,
+ [TCG_COND_GTU] = COND_GU,
+};
+
+static void tcg_out_brcond(TCGContext *s, int cond,
+ TCGArg arg1, TCGArg arg2, int const_arg2,
+ int label_index)
+{
+ if (const_arg2 && arg2 == 0)
+ /* andcc r, r, %g0 */
+ tcg_out_arithi(s, TCG_REG_G0, arg1, arg1, ARITH_ANDCC);
+ else
+ /* subcc r1, r2, %g0 */
+ tcg_out_arith(s, TCG_REG_G0, arg1, arg2, ARITH_SUBCC);
+ tcg_out_branch(s, tcg_cond_to_bcond[cond], label_index);
+ tcg_out_nop(s);
+}
+
/* Generate global QEMU prologue and epilogue code */
void tcg_target_qemu_prologue(TCGContext *s)
{
tcg_out32(s, SAVE | INSN_RD(TCG_REG_O6) | INSN_RS1(TCG_REG_O6) |
INSN_IMM13(-TCG_TARGET_STACK_MINFRAME));
- tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_O0) |
+ tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I0) |
INSN_RS2(TCG_REG_G0));
tcg_out_nop(s);
}
@@ -349,14 +409,10 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
case INDEX_op_goto_tb:
if (s->tb_jmp_offset) {
/* direct jump method */
- if (check_fit(args[0] - (unsigned long)s->code_ptr, 26)) {
- tcg_out32(s, BA |
- INSN_OFF22(args[0] - (unsigned long)s->code_ptr));
- } else {
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, args[0]);
- tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) |
- INSN_RS2(TCG_REG_G0));
- }
+ tcg_out32(s, SETHI | INSN_RD(TCG_REG_I5) |
+ ((args[0] & 0xffffe000) >> 10));
+ tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) |
+ INSN_IMM13((args[0] & 0x1fff)));
s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
} else {
/* indirect jump method */
@@ -374,8 +430,8 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
& 0x3fffffff));
tcg_out_nop(s);
} else {
- tcg_out_ld_ptr(s, TCG_REG_O7, (tcg_target_long)(s->tb_next + args[0]));
- tcg_out32(s, JMPL | INSN_RD(TCG_REG_O7) | INSN_RS1(TCG_REG_O7) |
+ tcg_out_ld_ptr(s, TCG_REG_I5, (tcg_target_long)(s->tb_next + args[0]));
+ tcg_out32(s, JMPL | INSN_RD(TCG_REG_O7) | INSN_RS1(TCG_REG_I5) |
INSN_RS2(TCG_REG_G0));
tcg_out_nop(s);
}
@@ -475,7 +531,8 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
#endif
case INDEX_op_brcond_i32:
- fprintf(stderr, "unimplemented brcond\n");
+ tcg_out_brcond(s, args[2], args[0], args[1], const_args[1],
+ args[3]);
break;
case INDEX_op_qemu_ld8u: