]> Git Repo - qemu.git/blobdiff - target/ppc/mem_helper.c
Include qemu/main-loop.h less
[qemu.git] / target / ppc / mem_helper.c
index 1ab8a6eab4ee2e56789ca8ddfb8ec2a68bd7326a..1351b53f284f56d5ba2096ee58bc5f4fdc92b6d2 100644 (file)
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
+
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "exec/exec-all.h"
 #include "qemu/host-utils.h"
+#include "qemu/main-loop.h"
 #include "exec/helper-proto.h"
-
 #include "helper_regs.h"
 #include "exec/cpu_ldst.h"
+#include "tcg.h"
+#include "internal.h"
+#include "qemu/atomic128.h"
 
-//#define DEBUG_OP
+/* #define DEBUG_OP */
 
 static inline bool needs_byteswap(const CPUPPCState *env)
 {
@@ -101,16 +105,17 @@ void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg)
     do_lsw(env, addr, nb, reg, GETPC());
 }
 
-/* PPC32 specification says we must generate an exception if
- * rA is in the range of registers to be loaded.
- * In an other hand, IBM says this is valid, but rA won't be loaded.
- * For now, I'll follow the spec...
+/*
+ * PPC32 specification says we must generate an exception if rA is in
+ * the range of registers to be loaded.  In an other hand, IBM says
+ * this is valid, but rA won't be loaded.  For now, I'll follow the
+ * spec...
  */
 void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,
                  uint32_t ra, uint32_t rb)
 {
     if (likely(xer_bc != 0)) {
-        int num_used_regs = (xer_bc + 3) / 4;
+        int num_used_regs = DIV_ROUND_UP(xer_bc, 4);
         if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) ||
                      lsw_reg_in_range(reg, num_used_regs, rb))) {
             raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
@@ -140,11 +145,13 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
     }
 }
 
-void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode)
+static void dcbz_common(CPUPPCState *env, target_ulong addr,
+                        uint32_t opcode, bool epid, uintptr_t retaddr)
 {
     target_ulong mask, dcbz_size = env->dcache_line_size;
     uint32_t i;
     void *haddr;
+    int mmu_idx = epid ? PPC_TLB_EPID_STORE : env->dmmu_idx;
 
 #if defined(TARGET_PPC64)
     /* Check for dcbz vs dcbzl on 970 */
@@ -164,21 +171,39 @@ void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode)
     }
 
     /* Try fast path translate */
-    haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, env->dmmu_idx);
+    haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, mmu_idx);
     if (haddr) {
         memset(haddr, 0, dcbz_size);
     } else {
         /* Slow path */
         for (i = 0; i < dcbz_size; i += 8) {
-            cpu_stq_data_ra(env, addr + i, 0, GETPC());
+            if (epid) {
+#if !defined(CONFIG_USER_ONLY)
+                /* Does not make sense on USER_ONLY config */
+                cpu_stq_eps_ra(env, addr + i, 0, retaddr);
+#endif
+            } else {
+                cpu_stq_data_ra(env, addr + i, 0, retaddr);
+            }
         }
     }
 }
 
+void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode)
+{
+    dcbz_common(env, addr, opcode, false, GETPC());
+}
+
+void helper_dcbzep(CPUPPCState *env, target_ulong addr, uint32_t opcode)
+{
+    dcbz_common(env, addr, opcode, true, GETPC());
+}
+
 void helper_icbi(CPUPPCState *env, target_ulong addr)
 {
     addr &= ~(env->dcache_line_size - 1);
-    /* Invalidate one cache line :
+    /*
+     * Invalidate one cache line :
      * PowerPC specification says this is to be treated like a load
      * (not a fetch) by the MMU. To be sure it will be so,
      * do the load "by hand".
@@ -186,6 +211,15 @@ void helper_icbi(CPUPPCState *env, target_ulong addr)
     cpu_ldl_data_ra(env, addr, GETPC());
 }
 
+void helper_icbiep(CPUPPCState *env, target_ulong addr)
+{
+#if !defined(CONFIG_USER_ONLY)
+    /* See comments above */
+    addr &= ~(env->dcache_line_size - 1);
+    cpu_ldl_epl_ra(env, addr, GETPC());
+#endif
+}
+
 /* XXX: to be tested */
 target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
                           uint32_t ra, uint32_t rb)
