Statistics
| Branch: | Revision:

root / target-ppc / mem_helper.c @ d1a0cf73

History | View | Annotate | Download (9.2 kB)

1 9a64fbe4 bellard
/*
2 2f5a189c Blue Swirl
 *  PowerPC memory access emulation helpers for QEMU.
3 5fafdf24 ths
 *
4 76a66253 j_mayer
 *  Copyright (c) 2003-2007 Jocelyn Mayer
5 9a64fbe4 bellard
 *
6 9a64fbe4 bellard
 * This library is free software; you can redistribute it and/or
7 9a64fbe4 bellard
 * modify it under the terms of the GNU Lesser General Public
8 9a64fbe4 bellard
 * License as published by the Free Software Foundation; either
9 9a64fbe4 bellard
 * version 2 of the License, or (at your option) any later version.
10 9a64fbe4 bellard
 *
11 9a64fbe4 bellard
 * This library is distributed in the hope that it will be useful,
12 9a64fbe4 bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 9a64fbe4 bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 9a64fbe4 bellard
 * Lesser General Public License for more details.
15 9a64fbe4 bellard
 *
16 9a64fbe4 bellard
 * You should have received a copy of the GNU Lesser General Public
17 8167ee88 Blue Swirl
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 9a64fbe4 bellard
 */
19 3e457172 Blue Swirl
#include "cpu.h"
20 1de7afc9 Paolo Bonzini
#include "qemu/host-utils.h"
21 a7812ae4 pbrook
#include "helper.h"
22 9a64fbe4 bellard
23 0411a972 j_mayer
#include "helper_regs.h"
24 0487d6a8 j_mayer
25 3e457172 Blue Swirl
#if !defined(CONFIG_USER_ONLY)
26 022c62cb Paolo Bonzini
#include "exec/softmmu_exec.h"
27 3e457172 Blue Swirl
#endif /* !defined(CONFIG_USER_ONLY) */
28 3e457172 Blue Swirl
29 fdabc366 bellard
//#define DEBUG_OP
30 d12d51d5 aliguori
31 9a64fbe4 bellard
/*****************************************************************************/
32 ff4a62cd aurel32
/* Memory load and stores */
33 ff4a62cd aurel32
34 2f5a189c Blue Swirl
static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr,
35 2f5a189c Blue Swirl
                                    target_long arg)
36 ff4a62cd aurel32
{
37 ff4a62cd aurel32
#if defined(TARGET_PPC64)
38 e42a61f1 Alexander Graf
    if (!msr_is_64bit(env, env->msr)) {
39 b327c654 Blue Swirl
        return (uint32_t)(addr + arg);
40 b327c654 Blue Swirl
    } else
41 ff4a62cd aurel32
#endif
42 b327c654 Blue Swirl
    {
43 b327c654 Blue Swirl
        return addr + arg;
44 b327c654 Blue Swirl
    }
45 ff4a62cd aurel32
}
46 ff4a62cd aurel32
47 2f5a189c Blue Swirl
void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
48 ff4a62cd aurel32
{
49 76db3ba4 aurel32
    for (; reg < 32; reg++) {
50 b327c654 Blue Swirl
        if (msr_le) {
51 2f5a189c Blue Swirl
            env->gpr[reg] = bswap32(cpu_ldl_data(env, addr));
52 b327c654 Blue Swirl
        } else {
53 2f5a189c Blue Swirl
            env->gpr[reg] = cpu_ldl_data(env, addr);
54 b327c654 Blue Swirl
        }
55 2f5a189c Blue Swirl
        addr = addr_add(env, addr, 4);
56 ff4a62cd aurel32
    }
57 ff4a62cd aurel32
}
58 ff4a62cd aurel32
59 2f5a189c Blue Swirl
void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
60 ff4a62cd aurel32
{
61 76db3ba4 aurel32
    for (; reg < 32; reg++) {
62 b327c654 Blue Swirl
        if (msr_le) {
63 2f5a189c Blue Swirl
            cpu_stl_data(env, addr, bswap32((uint32_t)env->gpr[reg]));
64 b327c654 Blue Swirl
        } else {
65 2f5a189c Blue Swirl
            cpu_stl_data(env, addr, (uint32_t)env->gpr[reg]);
66 b327c654 Blue Swirl
        }
67 2f5a189c Blue Swirl
        addr = addr_add(env, addr, 4);
68 ff4a62cd aurel32
    }
69 ff4a62cd aurel32
}
70 ff4a62cd aurel32
71 2f5a189c Blue Swirl
void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg)
72 dfbc799d aurel32
{
73 dfbc799d aurel32
    int sh;
74 b327c654 Blue Swirl
75 76db3ba4 aurel32
    for (; nb > 3; nb -= 4) {
76 2f5a189c Blue Swirl
        env->gpr[reg] = cpu_ldl_data(env, addr);
77 dfbc799d aurel32
        reg = (reg + 1) % 32;
78 2f5a189c Blue Swirl
        addr = addr_add(env, addr, 4);
79 dfbc799d aurel32
    }
80 dfbc799d aurel32
    if (unlikely(nb > 0)) {
81 dfbc799d aurel32
        env->gpr[reg] = 0;
82 76db3ba4 aurel32
        for (sh = 24; nb > 0; nb--, sh -= 8) {
83 2f5a189c Blue Swirl
            env->gpr[reg] |= cpu_ldub_data(env, addr) << sh;
84 2f5a189c Blue Swirl
            addr = addr_add(env, addr, 1);
85 dfbc799d aurel32
        }
86 dfbc799d aurel32
    }
87 dfbc799d aurel32
}
88 dfbc799d aurel32
/* PPC32 specification says we must generate an exception if
89 dfbc799d aurel32
 * rA is in the range of registers to be loaded.
90 dfbc799d aurel32
 * In an other hand, IBM says this is valid, but rA won't be loaded.
91 dfbc799d aurel32
 * For now, I'll follow the spec...
92 dfbc799d aurel32
 */
