]> git.proxmox.com Git - qemu.git/blame - target-ppc/op_helper.c
ppc: Split off misc helpers
[qemu.git] / target-ppc / op_helper.c
CommitLineData
9a64fbe4 1/*
b327c654 2 * PowerPC 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 */
7b239bec 19#include <string.h>
3e457172
BS
20#include "cpu.h"
21#include "dyngen-exec.h"
603fccce 22#include "host-utils.h"
a7812ae4 23#include "helper.h"
9a64fbe4 24
0411a972 25#include "helper_regs.h"
0487d6a8 26
3e457172
BS
27#if !defined(CONFIG_USER_ONLY)
28#include "softmmu_exec.h"
29#endif /* !defined(CONFIG_USER_ONLY) */
30
fdabc366 31//#define DEBUG_OP
d12d51d5 32
ff4a62cd
AJ
33/*****************************************************************************/
34/* Memory load and stores */
35
636aa200 36static inline target_ulong addr_add(target_ulong addr, target_long arg)
ff4a62cd
AJ
37{
38#if defined(TARGET_PPC64)
b327c654
BS
39 if (!msr_sf) {
40 return (uint32_t)(addr + arg);
41 } else
ff4a62cd 42#endif
b327c654
BS
43 {
44 return addr + arg;
45 }
ff4a62cd
AJ
46}
47
b327c654 48void helper_lmw(target_ulong addr, uint32_t reg)
ff4a62cd 49{
76db3ba4 50 for (; reg < 32; reg++) {
b327c654 51 if (msr_le) {
76db3ba4 52 env->gpr[reg] = bswap32(ldl(addr));
b327c654 53 } else {
76db3ba4 54 env->gpr[reg] = ldl(addr);
b327c654
BS
55 }
56 addr = addr_add(addr, 4);
ff4a62cd
AJ
57 }
58}
59
b327c654 60void helper_stmw(target_ulong addr, uint32_t reg)
ff4a62cd 61{
76db3ba4 62 for (; reg < 32; reg++) {
b327c654 63 if (msr_le) {
76db3ba4 64 stl(addr, bswap32((uint32_t)env->gpr[reg]));
b327c654 65 } else {
76db3ba4 66 stl(addr, (uint32_t)env->gpr[reg]);
b327c654
BS
67 }
68 addr = addr_add(addr, 4);
ff4a62cd
AJ
69 }
70}
71
dfbc799d
AJ
72void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
73{
74 int sh;
b327c654 75
76db3ba4
AJ
76 for (; nb > 3; nb -= 4) {
77 env->gpr[reg] = ldl(addr);
dfbc799d 78 reg = (reg + 1) % 32;
b327c654 79 addr = addr_add(addr, 4);
dfbc799d
AJ
80 }
81 if (unlikely(nb > 0)) {
82 env->gpr[reg] = 0;
76db3ba4
AJ
83 for (sh = 24; nb > 0; nb--, sh -= 8) {
84 env->gpr[reg] |= ldub(addr) << sh;
b327c654 85 addr = addr_add(addr, 1);
dfbc799d
AJ
86 }
87 }
88}
89/* PPC32 specification says we must generate an exception if
90 * rA is in the range of registers to be loaded.
91 * In an other hand, IBM says this is valid, but rA won't be loaded.
92 * For now, I'll follow the spec...
93 */
94void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
95{
96 if (likely(xer_bc != 0)) {
97 if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
98 (reg < rb && (reg + xer_bc) > rb))) {
e5f17ac6 99 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
e06fcd75
AJ
100 POWERPC_EXCP_INVAL |
101 POWERPC_EXCP_INVAL_LSWX);
dfbc799d
AJ
102 } else {
103 helper_lsw(addr, xer_bc, reg);
104 }
105 }
106}
107
108void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
109{
110 int sh;
b327c654 111
76db3ba4
AJ
112 for (; nb > 3; nb -= 4) {
113 stl(addr, env->gpr[reg]);
dfbc799d 114 reg = (reg + 1) % 32;
b327c654 115 addr = addr_add(addr, 4);
dfbc799d
AJ
116 }
117 if (unlikely(nb > 0)) {
a16b45e7 118 for (sh = 24; nb > 0; nb--, sh -= 8) {
76db3ba4 119 stb(addr, (env->gpr[reg] >> sh) & 0xFF);
a16b45e7
AJ
120 addr = addr_add(addr, 1);
121 }
dfbc799d
AJ
122 }
123}
124
799a8c8d
AJ
125static void do_dcbz(target_ulong addr, int dcache_line_size)
126{
799a8c8d 127 int i;
b327c654
BS
128
129 addr &= ~(dcache_line_size - 1);
130 for (i = 0; i < dcache_line_size; i += 4) {
131 stl(addr + i, 0);
799a8c8d 132 }
b327c654 133 if (env->reserve_addr == addr) {
18b21a2f 134 env->reserve_addr = (target_ulong)-1ULL;
b327c654 135 }
799a8c8d
AJ
136}
137
138void helper_dcbz(target_ulong addr)
139{
140 do_dcbz(addr, env->dcache_line_size);
141}
142
143void helper_dcbz_970(target_ulong addr)
144{
b327c654 145 if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
799a8c8d 146 do_dcbz(addr, 32);
b327c654 147 } else {
799a8c8d 148 do_dcbz(addr, env->dcache_line_size);
b327c654 149 }
799a8c8d
AJ
150}
151
37d269df
AJ
152void helper_icbi(target_ulong addr)
153{
76db3ba4 154 addr &= ~(env->dcache_line_size - 1);
37d269df
AJ
155 /* Invalidate one cache line :
156 * PowerPC specification says this is to be treated like a load
157 * (not a fetch) by the MMU. To be sure it will be so,
158 * do the load "by hand".
159 */
577f25a5 160 ldl(addr);
37d269df
AJ
161}
162
b327c654
BS
163/* XXX: to be tested */
164target_ulong helper_lscbx(target_ulong addr, uint32_t reg, uint32_t ra,
165 uint32_t rb)
bdb4b689
AJ
166{
167 int i, c, d;
b327c654 168
bdb4b689
AJ
169 d = 24;
170 for (i = 0; i < xer_bc; i++) {
76db3ba4 171 c = ldub(addr);
b327c654 172 addr = addr_add(addr, 1);
bdb4b689
AJ
173 /* ra (if not 0) and rb are never modified */
174 if (likely(reg != rb && (ra == 0 || reg != ra))) {
175 env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
176 }
b327c654 177 if (unlikely(c == xer_cmp)) {
bdb4b689 178 break;
b327c654 179 }
bdb4b689
AJ
180 if (likely(d != 0)) {
181 d -= 8;
182 } else {
183 d = 24;
184 reg++;
185 reg = reg & 0x1F;
186 }
187 }
188 return i;
189}
190
d6a46fe8
AJ
191/*****************************************************************************/
192/* Altivec extension helpers */
e2542fe2 193#if defined(HOST_WORDS_BIGENDIAN)
d6a46fe8
AJ
194#define HI_IDX 0
195#define LO_IDX 1
196#else
197#define HI_IDX 1
198#define LO_IDX 0
199#endif
200
cbfb6ae9 201#define LVE(name, access, swap, element) \
b327c654 202 void helper_##name(ppc_avr_t *r, target_ulong addr) \
cbfb6ae9
AJ
203 { \
204 size_t n_elems = ARRAY_SIZE(r->element); \
b327c654 205 int adjust = HI_IDX*(n_elems - 1); \
cbfb6ae9
AJ
206 int sh = sizeof(r->element[0]) >> 1; \
207 int index = (addr & 0xf) >> sh; \
b327c654
BS
208 \
209 if (msr_le) { \
210 r->element[LO_IDX ? index : (adjust - index)] = \
211 swap(access(addr)); \
212 } else { \
213 r->element[LO_IDX ? index : (adjust - index)] = \
214 access(addr); \
215 } \
cbfb6ae9
AJ
216 }
217#define I(x) (x)
218LVE(lvebx, ldub, I, u8)
219LVE(lvehx, lduw, bswap16, u16)
220LVE(lvewx, ldl, bswap32, u32)
221#undef I
222#undef LVE
223
b327c654
BS
224#define STVE(name, access, swap, element) \
225 void helper_##name(ppc_avr_t *r, target_ulong addr) \
226 { \
227 size_t n_elems = ARRAY_SIZE(r->element); \
228 int adjust = HI_IDX * (n_elems - 1); \
229 int sh = sizeof(r->element[0]) >> 1; \
230 int index = (addr & 0xf) >> sh; \
231 \
232 if (msr_le) { \
cbfb6ae9
AJ
233 access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
234 } else { \
235 access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
236 } \
237 }
238#define I(x) (x)
239STVE(stvebx, stb, I, u8)
240STVE(stvehx, stw, bswap16, u16)
241STVE(stvewx, stl, bswap32, u32)
242#undef I
243#undef LVE
244
d6a46fe8
AJ
245#undef HI_IDX
246#undef LO_IDX
247
fdabc366
FB
248/*****************************************************************************/
249/* Softmmu support */
b327c654 250#if !defined(CONFIG_USER_ONLY)
fdabc366
FB
251
252#define MMUSUFFIX _mmu
fdabc366
FB
253
254#define SHIFT 0
255#include "softmmu_template.h"
256
257#define SHIFT 1
258#include "softmmu_template.h"
259
260#define SHIFT 2
261#include "softmmu_template.h"
262
263#define SHIFT 3
264#include "softmmu_template.h"
265
266/* try to fill the TLB and return an exception if error. If retaddr is
267 NULL, it means that the function was called in C code (i.e. not
268 from generated code or from helper.c) */
269/* XXX: fix it to restore all registers */
1328c2bf 270void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx,
20503968 271 uintptr_t retaddr)
fdabc366
FB
272{
273 TranslationBlock *tb;
1328c2bf 274 CPUPPCState *saved_env;
fdabc366
FB
275 int ret;
276
fdabc366 277 saved_env = env;
bccd9ec5 278 env = env1;
97b348e7 279 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
76a66253 280 if (unlikely(ret != 0)) {
fdabc366
FB
281 if (likely(retaddr)) {
282 /* now we have a real cpu fault */
20503968 283 tb = tb_find_pc(retaddr);
fdabc366
FB
284 if (likely(tb)) {
285 /* the PC is inside the translated code. It means that we have
286 a virtual CPU fault */
20503968 287 cpu_restore_state(tb, env, retaddr);
76a66253 288 }
fdabc366 289 }
e5f17ac6 290 helper_raise_exception_err(env, env->exception_index, env->error_code);
fdabc366
FB
291 }
292 env = saved_env;
9a64fbe4 293}
76a66253 294#endif /* !CONFIG_USER_ONLY */