diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index ad5d42f570..aaa7f4cacf 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -87,6 +87,12 @@ static const int tcg_target_call_oarg_regs[2] = { TCG_REG_O1, }; +static inline int check_fit(tcg_target_long val, unsigned int bits) +{ + return ((val << ((sizeof(tcg_target_long) * 8 - bits)) + >> (sizeof(tcg_target_long) * 8 - bits)) == val); +} + static void patch_reloc(uint8_t *code_ptr, int type, tcg_target_long value, tcg_target_long addend) { @@ -97,6 +103,13 @@ static void patch_reloc(uint8_t *code_ptr, int type, tcg_abort(); *(uint32_t *)code_ptr = value; break; + case R_SPARC_WDISP22: + value -= (long)code_ptr; + value >>= 2; + if (!check_fit(value, 22)) + tcg_abort(); + *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x3fffff) | value; + break; default: tcg_abort(); } @@ -119,6 +132,8 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) case 'L': /* qemu_ld/st constraint */ ct->ct |= TCG_CT_REG; tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_I0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_I1); break; case 'I': ct->ct |= TCG_CT_CONST_S11; @@ -134,12 +149,6 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) return 0; } -static inline int check_fit(tcg_target_long val, unsigned int bits) -{ - return ((val << ((sizeof(tcg_target_long) * 8 - bits)) - >> (sizeof(tcg_target_long) * 8 - bits)) == val); -} - /* test if a constant matches the constraint */ static inline int tcg_target_const_match(tcg_target_long val, const TCGArgConstraint *arg_ct) @@ -192,8 +201,8 @@ static inline int tcg_target_const_match(tcg_target_long val, #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_SUB (INSN_OP(2) | INSN_OP3(0x04)) +#define ARITH_SUBCC (INSN_OP(2) | INSN_OP3(0x14)) #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)) @@ -333,8 +342,10 @@ static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) if (val != 0) { if (check_fit(val, 13)) tcg_out_arithi(s, reg, reg, val, ARITH_ADD); - else - fprintf(stderr, "unimplemented addi %ld\n", (long)val); + else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, val); + tcg_out_arith(s, reg, reg, TCG_REG_I5, ARITH_ADD); + } } } @@ -350,10 +361,12 @@ static void tcg_out_branch(TCGContext *s, int opc, int 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) + tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) | INSN_OFF22(l->u.value - (unsigned long)s->code_ptr))); - } else - fprintf(stderr, "unimplemented branch\n"); + } else { + tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP22, label_index, 0); + tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) | 0)); + } } static const uint8_t tcg_cond_to_bcond[10] = { @@ -375,7 +388,7 @@ static void tcg_out_brcond(TCGContext *s, int cond, { if (const_arg2 && arg2 == 0) /* andcc r, r, %g0 */ - tcg_out_arithi(s, TCG_REG_G0, arg1, arg1, ARITH_ANDCC); + tcg_out_arith(s, TCG_REG_G0, arg1, arg1, ARITH_ANDCC); else /* subcc r1, r2, %g0 */ tcg_out_arith(s, TCG_REG_G0, arg1, arg2, ARITH_SUBCC); @@ -393,6 +406,359 @@ void tcg_target_qemu_prologue(TCGContext *s) tcg_out_nop(s); } +#if defined(CONFIG_SOFTMMU) +extern void __ldb_mmu(void); +extern void __ldw_mmu(void); +extern void __ldl_mmu(void); +extern void __ldq_mmu(void); + +extern void __stb_mmu(void); +extern void __stw_mmu(void); +extern void __stl_mmu(void); +extern void __stq_mmu(void); + + +static void *qemu_ld_helpers[4] = { + __ldb_mmu, + __ldw_mmu, + __ldl_mmu, + __ldq_mmu, +}; + +static void *qemu_st_helpers[4] = { + __stb_mmu, + __stw_mmu, + __stl_mmu, + __stq_mmu, +}; +#endif + +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, ld_op; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + s_bits = opc & 3; + + r0 = TCG_REG_I0; + r1 = TCG_REG_I1; + +#if TARGET_LONG_BITS == 32 + ld_op = LDUW; +#else + ld_op = LDX; +#endif + +#if defined(CONFIG_SOFTMMU) + /* srl addr_reg, x, r1 */ + tcg_out_arithi(s, r1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS, + SHIFT_SRL); + /* and addr_reg, x, r0 */ + tcg_out_arithi(s, r0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1), + ARITH_AND); + + /* and r1, x, r1 */ + tcg_out_arithi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, + ARITH_AND); + + /* add r1, x, r1 */ + tcg_out_arithi(s, r1, r1, offsetof(CPUState, tlb_table[mem_index][0].addr_read), + ARITH_ADD); + + /* ld [env + r1], r1 */ + tcg_out_ldst(s, r1, TCG_AREG0, r1, ld_op); + + /* subcc r0, r1, %g0 */ + tcg_out_arith(s, TCG_REG_G0, r0, r1, ARITH_SUBCC); + + /* will become: + be label1 */ + label1_ptr = s->code_ptr; + tcg_out32(s, 0); + + /* mov (delay slot)*/ + tcg_out_mov(s, r0, addr_reg); + + /* XXX: move that code at the end of the TB */ + tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_ld_helpers[s_bits] + - (tcg_target_ulong)s->code_ptr) >> 2) + & 0x3fffffff)); + /* mov (delay slot)*/ + tcg_out_movi(s, TCG_TYPE_I32, r1, mem_index); + + switch(opc) { + case 0 | 4: + /* sll i0, 24/56, i0 */ + tcg_out_arithi(s, TCG_REG_I0, TCG_REG_I0, + sizeof(tcg_target_long) * 8 - 8, SHIFT_SLL); + /* sra i0, 24/56, data_reg */ + tcg_out_arithi(s, data_reg, TCG_REG_I0, + sizeof(tcg_target_long) * 8 - 8, SHIFT_SRA); + break; + case 1 | 4: + /* sll i0, 16/48, i0 */ + tcg_out_arithi(s, TCG_REG_I0, TCG_REG_I0, + sizeof(tcg_target_long) * 8 - 16, SHIFT_SLL); + /* sra i0, 16/48, data_reg */ + tcg_out_arithi(s, data_reg, TCG_REG_I0, + sizeof(tcg_target_long) * 8 - 16, SHIFT_SRA); + break; + case 2 | 4: + /* sll i0, 32, i0 */ + tcg_out_arithi(s, TCG_REG_I0, TCG_REG_I0, 32, SHIFT_SLL); + /* sra i0, 32, data_reg */ + tcg_out_arithi(s, data_reg, TCG_REG_I0, 32, SHIFT_SRA); + break; + case 0: + case 1: + case 2: + case 3: + default: + /* mov */ + tcg_out_mov(s, data_reg, TCG_REG_I0); + break; + } + + /* will become: + ba label2 */ + label2_ptr = s->code_ptr; + tcg_out32(s, 0); + + /* label1: */ + *label1_ptr = (INSN_OP(0) | COND_A | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)label1_ptr - + (unsigned long)s->code_ptr)); + + /* ld [r1 + x], r1 */ + tcg_out_ldst(s, r1, r1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_read), ld_op); + /* add x(r1), r0 */ + tcg_out_arith(s, r0, r1, r0, ARITH_ADD); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch(opc) { + case 0: + /* ldub [r0], data_reg */ + tcg_out_ldst(s, data_reg, r0, 0, LDUB); + break; + case 0 | 4: + /* ldsb [r0], data_reg */ + tcg_out_ldst(s, data_reg, r0, 0, LDSB); + break; + case 1: + /* lduh [r0], data_reg */ + tcg_out_ldst(s, data_reg, r0, 0, LDUH); + if (bswap) { + fprintf(stderr, "unimplemented %s with bswap\n", __func__); + } + break; + case 1 | 4: + /* ldsh [r0], data_reg */ + tcg_out_ldst(s, data_reg, r0, 0, LDSH); + if (bswap) { + fprintf(stderr, "unimplemented %s with bswap\n", __func__); + } + break; + case 2: + /* lduw [r0], data_reg */ + tcg_out_ldst(s, data_reg, r0, 0, LDUW); + if (bswap) { + fprintf(stderr, "unimplemented %s with bswap\n", __func__); + } + break; + case 2 | 4: + /* ldsw [r0], data_reg */ + tcg_out_ldst(s, data_reg, r0, 0, LDSW); + if (bswap) { + fprintf(stderr, "unimplemented %s with bswap\n", __func__); + } + break; + case 3: + /* ldx [r0], data_reg */ + tcg_out_ldst(s, data_reg, r0, 0, LDX); + if (bswap) { + fprintf(stderr, "unimplemented %s with bswap\n", __func__); + } + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = (INSN_OP(0) | COND_A | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)label2_ptr - + (unsigned long)s->code_ptr)); +#endif +} + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + int opc) +{ + int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, ld_op; +#if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; +#endif + + data_reg = *args++; + addr_reg = *args++; + mem_index = *args; + + s_bits = opc; + + r0 = TCG_REG_I5; + r1 = TCG_REG_I4; + +#if TARGET_LONG_BITS == 32 + ld_op = LDUW; +#else + ld_op = LDX; +#endif + +#if defined(CONFIG_SOFTMMU) + /* srl addr_reg, x, r1 */ + tcg_out_arithi(s, r1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS, + SHIFT_SRL); + /* and addr_reg, x, r0 */ + tcg_out_arithi(s, r0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1), + ARITH_AND); + + /* and r1, x, r1 */ + tcg_out_arithi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, + ARITH_AND); + + /* add r1, x, r1 */ + tcg_out_arithi(s, r1, r1, + offsetof(CPUState, tlb_table[mem_index][0].addr_write), + ARITH_ADD); + + /* ld [env + r1], r1 */ + tcg_out_ldst(s, r1, TCG_AREG0, r1, ld_op); + + /* subcc r0, r1, %g0 */ + tcg_out_arith(s, TCG_REG_G0, r0, r1, ARITH_SUBCC); + + /* will become: + be label1 */ + label1_ptr = s->code_ptr; + tcg_out32(s, 0); + /* mov (delay slot)*/ + tcg_out_mov(s, r0, addr_reg); + + switch(opc) { + case 0 | 4: + /* sll i0, 24/56, i0 */ + tcg_out_arithi(s, TCG_REG_I0, TCG_REG_I0, + sizeof(tcg_target_long) * 8 - 8, SHIFT_SLL); + /* sra i0, 24/56, data_reg */ + tcg_out_arithi(s, data_reg, TCG_REG_I0, + sizeof(tcg_target_long) * 8 - 8, SHIFT_SRA); + break; + case 1 | 4: + /* sll i0, 16/48, i0 */ + tcg_out_arithi(s, TCG_REG_I0, TCG_REG_I0, + sizeof(tcg_target_long) * 8 - 16, SHIFT_SLL); + /* sra i0, 16/48, data_reg */ + tcg_out_arithi(s, data_reg, TCG_REG_I0, + sizeof(tcg_target_long) * 8 - 16, SHIFT_SRA); + break; + case 2 | 4: + /* sll i0, 32, i0 */ + tcg_out_arithi(s, TCG_REG_I0, TCG_REG_I0, 32, SHIFT_SLL); + /* sra i0, 32, data_reg */ + tcg_out_arithi(s, data_reg, TCG_REG_I0, 32, SHIFT_SRA); + break; + case 0: + case 1: + case 2: + case 3: + default: + /* mov */ + tcg_out_mov(s, data_reg, TCG_REG_I0); + break; + } + + tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_st_helpers[s_bits] + - (tcg_target_ulong)s->code_ptr) >> 2) + & 0x3fffffff)); + /* mov (delay slot)*/ + tcg_out_movi(s, TCG_TYPE_I32, r1, mem_index); + + /* will become: + ba label2 */ + label2_ptr = s->code_ptr; + tcg_out32(s, 0); + + /* label1: */ + *label1_ptr = (INSN_OP(0) | COND_A | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)label1_ptr - + (unsigned long)s->code_ptr)); + + /* ld [r1 + x], r1 */ + tcg_out_ldst(s, r1, r1, offsetof(CPUTLBEntry, addend) - + offsetof(CPUTLBEntry, addr_write), ld_op); + /* add x(r1), r0 */ + tcg_out_arith(s, r0, r1, r0, ARITH_ADD); +#else + r0 = addr_reg; +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + bswap = 0; +#else + bswap = 1; +#endif + switch(opc) { + case 0: + /* stb data_reg, [r0] */ + tcg_out_ldst(s, data_reg, r0, 0, STB); + break; + case 1: + if (bswap) { + fprintf(stderr, "unimplemented %s with bswap\n", __func__); + } + /* sth data_reg, [r0] */ + tcg_out_ldst(s, data_reg, r0, 0, STH); + break; + case 2: + if (bswap) { + fprintf(stderr, "unimplemented %s with bswap\n", __func__); + } + /* stw data_reg, [r0] */ + tcg_out_ldst(s, data_reg, r0, 0, STW); + break; + case 3: + if (bswap) { + fprintf(stderr, "unimplemented %s with bswap\n", __func__); + } + /* stx data_reg, [r0] */ + tcg_out_ldst(s, data_reg, r0, 0, STX); + break; + default: + tcg_abort(); + } + +#if defined(CONFIG_SOFTMMU) + /* label2: */ + *label2_ptr = (INSN_OP(0) | COND_A | INSN_OP2(0x2) | + INSN_OFF22((unsigned long)label2_ptr - + (unsigned long)s->code_ptr)); +#endif +} + static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, const int *const_args) { @@ -437,10 +803,9 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, } break; case INDEX_op_jmp: - fprintf(stderr, "unimplemented jmp\n"); - break; case INDEX_op_br: - fprintf(stderr, "unimplemented br\n"); + tcg_out_branch(s, COND_A, args[0]); + tcg_out_nop(s); break; case INDEX_op_movi_i32: tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]); @@ -536,31 +901,31 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, break; case INDEX_op_qemu_ld8u: - fprintf(stderr, "unimplemented qld\n"); + tcg_out_qemu_ld(s, args, 0); break; case INDEX_op_qemu_ld8s: - fprintf(stderr, "unimplemented qld\n"); + tcg_out_qemu_ld(s, args, 0 | 4); break; case INDEX_op_qemu_ld16u: - fprintf(stderr, "unimplemented qld\n"); + tcg_out_qemu_ld(s, args, 1); break; case INDEX_op_qemu_ld16s: - fprintf(stderr, "unimplemented qld\n"); + tcg_out_qemu_ld(s, args, 1 | 4); break; case INDEX_op_qemu_ld32u: - fprintf(stderr, "unimplemented qld\n"); + tcg_out_qemu_ld(s, args, 2); break; case INDEX_op_qemu_ld32s: - fprintf(stderr, "unimplemented qld\n"); + tcg_out_qemu_ld(s, args, 2 | 4); break; case INDEX_op_qemu_st8: - fprintf(stderr, "unimplemented qst\n"); + tcg_out_qemu_st(s, args, 0); break; case INDEX_op_qemu_st16: - fprintf(stderr, "unimplemented qst\n"); + tcg_out_qemu_st(s, args, 1); break; case INDEX_op_qemu_st32: - fprintf(stderr, "unimplemented qst\n"); + tcg_out_qemu_st(s, args, 2); break; #if defined(__sparc_v9__) && !defined(__sparc_v8plus__) @@ -596,13 +961,14 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, goto gen_arith32; case INDEX_op_brcond_i64: - 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_ld64: - fprintf(stderr, "unimplemented qld\n"); + tcg_out_qemu_ld(s, args, 3); break; case INDEX_op_qemu_st64: - fprintf(stderr, "unimplemented qst\n"); + tcg_out_qemu_st(s, args, 3); break; #endif