~ahs3/+junk/cq-qemu

« back to all changes in this revision

Viewing changes to target-xtensa/op_helper.c

  • Committer: Al Stone
  • Date: 2012-02-09 01:17:20 UTC
  • Revision ID: albert.stone@canonical.com-20120209011720-tztl7ik3qayz80p4
first commit to bzr for qemu

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions are met:
 
7
 *     * Redistributions of source code must retain the above copyright
 
8
 *       notice, this list of conditions and the following disclaimer.
 
9
 *     * Redistributions in binary form must reproduce the above copyright
 
10
 *       notice, this list of conditions and the following disclaimer in the
 
11
 *       documentation and/or other materials provided with the distribution.
 
12
 *     * Neither the name of the Open Source and Linux Lab nor the
 
13
 *       names of its contributors may be used to endorse or promote products
 
14
 *       derived from this software without specific prior written permission.
 
15
 *
 
16
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
17
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
19
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 
20
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
21
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
22
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
23
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
25
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
26
 */
 
27
 
 
28
#include "cpu.h"
 
29
#include "dyngen-exec.h"
 
30
#include "helpers.h"
 
31
#include "host-utils.h"
 
32
 
 
33
static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
 
34
        void *retaddr);
 
35
 
 
36
#define ALIGNED_ONLY
 
37
#define MMUSUFFIX _mmu
 
38
 
 
39
#define SHIFT 0
 
40
#include "softmmu_template.h"
 
41
 
 
42
#define SHIFT 1
 
43
#include "softmmu_template.h"
 
44
 
 
45
#define SHIFT 2
 
46
#include "softmmu_template.h"
 
47
 
 
48
#define SHIFT 3
 
49
#include "softmmu_template.h"
 
50
 
 
51
static void do_restore_state(void *pc_ptr)
 
52
{
 
53
    TranslationBlock *tb;
 
54
    uint32_t pc = (uint32_t)(intptr_t)pc_ptr;
 
55
 
 
56
    tb = tb_find_pc(pc);
 
57
    if (tb) {
 
58
        cpu_restore_state(tb, env, pc);
 
59
    }
 
60
}
 
61
 
 
62
static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
 
63
        void *retaddr)
 
64
{
 
65
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) &&
 
66
            !xtensa_option_enabled(env->config, XTENSA_OPTION_HW_ALIGNMENT)) {
 
67
        do_restore_state(retaddr);
 
68
        HELPER(exception_cause_vaddr)(
 
69
                env->pc, LOAD_STORE_ALIGNMENT_CAUSE, addr);
 
70
    }
 
71
}
 
72
 
 
73
void tlb_fill(CPUState *env1, target_ulong vaddr, int is_write, int mmu_idx,
 
74
              void *retaddr)
 
75
{
 
76
    CPUState *saved_env = env;
 
77
 
 
78
    env = env1;
 
79
    {
 
80
        uint32_t paddr;
 
81
        uint32_t page_size;
 
82
        unsigned access;
 
83
        int ret = xtensa_get_physical_addr(env, vaddr, is_write, mmu_idx,
 
84
                &paddr, &page_size, &access);
 
85
 
 
86
        qemu_log("%s(%08x, %d, %d) -> %08x, ret = %d\n", __func__,
 
87
                vaddr, is_write, mmu_idx, paddr, ret);
 
88
 
 
89
        if (ret == 0) {
 
90
            tlb_set_page(env,
 
91
                    vaddr & TARGET_PAGE_MASK,
 
92
                    paddr & TARGET_PAGE_MASK,
 
93
                    access, mmu_idx, page_size);
 
94
        } else {
 
95
            do_restore_state(retaddr);
 
96
            HELPER(exception_cause_vaddr)(env->pc, ret, vaddr);
 
97
        }
 
98
    }
 
99
    env = saved_env;
 
100
}
 
101
 
 
102
void HELPER(exception)(uint32_t excp)
 
103
{
 
104
    env->exception_index = excp;
 
105
    cpu_loop_exit(env);
 
106
}
 
107
 
 
108
void HELPER(exception_cause)(uint32_t pc, uint32_t cause)
 