@@ -214,6 +248,98 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
     return i;
 }
 
+#ifdef TARGET_PPC64
+uint64_t helper_lq_le_parallel(CPUPPCState *env, target_ulong addr,
+                               uint32_t opidx)
+{
+    Int128 ret;
+
+    /* We will have raised EXCP_ATOMIC from the translator.  */
+    assert(HAVE_ATOMIC128);
+    ret = helper_atomic_ldo_le_mmu(env, addr, opidx, GETPC());
+    env->retxh = int128_gethi(ret);
+    return int128_getlo(ret);
+}
+
+uint64_t helper_lq_be_parallel(CPUPPCState *env, target_ulong addr,
+                               uint32_t opidx)
+{
+    Int128 ret;
+
+    /* We will have raised EXCP_ATOMIC from the translator.  */
+    assert(HAVE_ATOMIC128);
+    ret = helper_atomic_ldo_be_mmu(env, addr, opidx, GETPC());
+    env->retxh = int128_gethi(ret);
+    return int128_getlo(ret);
+}
+
+void helper_stq_le_parallel(CPUPPCState *env, target_ulong addr,
+                            uint64_t lo, uint64_t hi, uint32_t opidx)
+{
+    Int128 val;
+
+    /* We will have raised EXCP_ATOMIC from the translator.  */
+    assert(HAVE_ATOMIC128);
+    val = int128_make128(lo, hi);
+    helper_atomic_sto_le_mmu(env, addr, val, opidx, GETPC());
+}
+
+void helper_stq_be_parallel(CPUPPCState *env, target_ulong addr,
+                            uint64_t lo, uint64_t hi, uint32_t opidx)
+{
+    Int128 val;
+
+    /* We will have raised EXCP_ATOMIC from the translator.  */
+    assert(HAVE_ATOMIC128);
+    val = int128_make128(lo, hi);
+    helper_atomic_sto_be_mmu(env, addr, val, opidx, GETPC());
+}
+
+uint32_t helper_stqcx_le_parallel(CPUPPCState *env, target_ulong addr,
+                                  uint64_t new_lo, uint64_t new_hi,
+                                  uint32_t opidx)
+{
+    bool success = false;
+
+    /* We will have raised EXCP_ATOMIC from the translator.  */
+    assert(HAVE_CMPXCHG128);
+
+    if (likely(addr == env->reserve_addr)) {
+        Int128 oldv, cmpv, newv;
+
+        cmpv = int128_make128(env->reserve_val2, env->reserve_val);
+        newv = int128_make128(new_lo, new_hi);
+        oldv = helper_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv,
+                                             opidx, GETPC());
+        success = int128_eq(oldv, cmpv);
+    }
+    env->reserve_addr = -1;
+    return env->so + success * CRF_EQ_BIT;
+}
+
+uint32_t helper_stqcx_be_parallel(CPUPPCState *env, target_ulong addr,
+                                  uint64_t new_lo, uint64_t new_hi,
+                                  uint32_t opidx)
+{
+    bool success = false;
+
+    /* We will have raised EXCP_ATOMIC from the translator.  */
+    assert(HAVE_CMPXCHG128);
+
+    if (likely(addr == env->reserve_addr)) {
+        Int128 oldv, cmpv, newv;
+
+        cmpv = int128_make128(env->reserve_val2, env->reserve_val);
+        newv = int128_make128(new_lo, new_hi);
+        oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv,
+                                             opidx, GETPC());
+        success = int128_eq(oldv, cmpv);
+    }
+    env->reserve_addr = -1;
+    return env->so + success * CRF_EQ_BIT;
+}
+#endif
+
 /*****************************************************************************/
 /* Altivec extension helpers */
 #if defined(HOST_WORDS_BIGENDIAN)
@@ -224,17 +350,19 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
 #define LO_IDX 0
 #endif
 
