Statistics
| Branch: | Revision:

root / softmmu_template.h @ 3a607854

History | View | Annotate | Download (11.3 kB)

1 b92e5a22 bellard
/*
2 b92e5a22 bellard
 *  Software MMU support
3 b92e5a22 bellard
 * 
4 b92e5a22 bellard
 *  Copyright (c) 2003 Fabrice Bellard
5 b92e5a22 bellard
 *
6 b92e5a22 bellard
 * This library is free software; you can redistribute it and/or
7 b92e5a22 bellard
 * modify it under the terms of the GNU Lesser General Public
8 b92e5a22 bellard
 * License as published by the Free Software Foundation; either
9 b92e5a22 bellard
 * version 2 of the License, or (at your option) any later version.
10 b92e5a22 bellard
 *
11 b92e5a22 bellard
 * This library is distributed in the hope that it will be useful,
12 b92e5a22 bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 b92e5a22 bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 b92e5a22 bellard
 * Lesser General Public License for more details.
15 b92e5a22 bellard
 *
16 b92e5a22 bellard
 * You should have received a copy of the GNU Lesser General Public
17 b92e5a22 bellard
 * License along with this library; if not, write to the Free Software
18 b92e5a22 bellard
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 b92e5a22 bellard
 */
20 b92e5a22 bellard
#define DATA_SIZE (1 << SHIFT)
21 b92e5a22 bellard
22 b92e5a22 bellard
#if DATA_SIZE == 8
23 b92e5a22 bellard
#define SUFFIX q
24 61382a50 bellard
#define USUFFIX q
25 b92e5a22 bellard
#define DATA_TYPE uint64_t
26 b92e5a22 bellard
#elif DATA_SIZE == 4
27 b92e5a22 bellard
#define SUFFIX l
28 61382a50 bellard
#define USUFFIX l
29 b92e5a22 bellard
#define DATA_TYPE uint32_t
30 b92e5a22 bellard
#elif DATA_SIZE == 2
31 b92e5a22 bellard
#define SUFFIX w
32 61382a50 bellard
#define USUFFIX uw
33 b92e5a22 bellard
#define DATA_TYPE uint16_t
34 b92e5a22 bellard
#elif DATA_SIZE == 1
35 b92e5a22 bellard
#define SUFFIX b
36 61382a50 bellard
#define USUFFIX ub
37 b92e5a22 bellard
#define DATA_TYPE uint8_t
38 b92e5a22 bellard
#else
39 b92e5a22 bellard
#error unsupported data size
40 b92e5a22 bellard
#endif
41 b92e5a22 bellard
42 b769d8fe bellard
#ifdef SOFTMMU_CODE_ACCESS
43 b769d8fe bellard
#define READ_ACCESS_TYPE 2
44 84b7b8e7 bellard
#define ADDR_READ addr_code
45 b769d8fe bellard
#else
46 b769d8fe bellard
#define READ_ACCESS_TYPE 0
47 84b7b8e7 bellard
#define ADDR_READ addr_read
48 b769d8fe bellard
#endif
49 b769d8fe bellard
50 c27004ec bellard
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, 
51 61382a50 bellard
                                                        int is_user,
52 61382a50 bellard
                                                        void *retaddr);
53 108c49b8 bellard
static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, 
54 c27004ec bellard
                                              target_ulong tlb_addr)
55 b92e5a22 bellard
{
56 b92e5a22 bellard
    DATA_TYPE res;
57 b92e5a22 bellard
    int index;
58 b92e5a22 bellard
59 b92e5a22 bellard
    index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
60 b92e5a22 bellard
#if SHIFT <= 2
61 a4193c8a bellard
    res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr);
62 b92e5a22 bellard
#else
63 b92e5a22 bellard
#ifdef TARGET_WORDS_BIGENDIAN
64 a4193c8a bellard
    res = (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr) << 32;
65 a4193c8a bellard
    res |= io_mem_read[index][2](io_mem_opaque[index], physaddr + 4);
66 b92e5a22 bellard
#else
67 a4193c8a bellard
    res = io_mem_read[index][2](io_mem_opaque[index], physaddr);
68 a4193c8a bellard
    res |= (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr + 4) << 32;
69 b92e5a22 bellard
#endif
70 b92e5a22 bellard
#endif /* SHIFT > 2 */
71 f1c85677 bellard
#ifdef USE_KQEMU
72 f1c85677 bellard
    env->last_io_time = cpu_get_time_fast();
73 f1c85677 bellard
#endif
74 b92e5a22 bellard
    return res;
75 b92e5a22 bellard
}
76 b92e5a22 bellard
77 b92e5a22 bellard
/* handle all cases except unaligned access which span two pages */
78 c27004ec bellard
DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
79 61382a50 bellard
                                                         int is_user)
