tcg-arm: Split out tcg_out_tlb_read

Share code between qemu_ld and qemu_st to process the tlb.

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2013-03-12 18:18:07 -07:00 committed by Aurelien Jarno
parent 9feac1d770
commit cee87be80a

View file

@ -1147,40 +1147,15 @@ static TCGReg tcg_out_arg_reg64(TCGContext *s, TCGReg argreg,
argreg = tcg_out_arg_reg32(s, argreg, arghi); argreg = tcg_out_arg_reg32(s, argreg, arghi);
return argreg; return argreg;
} }
#endif /* SOFTMMU */
#define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS) #define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)
static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) /* Load and compare a TLB entry, leaving the flags set. Leaves R0 pointing
to the tlb entry. Clobbers R1 and TMP. */
static void tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
int s_bits, int tlb_offset)
{ {
int addr_reg, data_reg, data_reg2, bswap;
#ifdef CONFIG_SOFTMMU
int mem_index, s_bits, tlb_offset;
TCGReg argreg;
# if TARGET_LONG_BITS == 64
int addr_reg2;
# endif
uint32_t *label_ptr;
#endif
#ifdef TARGET_WORDS_BIGENDIAN
bswap = 1;
#else
bswap = 0;
#endif
data_reg = *args++;
if (opc == 3)
data_reg2 = *args++;
else
data_reg2 = 0; /* suppress warning */
addr_reg = *args++;
#ifdef CONFIG_SOFTMMU
# if TARGET_LONG_BITS == 64
addr_reg2 = *args++;
# endif
mem_index = *args;
s_bits = opc & 3;
/* Should generate something like the following: /* Should generate something like the following:
* shr r8, addr_reg, #TARGET_PAGE_BITS * shr r8, addr_reg, #TARGET_PAGE_BITS
* and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8 * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8
@ -1190,13 +1165,13 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
# error # error
# endif # endif
tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_TMP, tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_TMP,
0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS)); 0, addrlo, SHIFT_IMM_LSR(TARGET_PAGE_BITS));
tcg_out_dat_imm(s, COND_AL, ARITH_AND, tcg_out_dat_imm(s, COND_AL, ARITH_AND,
TCG_REG_R0, TCG_REG_TMP, CPU_TLB_SIZE - 1); TCG_REG_R0, TCG_REG_TMP, CPU_TLB_SIZE - 1);
tcg_out_dat_reg(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_AREG0, tcg_out_dat_reg(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_AREG0,
TCG_REG_R0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS)); TCG_REG_R0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS));
/* We assume that the offset is contained within 20 bits. */ /* We assume that the offset is contained within 20 bits. */
tlb_offset = offsetof(CPUArchState, tlb_table[mem_index][0].addr_read);
assert((tlb_offset & ~0xfffff) == 0); assert((tlb_offset & ~0xfffff) == 0);
if (tlb_offset > 0xfff) { if (tlb_offset > 0xfff) {
tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_REG_R0, tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_REG_R0,
@ -1206,16 +1181,48 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
tcg_out_ld32_12wb(s, COND_AL, TCG_REG_R1, TCG_REG_R0, tlb_offset); tcg_out_ld32_12wb(s, COND_AL, TCG_REG_R1, TCG_REG_R0, tlb_offset);
tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, TCG_REG_R1, tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, TCG_REG_R1,
TCG_REG_TMP, SHIFT_IMM_LSL(TARGET_PAGE_BITS)); TCG_REG_TMP, SHIFT_IMM_LSL(TARGET_PAGE_BITS));
/* Check alignment. */ /* Check alignment. */
if (s_bits) if (s_bits) {
tcg_out_dat_imm(s, COND_EQ, ARITH_TST, tcg_out_dat_imm(s, COND_EQ, ARITH_TST,
0, addr_reg, (1 << s_bits) - 1); 0, addrlo, (1 << s_bits) - 1);
# if TARGET_LONG_BITS == 64 }
/* XXX: possibly we could use a block data load in the first access. */
tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0, 4); if (TARGET_LONG_BITS == 64) {
tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0, /* XXX: possibly we could use a block data load in the first access. */
TCG_REG_R1, addr_reg2, SHIFT_IMM_LSL(0)); tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0, 4);
# endif tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
TCG_REG_R1, addrhi, SHIFT_IMM_LSL(0));
}
}
#endif /* SOFTMMU */
static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
{
TCGReg addr_reg, data_reg, data_reg2;
bool bswap;
#ifdef CONFIG_SOFTMMU
int mem_index, s_bits;
TCGReg argreg, addr_reg2;
uint32_t *label_ptr;
#endif
#ifdef TARGET_WORDS_BIGENDIAN
bswap = 1;
#else
bswap = 0;
#endif
data_reg = *args++;
data_reg2 = (opc == 3 ? *args++ : 0);
addr_reg = *args++;
#ifdef CONFIG_SOFTMMU
addr_reg2 = (TARGET_LONG_BITS == 64 ? *args++ : 0);
mem_index = *args;
s_bits = opc & 3;
tcg_out_tlb_read(s, addr_reg, addr_reg2, s_bits,
offsetof(CPUArchState, tlb_table[mem_index][0].addr_read));
tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0, tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,
offsetof(CPUTLBEntry, addend) offsetof(CPUTLBEntry, addend)
- offsetof(CPUTLBEntry, addr_read)); - offsetof(CPUTLBEntry, addr_read));
@ -1271,11 +1278,11 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
*/ */
argreg = TCG_REG_R0; argreg = TCG_REG_R0;
argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0); argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0);
#if TARGET_LONG_BITS == 64 if (TARGET_LONG_BITS == 64) {
argreg = tcg_out_arg_reg64(s, argreg, addr_reg, addr_reg2); argreg = tcg_out_arg_reg64(s, argreg, addr_reg, addr_reg2);
#else } else {
argreg = tcg_out_arg_reg32(s, argreg, addr_reg); argreg = tcg_out_arg_reg32(s, argreg, addr_reg);
#endif }
argreg = tcg_out_arg_imm32(s, argreg, mem_index); argreg = tcg_out_arg_imm32(s, argreg, mem_index);
tcg_out_call(s, (tcg_target_long) qemu_ld_helpers[s_bits]); tcg_out_call(s, (tcg_target_long) qemu_ld_helpers[s_bits]);
@ -1302,8 +1309,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
#else /* !CONFIG_SOFTMMU */ #else /* !CONFIG_SOFTMMU */
if (GUEST_BASE) { if (GUEST_BASE) {
uint32_t offset = GUEST_BASE; uint32_t offset = GUEST_BASE;
int i; int i, rot;
int rot;
while (offset) { while (offset) {
i = ctz32(offset) & ~1; i = ctz32(offset) & ~1;
@ -1362,68 +1368,33 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
#endif #endif
} }
static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
{ {
int addr_reg, data_reg, data_reg2, bswap; TCGReg addr_reg, data_reg, data_reg2;
bool bswap;
#ifdef CONFIG_SOFTMMU #ifdef CONFIG_SOFTMMU
int mem_index, s_bits, tlb_offset; int mem_index, s_bits;
TCGReg argreg; TCGReg argreg, addr_reg2;
# if TARGET_LONG_BITS == 64
int addr_reg2;
# endif
uint32_t *label_ptr; uint32_t *label_ptr;
#endif #endif
#ifdef TARGET_WORDS_BIGENDIAN #ifdef TARGET_WORDS_BIGENDIAN
bswap = 1; bswap = 1;
#else #else
bswap = 0; bswap = 0;
#endif #endif
data_reg = *args++; data_reg = *args++;
if (opc == 3) data_reg2 = (opc == 3 ? *args++ : 0);
data_reg2 = *args++;
else
data_reg2 = 0; /* suppress warning */
addr_reg = *args++; addr_reg = *args++;
#ifdef CONFIG_SOFTMMU #ifdef CONFIG_SOFTMMU
# if TARGET_LONG_BITS == 64 addr_reg2 = (TARGET_LONG_BITS == 64 ? *args++ : 0);
addr_reg2 = *args++;
# endif
mem_index = *args; mem_index = *args;
s_bits = opc & 3; s_bits = opc & 3;
/* Should generate something like the following: tcg_out_tlb_read(s, addr_reg, addr_reg2, s_bits,
* shr r8, addr_reg, #TARGET_PAGE_BITS offsetof(CPUArchState,
* and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8 tlb_table[mem_index][0].addr_write));
* add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS
*/
tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
TCG_REG_TMP, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS));
tcg_out_dat_imm(s, COND_AL, ARITH_AND,
TCG_REG_R0, TCG_REG_TMP, CPU_TLB_SIZE - 1);
tcg_out_dat_reg(s, COND_AL, ARITH_ADD, TCG_REG_R0,
TCG_AREG0, TCG_REG_R0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS));
/* We assume that the offset is contained within 20 bits. */
tlb_offset = offsetof(CPUArchState, tlb_table[mem_index][0].addr_write);
assert((tlb_offset & ~0xfffff) == 0);
if (tlb_offset > 0xfff) {
tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_REG_R0,
0xa00 | (tlb_offset >> 12));
tlb_offset &= 0xfff;
}
tcg_out_ld32_12wb(s, COND_AL, TCG_REG_R1, TCG_REG_R0, tlb_offset);
tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, TCG_REG_R1,
TCG_REG_TMP, SHIFT_IMM_LSL(TARGET_PAGE_BITS));
/* Check alignment. */
if (s_bits)
tcg_out_dat_imm(s, COND_EQ, ARITH_TST,
0, addr_reg, (1 << s_bits) - 1);
# if TARGET_LONG_BITS == 64
/* XXX: possibly we could use a block data load in the first access. */
tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0, 4);
tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
TCG_REG_R1, addr_reg2, SHIFT_IMM_LSL(0));
# endif
tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0, tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,
offsetof(CPUTLBEntry, addend) offsetof(CPUTLBEntry, addend)
- offsetof(CPUTLBEntry, addr_write)); - offsetof(CPUTLBEntry, addr_write));
@ -1472,11 +1443,11 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
*/ */
argreg = TCG_REG_R0; argreg = TCG_REG_R0;
argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0); argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0);
#if TARGET_LONG_BITS == 64 if (TARGET_LONG_BITS == 64) {
argreg = tcg_out_arg_reg64(s, argreg, addr_reg, addr_reg2); argreg = tcg_out_arg_reg64(s, argreg, addr_reg, addr_reg2);
#else } else {
argreg = tcg_out_arg_reg32(s, argreg, addr_reg); argreg = tcg_out_arg_reg32(s, argreg, addr_reg);
#endif }
switch (opc) { switch (opc) {
case 0: case 0: