Re: [Qemu-devel] [RFC v3 05/13] target-arm: translate: implement qemu_ldlink and qemu_stcond ops

2015-07-17 Thread Alex Bennée

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

2015-07-17 Thread alvise rigo
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

2015-07-10 Thread Alvise Rigo
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,
+