80 b92e5a22 bellard
{
81 b92e5a22 bellard
    DATA_TYPE res;
82 61382a50 bellard
    int index;
83 c27004ec bellard
    target_ulong tlb_addr;
84 108c49b8 bellard
    target_phys_addr_t physaddr;
85 b92e5a22 bellard
    void *retaddr;
86 b92e5a22 bellard
    
87 b92e5a22 bellard
    /* test if there is match for unaligned or IO access */
88 b92e5a22 bellard
    /* XXX: could done more in memory macro in a non portable way */
89 b92e5a22 bellard
    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
90 b92e5a22 bellard
 redo:
91 84b7b8e7 bellard
    tlb_addr = env->tlb_table[is_user][index].ADDR_READ;
92 b92e5a22 bellard
    if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
93 84b7b8e7 bellard
        physaddr = addr + env->tlb_table[is_user][index].addend;
94 b92e5a22 bellard
        if (tlb_addr & ~TARGET_PAGE_MASK) {
95 b92e5a22 bellard
            /* IO access */
96 b92e5a22 bellard
            if ((addr & (DATA_SIZE - 1)) != 0)
97 b92e5a22 bellard
                goto do_unaligned_access;
98 b92e5a22 bellard
            res = glue(io_read, SUFFIX)(physaddr, tlb_addr);
99 98699967 bellard
        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
100 b92e5a22 bellard
            /* slow unaligned access (it spans two pages or IO) */
101 b92e5a22 bellard
        do_unaligned_access:
102 61382a50 bellard
            retaddr = GETPC();
103 a64d4718 bellard
#ifdef ALIGNED_ONLY
104 a64d4718 bellard
            do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr);
105 a64d4718 bellard
#endif
106 61382a50 bellard
            res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, 
107 61382a50 bellard
                                                         is_user, retaddr);
108 b92e5a22 bellard
        } else {
109 a64d4718 bellard
            /* unaligned/aligned access in the same page */
110 a64d4718 bellard
#ifdef ALIGNED_ONLY
111 a64d4718 bellard
            if ((addr & (DATA_SIZE - 1)) != 0) {
112 a64d4718 bellard
                retaddr = GETPC();
113 a64d4718 bellard
                do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr);
114 a64d4718 bellard
            }
115 a64d4718 bellard
#endif
116 108c49b8 bellard
            res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr);
117 b92e5a22 bellard
        }
118 b92e5a22 bellard
    } else {
119 b92e5a22 bellard
        /* the page is not in the TLB : fill it */
120 61382a50 bellard
        retaddr = GETPC();
121 a64d4718 bellard
#ifdef ALIGNED_ONLY
122 a64d4718 bellard
        if ((addr & (DATA_SIZE - 1)) != 0)
123 a64d4718 bellard
            do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr);
124 a64d4718 bellard
#endif
125 b769d8fe bellard
        tlb_fill(addr, READ_ACCESS_TYPE, is_user, retaddr);
126 b92e5a22 bellard
        goto redo;
127 b92e5a22 bellard
    }
128 b92e5a22 bellard
    return res;
129 b92e5a22 bellard
}
130 b92e5a22 bellard
131 b92e5a22 bellard
/* handle all unaligned cases */
132 c27004ec bellard
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, 
133 61382a50 bellard
                                                        int is_user,
134 61382a50 bellard
                                                        void *retaddr)
135 b92e5a22 bellard
{
136 b92e5a22 bellard
    DATA_TYPE res, res1, res2;
137 61382a50 bellard
    int index, shift;
138 108c49b8 bellard
    target_phys_addr_t physaddr;
139 c27004ec bellard
    target_ulong tlb_addr, addr1, addr2;
140 b92e5a22 bellard
141 b92e5a22 bellard
    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
142 b92e5a22 bellard
 redo:
143 84b7b8e7 bellard
    tlb_addr = env->tlb_table[is_user][index].ADDR_READ;
144 b92e5a22 bellard
    if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
145 84b7b8e7 bellard
        physaddr = addr + env->tlb_table[is_user][index].addend;
146 b92e5a22 bellard
        if (tlb_addr & ~TARGET_PAGE_MASK) {
147 b92e5a22 bellard
            /* IO access */
148 b92e5a22 bellard
            if ((addr & (DATA_SIZE - 1)) != 0)
149 b92e5a22 bellard
                goto do_unaligned_access;
150 b92e5a22 bellard
            res = glue(io_read, SUFFIX)(physaddr, tlb_addr);
151 98699967 bellard
        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
152 b92e5a22 bellard
        do_unaligned_access:
153 b92e5a22 bellard
            /* slow unaligned access (it spans two pages) */
154 b92e5a22 bellard
            addr1 = addr & ~(DATA_SIZE - 1);
155 b92e5a22 bellard
            addr2 = addr1 + DATA_SIZE;
156 61382a50 bellard
            res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1, 
157 61382a50 bellard
                                                          is_user, retaddr);
158 61382a50 bellard
            res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2, 
159 61382a50 bellard
                                                          is_user, retaddr);
