qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 3/3] target-m68k: add cas/cas2 ops


From: Richard Henderson
Subject: Re: [Qemu-devel] [PATCH 3/3] target-m68k: add cas/cas2 ops
Date: Mon, 31 Oct 2016 08:34:21 -0600
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.4.0

On 10/31/2016 03:20 AM, Laurent Vivier wrote:
+    /* FIXME: this sequence is not atomic */
+
+    /* if (R1) == Dc1 && (R2) == Dc2 then
+     *     (R1) = Du1
+     *     (R2) = Du2
+     *     Dc1 = (R1) (because Dc1 == (R1))
+     *     Dc2 = (R2) (because Dc2 == (R2))
+     * else
+     *     Dc1 = (R1)
+     *     Dc2 = (R2)
+     */

We'll need to handle this in a helper, I think. And there is an interesting subcase that's worth handling: When (R1) and (R2) are consecutive, i.e. we're performing a "normal" 64-bit cmpxchg, rather than two disjoint 32-bit cmpxchgs.

While we could pack the Dc and Du data into uint64_t, getting the flags exactly right probably requires more help so let's do everything in the helper, including updating the registers. Like so:

void HELPER(cas2l)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2)
{
    uint32_t Dc1 = extract32(regs, 9, 3);
    uint32_t Dc2 = extract32(regs, 6, 3);
    uint32_t Du1 = extract32(regs, 3, 3);
    uint32_t Du2 = extract32(regs, 0, 3);
    uint32_t c1 = env->dregs[Dc1];
    uint32_t c2 = env->dregs[Dc2];
    uint32_t u1 = env->dregs[Du1];
    uint32_t u2 = env->dregs[Du2];
    uint32_t l1, l2;
    uint64_t c, u, l;
    uintptr_t ra = GETPC();
    int mmu_idx = cpu_mmu_index(env, 0);
    TCGMemOpIdx oi;

    if (parallel_cpus) {
        /* We're executing in a parallel context -- must be atomic.  */
        if ((a1 & 7) == 0 && a2 == a1 + 4) {
            c = deposit64(c2, 32, 32, c1);
            u = deposit64(u2, 32, 32, u1);
            oi = make_memop_idx(MO_BEQ, mmu_idx);
            l = helper_atomic_cmpxchgq_be_mmu(env, a1, c, u, oi, ra);
            l1 = l >> 32;
            l2 = l;
        } else if ((a2 & 7) == 0 && a1 == a2 + 4) {
            c = deposit64(c1, 32, 32, c2);
            u = deposit64(u1, 32, 32, u2);
            oi = make_memop_idx(MO_BEQ, mmu_idx);
            l = helper_atomic_cmpxchgq_be_mmu(env, a1, c, u, oi, ra);
            l2 = l >> 32;
            l1 = l;
        } else {
            /* Tell the main loop we need to serialize this insn.  */
            cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
        }
    } else {
        /* We're executing in a serial context -- no need to be atomic.  */
        oi = make_memop_idx(MO_BEUL, mmu_idx);
        l1 = helper_be_ldul_mmu(env, a1, oi, ra);
        l2 = helper_be_ldul_mmu(env, a2, oi, ra);
        if (l1 == c1 && l2 == c2) {
            helper_be_stl_mmu(env, a1, u1, oi, ra);
            helper_be_stl_mmu(env, a2, u2, oi, ra);
        }
    }

    if (c1 != l1) {
        env->cc_n = c1;
        env->cc_v = l1;
    } else {
        env->cc_n = c2;
        env->cc_v = l2;
    }
    env->cc_op = CC_OP_CMPL;
    env->dregs[Dc1] = l1;
    env->dregs[Dc2] = l2;
}

where cas2w would be similar (but could probably drop the special case for aX = aY + 2, because surely anyone sane would have just used cas.l in the first place).


r~



reply via email to

[Prev in Thread] Current Thread [Next in Thread]