-/* We use msr_le to determine index ordering in a vector.  However,
-   byteswapping is not simply controlled by msr_le.  We also need to take
-   into account endianness of the target.  This is done for the little-endian
-   PPC64 user-mode target. */
+/*
+ * We use msr_le to determine index ordering in a vector.  However,
+ * byteswapping is not simply controlled by msr_le.  We also need to
+ * take into account endianness of the target.  This is done for the
+ * little-endian PPC64 user-mode target.
+ */
 
 #define LVE(name, access, swap, element)                        \
     void helper_##name(CPUPPCState *env, ppc_avr_t *r,          \
                        target_ulong addr)                       \
     {                                                           \
         size_t n_elems = ARRAY_SIZE(r->element);                \
-        int adjust = HI_IDX*(n_elems - 1);                      \
+        int adjust = HI_IDX * (n_elems - 1);                    \
         int sh = sizeof(r->element[0]) >> 1;                    \
         int index = (addr & 0xf) >> sh;                         \
         if (msr_le) {                                           \
@@ -284,17 +412,82 @@ STVE(stvewx, cpu_stl_data_ra, bswap32, u32)
 #undef I
 #undef LVE
 
+#ifdef TARGET_PPC64
+#define GET_NB(rb) ((rb >> 56) & 0xFF)
+
+#define VSX_LXVL(name, lj)                                              \
+void helper_##name(CPUPPCState *env, target_ulong addr,                 \
+                   ppc_vsr_t *xt, target_ulong rb)                      \
+{                                                                       \
+    ppc_vsr_t t;                                                        \
+    uint64_t nb = GET_NB(rb);                                           \
+    int i;                                                              \
+                                                                        \
+    t.s128 = int128_zero();                                             \
+    if (nb) {                                                           \
+        nb = (nb >= 16) ? 16 : nb;                                      \
+        if (msr_le && !lj) {                                            \
+            for (i = 16; i > 16 - nb; i--) {                            \
+                t.VsrB(i - 1) = cpu_ldub_data_ra(env, addr, GETPC());   \
+                addr = addr_add(env, addr, 1);                          \
+            }                                                           \
+        } else {                                                        \
+            for (i = 0; i < nb; i++) {                                  \
+                t.VsrB(i) = cpu_ldub_data_ra(env, addr, GETPC());       \
+                addr = addr_add(env, addr, 1);                          \
+            }                                                           \
+        }                                                               \
+    }                                                                   \
+    *xt = t;                                                            \
+}
+
+VSX_LXVL(lxvl, 0)
+VSX_LXVL(lxvll, 1)
+#undef VSX_LXVL
+
+#define VSX_STXVL(name, lj)                                       \
+void helper_##name(CPUPPCState *env, target_ulong addr,           \
+                   ppc_vsr_t *xt, target_ulong rb)                \
+{                                                                 \
+    target_ulong nb = GET_NB(rb);                                 \
+    int i;                                                        \
+                                                                  \
+    if (!nb) {                                                    \
+        return;                                                   \
+    }                                                             \
+                                                                  \
+    nb = (nb >= 16) ? 16 : nb;                                    \
+    if (msr_le && !lj) {                                          \
+        for (i = 16; i > 16 - nb; i--) {                          \
+            cpu_stb_data_ra(env, addr, xt->VsrB(i - 1), GETPC()); \
+            addr = addr_add(env, addr, 1);                        \
+        }                                                         \
+    } else {                                                      \
+        for (i = 0; i < nb; i++) {                                \
+            cpu_stb_data_ra(env, addr, xt->VsrB(i), GETPC());     \
+            addr = addr_add(env, addr, 1);                        \
+        }                                                         \
+    }                                                             \
+}
+
+VSX_STXVL(stxvl, 0)
+VSX_STXVL(stxvll, 1)
+#undef VSX_STXVL
+#undef GET_NB
+#endif /* TARGET_PPC64 */
+
 #undef HI_IDX
 #undef LO_IDX
 
 void helper_tbegin(CPUPPCState *env)
 {
-    /* As a degenerate implementation, always fail tbegin.  The reason
+    /*
+     * As a degenerate implementation, always fail tbegin.  The reason
      * given is "Nesting overflow".  The "persistent" bit is set,
      * providing a hint to the error handler to not retry.  The TFIAR
      * captures the address of the failure, which is this tbegin
-     * instruction.  Instruction execution will continue with the
-     * next instruction in memory, which is precisely what we want.
+     * instruction.  Instruction execution will continue with the next
+     * instruction in memory, which is precisely what we want.
      */
 
     env->spr[SPR_TEXASR] =
This page took 0.03236 seconds and 4 git commands to generate.