160 b92e5a22 bellard
            shift = (addr & (DATA_SIZE - 1)) * 8;
161 b92e5a22 bellard
#ifdef TARGET_WORDS_BIGENDIAN
162 b92e5a22 bellard
            res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift));
163 b92e5a22 bellard
#else
164 b92e5a22 bellard
            res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift));
165 b92e5a22 bellard
#endif
166 6986f88c bellard
            res = (DATA_TYPE)res;
167 b92e5a22 bellard
        } else {
168 b92e5a22 bellard
            /* unaligned/aligned access in the same page */
169 108c49b8 bellard
            res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr);
170 b92e5a22 bellard
        }
171 b92e5a22 bellard
    } else {
172 b92e5a22 bellard
        /* the page is not in the TLB : fill it */
173 b769d8fe bellard
        tlb_fill(addr, READ_ACCESS_TYPE, is_user, retaddr);
174 b92e5a22 bellard
        goto redo;
175 b92e5a22 bellard
    }
176 b92e5a22 bellard
    return res;
177 b92e5a22 bellard
}
178 b92e5a22 bellard
179 b769d8fe bellard
#ifndef SOFTMMU_CODE_ACCESS
180 b769d8fe bellard
181 c27004ec bellard
static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, 
182 b769d8fe bellard
                                                   DATA_TYPE val, 
183 b769d8fe bellard
                                                   int is_user,
184 b769d8fe bellard
                                                   void *retaddr);
185 b769d8fe bellard
186 108c49b8 bellard
static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, 
187 b769d8fe bellard
                                          DATA_TYPE val,
188 c27004ec bellard
                                          target_ulong tlb_addr,
189 b769d8fe bellard
                                          void *retaddr)
190 b769d8fe bellard
{
191 b769d8fe bellard
    int index;
192 b769d8fe bellard
193 b769d8fe bellard
    index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
194 b769d8fe bellard
    env->mem_write_vaddr = tlb_addr;
195 b769d8fe bellard
    env->mem_write_pc = (unsigned long)retaddr;
196 b769d8fe bellard
#if SHIFT <= 2
197 b769d8fe bellard
    io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val);
198 b769d8fe bellard
#else
199 b769d8fe bellard
#ifdef TARGET_WORDS_BIGENDIAN
200 b769d8fe bellard
    io_mem_write[index][2](io_mem_opaque[index], physaddr, val >> 32);
201 b769d8fe bellard
    io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val);
202 b769d8fe bellard
#else
203 b769d8fe bellard
    io_mem_write[index][2](io_mem_opaque[index], physaddr, val);
204 b769d8fe bellard
    io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32);
205 b769d8fe bellard
#endif
206 b769d8fe bellard
#endif /* SHIFT > 2 */
207 f1c85677 bellard
#ifdef USE_KQEMU
208 f1c85677 bellard
    env->last_io_time = cpu_get_time_fast();
209 f1c85677 bellard
#endif
210 b769d8fe bellard
}
211 b92e5a22 bellard
212 c27004ec bellard
void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, 
213 61382a50 bellard
                                                    DATA_TYPE val,
214 61382a50 bellard
                                                    int is_user)
215 b92e5a22 bellard
{
216 108c49b8 bellard
    target_phys_addr_t physaddr;
217 c27004ec bellard
    target_ulong tlb_addr;
218 b92e5a22 bellard
    void *retaddr;
219 61382a50 bellard
    int index;
220 b92e5a22 bellard
    
221 b92e5a22 bellard
    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
222 b92e5a22 bellard
 redo:
223 84b7b8e7 bellard
    tlb_addr = env->tlb_table[is_user][index].addr_write;
224 b92e5a22 bellard
    if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
225 84b7b8e7 bellard
        physaddr = addr + env->tlb_table[is_user][index].addend;
226 b92e5a22 bellard
        if (tlb_addr & ~TARGET_PAGE_MASK) {
227 b92e5a22 bellard
            /* IO access */
228 b92e5a22 bellard
            if ((addr & (DATA_SIZE - 1)) != 0)
229 b92e5a22 bellard
                goto do_unaligned_access;
230 d720b93d bellard
            retaddr = GETPC();
231 d720b93d bellard
            glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr);
232 98699967 bellard
        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
233 b92e5a22 bellard
        do_unaligned_access:
234 61382a50 bellard
            retaddr = GETPC();
235 a64d4718 bellard
#ifdef ALIGNED_ONLY
236 a64d4718 bellard
            do_unaligned_access(addr, 1, is_user, retaddr);
237 a64d4718 bellard
#endif
238 61382a50 bellard
            glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, 
239 61382a50 bellard
                                                   is_user, retaddr);
