diff mbox

[06/24] target-arm: A64: Implement store-exclusive for system mode

Message ID 1390335150-13470-7-git-send-email-peter.maydell@linaro.org
State Superseded
Headers show

Commit Message

Peter Maydell Jan. 21, 2014, 8:12 p.m. UTC
System mode store-exclusive use a different code path to usermode ones;
implement this missing code, in a similar way to the 32 bit version.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/translate-a64.c | 68 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 62 insertions(+), 6 deletions(-)

Comments

Peter Maydell Jan. 22, 2014, 10:42 a.m. UTC | #1
On 22 January 2014 02:19, Hu Tao <hutao@cn.fujitsu.com> wrote:
> On Tue, Jan 21, 2014 at 08:12:12PM +0000, Peter Maydell wrote:
>> +    if (is_pair) {
>> +        TCGv_i64 addrhi = tcg_temp_new_i64();
>> +        TCGv_i64 tmphi = tcg_temp_new_i64();
>> +
>> +        tcg_gen_addi_i64(addrhi, addr, 1 << size);
>> +        tcg_gen_qemu_ld_i64(tmphi, addrhi, get_mem_index(s), MO_TE + size);
>> +        tcg_gen_brcond_i64(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label);
>
> s/tmp/tmphi/

Thanks, nice catch.

>> +
>> +        tcg_temp_free_i64(tmphi);
>> +        tcg_temp_free_i64(addrhi);
>
> Can addrhi be saved and free after doing store?

It would have to be made a local-temp to avoid the branch
trashing it. I preferred to make it a local and recalculate for
the store on the basis that the TCG backend really ought to
be capable of turning "add tmp, addr, 4; load from tmp" into
a single "load from addr+4" instruction, and having the
constant go into a local-temp would probably defeat that.

thanks
-- PMM
diff mbox

Patch

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index e0f6765..5aa1f17 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1422,12 +1422,68 @@  static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
 }
 #else
 static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
-                                TCGv_i64 addr, int size, int is_pair)
-{
-    qemu_log_mask(LOG_UNIMP,
-                  "%s:%d: system mode store_exclusive unsupported "
-                  "at pc=%016" PRIx64 "\n",
-                  __FILE__, __LINE__, s->pc - 4);
+                                TCGv_i64 inaddr, int size, int is_pair)
+{
+    /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]
+     *     && (!is_pair || env->exclusive_high == [addr + datasize])) {
+     *     [addr] = {Rt};
+     *     if (is_pair) {
+     *         [addr + datasize] = {Rt2};
+     *     }
+     *     {Rd} = 0;
+     * } else {
+     *     {Rd} = 1;
+     * }
+     * env->exclusive_addr = -1;
+     */
+    int fail_label = gen_new_label();
+    int done_label = gen_new_label();
+    TCGv_i64 addr = tcg_temp_local_new_i64();
+    TCGv_i64 tmp;
+
+    /* Copy input into a local temp so it is not trashed when the
+     * basic block ends at the branch insn.
+     */
+    tcg_gen_mov_i64(addr, inaddr);
+    tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label);
+
+    tmp = tcg_temp_new_i64();
+    tcg_gen_qemu_ld_i64(tmp, addr, get_mem_index(s), MO_TE + size);
+    tcg_gen_brcond_i64(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label);
+    tcg_temp_free_i64(tmp);
+
+    if (is_pair) {
+        TCGv_i64 addrhi = tcg_temp_new_i64();
+        TCGv_i64 tmphi = tcg_temp_new_i64();
+
+        tcg_gen_addi_i64(addrhi, addr, 1 << size);
+        tcg_gen_qemu_ld_i64(tmphi, addrhi, get_mem_index(s), MO_TE + size);
+        tcg_gen_brcond_i64(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label);
+
+        tcg_temp_free_i64(tmphi);
+        tcg_temp_free_i64(addrhi);
+    }
+
+    /* We seem to still have the exclusive monitor, so do the store */
+    tcg_gen_qemu_st_i64(cpu_reg(s, rt), addr, get_mem_index(s), MO_TE + size);
+    if (is_pair) {
+        TCGv_i64 addrhi = tcg_temp_new_i64();
+
+        tcg_gen_addi_i64(addrhi, addr, 1 << size);
+        tcg_gen_qemu_st_i64(cpu_reg(s, rt2), addrhi,
+                            get_mem_index(s), MO_TE + size);
+        tcg_temp_free_i64(addrhi);
+    }
+
+    tcg_temp_free_i64(addr);
+
+    tcg_gen_movi_i64(cpu_reg(s, rd), 0);
+    tcg_gen_br(done_label);
+    gen_set_label(fail_label);
+    tcg_gen_movi_i64(cpu_reg(s, rd), 1);
+    gen_set_label(done_label);
+    tcg_gen_movi_i64(cpu_exclusive_addr, -1);
+
 }
 #endif