1fcf5ef2aSThomas Huth /* 2fcf5ef2aSThomas Huth * PowerPC memory access emulation helpers for QEMU. 3fcf5ef2aSThomas Huth * 4fcf5ef2aSThomas Huth * Copyright (c) 2003-2007 Jocelyn Mayer 5fcf5ef2aSThomas Huth * 6fcf5ef2aSThomas Huth * This library is free software; you can redistribute it and/or 7fcf5ef2aSThomas Huth * modify it under the terms of the GNU Lesser General Public 8fcf5ef2aSThomas Huth * License as published by the Free Software Foundation; either 96bd039cdSChetan Pant * version 2.1 of the License, or (at your option) any later version. 10fcf5ef2aSThomas Huth * 11fcf5ef2aSThomas Huth * This library is distributed in the hope that it will be useful, 12fcf5ef2aSThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of 13fcf5ef2aSThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14fcf5ef2aSThomas Huth * Lesser General Public License for more details. 15fcf5ef2aSThomas Huth * 16fcf5ef2aSThomas Huth * You should have received a copy of the GNU Lesser General Public 17fcf5ef2aSThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18fcf5ef2aSThomas Huth */ 19db725815SMarkus Armbruster 20fcf5ef2aSThomas Huth #include "qemu/osdep.h" 21fcf5ef2aSThomas Huth #include "cpu.h" 22fcf5ef2aSThomas Huth #include "exec/exec-all.h" 23fcf5ef2aSThomas Huth #include "qemu/host-utils.h" 24fcf5ef2aSThomas Huth #include "exec/helper-proto.h" 25fcf5ef2aSThomas Huth #include "helper_regs.h" 26fcf5ef2aSThomas Huth #include "exec/cpu_ldst.h" 276914bc4fSNikunj A Dadhania #include "internal.h" 28f34ec0f6SRichard Henderson #include "qemu/atomic128.h" 29fcf5ef2aSThomas Huth 305a2c8b9eSDavid Gibson /* #define DEBUG_OP */ 31fcf5ef2aSThomas Huth 32fcf5ef2aSThomas Huth static inline bool needs_byteswap(const CPUPPCState *env) 33fcf5ef2aSThomas Huth { 34ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN 351922322cSVíctor Colombo return FIELD_EX64(env->msr, MSR, LE); 36fcf5ef2aSThomas Huth #else 371922322cSVíctor Colombo return !FIELD_EX64(env->msr, MSR, LE); 38fcf5ef2aSThomas Huth #endif 39fcf5ef2aSThomas Huth } 40fcf5ef2aSThomas Huth 41fcf5ef2aSThomas Huth /*****************************************************************************/ 42fcf5ef2aSThomas Huth /* Memory load and stores */ 43fcf5ef2aSThomas Huth 44fcf5ef2aSThomas Huth static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr, 45fcf5ef2aSThomas Huth target_long arg) 46fcf5ef2aSThomas Huth { 47fcf5ef2aSThomas Huth #if defined(TARGET_PPC64) 48fcf5ef2aSThomas Huth if (!msr_is_64bit(env, env->msr)) { 49fcf5ef2aSThomas Huth return (uint32_t)(addr + arg); 50fcf5ef2aSThomas Huth } else 51fcf5ef2aSThomas Huth #endif 52fcf5ef2aSThomas Huth { 53fcf5ef2aSThomas Huth return addr + arg; 54fcf5ef2aSThomas Huth } 55fcf5ef2aSThomas Huth } 56fcf5ef2aSThomas Huth 57bb99b391SRichard Henderson static void *probe_contiguous(CPUPPCState *env, target_ulong addr, uint32_t nb, 58bb99b391SRichard Henderson MMUAccessType access_type, int mmu_idx, 59bb99b391SRichard Henderson uintptr_t raddr) 60bb99b391SRichard Henderson { 61bb99b391SRichard Henderson void *host1, *host2; 62bb99b391SRichard Henderson uint32_t nb_pg1, nb_pg2; 63bb99b391SRichard Henderson 64bb99b391SRichard Henderson nb_pg1 = -(addr | TARGET_PAGE_MASK); 65bb99b391SRichard Henderson if (likely(nb <= nb_pg1)) { 66bb99b391SRichard Henderson /* The entire operation is on a single page. */ 67bb99b391SRichard Henderson return probe_access(env, addr, nb, access_type, mmu_idx, raddr); 68bb99b391SRichard Henderson } 69bb99b391SRichard Henderson 70bb99b391SRichard Henderson /* The operation spans two pages. */ 71bb99b391SRichard Henderson nb_pg2 = nb - nb_pg1; 72bb99b391SRichard Henderson host1 = probe_access(env, addr, nb_pg1, access_type, mmu_idx, raddr); 73bb99b391SRichard Henderson addr = addr_add(env, addr, nb_pg1); 74bb99b391SRichard Henderson host2 = probe_access(env, addr, nb_pg2, access_type, mmu_idx, raddr); 75bb99b391SRichard Henderson 76bb99b391SRichard Henderson /* If the two host pages are contiguous, optimize. */ 77bb99b391SRichard Henderson if (host2 == host1 + nb_pg1) { 78bb99b391SRichard Henderson return host1; 79bb99b391SRichard Henderson } 80bb99b391SRichard Henderson return NULL; 81bb99b391SRichard Henderson } 82bb99b391SRichard Henderson 83fcf5ef2aSThomas Huth void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg) 84fcf5ef2aSThomas Huth { 852ca2ef49SRichard Henderson uintptr_t raddr = GETPC(); 86fb00f730SRichard Henderson int mmu_idx = ppc_env_mmu_index(env, false); 872ca2ef49SRichard Henderson void *host = probe_contiguous(env, addr, (32 - reg) * 4, 882ca2ef49SRichard Henderson MMU_DATA_LOAD, mmu_idx, raddr); 892ca2ef49SRichard Henderson 902ca2ef49SRichard Henderson if (likely(host)) { 912ca2ef49SRichard Henderson /* Fast path -- the entire operation is in RAM at host. */ 92fcf5ef2aSThomas Huth for (; reg < 32; reg++) { 932ca2ef49SRichard Henderson env->gpr[reg] = (uint32_t)ldl_be_p(host); 942ca2ef49SRichard Henderson host += 4; 95fcf5ef2aSThomas Huth } 962ca2ef49SRichard Henderson } else { 972ca2ef49SRichard Henderson /* Slow path -- at least some of the operation requires i/o. */ 982ca2ef49SRichard Henderson for (; reg < 32; reg++) { 992ca2ef49SRichard Henderson env->gpr[reg] = cpu_ldl_mmuidx_ra(env, addr, mmu_idx, raddr); 100fcf5ef2aSThomas Huth addr = addr_add(env, addr, 4); 101fcf5ef2aSThomas Huth } 102fcf5ef2aSThomas Huth } 1032ca2ef49SRichard Henderson } 104fcf5ef2aSThomas Huth 105fcf5ef2aSThomas Huth void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg) 106fcf5ef2aSThomas Huth { 1072ca2ef49SRichard Henderson uintptr_t raddr = GETPC(); 108fb00f730SRichard Henderson int mmu_idx = ppc_env_mmu_index(env, false); 1092ca2ef49SRichard Henderson void *host = probe_contiguous(env, addr, (32 - reg) * 4, 1102ca2ef49SRichard Henderson MMU_DATA_STORE, mmu_idx, raddr); 1112ca2ef49SRichard Henderson 1122ca2ef49SRichard Henderson if (likely(host)) { 1132ca2ef49SRichard Henderson /* Fast path -- the entire operation is in RAM at host. */ 114fcf5ef2aSThomas Huth for (; reg < 32; reg++) { 1152ca2ef49SRichard Henderson stl_be_p(host, env->gpr[reg]); 1162ca2ef49SRichard Henderson host += 4; 117fcf5ef2aSThomas Huth } 1182ca2ef49SRichard Henderson } else { 1192ca2ef49SRichard Henderson /* Slow path -- at least some of the operation requires i/o. */ 1202ca2ef49SRichard Henderson for (; reg < 32; reg++) { 1212ca2ef49SRichard Henderson cpu_stl_mmuidx_ra(env, addr, env->gpr[reg], mmu_idx, raddr); 122fcf5ef2aSThomas Huth addr = addr_add(env, addr, 4); 123fcf5ef2aSThomas Huth } 124fcf5ef2aSThomas Huth } 1252ca2ef49SRichard Henderson } 126fcf5ef2aSThomas Huth 127fcf5ef2aSThomas Huth static void do_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, 128fcf5ef2aSThomas Huth uint32_t reg, uintptr_t raddr) 129fcf5ef2aSThomas Huth { 130bb99b391SRichard Henderson int mmu_idx; 131bb99b391SRichard Henderson void *host; 132bb99b391SRichard Henderson uint32_t val; 133fcf5ef2aSThomas Huth 134bb99b391SRichard Henderson if (unlikely(nb == 0)) { 135bb99b391SRichard Henderson return; 136bb99b391SRichard Henderson } 137bb99b391SRichard Henderson 138fb00f730SRichard Henderson mmu_idx = ppc_env_mmu_index(env, false); 139bb99b391SRichard Henderson host = probe_contiguous(env, addr, nb, MMU_DATA_LOAD, mmu_idx, raddr); 140bb99b391SRichard Henderson 141bb99b391SRichard Henderson if (likely(host)) { 142bb99b391SRichard Henderson /* Fast path -- the entire operation is in RAM at host. */ 143fcf5ef2aSThomas Huth for (; nb > 3; nb -= 4) { 144bb99b391SRichard Henderson env->gpr[reg] = (uint32_t)ldl_be_p(host); 145bb99b391SRichard Henderson reg = (reg + 1) % 32; 146bb99b391SRichard Henderson host += 4; 147bb99b391SRichard Henderson } 148bb99b391SRichard Henderson switch (nb) { 149bb99b391SRichard Henderson default: 150bb99b391SRichard Henderson return; 151bb99b391SRichard Henderson case 1: 152bb99b391SRichard Henderson val = ldub_p(host) << 24; 153bb99b391SRichard Henderson break; 154bb99b391SRichard Henderson case 2: 155bb99b391SRichard Henderson val = lduw_be_p(host) << 16; 156bb99b391SRichard Henderson break; 157bb99b391SRichard Henderson case 3: 158bb99b391SRichard Henderson val = (lduw_be_p(host) << 16) | (ldub_p(host + 2) << 8); 159bb99b391SRichard Henderson break; 160bb99b391SRichard Henderson } 161bb99b391SRichard Henderson } else { 162bb99b391SRichard Henderson /* Slow path -- at least some of the operation requires i/o. */ 163bb99b391SRichard Henderson for (; nb > 3; nb -= 4) { 164bb99b391SRichard Henderson env->gpr[reg] = cpu_ldl_mmuidx_ra(env, addr, mmu_idx, raddr); 165fcf5ef2aSThomas Huth reg = (reg + 1) % 32; 166fcf5ef2aSThomas Huth addr = addr_add(env, addr, 4); 167fcf5ef2aSThomas Huth } 168bb99b391SRichard Henderson switch (nb) { 169bb99b391SRichard Henderson default: 170bb99b391SRichard Henderson return; 171bb99b391SRichard Henderson case 1: 172bb99b391SRichard Henderson val = cpu_ldub_mmuidx_ra(env, addr, mmu_idx, raddr) << 24; 173bb99b391SRichard Henderson break; 174bb99b391SRichard Henderson case 2: 175bb99b391SRichard Henderson val = cpu_lduw_mmuidx_ra(env, addr, mmu_idx, raddr) << 16; 176bb99b391SRichard Henderson break; 177bb99b391SRichard Henderson case 3: 178bb99b391SRichard Henderson val = cpu_lduw_mmuidx_ra(env, addr, mmu_idx, raddr) << 16; 179bb99b391SRichard Henderson addr = addr_add(env, addr, 2); 180bb99b391SRichard Henderson val |= cpu_ldub_mmuidx_ra(env, addr, mmu_idx, raddr) << 8; 181bb99b391SRichard Henderson break; 182fcf5ef2aSThomas Huth } 183fcf5ef2aSThomas Huth } 184bb99b391SRichard Henderson env->gpr[reg] = val; 185fcf5ef2aSThomas Huth } 186fcf5ef2aSThomas Huth 187bb99b391SRichard Henderson void helper_lsw(CPUPPCState *env, target_ulong addr, 188bb99b391SRichard Henderson uint32_t nb, uint32_t reg) 189fcf5ef2aSThomas Huth { 190fcf5ef2aSThomas Huth do_lsw(env, addr, nb, reg, GETPC()); 191fcf5ef2aSThomas Huth } 192fcf5ef2aSThomas Huth 1935a2c8b9eSDavid Gibson /* 1945a2c8b9eSDavid Gibson * PPC32 specification says we must generate an exception if rA is in 1955a2c8b9eSDavid Gibson * the range of registers to be loaded. In an other hand, IBM says 1965a2c8b9eSDavid Gibson * this is valid, but rA won't be loaded. For now, I'll follow the 1975a2c8b9eSDavid Gibson * spec... 198fcf5ef2aSThomas Huth */ 199fcf5ef2aSThomas Huth void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg, 200fcf5ef2aSThomas Huth uint32_t ra, uint32_t rb) 201fcf5ef2aSThomas Huth { 202fcf5ef2aSThomas Huth if (likely(xer_bc != 0)) { 203f0704d78SMarc-André Lureau int num_used_regs = DIV_ROUND_UP(xer_bc, 4); 204fcf5ef2aSThomas Huth if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) || 205fcf5ef2aSThomas Huth lsw_reg_in_range(reg, num_used_regs, rb))) { 206fcf5ef2aSThomas Huth raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 207fcf5ef2aSThomas Huth POWERPC_EXCP_INVAL | 208fcf5ef2aSThomas Huth POWERPC_EXCP_INVAL_LSWX, GETPC()); 209fcf5ef2aSThomas Huth } else { 210fcf5ef2aSThomas Huth do_lsw(env, addr, xer_bc, reg, GETPC()); 211fcf5ef2aSThomas Huth } 212fcf5ef2aSThomas Huth } 213fcf5ef2aSThomas Huth } 214fcf5ef2aSThomas Huth 215fcf5ef2aSThomas Huth void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb, 216fcf5ef2aSThomas Huth uint32_t reg) 217fcf5ef2aSThomas Huth { 218bb99b391SRichard Henderson uintptr_t raddr = GETPC(); 219bb99b391SRichard Henderson int mmu_idx; 220bb99b391SRichard Henderson void *host; 221bb99b391SRichard Henderson uint32_t val; 222fcf5ef2aSThomas Huth 223bb99b391SRichard Henderson if (unlikely(nb == 0)) { 224bb99b391SRichard Henderson return; 225bb99b391SRichard Henderson } 226bb99b391SRichard Henderson 227fb00f730SRichard Henderson mmu_idx = ppc_env_mmu_index(env, false); 228bb99b391SRichard Henderson host = probe_contiguous(env, addr, nb, MMU_DATA_STORE, mmu_idx, raddr); 229bb99b391SRichard Henderson 230bb99b391SRichard Henderson if (likely(host)) { 231bb99b391SRichard Henderson /* Fast path -- the entire operation is in RAM at host. */ 232fcf5ef2aSThomas Huth for (; nb > 3; nb -= 4) { 233bb99b391SRichard Henderson stl_be_p(host, env->gpr[reg]); 234bb99b391SRichard Henderson reg = (reg + 1) % 32; 235bb99b391SRichard Henderson host += 4; 236bb99b391SRichard Henderson } 237bb99b391SRichard Henderson val = env->gpr[reg]; 238bb99b391SRichard Henderson switch (nb) { 239bb99b391SRichard Henderson case 1: 240bb99b391SRichard Henderson stb_p(host, val >> 24); 241bb99b391SRichard Henderson break; 242bb99b391SRichard Henderson case 2: 243bb99b391SRichard Henderson stw_be_p(host, val >> 16); 244bb99b391SRichard Henderson break; 245bb99b391SRichard Henderson case 3: 246bb99b391SRichard Henderson stw_be_p(host, val >> 16); 247bb99b391SRichard Henderson stb_p(host + 2, val >> 8); 248bb99b391SRichard Henderson break; 249bb99b391SRichard Henderson } 250bb99b391SRichard Henderson } else { 251bb99b391SRichard Henderson for (; nb > 3; nb -= 4) { 252bb99b391SRichard Henderson cpu_stl_mmuidx_ra(env, addr, env->gpr[reg], mmu_idx, raddr); 253fcf5ef2aSThomas Huth reg = (reg + 1) % 32; 254fcf5ef2aSThomas Huth addr = addr_add(env, addr, 4); 255fcf5ef2aSThomas Huth } 256bb99b391SRichard Henderson val = env->gpr[reg]; 257bb99b391SRichard Henderson switch (nb) { 258bb99b391SRichard Henderson case 1: 259bb99b391SRichard Henderson cpu_stb_mmuidx_ra(env, addr, val >> 24, mmu_idx, raddr); 260bb99b391SRichard Henderson break; 261bb99b391SRichard Henderson case 2: 262bb99b391SRichard Henderson cpu_stw_mmuidx_ra(env, addr, val >> 16, mmu_idx, raddr); 263bb99b391SRichard Henderson break; 264bb99b391SRichard Henderson case 3: 265bb99b391SRichard Henderson cpu_stw_mmuidx_ra(env, addr, val >> 16, mmu_idx, raddr); 266bb99b391SRichard Henderson addr = addr_add(env, addr, 2); 267bb99b391SRichard Henderson cpu_stb_mmuidx_ra(env, addr, val >> 8, mmu_idx, raddr); 268bb99b391SRichard Henderson break; 269fcf5ef2aSThomas Huth } 270fcf5ef2aSThomas Huth } 271fcf5ef2aSThomas Huth } 272fcf5ef2aSThomas Huth 27350728199SRoman Kapl static void dcbz_common(CPUPPCState *env, target_ulong addr, 274c6d84fd7SRichard Henderson int mmu_idx, int dcbz_size, uintptr_t retaddr) 275fcf5ef2aSThomas Huth { 276521a80d8SRichard Henderson target_ulong mask = ~(target_ulong)(dcbz_size - 1); 277fcf5ef2aSThomas Huth void *haddr; 278fcf5ef2aSThomas Huth 279fcf5ef2aSThomas Huth /* Align address */ 280fcf5ef2aSThomas Huth addr &= mask; 281fcf5ef2aSThomas Huth 282fcf5ef2aSThomas Huth /* Check reservation */ 283*f6bcc5b8SRichard Henderson if (unlikely((env->reserve_addr & mask) == addr)) { 284fcf5ef2aSThomas Huth env->reserve_addr = (target_ulong)-1ULL; 285fcf5ef2aSThomas Huth } 286fcf5ef2aSThomas Huth 287fcf5ef2aSThomas Huth /* Try fast path translate */ 288*f6bcc5b8SRichard Henderson #ifdef CONFIG_USER_ONLY 289*f6bcc5b8SRichard Henderson haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, mmu_idx); 290*f6bcc5b8SRichard Henderson #else 2914dcf078fSRichard Henderson haddr = probe_write(env, addr, dcbz_size, mmu_idx, retaddr); 292*f6bcc5b8SRichard Henderson if (unlikely(!haddr)) { 293fcf5ef2aSThomas Huth /* Slow path */ 294521a80d8SRichard Henderson for (int i = 0; i < dcbz_size; i += 8) { 2955a376e4fSRichard Henderson cpu_stq_mmuidx_ra(env, addr + i, 0, mmu_idx, retaddr); 296fcf5ef2aSThomas Huth } 297*f6bcc5b8SRichard Henderson return; 298fcf5ef2aSThomas Huth } 299*f6bcc5b8SRichard Henderson #endif 300*f6bcc5b8SRichard Henderson 301*f6bcc5b8SRichard Henderson set_helper_retaddr(retaddr); 302*f6bcc5b8SRichard Henderson memset(haddr, 0, dcbz_size); 303*f6bcc5b8SRichard Henderson clear_helper_retaddr(); 30450728199SRoman Kapl } 30550728199SRoman Kapl 306c6d84fd7SRichard Henderson void helper_dcbz(CPUPPCState *env, target_ulong addr, int mmu_idx) 30750728199SRoman Kapl { 308c6d84fd7SRichard Henderson dcbz_common(env, addr, mmu_idx, env->dcache_line_size, GETPC()); 30950728199SRoman Kapl } 310fcf5ef2aSThomas Huth 31162fe57c6SRichard Henderson #ifdef TARGET_PPC64 31262fe57c6SRichard Henderson void helper_dcbzl(CPUPPCState *env, target_ulong addr) 31362fe57c6SRichard Henderson { 31462fe57c6SRichard Henderson int dcbz_size = env->dcache_line_size; 31562fe57c6SRichard Henderson 31662fe57c6SRichard Henderson /* 31762fe57c6SRichard Henderson * The translator checked for POWERPC_EXCP_970. 31862fe57c6SRichard Henderson * All that's left is to check HID5. 31962fe57c6SRichard Henderson */ 32062fe57c6SRichard Henderson if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) { 32162fe57c6SRichard Henderson dcbz_size = 32; 32262fe57c6SRichard Henderson } 32362fe57c6SRichard Henderson 324c6d84fd7SRichard Henderson dcbz_common(env, addr, ppc_env_mmu_index(env, false), dcbz_size, GETPC()); 32562fe57c6SRichard Henderson } 32662fe57c6SRichard Henderson #endif 32762fe57c6SRichard Henderson 328fcf5ef2aSThomas Huth void helper_icbi(CPUPPCState *env, target_ulong addr) 329fcf5ef2aSThomas Huth { 330fcf5ef2aSThomas Huth addr &= ~(env->dcache_line_size - 1); 3315a2c8b9eSDavid Gibson /* 3325a2c8b9eSDavid Gibson * Invalidate one cache line : 333fcf5ef2aSThomas Huth * PowerPC specification says this is to be treated like a load 334fcf5ef2aSThomas Huth * (not a fetch) by the MMU. To be sure it will be so, 335fcf5ef2aSThomas Huth * do the load "by hand". 336fcf5ef2aSThomas Huth */ 337fcf5ef2aSThomas Huth cpu_ldl_data_ra(env, addr, GETPC()); 338fcf5ef2aSThomas Huth } 339fcf5ef2aSThomas Huth 34050728199SRoman Kapl void helper_icbiep(CPUPPCState *env, target_ulong addr) 34150728199SRoman Kapl { 34250728199SRoman Kapl #if !defined(CONFIG_USER_ONLY) 34350728199SRoman Kapl /* See comments above */ 34450728199SRoman Kapl addr &= ~(env->dcache_line_size - 1); 3455a376e4fSRichard Henderson cpu_ldl_mmuidx_ra(env, addr, PPC_TLB_EPID_LOAD, GETPC()); 34650728199SRoman Kapl #endif 34750728199SRoman Kapl } 34850728199SRoman Kapl 349fcf5ef2aSThomas Huth /* XXX: to be tested */ 350fcf5ef2aSThomas Huth target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg, 351fcf5ef2aSThomas Huth uint32_t ra, uint32_t rb) 352fcf5ef2aSThomas Huth { 353fcf5ef2aSThomas Huth int i, c, d; 354fcf5ef2aSThomas Huth 355fcf5ef2aSThomas Huth d = 24; 356fcf5ef2aSThomas Huth for (i = 0; i < xer_bc; i++) { 357fcf5ef2aSThomas Huth c = cpu_ldub_data_ra(env, addr, GETPC()); 358fcf5ef2aSThomas Huth addr = addr_add(env, addr, 1); 359fcf5ef2aSThomas Huth /* ra (if not 0) and rb are never modified */ 360fcf5ef2aSThomas Huth if (likely(reg != rb && (ra == 0 || reg != ra))) { 361fcf5ef2aSThomas Huth env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d); 362fcf5ef2aSThomas Huth } 363fcf5ef2aSThomas Huth if (unlikely(c == xer_cmp)) { 364fcf5ef2aSThomas Huth break; 365fcf5ef2aSThomas Huth } 366fcf5ef2aSThomas Huth if (likely(d != 0)) { 367fcf5ef2aSThomas Huth d -= 8; 368fcf5ef2aSThomas Huth } else { 369fcf5ef2aSThomas Huth d = 24; 370fcf5ef2aSThomas Huth reg++; 371fcf5ef2aSThomas Huth reg = reg & 0x1F; 372fcf5ef2aSThomas Huth } 373fcf5ef2aSThomas Huth } 374fcf5ef2aSThomas Huth return i; 375fcf5ef2aSThomas Huth } 376fcf5ef2aSThomas Huth 377fcf5ef2aSThomas Huth /*****************************************************************************/ 378fcf5ef2aSThomas Huth /* Altivec extension helpers */ 379e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 380fcf5ef2aSThomas Huth #define HI_IDX 0 381fcf5ef2aSThomas Huth #define LO_IDX 1 382fcf5ef2aSThomas Huth #else 383fcf5ef2aSThomas Huth #define HI_IDX 1 384fcf5ef2aSThomas Huth #define LO_IDX 0 385fcf5ef2aSThomas Huth #endif 386fcf5ef2aSThomas Huth 3875a2c8b9eSDavid Gibson /* 3881922322cSVíctor Colombo * We use MSR_LE to determine index ordering in a vector. However, 3891922322cSVíctor Colombo * byteswapping is not simply controlled by MSR_LE. We also need to 3905a2c8b9eSDavid Gibson * take into account endianness of the target. This is done for the 3915a2c8b9eSDavid Gibson * little-endian PPC64 user-mode target. 3925a2c8b9eSDavid Gibson */ 393fcf5ef2aSThomas Huth 394fcf5ef2aSThomas Huth #define LVE(name, access, swap, element) \ 395fcf5ef2aSThomas Huth void helper_##name(CPUPPCState *env, ppc_avr_t *r, \ 396fcf5ef2aSThomas Huth target_ulong addr) \ 397fcf5ef2aSThomas Huth { \ 398fcf5ef2aSThomas Huth size_t n_elems = ARRAY_SIZE(r->element); \ 399fcf5ef2aSThomas Huth int adjust = HI_IDX * (n_elems - 1); \ 400fcf5ef2aSThomas Huth int sh = sizeof(r->element[0]) >> 1; \ 401fcf5ef2aSThomas Huth int index = (addr & 0xf) >> sh; \ 4021922322cSVíctor Colombo if (FIELD_EX64(env->msr, MSR, LE)) { \ 403fcf5ef2aSThomas Huth index = n_elems - index - 1; \ 404fcf5ef2aSThomas Huth } \ 405fcf5ef2aSThomas Huth \ 406fcf5ef2aSThomas Huth if (needs_byteswap(env)) { \ 407fcf5ef2aSThomas Huth r->element[LO_IDX ? index : (adjust - index)] = \ 408fcf5ef2aSThomas Huth swap(access(env, addr, GETPC())); \ 409fcf5ef2aSThomas Huth } else { \ 410fcf5ef2aSThomas Huth r->element[LO_IDX ? index : (adjust - index)] = \ 411fcf5ef2aSThomas Huth access(env, addr, GETPC()); \ 412fcf5ef2aSThomas Huth } \ 413fcf5ef2aSThomas Huth } 414fcf5ef2aSThomas Huth #define I(x) (x) 41521b5f546SChinmay Rath LVE(LVEBX, cpu_ldub_data_ra, I, u8) 41621b5f546SChinmay Rath LVE(LVEHX, cpu_lduw_data_ra, bswap16, u16) 41721b5f546SChinmay Rath LVE(LVEWX, cpu_ldl_data_ra, bswap32, u32) 418fcf5ef2aSThomas Huth #undef I 419fcf5ef2aSThomas Huth #undef LVE 420fcf5ef2aSThomas Huth 421fcf5ef2aSThomas Huth #define STVE(name, access, swap, element) \ 422fcf5ef2aSThomas Huth void helper_##name(CPUPPCState *env, ppc_avr_t *r, \ 423fcf5ef2aSThomas Huth target_ulong addr) \ 424fcf5ef2aSThomas Huth { \ 425fcf5ef2aSThomas Huth size_t n_elems = ARRAY_SIZE(r->element); \ 426fcf5ef2aSThomas Huth int adjust = HI_IDX * (n_elems - 1); \ 427fcf5ef2aSThomas Huth int sh = sizeof(r->element[0]) >> 1; \ 428fcf5ef2aSThomas Huth int index = (addr & 0xf) >> sh; \ 4291922322cSVíctor Colombo if (FIELD_EX64(env->msr, MSR, LE)) { \ 430fcf5ef2aSThomas Huth index = n_elems - index - 1; \ 431fcf5ef2aSThomas Huth } \ 432fcf5ef2aSThomas Huth \ 433fcf5ef2aSThomas Huth if (needs_byteswap(env)) { \ 434fcf5ef2aSThomas Huth access(env, addr, swap(r->element[LO_IDX ? index : \ 435fcf5ef2aSThomas Huth (adjust - index)]), \ 436fcf5ef2aSThomas Huth GETPC()); \ 437fcf5ef2aSThomas Huth } else { \ 438fcf5ef2aSThomas Huth access(env, addr, r->element[LO_IDX ? index : \ 439fcf5ef2aSThomas Huth (adjust - index)], GETPC()); \ 440fcf5ef2aSThomas Huth } \ 441fcf5ef2aSThomas Huth } 442fcf5ef2aSThomas Huth #define I(x) (x) 44321b5f546SChinmay Rath STVE(STVEBX, cpu_stb_data_ra, I, u8) 44421b5f546SChinmay Rath STVE(STVEHX, cpu_stw_data_ra, bswap16, u16) 44521b5f546SChinmay Rath STVE(STVEWX, cpu_stl_data_ra, bswap32, u32) 446fcf5ef2aSThomas Huth #undef I 447fcf5ef2aSThomas Huth #undef LVE 448fcf5ef2aSThomas Huth 4496914bc4fSNikunj A Dadhania #ifdef TARGET_PPC64 4506914bc4fSNikunj A Dadhania #define GET_NB(rb) ((rb >> 56) & 0xFF) 4516914bc4fSNikunj A Dadhania 4526914bc4fSNikunj A Dadhania #define VSX_LXVL(name, lj) \ 4536914bc4fSNikunj A Dadhania void helper_##name(CPUPPCState *env, target_ulong addr, \ 4542aba168eSMark Cave-Ayland ppc_vsr_t *xt, target_ulong rb) \ 4556914bc4fSNikunj A Dadhania { \ 4562a175830SMark Cave-Ayland ppc_vsr_t t; \ 4576914bc4fSNikunj A Dadhania uint64_t nb = GET_NB(rb); \ 4582a175830SMark Cave-Ayland int i; \ 4596914bc4fSNikunj A Dadhania \ 4602a175830SMark Cave-Ayland t.s128 = int128_zero(); \ 4616914bc4fSNikunj A Dadhania if (nb) { \ 4626914bc4fSNikunj A Dadhania nb = (nb >= 16) ? 16 : nb; \ 4631922322cSVíctor Colombo if (FIELD_EX64(env->msr, MSR, LE) && !lj) { \ 4646914bc4fSNikunj A Dadhania for (i = 16; i > 16 - nb; i--) { \ 4652a175830SMark Cave-Ayland t.VsrB(i - 1) = cpu_ldub_data_ra(env, addr, GETPC()); \ 4666914bc4fSNikunj A Dadhania addr = addr_add(env, addr, 1); \ 4676914bc4fSNikunj A Dadhania } \ 4686914bc4fSNikunj A Dadhania } else { \ 4696914bc4fSNikunj A Dadhania for (i = 0; i < nb; i++) { \ 4702a175830SMark Cave-Ayland t.VsrB(i) = cpu_ldub_data_ra(env, addr, GETPC()); \ 4716914bc4fSNikunj A Dadhania addr = addr_add(env, addr, 1); \ 4726914bc4fSNikunj A Dadhania } \ 4736914bc4fSNikunj A Dadhania } \ 4746914bc4fSNikunj A Dadhania } \ 4752a175830SMark Cave-Ayland *xt = t; \ 4766914bc4fSNikunj A Dadhania } 4776914bc4fSNikunj A Dadhania 4786914bc4fSNikunj A Dadhania VSX_LXVL(lxvl, 0) 479176e44e7SNikunj A Dadhania VSX_LXVL(lxvll, 1) 4806914bc4fSNikunj A Dadhania #undef VSX_LXVL 481681c2478SNikunj A Dadhania 482681c2478SNikunj A Dadhania #define VSX_STXVL(name, lj) \ 483681c2478SNikunj A Dadhania void helper_##name(CPUPPCState *env, target_ulong addr, \ 4842aba168eSMark Cave-Ayland ppc_vsr_t *xt, target_ulong rb) \ 485681c2478SNikunj A Dadhania { \ 486681c2478SNikunj A Dadhania target_ulong nb = GET_NB(rb); \ 4872a175830SMark Cave-Ayland int i; \ 488681c2478SNikunj A Dadhania \ 489681c2478SNikunj A Dadhania if (!nb) { \ 490681c2478SNikunj A Dadhania return; \ 491681c2478SNikunj A Dadhania } \ 4922a175830SMark Cave-Ayland \ 493681c2478SNikunj A Dadhania nb = (nb >= 16) ? 16 : nb; \ 4941922322cSVíctor Colombo if (FIELD_EX64(env->msr, MSR, LE) && !lj) { \ 495681c2478SNikunj A Dadhania for (i = 16; i > 16 - nb; i--) { \ 4962a175830SMark Cave-Ayland cpu_stb_data_ra(env, addr, xt->VsrB(i - 1), GETPC()); \ 497681c2478SNikunj A Dadhania addr = addr_add(env, addr, 1); \ 498681c2478SNikunj A Dadhania } \ 499681c2478SNikunj A Dadhania } else { \ 500681c2478SNikunj A Dadhania for (i = 0; i < nb; i++) { \ 5012a175830SMark Cave-Ayland cpu_stb_data_ra(env, addr, xt->VsrB(i), GETPC()); \ 502681c2478SNikunj A Dadhania addr = addr_add(env, addr, 1); \ 503681c2478SNikunj A Dadhania } \ 504681c2478SNikunj A Dadhania } \ 505681c2478SNikunj A Dadhania } 506681c2478SNikunj A Dadhania 507681c2478SNikunj A Dadhania VSX_STXVL(stxvl, 0) 508e122090dSNikunj A Dadhania VSX_STXVL(stxvll, 1) 509681c2478SNikunj A Dadhania #undef VSX_STXVL 5106914bc4fSNikunj A Dadhania #undef GET_NB 5116914bc4fSNikunj A Dadhania #endif /* TARGET_PPC64 */ 5126914bc4fSNikunj A Dadhania 513fcf5ef2aSThomas Huth #undef HI_IDX 514fcf5ef2aSThomas Huth #undef LO_IDX 515fcf5ef2aSThomas Huth 516fcf5ef2aSThomas Huth void helper_tbegin(CPUPPCState *env) 517fcf5ef2aSThomas Huth { 5185a2c8b9eSDavid Gibson /* 5195a2c8b9eSDavid Gibson * As a degenerate implementation, always fail tbegin. The reason 520fcf5ef2aSThomas Huth * given is "Nesting overflow". The "persistent" bit is set, 521fcf5ef2aSThomas Huth * providing a hint to the error handler to not retry. The TFIAR 522fcf5ef2aSThomas Huth * captures the address of the failure, which is this tbegin 5235a2c8b9eSDavid Gibson * instruction. Instruction execution will continue with the next 5245a2c8b9eSDavid Gibson * instruction in memory, which is precisely what we want. 525fcf5ef2aSThomas Huth */ 526fcf5ef2aSThomas Huth 527fcf5ef2aSThomas Huth env->spr[SPR_TEXASR] = 528fcf5ef2aSThomas Huth (1ULL << TEXASR_FAILURE_PERSISTENT) | 529fcf5ef2aSThomas Huth (1ULL << TEXASR_NESTING_OVERFLOW) | 5309de754d3SVíctor Colombo (FIELD_EX64_HV(env->msr) << TEXASR_PRIVILEGE_HV) | 531d41ccf6eSVíctor Colombo (FIELD_EX64(env->msr, MSR, PR) << TEXASR_PRIVILEGE_PR) | 532fcf5ef2aSThomas Huth (1ULL << TEXASR_FAILURE_SUMMARY) | 533fcf5ef2aSThomas Huth (1ULL << TEXASR_TFIAR_EXACT); 5349de754d3SVíctor Colombo env->spr[SPR_TFIAR] = env->nip | (FIELD_EX64_HV(env->msr) << 1) | 535d41ccf6eSVíctor Colombo FIELD_EX64(env->msr, MSR, PR); 536fcf5ef2aSThomas Huth env->spr[SPR_TFHAR] = env->nip + 4; 537fcf5ef2aSThomas Huth env->crf[0] = 0xB; /* 0b1010 = transaction failure */ 538fcf5ef2aSThomas Huth } 539