109
{
 
110
    uint32_t vector;
 
111
 
 
112
    env->pc = pc;
 
113
    if (env->sregs[PS] & PS_EXCM) {
 
114
        if (env->config->ndepc) {
 
115
            env->sregs[DEPC] = pc;
 
116
        } else {
 
117
            env->sregs[EPC1] = pc;
 
118
        }
 
119
        vector = EXC_DOUBLE;
 
120
    } else {
 
121
        env->sregs[EPC1] = pc;
 
122
        vector = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
 
123
    }
 
124
 
 
125
    env->sregs[EXCCAUSE] = cause;
 
126
    env->sregs[PS] |= PS_EXCM;
 
127
 
 
128
    HELPER(exception)(vector);
 
129
}
 
130
 
 
131
void HELPER(exception_cause_vaddr)(uint32_t pc, uint32_t cause, uint32_t vaddr)
 
132
{
 
133
    env->sregs[EXCVADDR] = vaddr;
 
134
    HELPER(exception_cause)(pc, cause);
 
135
}
 
136
 
 
137
uint32_t HELPER(nsa)(uint32_t v)
 
138
{
 
139
    if (v & 0x80000000) {
 
140
        v = ~v;
 
141
    }
 
142
    return v ? clz32(v) - 1 : 31;
 
143
}
 
144
 
 
145
uint32_t HELPER(nsau)(uint32_t v)
 
146
{
 
147
    return v ? clz32(v) : 32;
 
148
}
 
149
 
 
150
static void copy_window_from_phys(CPUState *env,
 
151
        uint32_t window, uint32_t phys, uint32_t n)
 
152
{
 
153
    assert(phys < env->config->nareg);
 
154
    if (phys + n <= env->config->nareg) {
 
155
        memcpy(env->regs + window, env->phys_regs + phys,
 
156
                n * sizeof(uint32_t));
 
157
    } else {
 
158
        uint32_t n1 = env->config->nareg - phys;
 
159
        memcpy(env->regs + window, env->phys_regs + phys,
 
160
                n1 * sizeof(uint32_t));
 
161
        memcpy(env->regs + window + n1, env->phys_regs,
 
162
                (n - n1) * sizeof(uint32_t));
 
163
    }
 
164
}
 
165
 
 
166
static void copy_phys_from_window(CPUState *env,
 
167
        uint32_t phys, uint32_t window, uint32_t n)
 
168
{
 
169
    assert(phys < env->config->nareg);
 
170
    if (phys + n <= env->config->nareg) {
 
171
        memcpy(env->phys_regs + phys, env->regs + window,
 
172
                n * sizeof(uint32_t));
 
173
    } else {
 
174
        uint32_t n1 = env->config->nareg - phys;
 
175
        memcpy(env->phys_regs + phys, env->regs + window,
 
176
                n1 * sizeof(uint32_t));
 
177
        memcpy(env->phys_regs, env->regs + window + n1,
 
178
                (n - n1) * sizeof(uint32_t));
 
179
    }
 
180
}
 
181
 
 
182
 
 
183
static inline unsigned windowbase_bound(unsigned a, const CPUState *env)
 
184
{
 
185
    return a & (env->config->nareg / 4 - 1);
 
186
}
 
187
 
 
188
static inline unsigned windowstart_bit(unsigned a, const CPUState *env)
 
189
{
 
190
    return 1 << windowbase_bound(a, env);
 
191
}
 
192
 
 
193
void xtensa_sync_window_from_phys(CPUState *env)
 
194
{
 
195
    copy_window_from_phys(env, 0, env->sregs[WINDOW_BASE] * 4, 16);
 
196
}
 
197
 
 
198
void xtensa_sync_phys_from_window(CPUState *env)
 
199
{
 
200
    copy_phys_from_window(env, env->sregs[WINDOW_BASE] * 4, 0, 16);
 
201
}
 
202
 
 
203
static void rotate_window_abs(uint32_t position)
 
204
{
 
205
    xtensa_sync_phys_from_window(env);
 
206
    env->sregs[WINDOW_BASE] = windowbase_bound(position, env);
 
207
    xtensa_sync_window_from_phys(env);
 
208
}
 
209
 
 
210
static void rotate_window(uint32_t delta)
 
211
{
 
212
    rotate_window_abs(env->sregs[WINDOW_BASE] + delta);
 
213
}
 
214
 
 
215
void HELPER(wsr_windowbase)(uint32_t v)
 
216
{
 
217
    rotate_window_abs(v);
 
218
}
 
219
 
 
220
void HELPER(entry)(uint32_t pc, uint32_t s, uint32_t imm)
 
