blob: 2d7a349c32012d78472f6a353ac576e4b3c1cae9 [file] [log] [blame]
bellard9a64fbe2004-01-04 22:58:38 +00001/*
Blue Swirl2f5a1892012-05-30 04:23:40 +00002 * PowerPC memory access emulation helpers for QEMU.
ths5fafdf22007-09-16 21:08:06 +00003 *
j_mayer76a66252007-03-07 08:32:30 +00004 * Copyright (c) 2003-2007 Jocelyn Mayer
bellard9a64fbe2004-01-04 22:58:38 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
bellard9a64fbe2004-01-04 22:58:38 +000018 */
Blue Swirl3e457172011-07-13 12:44:15 +000019#include "cpu.h"
j_mayer603fccc2007-10-28 12:54:53 +000020#include "host-utils.h"
pbrooka7812ae2008-11-17 14:43:54 +000021#include "helper.h"
bellard9a64fbe2004-01-04 22:58:38 +000022
j_mayer0411a972007-10-25 21:35:50 +000023#include "helper_regs.h"
j_mayer0487d6a2007-03-20 22:11:31 +000024
Blue Swirl3e457172011-07-13 12:44:15 +000025#if !defined(CONFIG_USER_ONLY)
Paolo Bonzini022c62c2012-12-17 18:19:49 +010026#include "exec/softmmu_exec.h"
Blue Swirl3e457172011-07-13 12:44:15 +000027#endif /* !defined(CONFIG_USER_ONLY) */
28
bellardfdabc362005-07-04 22:17:05 +000029//#define DEBUG_OP
aliguorid12d51d2009-01-15 21:48:06 +000030
bellard9a64fbe2004-01-04 22:58:38 +000031/*****************************************************************************/
aurel32ff4a62c2008-11-30 16:23:56 +000032/* Memory load and stores */
33
Blue Swirl2f5a1892012-05-30 04:23:40 +000034static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr,
35 target_long arg)
aurel32ff4a62c2008-11-30 16:23:56 +000036{
37#if defined(TARGET_PPC64)
Alexander Grafe42a61f2012-06-20 21:20:29 +020038 if (!msr_is_64bit(env, env->msr)) {
Blue Swirlb327c652012-05-30 04:23:21 +000039 return (uint32_t)(addr + arg);
40 } else
aurel32ff4a62c2008-11-30 16:23:56 +000041#endif
Blue Swirlb327c652012-05-30 04:23:21 +000042 {
43 return addr + arg;
aurel32ff4a62c2008-11-30 16:23:56 +000044 }
45}
46
Blue Swirl2f5a1892012-05-30 04:23:40 +000047void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
aurel32ff4a62c2008-11-30 16:23:56 +000048{
aurel3276db3ba2008-12-08 18:11:21 +000049 for (; reg < 32; reg++) {
Blue Swirlb327c652012-05-30 04:23:21 +000050 if (msr_le) {
Blue Swirl2f5a1892012-05-30 04:23:40 +000051 env->gpr[reg] = bswap32(cpu_ldl_data(env, addr));
Blue Swirlb327c652012-05-30 04:23:21 +000052 } else {
Blue Swirl2f5a1892012-05-30 04:23:40 +000053 env->gpr[reg] = cpu_ldl_data(env, addr);
Blue Swirlb327c652012-05-30 04:23:21 +000054 }
Blue Swirl2f5a1892012-05-30 04:23:40 +000055 addr = addr_add(env, addr, 4);
Blue Swirlb327c652012-05-30 04:23:21 +000056 }
57}
58
Blue Swirl2f5a1892012-05-30 04:23:40 +000059void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
Blue Swirlb327c652012-05-30 04:23:21 +000060{
61 for (; reg < 32; reg++) {
62 if (msr_le) {
Blue Swirl2f5a1892012-05-30 04:23:40 +000063 cpu_stl_data(env, addr, bswap32((uint32_t)env->gpr[reg]));
Blue Swirlb327c652012-05-30 04:23:21 +000064 } else {
Blue Swirl2f5a1892012-05-30 04:23:40 +000065 cpu_stl_data(env, addr, (uint32_t)env->gpr[reg]);
Blue Swirlb327c652012-05-30 04:23:21 +000066 }
Blue Swirl2f5a1892012-05-30 04:23:40 +000067 addr = addr_add(env, addr, 4);
aurel32ff4a62c2008-11-30 16:23:56 +000068 }
69}
70
Blue Swirl2f5a1892012-05-30 04:23:40 +000071void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg)
aurel32dfbc7992008-11-30 16:24:21 +000072{
73 int sh;
Blue Swirlb327c652012-05-30 04:23:21 +000074
aurel3276db3ba2008-12-08 18:11:21 +000075 for (; nb > 3; nb -= 4) {
Blue Swirl2f5a1892012-05-30 04:23:40 +000076 env->gpr[reg] = cpu_ldl_data(env, addr);
aurel32dfbc7992008-11-30 16:24:21 +000077 reg = (reg + 1) % 32;
Blue Swirl2f5a1892012-05-30 04:23:40 +000078 addr = addr_add(env, addr, 4);
aurel32dfbc7992008-11-30 16:24:21 +000079 }
80 if (unlikely(nb > 0)) {
81 env->gpr[reg] = 0;
aurel3276db3ba2008-12-08 18:11:21 +000082 for (sh = 24; nb > 0; nb--, sh -= 8) {
Blue Swirl2f5a1892012-05-30 04:23:40 +000083 env->gpr[reg] |= cpu_ldub_data(env, addr) << sh;
84 addr = addr_add(env, addr, 1);
aurel32dfbc7992008-11-30 16:24:21 +000085 }
86 }
87}
88/* PPC32 specification says we must generate an exception if
89 * rA is in the range of registers to be loaded.
90 * In an other hand, IBM says this is valid, but rA won't be loaded.
91 * For now, I'll follow the spec...
92 */
Blue Swirl2f5a1892012-05-30 04:23:40 +000093void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,
94 uint32_t ra, uint32_t rb)
aurel32dfbc7992008-11-30 16:24:21 +000095{
96 if (likely(xer_bc != 0)) {
97 if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
98 (reg < rb && (reg + xer_bc) > rb))) {
Blue Swirle5f17ac2012-05-30 04:23:23 +000099 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
aurel32e06fcd72008-12-11 22:42:14 +0000100 POWERPC_EXCP_INVAL |
101 POWERPC_EXCP_INVAL_LSWX);
aurel32dfbc7992008-11-30 16:24:21 +0000102 } else {
Blue Swirl2f5a1892012-05-30 04:23:40 +0000103 helper_lsw(env, addr, xer_bc, reg);
aurel32dfbc7992008-11-30 16:24:21 +0000104 }
105 }
106}
107
Blue Swirl2f5a1892012-05-30 04:23:40 +0000108void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
109 uint32_t reg)
aurel32dfbc7992008-11-30 16:24:21 +0000110{
111 int sh;
Blue Swirlb327c652012-05-30 04:23:21 +0000112
aurel3276db3ba2008-12-08 18:11:21 +0000113 for (; nb > 3; nb -= 4) {
Blue Swirl2f5a1892012-05-30 04:23:40 +0000114 cpu_stl_data(env, addr, env->gpr[reg]);
aurel32dfbc7992008-11-30 16:24:21 +0000115 reg = (reg + 1) % 32;
Blue Swirl2f5a1892012-05-30 04:23:40 +0000116 addr = addr_add(env, addr, 4);
aurel32dfbc7992008-11-30 16:24:21 +0000117 }
118 if (unlikely(nb > 0)) {
aurel32a16b45e2008-12-29 09:46:58 +0000119 for (sh = 24; nb > 0; nb--, sh -= 8) {
Blue Swirl2f5a1892012-05-30 04:23:40 +0000120 cpu_stb_data(env, addr, (env->gpr[reg] >> sh) & 0xFF);
121 addr = addr_add(env, addr, 1);
aurel32a16b45e2008-12-29 09:46:58 +0000122 }
aurel32dfbc7992008-11-30 16:24:21 +0000123 }
124}
125
Blue Swirl2f5a1892012-05-30 04:23:40 +0000126static void do_dcbz(CPUPPCState *env, target_ulong addr, int dcache_line_size)
aurel32799a8c82008-11-30 16:24:05 +0000127{
aurel32799a8c82008-11-30 16:24:05 +0000128 int i;
Blue Swirlb327c652012-05-30 04:23:21 +0000129
130 addr &= ~(dcache_line_size - 1);
131 for (i = 0; i < dcache_line_size; i += 4) {
Blue Swirl2f5a1892012-05-30 04:23:40 +0000132 cpu_stl_data(env, addr + i, 0);
aurel32799a8c82008-11-30 16:24:05 +0000133 }
Blue Swirlb327c652012-05-30 04:23:21 +0000134 if (env->reserve_addr == addr) {
Nathan Froyd18b21a22009-08-03 08:43:25 -0700135 env->reserve_addr = (target_ulong)-1ULL;
Blue Swirlb327c652012-05-30 04:23:21 +0000136 }
aurel32799a8c82008-11-30 16:24:05 +0000137}
138
Blue Swirl2f5a1892012-05-30 04:23:40 +0000139void helper_dcbz(CPUPPCState *env, target_ulong addr)
aurel32799a8c82008-11-30 16:24:05 +0000140{
Blue Swirl2f5a1892012-05-30 04:23:40 +0000141 do_dcbz(env, addr, env->dcache_line_size);
aurel32799a8c82008-11-30 16:24:05 +0000142}
143
Blue Swirl2f5a1892012-05-30 04:23:40 +0000144void helper_dcbz_970(CPUPPCState *env, target_ulong addr)
aurel32799a8c82008-11-30 16:24:05 +0000145{
Blue Swirlb327c652012-05-30 04:23:21 +0000146 if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
Blue Swirl2f5a1892012-05-30 04:23:40 +0000147 do_dcbz(env, addr, 32);
Blue Swirlb327c652012-05-30 04:23:21 +0000148 } else {
Blue Swirl2f5a1892012-05-30 04:23:40 +0000149 do_dcbz(env, addr, env->dcache_line_size);
Blue Swirlb327c652012-05-30 04:23:21 +0000150 }
aurel32799a8c82008-11-30 16:24:05 +0000151}
152
Blue Swirl2f5a1892012-05-30 04:23:40 +0000153void helper_icbi(CPUPPCState *env, target_ulong addr)
aurel3237d269d2008-11-30 16:24:13 +0000154{
aurel3276db3ba2008-12-08 18:11:21 +0000155 addr &= ~(env->dcache_line_size - 1);
aurel3237d269d2008-11-30 16:24:13 +0000156 /* Invalidate one cache line :
157 * PowerPC specification says this is to be treated like a load
158 * (not a fetch) by the MMU. To be sure it will be so,
159 * do the load "by hand".
160 */
Blue Swirl2f5a1892012-05-30 04:23:40 +0000161 cpu_ldl_data(env, addr);
aurel3237d269d2008-11-30 16:24:13 +0000162}
163
Blue Swirlb327c652012-05-30 04:23:21 +0000164/* XXX: to be tested */
Blue Swirl2f5a1892012-05-30 04:23:40 +0000165target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
166 uint32_t ra, uint32_t rb)
aurel32bdb4b682008-11-30 16:24:30 +0000167{
168 int i, c, d;
Blue Swirlb327c652012-05-30 04:23:21 +0000169
aurel32bdb4b682008-11-30 16:24:30 +0000170 d = 24;
171 for (i = 0; i < xer_bc; i++) {
Blue Swirl2f5a1892012-05-30 04:23:40 +0000172 c = cpu_ldub_data(env, addr);
173 addr = addr_add(env, addr, 1);
aurel32bdb4b682008-11-30 16:24:30 +0000174 /* ra (if not 0) and rb are never modified */
175 if (likely(reg != rb && (ra == 0 || reg != ra))) {
176 env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
177 }
Blue Swirlb327c652012-05-30 04:23:21 +0000178 if (unlikely(c == xer_cmp)) {
aurel32bdb4b682008-11-30 16:24:30 +0000179 break;
Blue Swirlb327c652012-05-30 04:23:21 +0000180 }
aurel32bdb4b682008-11-30 16:24:30 +0000181 if (likely(d != 0)) {
182 d -= 8;
183 } else {
184 d = 24;
185 reg++;
186 reg = reg & 0x1F;
187 }
188 }
189 return i;
190}
191
aurel32ff4a62c2008-11-30 16:23:56 +0000192/*****************************************************************************/
aurel32d6a46fe2009-01-03 13:31:19 +0000193/* Altivec extension helpers */
Juan Quintelae2542fe2009-07-27 16:13:06 +0200194#if defined(HOST_WORDS_BIGENDIAN)
aurel32d6a46fe2009-01-03 13:31:19 +0000195#define HI_IDX 0
196#define LO_IDX 1
197#else
198#define HI_IDX 1
199#define LO_IDX 0
200#endif
201
aurel32cbfb6ae2009-01-04 22:13:10 +0000202#define LVE(name, access, swap, element) \
Blue Swirl2f5a1892012-05-30 04:23:40 +0000203 void helper_##name(CPUPPCState *env, ppc_avr_t *r, \
204 target_ulong addr) \
aurel32cbfb6ae2009-01-04 22:13:10 +0000205 { \
206 size_t n_elems = ARRAY_SIZE(r->element); \
Blue Swirlb327c652012-05-30 04:23:21 +0000207 int adjust = HI_IDX*(n_elems - 1); \
aurel32cbfb6ae2009-01-04 22:13:10 +0000208 int sh = sizeof(r->element[0]) >> 1; \
209 int index = (addr & 0xf) >> sh; \
Blue Swirlb327c652012-05-30 04:23:21 +0000210 \
211 if (msr_le) { \
212 r->element[LO_IDX ? index : (adjust - index)] = \
Blue Swirl2f5a1892012-05-30 04:23:40 +0000213 swap(access(env, addr)); \
Blue Swirlb327c652012-05-30 04:23:21 +0000214 } else { \
215 r->element[LO_IDX ? index : (adjust - index)] = \
Blue Swirl2f5a1892012-05-30 04:23:40 +0000216 access(env, addr); \
Blue Swirlb327c652012-05-30 04:23:21 +0000217 } \
aurel32cbfb6ae2009-01-04 22:13:10 +0000218 }
219#define I(x) (x)
Blue Swirl2f5a1892012-05-30 04:23:40 +0000220LVE(lvebx, cpu_ldub_data, I, u8)
221LVE(lvehx, cpu_lduw_data, bswap16, u16)
222LVE(lvewx, cpu_ldl_data, bswap32, u32)
aurel32cbfb6ae2009-01-04 22:13:10 +0000223#undef I
224#undef LVE
225
Blue Swirlb327c652012-05-30 04:23:21 +0000226#define STVE(name, access, swap, element) \
Blue Swirl2f5a1892012-05-30 04:23:40 +0000227 void helper_##name(CPUPPCState *env, ppc_avr_t *r, \
228 target_ulong addr) \
Blue Swirlb327c652012-05-30 04:23:21 +0000229 { \
230 size_t n_elems = ARRAY_SIZE(r->element); \
231 int adjust = HI_IDX * (n_elems - 1); \
232 int sh = sizeof(r->element[0]) >> 1; \
233 int index = (addr & 0xf) >> sh; \
234 \
235 if (msr_le) { \
Blue Swirl2f5a1892012-05-30 04:23:40 +0000236 access(env, addr, swap(r->element[LO_IDX ? index : \
237 (adjust - index)])); \
aurel32cbfb6ae2009-01-04 22:13:10 +0000238 } else { \
Blue Swirl2f5a1892012-05-30 04:23:40 +0000239 access(env, addr, r->element[LO_IDX ? index : \
240 (adjust - index)]); \
aurel32cbfb6ae2009-01-04 22:13:10 +0000241 } \
242 }
243#define I(x) (x)
Blue Swirl2f5a1892012-05-30 04:23:40 +0000244STVE(stvebx, cpu_stb_data, I, u8)
245STVE(stvehx, cpu_stw_data, bswap16, u16)
246STVE(stvewx, cpu_stl_data, bswap32, u32)
aurel32cbfb6ae2009-01-04 22:13:10 +0000247#undef I
248#undef LVE
249
aurel32d6a46fe2009-01-03 13:31:19 +0000250#undef HI_IDX
251#undef LO_IDX
252
253/*****************************************************************************/
bellardfdabc362005-07-04 22:17:05 +0000254/* Softmmu support */
Blue Swirlb327c652012-05-30 04:23:21 +0000255#if !defined(CONFIG_USER_ONLY)
bellardfdabc362005-07-04 22:17:05 +0000256
257#define MMUSUFFIX _mmu
bellardfdabc362005-07-04 22:17:05 +0000258
259#define SHIFT 0
Paolo Bonzini022c62c2012-12-17 18:19:49 +0100260#include "exec/softmmu_template.h"
bellardfdabc362005-07-04 22:17:05 +0000261
262#define SHIFT 1
Paolo Bonzini022c62c2012-12-17 18:19:49 +0100263#include "exec/softmmu_template.h"
bellardfdabc362005-07-04 22:17:05 +0000264
265#define SHIFT 2
Paolo Bonzini022c62c2012-12-17 18:19:49 +0100266#include "exec/softmmu_template.h"
bellardfdabc362005-07-04 22:17:05 +0000267
268#define SHIFT 3
Paolo Bonzini022c62c2012-12-17 18:19:49 +0100269#include "exec/softmmu_template.h"
bellardfdabc362005-07-04 22:17:05 +0000270
271/* try to fill the TLB and return an exception if error. If retaddr is
272 NULL, it means that the function was called in C code (i.e. not
273 from generated code or from helper.c) */
274/* XXX: fix it to restore all registers */
Blue Swirl2f5a1892012-05-30 04:23:40 +0000275void tlb_fill(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx,
Blue Swirl20503962012-04-09 14:20:20 +0000276 uintptr_t retaddr)
bellardfdabc362005-07-04 22:17:05 +0000277{
bellardfdabc362005-07-04 22:17:05 +0000278 int ret;
279
Blue Swirl97b348e2011-08-01 16:12:17 +0000280 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
j_mayer76a66252007-03-07 08:32:30 +0000281 if (unlikely(ret != 0)) {
bellardfdabc362005-07-04 22:17:05 +0000282 if (likely(retaddr)) {
283 /* now we have a real cpu fault */
Blue Swirla8a826a2012-12-04 20:16:07 +0000284 cpu_restore_state(env, retaddr);
bellardfdabc362005-07-04 22:17:05 +0000285 }
Blue Swirle5f17ac2012-05-30 04:23:23 +0000286 helper_raise_exception_err(env, env->exception_index, env->error_code);
bellardfdabc362005-07-04 22:17:05 +0000287 }
bellardfdabc362005-07-04 22:17:05 +0000288}
j_mayer76a66252007-03-07 08:32:30 +0000289#endif /* !CONFIG_USER_ONLY */