93 2f5a189c Blue Swirl
void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,
94 2f5a189c Blue Swirl
                 uint32_t ra, uint32_t rb)
95 dfbc799d aurel32
{
96 dfbc799d aurel32
    if (likely(xer_bc != 0)) {
97 dfbc799d aurel32
        if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
98 dfbc799d aurel32
                     (reg < rb && (reg + xer_bc) > rb))) {
99 e5f17ac6 Blue Swirl
            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
100 e06fcd75 aurel32
                                       POWERPC_EXCP_INVAL |
101 e06fcd75 aurel32
                                       POWERPC_EXCP_INVAL_LSWX);
102 dfbc799d aurel32
        } else {
103 2f5a189c Blue Swirl
            helper_lsw(env, addr, xer_bc, reg);
104 dfbc799d aurel32
        }
105 dfbc799d aurel32
    }
106 dfbc799d aurel32
}
107 dfbc799d aurel32
108 2f5a189c Blue Swirl
void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
109 2f5a189c Blue Swirl
                 uint32_t reg)
110 dfbc799d aurel32
{
111 dfbc799d aurel32
    int sh;
112 b327c654 Blue Swirl
113 76db3ba4 aurel32
    for (; nb > 3; nb -= 4) {
114 2f5a189c Blue Swirl
        cpu_stl_data(env, addr, env->gpr[reg]);
115 dfbc799d aurel32
        reg = (reg + 1) % 32;
116 2f5a189c Blue Swirl
        addr = addr_add(env, addr, 4);
117 dfbc799d aurel32
    }
118 dfbc799d aurel32
    if (unlikely(nb > 0)) {
119 a16b45e7 aurel32
        for (sh = 24; nb > 0; nb--, sh -= 8) {
120 2f5a189c Blue Swirl
            cpu_stb_data(env, addr, (env->gpr[reg] >> sh) & 0xFF);
121 2f5a189c Blue Swirl
            addr = addr_add(env, addr, 1);
122 a16b45e7 aurel32
        }
123 dfbc799d aurel32
    }
124 dfbc799d aurel32
}
125 dfbc799d aurel32
126 2f5a189c Blue Swirl
static void do_dcbz(CPUPPCState *env, target_ulong addr, int dcache_line_size)
127 799a8c8d aurel32
{
128 799a8c8d aurel32
    int i;
129 b327c654 Blue Swirl
130 b327c654 Blue Swirl
    addr &= ~(dcache_line_size - 1);
131 b327c654 Blue Swirl
    for (i = 0; i < dcache_line_size; i += 4) {
132 2f5a189c Blue Swirl
        cpu_stl_data(env, addr + i, 0);
133 799a8c8d aurel32
    }
134 b327c654 Blue Swirl
    if (env->reserve_addr == addr) {
135 18b21a2f Nathan Froyd
        env->reserve_addr = (target_ulong)-1ULL;
136 b327c654 Blue Swirl
    }
137 799a8c8d aurel32
}
138 799a8c8d aurel32
139 8e33944f Alexander Graf
void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t is_dcbzl)
140 799a8c8d aurel32
{
141 8e33944f Alexander Graf
    int dcbz_size = env->dcache_line_size;
142 799a8c8d aurel32
143 8e33944f Alexander Graf
#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
144 8e33944f Alexander Graf
    if (!is_dcbzl &&
145 8e33944f Alexander Graf
        (env->excp_model == POWERPC_EXCP_970) &&
146 8e33944f Alexander Graf
        ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
147 8e33944f Alexander Graf
        dcbz_size = 32;
148 b327c654 Blue Swirl
    }
149 8e33944f Alexander Graf
#endif
150 8e33944f Alexander Graf
151 8e33944f Alexander Graf
    /* XXX add e500mc support */
152 8e33944f Alexander Graf
153 8e33944f Alexander Graf
    do_dcbz(env, addr, dcbz_size);
154 799a8c8d aurel32
}
155 799a8c8d aurel32
156 2f5a189c Blue Swirl
void helper_icbi(CPUPPCState *env, target_ulong addr)
157 37d269df aurel32
{
158 76db3ba4 aurel32
    addr &= ~(env->dcache_line_size - 1);
159 37d269df aurel32
    /* Invalidate one cache line :
160 37d269df aurel32
     * PowerPC specification says this is to be treated like a load
161 37d269df aurel32
     * (not a fetch) by the MMU. To be sure it will be so,
162 37d269df aurel32
     * do the load "by hand".
163 37d269df aurel32
     */
164 2f5a189c Blue Swirl
    cpu_ldl_data(env, addr);
165 37d269df aurel32
}
166 37d269df aurel32
167 b327c654 Blue Swirl
/* XXX: to be tested */
168 2f5a189c Blue Swirl
target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
169 2f5a189c Blue Swirl
                          uint32_t ra, uint32_t rb)