221
{
 
222
    int callinc = (env->sregs[PS] & PS_CALLINC) >> PS_CALLINC_SHIFT;
 
223
    if (s > 3 || ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
 
224
        qemu_log("Illegal entry instruction(pc = %08x), PS = %08x\n",
 
225
                pc, env->sregs[PS]);
 
226
        HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE);
 
227
    } else {
 
228
        env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - (imm << 3);
 
229
        rotate_window(callinc);
 
230
        env->sregs[WINDOW_START] |=
 
231
            windowstart_bit(env->sregs[WINDOW_BASE], env);
 
232
    }
 
233
}
 
234
 
 
235
void HELPER(window_check)(uint32_t pc, uint32_t w)
 
236
{
 
237
    uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
 
238
    uint32_t windowstart = env->sregs[WINDOW_START];
 
239
    uint32_t m, n;
 
240
 
 
241
    if ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) {
 
242
        return;
 
243
    }
 
244
 
 
245
    for (n = 1; ; ++n) {
 
246
        if (n > w) {
 
247
            return;
 
248
        }
 
249
        if (windowstart & windowstart_bit(windowbase + n, env)) {
 
250
            break;
 
251
        }
 
252
    }
 
253
 
 
254
    m = windowbase_bound(windowbase + n, env);
 
255
    rotate_window(n);
 
256
    env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
 
257
        (windowbase << PS_OWB_SHIFT) | PS_EXCM;
 
258
    env->sregs[EPC1] = env->pc = pc;
 
259
 
 
260
    if (windowstart & windowstart_bit(m + 1, env)) {
 
261
        HELPER(exception)(EXC_WINDOW_OVERFLOW4);
 
262
    } else if (windowstart & windowstart_bit(m + 2, env)) {
 
263
        HELPER(exception)(EXC_WINDOW_OVERFLOW8);
 
264
    } else {
 
265
        HELPER(exception)(EXC_WINDOW_OVERFLOW12);
 
266
    }
 
267
}
 
268
 
 
269
uint32_t HELPER(retw)(uint32_t pc)
 
270
{
 
271
    int n = (env->regs[0] >> 30) & 0x3;
 
272
    int m = 0;
 
273
    uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
 
274
    uint32_t windowstart = env->sregs[WINDOW_START];
 
275
    uint32_t ret_pc = 0;
 
276
 
 
277
    if (windowstart & windowstart_bit(windowbase - 1, env)) {
 
278
        m = 1;
 
279
    } else if (windowstart & windowstart_bit(windowbase - 2, env)) {
 
280
        m = 2;
 
281
    } else if (windowstart & windowstart_bit(windowbase - 3, env)) {
 
282
        m = 3;
 
283
    }
 
284
 
 
285
    if (n == 0 || (m != 0 && m != n) ||
 
286
            ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
 
287
        qemu_log("Illegal retw instruction(pc = %08x), "
 
288
                "PS = %08x, m = %d, n = %d\n",
 
289
                pc, env->sregs[PS], m, n);
 
290
        HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE);
 
291
    } else {
 
292
        int owb = windowbase;
 
293
 
 
294
        ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff);
 
295
 
 
296
        rotate_window(-n);
 
297
        if (windowstart & windowstart_bit(env->sregs[WINDOW_BASE], env)) {
 
298
            env->sregs[WINDOW_START] &= ~windowstart_bit(owb, env);
 
299
        } else {
 
300
            /* window underflow */
 
301
            env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
 
302
                (windowbase << PS_OWB_SHIFT) | PS_EXCM;
 
303
            env->sregs[EPC1] = env->pc = pc;
 
304
 
 
305
            if (n == 1) {
 
306
                HELPER(exception)(EXC_WINDOW_UNDERFLOW4);
 
307
            } else if (n == 2) {
 
308
                HELPER(exception)(EXC_WINDOW_UNDERFLOW8);
 
309
            } else if (n == 3) {
 
310
                HELPER(exception)(EXC_WINDOW_UNDERFLOW12);
 
311
            }
 
312
        }
 
313
    }
 
314
    return ret_pc;
 
315
}
 
316
 
 
317
void HELPER(rotw)(uint32_t imm4)
 
318
{
 
319
    rotate_window(imm4);
 
320
}
 
321
 
 
322
void HELPER(restore_owb)(void)
 
