Re: [Qemu-devel] [RFC v3 05/13] target-arm: translate: implement qemu_ldlink and qemu_stcond ops
Alvise Rigo a.r...@virtualopensystems.com writes: Implement strex and ldrex instruction relying on TCG's qemu_ldlink and qemu_stcond. For the time being only the 32bit instructions are supported. Suggested-by: Jani Kokkonen jani.kokko...@huawei.com Suggested-by: Claudio Fontana claudio.font...@huawei.com Signed-off-by: Alvise Rigo a.r...@virtualopensystems.com --- target-arm/translate.c | 87 ++- tcg/arm/tcg-target.c | 121 + 2 files changed, 178 insertions(+), 30 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 80302cd..0366c76 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -72,6 +72,8 @@ static TCGv_i64 cpu_exclusive_test; static TCGv_i32 cpu_exclusive_info; #endif +static TCGv_i32 cpu_ll_sc_context; + /* FIXME: These should be removed. */ static TCGv_i32 cpu_F0s, cpu_F1s; static TCGv_i64 cpu_F0d, cpu_F1d; @@ -103,6 +105,8 @@ void arm_translate_init(void) offsetof(CPUARMState, exclusive_addr), exclusive_addr); cpu_exclusive_val = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUARMState, exclusive_val), exclusive_val); +cpu_ll_sc_context = tcg_global_mem_new_i32(TCG_AREG0, +offsetof(CPUARMState, ll_sc_context), ll_sc_context); #ifdef CONFIG_USER_ONLY cpu_exclusive_test = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUARMState, exclusive_test), exclusive_test); @@ -961,6 +965,18 @@ DO_GEN_ST(8, MO_UB) DO_GEN_ST(16, MO_TEUW) DO_GEN_ST(32, MO_TEUL) +/* Load/Store exclusive generators (always unsigned) */ +static inline void gen_aa32_ldex32(TCGv_i32 val, TCGv_i32 addr, int index) +{ +tcg_gen_qemu_ldlink_i32(val, addr, index, MO_TEUL | MO_EXCL); +} + +static inline void gen_aa32_stex32(TCGv_i32 is_dirty, TCGv_i32 val, + TCGv_i32 addr, int index) +{ +tcg_gen_qemu_stcond_i32(is_dirty, val, addr, index, MO_TEUL | MO_EXCL); +} + static inline void gen_set_pc_im(DisasContext *s, target_ulong val) { tcg_gen_movi_i32(cpu_R[15], val); @@ -7427,6 +7443,26 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2, store_reg(s, rt, tmp); } +static void gen_load_exclusive_multi(DisasContext *s, int rt, int rt2, + TCGv_i32 addr, int size) +{ +TCGv_i32 tmp = tcg_temp_new_i32(); + +switch (size) { +case 0: +case 1: +abort(); +case 2: +gen_aa32_ldex32(tmp, addr, get_mem_index(s)); +break; +case 3: +default: +abort(); +} + +store_reg(s, rt, tmp); +} + static void gen_clrex(DisasContext *s) { gen_helper_atomic_clear(cpu_env); @@ -7460,6 +7496,52 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, tcg_temp_free_i64(val); tcg_temp_free_i32(tmp_size); } + +static void gen_store_exclusive_multi(DisasContext *s, int rd, int rt, int rt2, + TCGv_i32 addr, int size) +{ +TCGv_i32 tmp; +TCGv_i32 is_dirty; +TCGLabel *done_label; +TCGLabel *fail_label; + +fail_label = gen_new_label(); +done_label = gen_new_label(); + +tmp = tcg_temp_new_i32(); +is_dirty = tcg_temp_new_i32(); + +/* Fail if we are not in LL/SC context. */ +tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ll_sc_context, 1, fail_label); + +tmp = load_reg(s, rt); +switch (size) { +case 0: +case 1: +abort(); +break; +case 2: +gen_aa32_stex32(is_dirty, tmp, addr, get_mem_index(s)); +break; +case 3: +default: +abort(); +} + +tcg_temp_free_i32(tmp); + +/* Check if the store conditional has to fail. */ +tcg_gen_brcondi_i32(TCG_COND_EQ, is_dirty, 1, fail_label); +tcg_temp_free_i32(is_dirty); + +tcg_temp_free_i32(tmp); + +tcg_gen_movi_i32(cpu_R[rd], 0); /* is_dirty = 0 */ +tcg_gen_br(done_label); +gen_set_label(fail_label); +tcg_gen_movi_i32(cpu_R[rd], 1); /* is_dirty = 1 */ +gen_set_label(done_label); +} #endif /* gen_srs: @@ -8308,7 +8390,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) } else if (insn (1 20)) { switch (op1) { case 0: /* ldrex */ -gen_load_exclusive(s, rd, 15, addr, 2); +gen_load_exclusive_multi(s, rd, 15, addr, 2); break; case 1: /* ldrexd */ gen_load_exclusive(s, rd, rd + 1, addr, 3); @@ -8326,7 +8408,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) rm = insn 0xf; switch (op1) {
Re: [Qemu-devel] [RFC v3 05/13] target-arm: translate: implement qemu_ldlink and qemu_stcond ops
On Fri, Jul 17, 2015 at 2:51 PM, Alex Bennée alex.ben...@linaro.org wrote: Alvise Rigo a.r...@virtualopensystems.com writes: Implement strex and ldrex instruction relying on TCG's qemu_ldlink and qemu_stcond. For the time being only the 32bit instructions are supported. Suggested-by: Jani Kokkonen jani.kokko...@huawei.com Suggested-by: Claudio Fontana claudio.font...@huawei.com Signed-off-by: Alvise Rigo a.r...@virtualopensystems.com --- target-arm/translate.c | 87 ++- tcg/arm/tcg-target.c | 121 + 2 files changed, 178 insertions(+), 30 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 80302cd..0366c76 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -72,6 +72,8 @@ static TCGv_i64 cpu_exclusive_test; static TCGv_i32 cpu_exclusive_info; #endif +static TCGv_i32 cpu_ll_sc_context; + /* FIXME: These should be removed. */ static TCGv_i32 cpu_F0s, cpu_F1s; static TCGv_i64 cpu_F0d, cpu_F1d; @@ -103,6 +105,8 @@ void arm_translate_init(void) offsetof(CPUARMState, exclusive_addr), exclusive_addr); cpu_exclusive_val = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUARMState, exclusive_val), exclusive_val); +cpu_ll_sc_context = tcg_global_mem_new_i32(TCG_AREG0, +offsetof(CPUARMState, ll_sc_context), ll_sc_context); #ifdef CONFIG_USER_ONLY cpu_exclusive_test = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUARMState, exclusive_test), exclusive_test); @@ -961,6 +965,18 @@ DO_GEN_ST(8, MO_UB) DO_GEN_ST(16, MO_TEUW) DO_GEN_ST(32, MO_TEUL) +/* Load/Store exclusive generators (always unsigned) */ +static inline void gen_aa32_ldex32(TCGv_i32 val, TCGv_i32 addr, int index) +{ +tcg_gen_qemu_ldlink_i32(val, addr, index, MO_TEUL | MO_EXCL); +} + +static inline void gen_aa32_stex32(TCGv_i32 is_dirty, TCGv_i32 val, + TCGv_i32 addr, int index) +{ +tcg_gen_qemu_stcond_i32(is_dirty, val, addr, index, MO_TEUL | MO_EXCL); +} + static inline void gen_set_pc_im(DisasContext *s, target_ulong val) { tcg_gen_movi_i32(cpu_R[15], val); @@ -7427,6 +7443,26 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2, store_reg(s, rt, tmp); } +static void gen_load_exclusive_multi(DisasContext *s, int rt, int rt2, + TCGv_i32 addr, int size) +{ +TCGv_i32 tmp = tcg_temp_new_i32(); + +switch (size) { +case 0: +case 1: +abort(); +case 2: +gen_aa32_ldex32(tmp, addr, get_mem_index(s)); +break; +case 3: +default: +abort(); +} + +store_reg(s, rt, tmp); +} + static void gen_clrex(DisasContext *s) { gen_helper_atomic_clear(cpu_env); @@ -7460,6 +7496,52 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, tcg_temp_free_i64(val); tcg_temp_free_i32(tmp_size); } + +static void gen_store_exclusive_multi(DisasContext *s, int rd, int rt, int rt2, + TCGv_i32 addr, int size) +{ +TCGv_i32 tmp; +TCGv_i32 is_dirty; +TCGLabel *done_label; +TCGLabel *fail_label; + +fail_label = gen_new_label(); +done_label = gen_new_label(); + +tmp = tcg_temp_new_i32(); +is_dirty = tcg_temp_new_i32(); + +/* Fail if we are not in LL/SC context. */ +tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ll_sc_context, 1, fail_label); + +tmp = load_reg(s, rt); +switch (size) { +case 0: +case 1: +abort(); +break; +case 2: +gen_aa32_stex32(is_dirty, tmp, addr, get_mem_index(s)); +break; +case 3: +default: +abort(); +} + +tcg_temp_free_i32(tmp); + +/* Check if the store conditional has to fail. */ +tcg_gen_brcondi_i32(TCG_COND_EQ, is_dirty, 1, fail_label); +tcg_temp_free_i32(is_dirty); + +tcg_temp_free_i32(tmp); + +tcg_gen_movi_i32(cpu_R[rd], 0); /* is_dirty = 0 */ +tcg_gen_br(done_label); +gen_set_label(fail_label); +tcg_gen_movi_i32(cpu_R[rd], 1); /* is_dirty = 1 */ +gen_set_label(done_label); +} #endif /* gen_srs: @@ -8308,7 +8390,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) } else if (insn (1 20)) { switch (op1) { case 0: /* ldrex */ -gen_load_exclusive(s, rd, 15, addr, 2); +gen_load_exclusive_multi(s, rd, 15, addr, 2); break; case 1: /* ldrexd */ gen_load_exclusive(s, rd, rd + 1, addr, 3); @@ -8326,7 +8408,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) rm =
[Qemu-devel] [RFC v3 05/13] target-arm: translate: implement qemu_ldlink and qemu_stcond ops
Implement strex and ldrex instruction relying on TCG's qemu_ldlink and qemu_stcond. For the time being only the 32bit instructions are supported. Suggested-by: Jani Kokkonen jani.kokko...@huawei.com Suggested-by: Claudio Fontana claudio.font...@huawei.com Signed-off-by: Alvise Rigo a.r...@virtualopensystems.com --- target-arm/translate.c | 87 ++- tcg/arm/tcg-target.c | 121 + 2 files changed, 178 insertions(+), 30 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 80302cd..0366c76 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -72,6 +72,8 @@ static TCGv_i64 cpu_exclusive_test; static TCGv_i32 cpu_exclusive_info; #endif +static TCGv_i32 cpu_ll_sc_context; + /* FIXME: These should be removed. */ static TCGv_i32 cpu_F0s, cpu_F1s; static TCGv_i64 cpu_F0d, cpu_F1d; @@ -103,6 +105,8 @@ void arm_translate_init(void) offsetof(CPUARMState, exclusive_addr), exclusive_addr); cpu_exclusive_val = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUARMState, exclusive_val), exclusive_val); +cpu_ll_sc_context = tcg_global_mem_new_i32(TCG_AREG0, +offsetof(CPUARMState, ll_sc_context), ll_sc_context); #ifdef CONFIG_USER_ONLY cpu_exclusive_test = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUARMState, exclusive_test), exclusive_test); @@ -961,6 +965,18 @@ DO_GEN_ST(8, MO_UB) DO_GEN_ST(16, MO_TEUW) DO_GEN_ST(32, MO_TEUL) +/* Load/Store exclusive generators (always unsigned) */ +static inline void gen_aa32_ldex32(TCGv_i32 val, TCGv_i32 addr, int index) +{ +tcg_gen_qemu_ldlink_i32(val, addr, index, MO_TEUL | MO_EXCL); +} + +static inline void gen_aa32_stex32(TCGv_i32 is_dirty, TCGv_i32 val, + TCGv_i32 addr, int index) +{ +tcg_gen_qemu_stcond_i32(is_dirty, val, addr, index, MO_TEUL | MO_EXCL); +} + static inline void gen_set_pc_im(DisasContext *s, target_ulong val) { tcg_gen_movi_i32(cpu_R[15], val); @@ -7427,6 +7443,26 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2, store_reg(s, rt, tmp); } +static void gen_load_exclusive_multi(DisasContext *s, int rt, int rt2, + TCGv_i32 addr, int size) +{ +TCGv_i32 tmp = tcg_temp_new_i32(); + +switch (size) { +case 0: +case 1: +abort(); +case 2: +gen_aa32_ldex32(tmp, addr, get_mem_index(s)); +break; +case 3: +default: +abort(); +} + +store_reg(s, rt, tmp); +} + static void gen_clrex(DisasContext *s) { gen_helper_atomic_clear(cpu_env); @@ -7460,6 +7496,52 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, tcg_temp_free_i64(val); tcg_temp_free_i32(tmp_size); } + +static void gen_store_exclusive_multi(DisasContext *s, int rd, int rt, int rt2, + TCGv_i32 addr, int size) +{ +TCGv_i32 tmp; +TCGv_i32 is_dirty; +TCGLabel *done_label; +TCGLabel *fail_label; + +fail_label = gen_new_label(); +done_label = gen_new_label(); + +tmp = tcg_temp_new_i32(); +is_dirty = tcg_temp_new_i32(); + +/* Fail if we are not in LL/SC context. */ +tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ll_sc_context, 1, fail_label); + +tmp = load_reg(s, rt); +switch (size) { +case 0: +case 1: +abort(); +break; +case 2: +gen_aa32_stex32(is_dirty, tmp, addr, get_mem_index(s)); +break; +case 3: +default: +abort(); +} + +tcg_temp_free_i32(tmp); + +/* Check if the store conditional has to fail. */ +tcg_gen_brcondi_i32(TCG_COND_EQ, is_dirty, 1, fail_label); +tcg_temp_free_i32(is_dirty); + +tcg_temp_free_i32(tmp); + +tcg_gen_movi_i32(cpu_R[rd], 0); /* is_dirty = 0 */ +tcg_gen_br(done_label); +gen_set_label(fail_label); +tcg_gen_movi_i32(cpu_R[rd], 1); /* is_dirty = 1 */ +gen_set_label(done_label); +} #endif /* gen_srs: @@ -8308,7 +8390,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) } else if (insn (1 20)) { switch (op1) { case 0: /* ldrex */ -gen_load_exclusive(s, rd, 15, addr, 2); +gen_load_exclusive_multi(s, rd, 15, addr, 2); break; case 1: /* ldrexd */ gen_load_exclusive(s, rd, rd + 1, addr, 3); @@ -8326,7 +8408,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) rm = insn 0xf; switch (op1) { case 0: /* strex */ -gen_store_exclusive(s, rd, rm, 15, addr, 2); +gen_store_exclusive_multi(s, rd, rm, 15, +