]> Git Repo - qemu.git/blame - target/ppc/mem_helper.c
target-ppc: Consolidate instruction decode helpers
[qemu.git] / target / ppc / mem_helper.c
CommitLineData
9a64fbe4 1/*
2f5a189c 2 * PowerPC memory access emulation helpers for QEMU.
5fafdf24 3 *
76a66253 4 * Copyright (c) 2003-2007 Jocelyn Mayer
9a64fbe4
FB
5 *
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
8167ee88 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
9a64fbe4 18 */
0d75590d 19#include "qemu/osdep.h"
3e457172 20#include "cpu.h"
63c91552 21#include "exec/exec-all.h"
1de7afc9 22#include "qemu/host-utils.h"
2ef6175a 23#include "exec/helper-proto.h"
9a64fbe4 24
0411a972 25#include "helper_regs.h"
f08b6170 26#include "exec/cpu_ldst.h"
3e457172 27
fdabc366 28//#define DEBUG_OP
d12d51d5 29
e22c357b
DK
30static inline bool needs_byteswap(const CPUPPCState *env)
31{
32#if defined(TARGET_WORDS_BIGENDIAN)
33 return msr_le;
34#else
35 return !msr_le;
36#endif
37}
38
ff4a62cd
AJ
39/*****************************************************************************/
40/* Memory load and stores */
41
2f5a189c
BS
42static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr,
43 target_long arg)
ff4a62cd
AJ
44{
45#if defined(TARGET_PPC64)
e42a61f1 46 if (!msr_is_64bit(env, env->msr)) {
b327c654
BS
47 return (uint32_t)(addr + arg);
48 } else
ff4a62cd 49#endif
b327c654
BS
50 {
51 return addr + arg;
52 }
ff4a62cd
AJ
53}
54
2f5a189c 55void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
ff4a62cd 56{
76db3ba4 57 for (; reg < 32; reg++) {
e22c357b 58 if (needs_byteswap(env)) {
af6d376e 59 env->gpr[reg] = bswap32(cpu_ldl_data_ra(env, addr, GETPC()));
b327c654 60 } else {
af6d376e 61 env->gpr[reg] = cpu_ldl_data_ra(env, addr, GETPC());
b327c654 62 }
2f5a189c 63 addr = addr_add(env, addr, 4);
ff4a62cd
AJ
64 }
65}
66
2f5a189c 67void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
ff4a62cd 68{
76db3ba4 69 for (; reg < 32; reg++) {
e22c357b 70 if (needs_byteswap(env)) {
af6d376e
BH
71 cpu_stl_data_ra(env, addr, bswap32((uint32_t)env->gpr[reg]),
72 GETPC());
b327c654 73 } else {
af6d376e 74 cpu_stl_data_ra(env, addr, (uint32_t)env->gpr[reg], GETPC());
b327c654 75 }
2f5a189c 76 addr = addr_add(env, addr, 4);
ff4a62cd
AJ
77 }
78}
79
e41029b3
BH
80static void do_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
81 uint32_t reg, uintptr_t raddr)
dfbc799d
AJ
82{
83 int sh;
b327c654 84
76db3ba4 85 for (; nb > 3; nb -= 4) {
e41029b3 86 env->gpr[reg] = cpu_ldl_data_ra(env, addr, raddr);
dfbc799d 87 reg = (reg + 1) % 32;
2f5a189c 88 addr = addr_add(env, addr, 4);
dfbc799d
AJ
89 }
90 if (unlikely(nb > 0)) {
91 env->gpr[reg] = 0;
76db3ba4 92 for (sh = 24; nb > 0; nb--, sh -= 8) {
e41029b3 93 env->gpr[reg] |= cpu_ldub_data_ra(env, addr, raddr) << sh;
2f5a189c 94 addr = addr_add(env, addr, 1);
dfbc799d
AJ
95 }
96 }
97}
e41029b3
BH
98
99void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg)
100{
101 do_lsw(env, addr, nb, reg, GETPC());
102}
103
dfbc799d
AJ
104/* PPC32 specification says we must generate an exception if
105 * rA is in the range of registers to be loaded.
106 * In an other hand, IBM says this is valid, but rA won't be loaded.
107 * For now, I'll follow the spec...
108 */
2f5a189c
BS
109void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,
110 uint32_t ra, uint32_t rb)
dfbc799d
AJ
111{
112 if (likely(xer_bc != 0)) {
488661ee 113 int num_used_regs = (xer_bc + 3) / 4;
537d3e8e
TH
114 if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) ||
115 lsw_reg_in_range(reg, num_used_regs, rb))) {
e41029b3
BH
116 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
117 POWERPC_EXCP_INVAL |
118 POWERPC_EXCP_INVAL_LSWX, GETPC());
dfbc799d 119 } else {
e41029b3 120 do_lsw(env, addr, xer_bc, reg, GETPC());
dfbc799d
AJ
121 }
122 }
123}
124
2f5a189c
BS
125void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
126 uint32_t reg)
dfbc799d
AJ
127{
128 int sh;
b327c654 129
76db3ba4 130 for (; nb > 3; nb -= 4) {
e41029b3 131 cpu_stl_data_ra(env, addr, env->gpr[reg], GETPC());
dfbc799d 132 reg = (reg + 1) % 32;
2f5a189c 133 addr = addr_add(env, addr, 4);
dfbc799d
AJ
134 }
135 if (unlikely(nb > 0)) {
a16b45e7 136 for (sh = 24; nb > 0; nb--, sh -= 8) {
e41029b3 137 cpu_stb_data_ra(env, addr, (env->gpr[reg] >> sh) & 0xFF, GETPC());
2f5a189c 138 addr = addr_add(env, addr, 1);
a16b45e7 139 }
dfbc799d
AJ
140 }
141}
142
c9f82d01 143void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode)
799a8c8d 144{
c9f82d01
BH
145 target_ulong mask, dcbz_size = env->dcache_line_size;
146 uint32_t i;
147 void *haddr;
799a8c8d 148
414f5d14 149#if defined(TARGET_PPC64)
c9f82d01
BH
150 /* Check for dcbz vs dcbzl on 970 */
151 if (env->excp_model == POWERPC_EXCP_970 &&
152 !(opcode & 0x00200000) && ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
8e33944f 153 dcbz_size = 32;
b327c654 154 }
8e33944f
AG
155#endif
156
c9f82d01
BH
157 /* Align address */
158 mask = ~(dcbz_size - 1);
159 addr &= mask;
160
161 /* Check reservation */
162 if ((env->reserve_addr & mask) == (addr & mask)) {
163 env->reserve_addr = (target_ulong)-1ULL;
164 }
8e33944f 165
c9f82d01
BH
166 /* Try fast path translate */
167 haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, env->dmmu_idx);
168 if (haddr) {
169 memset(haddr, 0, dcbz_size);
170 } else {
171 /* Slow path */
172 for (i = 0; i < dcbz_size; i += 8) {
173 cpu_stq_data_ra(env, addr + i, 0, GETPC());
174 }
175 }
799a8c8d
AJ
176}
177
2f5a189c 178void helper_icbi(CPUPPCState *env, target_ulong addr)
37d269df 179{
76db3ba4 180 addr &= ~(env->dcache_line_size - 1);
37d269df
AJ
181 /* Invalidate one cache line :
182 * PowerPC specification says this is to be treated like a load
183 * (not a fetch) by the MMU. To be sure it will be so,
184 * do the load "by hand".
185 */
af6d376e 186 cpu_ldl_data_ra(env, addr, GETPC());
37d269df
AJ
187}
188
b327c654 189/* XXX: to be tested */
2f5a189c
BS
190target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
191 uint32_t ra, uint32_t rb)
bdb4b689
AJ
192{
193 int i, c, d;
b327c654 194
bdb4b689
AJ
195 d = 24;
196 for (i = 0; i < xer_bc; i++) {
b00a3b36 197 c = cpu_ldub_data_ra(env, addr, GETPC());
2f5a189c 198 addr = addr_add(env, addr, 1);
bdb4b689
AJ
199 /* ra (if not 0) and rb are never modified */
200 if (likely(reg != rb && (ra == 0 || reg != ra))) {
201 env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
202 }
b327c654 203 if (unlikely(c == xer_cmp)) {
bdb4b689 204 break;
b327c654 205 }
bdb4b689
AJ
206 if (likely(d != 0)) {
207 d -= 8;
208 } else {
209 d = 24;
210 reg++;
211 reg = reg & 0x1F;
212 }
213 }
214 return i;
215}
216
d6a46fe8
AJ
217/*****************************************************************************/
218/* Altivec extension helpers */
e2542fe2 219#if defined(HOST_WORDS_BIGENDIAN)
d6a46fe8
AJ
220#define HI_IDX 0
221#define LO_IDX 1
222#else
223#define HI_IDX 1
224#define LO_IDX 0
225#endif
226
e22c357b
DK
227/* We use msr_le to determine index ordering in a vector. However,
228 byteswapping is not simply controlled by msr_le. We also need to take
229 into account endianness of the target. This is done for the little-endian
230 PPC64 user-mode target. */
231
cbfb6ae9 232#define LVE(name, access, swap, element) \
2f5a189c
BS
233 void helper_##name(CPUPPCState *env, ppc_avr_t *r, \
234 target_ulong addr) \
cbfb6ae9
AJ
235 { \
236 size_t n_elems = ARRAY_SIZE(r->element); \
b327c654 237 int adjust = HI_IDX*(n_elems - 1); \
cbfb6ae9
AJ
238 int sh = sizeof(r->element[0]) >> 1; \
239 int index = (addr & 0xf) >> sh; \
b327c654 240 if (msr_le) { \
bbfb6f13 241 index = n_elems - index - 1; \
e22c357b
DK
242 } \
243 \
244 if (needs_byteswap(env)) { \
b327c654 245 r->element[LO_IDX ? index : (adjust - index)] = \
bcd510b1 246 swap(access(env, addr, GETPC())); \
b327c654
BS
247 } else { \
248 r->element[LO_IDX ? index : (adjust - index)] = \
bcd510b1 249 access(env, addr, GETPC()); \
b327c654 250 } \
cbfb6ae9
AJ
251 }
252#define I(x) (x)
bcd510b1
BH
253LVE(lvebx, cpu_ldub_data_ra, I, u8)
254LVE(lvehx, cpu_lduw_data_ra, bswap16, u16)
255LVE(lvewx, cpu_ldl_data_ra, bswap32, u32)
cbfb6ae9
AJ
256#undef I
257#undef LVE
258
b327c654 259#define STVE(name, access, swap, element) \
2f5a189c
BS
260 void helper_##name(CPUPPCState *env, ppc_avr_t *r, \
261 target_ulong addr) \
b327c654
BS
262 { \
263 size_t n_elems = ARRAY_SIZE(r->element); \
264 int adjust = HI_IDX * (n_elems - 1); \
265 int sh = sizeof(r->element[0]) >> 1; \
266 int index = (addr & 0xf) >> sh; \
b327c654 267 if (msr_le) { \
bbfb6f13 268 index = n_elems - index - 1; \
e22c357b
DK
269 } \
270 \
271 if (needs_byteswap(env)) { \
2f5a189c 272 access(env, addr, swap(r->element[LO_IDX ? index : \
bcd510b1
BH
273 (adjust - index)]), \
274 GETPC()); \
cbfb6ae9 275 } else { \
2f5a189c 276 access(env, addr, r->element[LO_IDX ? index : \
bcd510b1 277 (adjust - index)], GETPC()); \
cbfb6ae9
AJ
278 } \
279 }
280#define I(x) (x)
bcd510b1
BH
281STVE(stvebx, cpu_stb_data_ra, I, u8)
282STVE(stvehx, cpu_stw_data_ra, bswap16, u16)
283STVE(stvewx, cpu_stl_data_ra, bswap32, u32)
cbfb6ae9
AJ
284#undef I
285#undef LVE
286
d6a46fe8
AJ
287#undef HI_IDX
288#undef LO_IDX
0ff93d11
TM
289
290void helper_tbegin(CPUPPCState *env)
291{
292 /* As a degenerate implementation, always fail tbegin. The reason
293 * given is "Nesting overflow". The "persistent" bit is set,
294 * providing a hint to the error handler to not retry. The TFIAR
295 * captures the address of the failure, which is this tbegin
296 * instruction. Instruction execution will continue with the
297 * next instruction in memory, which is precisely what we want.
298 */
299
300 env->spr[SPR_TEXASR] =
301 (1ULL << TEXASR_FAILURE_PERSISTENT) |
302 (1ULL << TEXASR_NESTING_OVERFLOW) |
303 (msr_hv << TEXASR_PRIVILEGE_HV) |
304 (msr_pr << TEXASR_PRIVILEGE_PR) |
305 (1ULL << TEXASR_FAILURE_SUMMARY) |
306 (1ULL << TEXASR_TFIAR_EXACT);
307 env->spr[SPR_TFIAR] = env->nip | (msr_hv << 1) | msr_pr;
308 env->spr[SPR_TFHAR] = env->nip + 4;
309 env->crf[0] = 0xB; /* 0b1010 = transaction failure */
310}
This page took 1.127346 seconds and 4 git commands to generate.