323
{
 
324
    rotate_window_abs((env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT);
 
325
}
 
326
 
 
327
void HELPER(movsp)(uint32_t pc)
 
328
{
 
329
    if ((env->sregs[WINDOW_START] &
 
330
            (windowstart_bit(env->sregs[WINDOW_BASE] - 3, env) |
 
331
             windowstart_bit(env->sregs[WINDOW_BASE] - 2, env) |
 
332
             windowstart_bit(env->sregs[WINDOW_BASE] - 1, env))) == 0) {
 
333
        HELPER(exception_cause)(pc, ALLOCA_CAUSE);
 
334
    }
 
335
}
 
336
 
 
337
void HELPER(wsr_lbeg)(uint32_t v)
 
338
{
 
339
    if (env->sregs[LBEG] != v) {
 
340
        tb_invalidate_phys_page_range(
 
341
                env->sregs[LEND] - 1, env->sregs[LEND], 0);
 
342
        env->sregs[LBEG] = v;
 
343
    }
 
344
}
 
345
 
 
346
void HELPER(wsr_lend)(uint32_t v)
 
347
{
 
348
    if (env->sregs[LEND] != v) {
 
349
        tb_invalidate_phys_page_range(
 
350
                env->sregs[LEND] - 1, env->sregs[LEND], 0);
 
351
        env->sregs[LEND] = v;
 
352
        tb_invalidate_phys_page_range(
 
353
                env->sregs[LEND] - 1, env->sregs[LEND], 0);
 
354
    }
 
355
}
 
356
 
 
357
void HELPER(dump_state)(void)
 
358
{
 
359
    cpu_dump_state(env, stderr, fprintf, 0);
 
360
}
 
361
 
 
362
void HELPER(waiti)(uint32_t pc, uint32_t intlevel)
 
363
{
 
364
    env->pc = pc;
 
365
    env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
 
366
        (intlevel << PS_INTLEVEL_SHIFT);
 
367
    check_interrupts(env);
 
368
    if (env->pending_irq_level) {
 
369
        cpu_loop_exit(env);
 
370
        return;
 
371
    }
 
372
 
 
373
    env->halt_clock = qemu_get_clock_ns(vm_clock);
 
374
    env->halted = 1;
 
375
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
 
376
        xtensa_rearm_ccompare_timer(env);
 
377
    }
 
378
    HELPER(exception)(EXCP_HLT);
 
379
}
 
380
 
 
381
void HELPER(timer_irq)(uint32_t id, uint32_t active)
 
382
{
 
383
    xtensa_timer_irq(env, id, active);
 
384
}
 
385
 
 
386
void HELPER(advance_ccount)(uint32_t d)
 
387
{
 
388
    xtensa_advance_ccount(env, d);
 
389
}
 
390
 
 
391
void HELPER(check_interrupts)(CPUState *env)
 
392
{
 
393
    check_interrupts(env);
 
394
}
 
395
 
 
396
void HELPER(wsr_rasid)(uint32_t v)
 
397
{
 
398
    v = (v & 0xffffff00) | 0x1;
 
399
    if (v != env->sregs[RASID]) {
 
400
        env->sregs[RASID] = v;
 
401
        tlb_flush(env, 1);
 
402
    }
 
403
}
 
404
 
 
405
static uint32_t get_page_size(const CPUState *env, bool dtlb, uint32_t way)
 
406
{
 
407
    uint32_t tlbcfg = env->sregs[dtlb ? DTLBCFG : ITLBCFG];
 
408
 
 
409
    switch (way) {
 
410
    case 4:
 
411
        return (tlbcfg >> 16) & 0x3;
 
412
 
 
413
    case 5:
 
414
        return (tlbcfg >> 20) & 0x1;
 
415
 
 
416
    case 6:
 
417
        return (tlbcfg >> 24) & 0x1;
 
418
 
 
419
    default:
 
420
        return 0;
 
421
    }
 
422
}
 
423
 
 
424
/*!
 
425
 * Get bit mask for the virtual address bits translated by the TLB way
 
426
 */
 
427
uint32_t xtensa_tlb_get_addr_mask(const CPUState *env, bool dtlb, uint32_t way)
 