240 b92e5a22 bellard
        } else {
241 b92e5a22 bellard
            /* aligned/unaligned access in the same page */
242 a64d4718 bellard
#ifdef ALIGNED_ONLY
243 a64d4718 bellard
            if ((addr & (DATA_SIZE - 1)) != 0) {
244 a64d4718 bellard
                retaddr = GETPC();
245 a64d4718 bellard
                do_unaligned_access(addr, 1, is_user, retaddr);
246 a64d4718 bellard
            }
247 a64d4718 bellard
#endif
248 108c49b8 bellard
            glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val);
249 b92e5a22 bellard
        }
250 b92e5a22 bellard
    } else {
251 b92e5a22 bellard
        /* the page is not in the TLB : fill it */
252 61382a50 bellard
        retaddr = GETPC();
253 a64d4718 bellard
#ifdef ALIGNED_ONLY
254 a64d4718 bellard
        if ((addr & (DATA_SIZE - 1)) != 0)
255 a64d4718 bellard
            do_unaligned_access(addr, 1, is_user, retaddr);
256 a64d4718 bellard
#endif
257 61382a50 bellard
        tlb_fill(addr, 1, is_user, retaddr);
258 b92e5a22 bellard
        goto redo;
259 b92e5a22 bellard
    }
260 b92e5a22 bellard
}
261 b92e5a22 bellard
262 b92e5a22 bellard
/* handles all unaligned cases */
263 c27004ec bellard
static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, 
264 61382a50 bellard
                                                   DATA_TYPE val,
265 61382a50 bellard
                                                   int is_user,
266 61382a50 bellard
                                                   void *retaddr)
267 b92e5a22 bellard
{
268 108c49b8 bellard
    target_phys_addr_t physaddr;
269 c27004ec bellard
    target_ulong tlb_addr;
270 61382a50 bellard
    int index, i;
271 b92e5a22 bellard
272 b92e5a22 bellard
    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
273 b92e5a22 bellard
 redo:
274 84b7b8e7 bellard
    tlb_addr = env->tlb_table[is_user][index].addr_write;
275 b92e5a22 bellard
    if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
276 84b7b8e7 bellard
        physaddr = addr + env->tlb_table[is_user][index].addend;
277 b92e5a22 bellard
        if (tlb_addr & ~TARGET_PAGE_MASK) {
278 b92e5a22 bellard
            /* IO access */
279 b92e5a22 bellard
            if ((addr & (DATA_SIZE - 1)) != 0)
280 b92e5a22 bellard
                goto do_unaligned_access;
281 d720b93d bellard
            glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr);
282 98699967 bellard
        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
283 b92e5a22 bellard
        do_unaligned_access:
284 b92e5a22 bellard
            /* XXX: not efficient, but simple */
285 b92e5a22 bellard
            for(i = 0;i < DATA_SIZE; i++) {
286 b92e5a22 bellard
#ifdef TARGET_WORDS_BIGENDIAN
287 61382a50 bellard
                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), 
288 61382a50 bellard
                                          is_user, retaddr);
289 b92e5a22 bellard
#else
290 61382a50 bellard
                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8), 
291 61382a50 bellard
                                          is_user, retaddr);
292 b92e5a22 bellard
#endif
293 b92e5a22 bellard
            }
294 b92e5a22 bellard
        } else {
295 b92e5a22 bellard
            /* aligned/unaligned access in the same page */
296 108c49b8 bellard
            glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val);
297 b92e5a22 bellard
        }
298 b92e5a22 bellard
    } else {
299 b92e5a22 bellard
        /* the page is not in the TLB : fill it */
300 61382a50 bellard
        tlb_fill(addr, 1, is_user, retaddr);
301 b92e5a22 bellard
        goto redo;
302 b92e5a22 bellard
    }
303 b92e5a22 bellard
}
304 b92e5a22 bellard
305 b769d8fe bellard
#endif /* !defined(SOFTMMU_CODE_ACCESS) */
306 b769d8fe bellard
307 b769d8fe bellard
#undef READ_ACCESS_TYPE
308 b92e5a22 bellard
#undef SHIFT
309 b92e5a22 bellard
#undef DATA_TYPE
310 b92e5a22 bellard
#undef SUFFIX
311 61382a50 bellard
#undef USUFFIX
312 b92e5a22 bellard
#undef DATA_SIZE
313 84b7b8e7 bellard
#undef ADDR_READ