170 bdb4b689 aurel32
{
171 bdb4b689 aurel32
    int i, c, d;
172 b327c654 Blue Swirl
173 bdb4b689 aurel32
    d = 24;
174 bdb4b689 aurel32
    for (i = 0; i < xer_bc; i++) {
175 2f5a189c Blue Swirl
        c = cpu_ldub_data(env, addr);
176 2f5a189c Blue Swirl
        addr = addr_add(env, addr, 1);
177 bdb4b689 aurel32
        /* ra (if not 0) and rb are never modified */
178 bdb4b689 aurel32
        if (likely(reg != rb && (ra == 0 || reg != ra))) {
179 bdb4b689 aurel32
            env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
180 bdb4b689 aurel32
        }
181 b327c654 Blue Swirl
        if (unlikely(c == xer_cmp)) {
182 bdb4b689 aurel32
            break;
183 b327c654 Blue Swirl
        }
184 bdb4b689 aurel32
        if (likely(d != 0)) {
185 bdb4b689 aurel32
            d -= 8;
186 bdb4b689 aurel32
        } else {
187 bdb4b689 aurel32
            d = 24;
188 bdb4b689 aurel32
            reg++;
189 bdb4b689 aurel32
            reg = reg & 0x1F;
190 bdb4b689 aurel32
        }
191 bdb4b689 aurel32
    }
192 bdb4b689 aurel32
    return i;
193 bdb4b689 aurel32
}
194 bdb4b689 aurel32
195 ff4a62cd aurel32
/*****************************************************************************/
196 d6a46fe8 aurel32
/* Altivec extension helpers */
197 e2542fe2 Juan Quintela
#if defined(HOST_WORDS_BIGENDIAN)
198 d6a46fe8 aurel32
#define HI_IDX 0
199 d6a46fe8 aurel32
#define LO_IDX 1
200 d6a46fe8 aurel32
#else
201 d6a46fe8 aurel32
#define HI_IDX 1
202 d6a46fe8 aurel32
#define LO_IDX 0
203 d6a46fe8 aurel32
#endif
204 d6a46fe8 aurel32
205 cbfb6ae9 aurel32
#define LVE(name, access, swap, element)                        \
206 2f5a189c Blue Swirl
    void helper_##name(CPUPPCState *env, ppc_avr_t *r,          \
207 2f5a189c Blue Swirl
                       target_ulong addr)                       \
208 cbfb6ae9 aurel32
    {                                                           \
209 cbfb6ae9 aurel32
        size_t n_elems = ARRAY_SIZE(r->element);                \
210 b327c654 Blue Swirl
        int adjust = HI_IDX*(n_elems - 1);                      \
211 cbfb6ae9 aurel32
        int sh = sizeof(r->element[0]) >> 1;                    \
212 cbfb6ae9 aurel32
        int index = (addr & 0xf) >> sh;                         \
213 b327c654 Blue Swirl
                                                                \
214 b327c654 Blue Swirl
        if (msr_le) {                                           \
215 b327c654 Blue Swirl
            r->element[LO_IDX ? index : (adjust - index)] =     \
216 2f5a189c Blue Swirl
                swap(access(env, addr));                        \
217 b327c654 Blue Swirl
        } else {                                                \
218 b327c654 Blue Swirl
            r->element[LO_IDX ? index : (adjust - index)] =     \
219 2f5a189c Blue Swirl
                access(env, addr);                              \
220 b327c654 Blue Swirl
        }                                                       \
221 cbfb6ae9 aurel32
    }