428
{
 
429
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 
430
        bool varway56 = dtlb ?
 
431
            env->config->dtlb.varway56 :
 
432
            env->config->itlb.varway56;
 
433
 
 
434
        switch (way) {
 
435
        case 4:
 
436
            return 0xfff00000 << get_page_size(env, dtlb, way) * 2;
 
437
 
 
438
        case 5:
 
439
            if (varway56) {
 
440
                return 0xf8000000 << get_page_size(env, dtlb, way);
 
441
            } else {
 
442
                return 0xf8000000;
 
443
            }
 
444
 
 
445
        case 6:
 
446
            if (varway56) {
 
447
                return 0xf0000000 << (1 - get_page_size(env, dtlb, way));
 
448
            } else {
 
449
                return 0xf0000000;
 
450
            }
 
451
 
 
452
        default:
 
453
            return 0xfffff000;
 
454
        }
 
455
    } else {
 
456
        return REGION_PAGE_MASK;
 
457
    }
 
458
}
 
459
 
 
460
/*!
 
461
 * Get bit mask for the 'VPN without index' field.
 
462
 * See ISA, 4.6.5.6, data format for RxTLB0
 
463
 */
 
464
static uint32_t get_vpn_mask(const CPUState *env, bool dtlb, uint32_t way)
 
465
{
 
466
    if (way < 4) {
 
467
        bool is32 = (dtlb ?
 
468
                env->config->dtlb.nrefillentries :
 
469
                env->config->itlb.nrefillentries) == 32;
 
470
        return is32 ? 0xffff8000 : 0xffffc000;
 
471
    } else if (way == 4) {
 
472
        return xtensa_tlb_get_addr_mask(env, dtlb, way) << 2;
 
473
    } else if (way <= 6) {
 
474
        uint32_t mask = xtensa_tlb_get_addr_mask(env, dtlb, way);
 
475
        bool varway56 = dtlb ?
 
476
            env->config->dtlb.varway56 :
 
477
            env->config->itlb.varway56;
 
478
 
 
479
        if (varway56) {
 
480
            return mask << (way == 5 ? 2 : 3);
 
481
        } else {
 
482
            return mask << 1;
 
483
        }
 
484
    } else {
 
485
        return 0xfffff000;
 
486
    }
 
487
}
 
488
 
 
489
/*!
 
490
 * Split virtual address into VPN (with index) and entry index
 
491
 * for the given TLB way
 
492
 */
 
493
void split_tlb_entry_spec_way(const CPUState *env, uint32_t v, bool dtlb,
 
494
        uint32_t *vpn, uint32_t wi, uint32_t *ei)
 
495
{
 
496
    bool varway56 = dtlb ?
 
497
        env->config->dtlb.varway56 :
 
498
        env->config->itlb.varway56;
 
499
 
 
500
    if (!dtlb) {
 
501
        wi &= 7;
 
502
    }
 
503
 
 
504
    if (wi < 4) {
 
505
        bool is32 = (dtlb ?
 
506
                env->config->dtlb.nrefillentries :
 
507
                env->config->itlb.nrefillentries) == 32;
 
508
        *ei = (v >> 12) & (is32 ? 0x7 : 0x3);
 
509
    } else {
 
510
        switch (wi) {
 
511
        case 4:
 
512
            {
 
513
                uint32_t eibase = 20 + get_page_size(env, dtlb, wi) * 2;
 
514
                *ei = (v >> eibase) & 0x3;
 
515
            }
 
516
            break;
 
517
 
 
518
        case 5:
 
519
            if (varway56) {
 
520
                uint32_t eibase = 27 + get_page_size(env, dtlb, wi);
 
521
                *ei = (v >> eibase) & 0x3;
 
522
            } else {
 
523
                *ei = (v >> 27) & 0x1;
 
524
            }
 
525
            break;
 
526
 
 
527
        case 6:
 
528
            if (varway56) {
 
529
                uint32_t eibase = 29 - get_page_size(env, dtlb, wi);
 
530
                *ei = (v >> eibase) & 0x7;
 
531
            } else {
 
532
                *ei = (v >> 28) & 0x1;
 
533
            }
 
534
            break;
 
535
 
 
536
        default:
 
537
            *ei = 0;
 
538
            break;
 
539
        }
 
540
    }
 
541
    *vpn = v & xtensa_tlb_get_addr_mask(env, dtlb, wi);
 
542
}
 
543
 
 
544
/*!
 
545
 * Split TLB address into TLB way, entry index and VPN (with index).
 
546
 * See ISA, 4.6.5.5 - 4.6.5.8 for the TLB addressing format
 
547
 */
 
548
static void split_tlb_entry_spec(uint32_t v, bool dtlb,
 
549
        uint32_t *vpn, uint32_t *wi, uint32_t *ei)
 
550
{
 
551
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 
552
        *wi = v & (dtlb ? 0xf : 0x7);
 
553
        split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei);
 
554
    } else {
 
555
        *vpn = v & REGION_PAGE_MASK;
 
556
        *wi = 0;
 
557
        *ei = (v >> 29) & 0x7;
 
558
    }
 
559
}
 
560
 
 
561
static xtensa_tlb_entry *get_tlb_entry(uint32_t v, bool dtlb, uint32_t *pwi)
 
562
{
 
563
    uint32_t vpn;
 
564
    uint32_t wi;
 
565
    uint32_t ei;
 
566
 
 
567
    split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei);
 
568
    if (pwi) {
 
569
        *pwi = wi;
 
570
    }
 
571
    return xtensa_tlb_get_entry(env, dtlb, wi, ei);
 
572
}
 
573
 
 
574
uint32_t HELPER(rtlb0)(uint32_t v, uint32_t dtlb)
 
575
{
 
576
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 
577
        uint32_t wi;
 
578
        const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi);
 
579
        return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
 
580
    } else {
 
581
        return v & REGION_PAGE_MASK;
 
582
    }
 
583
}
 
584
 
 
585
uint32_t HELPER(rtlb1)(uint32_t v, uint32_t dtlb)
 
586
{
 
587
    const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, NULL);
 
588
    return entry->paddr | entry->attr;
 
589
}
 
590
 
 
591
void HELPER(itlb)(uint32_t v, uint32_t dtlb)
 
592
{
 
593
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 
594
        uint32_t wi;
 
595
        xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi);
 
596
        if (entry->variable && entry->asid) {
 
597
            tlb_flush_page(env, entry->vaddr);
 
598
            entry->asid = 0;
 
599
        }
 
600
    }
 
601
}
 
602
 
 
603
uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb)
 
604
{
 
605
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 
606
        uint32_t wi;
 
607
        uint32_t ei;
 
608
        uint8_t ring;
 
609
        int res = xtensa_tlb_lookup(env, v, dtlb, &wi, &ei, &ring);
 
610
 
 
611
        switch (res) {
 
612
        case 0:
 
613
            if (ring >= xtensa_get_ring(env)) {
 
614
                return (v & 0xfffff000) | wi | (dtlb ? 0x10 : 0x8);
 
615
            }
 
616
            break;
 
617
 
 
618
        case INST_TLB_MULTI_HIT_CAUSE:
 
619
        case LOAD_STORE_TLB_MULTI_HIT_CAUSE:
 
620
            HELPER(exception_cause_vaddr)(env->pc, res, v);
 
621
            break;
 
622
        }
 
623
        return 0;
 
624
    } else {
 
625
        return (v & REGION_PAGE_MASK) | 0x1;
 
626
    }
 
627
}
 
628
 
 
629
void xtensa_tlb_set_entry(CPUState *env, bool dtlb,
 
630
        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
 
631
{
 
632
    xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
 
633
 
 
634
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 
635
        if (entry->variable) {
 
636
            if (entry->asid) {
 
637
                tlb_flush_page(env, entry->vaddr);
 
638
            }
 
639
            entry->vaddr = vpn;
 
640
            entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi);
 
641
            entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff;
 
642
            entry->attr = pte & 0xf;
 
643
        } else {
 
644
            qemu_log("%s %d, %d, %d trying to set immutable entry\n",
 
645
                    __func__, dtlb, wi, ei);
 
646
        }
 
647
    } else {
 
648
        tlb_flush_page(env, entry->vaddr);
 
649
        if (xtensa_option_enabled(env->config,
 
650
                    XTENSA_OPTION_REGION_TRANSLATION)) {
 
651
            entry->paddr = pte & REGION_PAGE_MASK;
 
652
        }
 
653
        entry->attr = pte & 0xf;
 
654
    }
 
655
}
 
656
 
 
657
void HELPER(wtlb)(uint32_t p, uint32_t v, uint32_t dtlb)
 
658
{
 
659
    uint32_t vpn;
 
660
    uint32_t wi;
 
661
    uint32_t ei;
 
662
    split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei);
 
663
    xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p);
 
664
}