222 cbfb6ae9 aurel32
#define I(x) (x)
223 2f5a189c Blue Swirl
LVE(lvebx, cpu_ldub_data, I, u8)
224 2f5a189c Blue Swirl
LVE(lvehx, cpu_lduw_data, bswap16, u16)
225 2f5a189c Blue Swirl
LVE(lvewx, cpu_ldl_data, bswap32, u32)
226 cbfb6ae9 aurel32
#undef I
227 cbfb6ae9 aurel32
#undef LVE
228 cbfb6ae9 aurel32
229 b327c654 Blue Swirl
#define STVE(name, access, swap, element)                               \
230 2f5a189c Blue Swirl
    void helper_##name(CPUPPCState *env, ppc_avr_t *r,                  \
231 2f5a189c Blue Swirl
                       target_ulong addr)                               \
232 b327c654 Blue Swirl
    {                                                                   \
233 b327c654 Blue Swirl
        size_t n_elems = ARRAY_SIZE(r->element);                        \
234 b327c654 Blue Swirl
        int adjust = HI_IDX * (n_elems - 1);                            \
235 b327c654 Blue Swirl
        int sh = sizeof(r->element[0]) >> 1;                            \
236 b327c654 Blue Swirl
        int index = (addr & 0xf) >> sh;                                 \
237 b327c654 Blue Swirl
                                                                        \
238 b327c654 Blue Swirl
        if (msr_le) {                                                   \
239 2f5a189c Blue Swirl
            access(env, addr, swap(r->element[LO_IDX ? index :          \
240 2f5a189c Blue Swirl
                                              (adjust - index)]));      \
241 cbfb6ae9 aurel32
        } else {                                                        \
242 2f5a189c Blue Swirl
            access(env, addr, r->element[LO_IDX ? index :               \
243 2f5a189c Blue Swirl
                                         (adjust - index)]);            \
244 cbfb6ae9 aurel32
        }                                                               \
245 cbfb6ae9 aurel32
    }
246 cbfb6ae9 aurel32
#define I(x) (x)
247 2f5a189c Blue Swirl
STVE(stvebx, cpu_stb_data, I, u8)
248 2f5a189c Blue Swirl
STVE(stvehx, cpu_stw_data, bswap16, u16)
249 2f5a189c Blue Swirl
STVE(stvewx, cpu_stl_data, bswap32, u32)
250 cbfb6ae9 aurel32
#undef I
251 cbfb6ae9 aurel32
#undef LVE
252 cbfb6ae9 aurel32
253 d6a46fe8 aurel32
#undef HI_IDX
254 d6a46fe8 aurel32
#undef LO_IDX
255 d6a46fe8 aurel32
256 d6a46fe8 aurel32
/*****************************************************************************/
257 fdabc366 bellard
/* Softmmu support */
258 b327c654 Blue Swirl
#if !defined(CONFIG_USER_ONLY)
259 fdabc366 bellard
260 fdabc366 bellard
#define MMUSUFFIX _mmu
261 fdabc366 bellard
262 fdabc366 bellard
#define SHIFT 0
263 022c62cb Paolo Bonzini
#include "exec/softmmu_template.h"
264 fdabc366 bellard
265 fdabc366 bellard
#define SHIFT 1
266 022c62cb Paolo Bonzini
#include "exec/softmmu_template.h"
267 fdabc366 bellard
268 fdabc366 bellard
#define SHIFT 2
269 022c62cb Paolo Bonzini
#include "exec/softmmu_template.h"
270 fdabc366 bellard
271 fdabc366 bellard
#define SHIFT 3
272 022c62cb Paolo Bonzini
#include "exec/softmmu_template.h"
273 fdabc366 bellard
274 fdabc366 bellard
/* try to fill the TLB and return an exception if error. If retaddr is
275 fdabc366 bellard
   NULL, it means that the function was called in C code (i.e. not
276 fdabc366 bellard
   from generated code or from helper.c) */
277 fdabc366 bellard
/* XXX: fix it to restore all registers */
278 2f5a189c Blue Swirl
void tlb_fill(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx,
279 20503968 Blue Swirl
              uintptr_t retaddr)
280 fdabc366 bellard
{
281 fdabc366 bellard
    int ret;
282 fdabc366 bellard
283 97b348e7 Blue Swirl
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
284 76a66253 j_mayer
    if (unlikely(ret != 0)) {
285 fdabc366 bellard
        if (likely(retaddr)) {
286 fdabc366 bellard
            /* now we have a real cpu fault */
287 a8a826a3 Blue Swirl
            cpu_restore_state(env, retaddr);
288 fdabc366 bellard
        }
289 e5f17ac6 Blue Swirl
        helper_raise_exception_err(env, env->exception_index, env->error_code);
290 fdabc366 bellard
    }
291 9a64fbe4 bellard
}
292 76a66253 j_mayer
#endif /* !CONFIG_USER_ONLY */