~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to target/xtensa/op_helper.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

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 "qemu/osdep.h"
 
29
#include "qemu/main-loop.h"
 
30
#include "cpu.h"
 
31
#include "exec/helper-proto.h"
 
32
#include "qemu/host-utils.h"
 
33
#include "exec/exec-all.h"
 
34
#include "exec/cpu_ldst.h"
 
35
#include "exec/address-spaces.h"
 
36
#include "qemu/timer.h"
 
37
 
 
38
void xtensa_cpu_do_unaligned_access(CPUState *cs,
 
39
        vaddr addr, MMUAccessType access_type,
 
40
        int mmu_idx, uintptr_t retaddr)
 
41
{
 
42
    XtensaCPU *cpu = XTENSA_CPU(cs);
 
43
    CPUXtensaState *env = &cpu->env;
 
44
 
 
45
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) &&
 
46
            !xtensa_option_enabled(env->config, XTENSA_OPTION_HW_ALIGNMENT)) {
 
47
        cpu_restore_state(CPU(cpu), retaddr);
 
48
        HELPER(exception_cause_vaddr)(env,
 
49
                env->pc, LOAD_STORE_ALIGNMENT_CAUSE, addr);
 
50
    }
 
51
}
 
52
 
 
53
void tlb_fill(CPUState *cs, target_ulong vaddr, MMUAccessType access_type,
 
54
              int mmu_idx, uintptr_t retaddr)
 
55
{
 
56
    XtensaCPU *cpu = XTENSA_CPU(cs);
 
57
    CPUXtensaState *env = &cpu->env;
 
58
    uint32_t paddr;
 
59
    uint32_t page_size;
 
60
    unsigned access;
 
61
    int ret = xtensa_get_physical_addr(env, true, vaddr, access_type, mmu_idx,
 
62
            &paddr, &page_size, &access);
 
63
 
 
64
    qemu_log_mask(CPU_LOG_MMU, "%s(%08x, %d, %d) -> %08x, ret = %d\n",
 
65
                  __func__, vaddr, access_type, mmu_idx, paddr, ret);
 
66
 
 
67
    if (ret == 0) {
 
68
        tlb_set_page(cs,
 
69
                     vaddr & TARGET_PAGE_MASK,
 
70
                     paddr & TARGET_PAGE_MASK,
 
71
                     access, mmu_idx, page_size);
 
72
    } else {
 
73
        cpu_restore_state(cs, retaddr);
 
74
        HELPER(exception_cause_vaddr)(env, env->pc, ret, vaddr);
 
75
    }
 
76
}
 
77
 
 
78
void xtensa_cpu_do_unassigned_access(CPUState *cs, hwaddr addr,
 
79
                                     bool is_write, bool is_exec, int opaque,
 
80
                                     unsigned size)
 
81
{
 
82
    XtensaCPU *cpu = XTENSA_CPU(cs);
 
83
    CPUXtensaState *env = &cpu->env;
 
84
 
 
85
    HELPER(exception_cause_vaddr)(env, env->pc,
 
86
                                  is_exec ?
 
87
                                  INSTR_PIF_ADDR_ERROR_CAUSE :
 
88
                                  LOAD_STORE_PIF_ADDR_ERROR_CAUSE,
 
89
                                  is_exec ? addr : cs->mem_io_vaddr);
 
90
}
 
91
 
 
92
static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr)
 
93
{
 
94
    uint32_t paddr;
 
95
    uint32_t page_size;
 
96
    unsigned access;
 
97
    int ret = xtensa_get_physical_addr(env, false, vaddr, 2, 0,
 
98
            &paddr, &page_size, &access);
 
99
    if (ret == 0) {
 
100
        tb_invalidate_phys_addr(&address_space_memory, paddr);
 
101
    }
 
102
}
 
103
 
 
104
void HELPER(exception)(CPUXtensaState *env, uint32_t excp)
 
105
{
 
106
    CPUState *cs = CPU(xtensa_env_get_cpu(env));
 
107
 
 
108
    cs->exception_index = excp;
 
109
    if (excp == EXCP_YIELD) {
 
110
        env->yield_needed = 0;
 
111
    }
 
112
    if (excp == EXCP_DEBUG) {
 
113
        env->exception_taken = 0;
 
114
    }
 
115
    cpu_loop_exit(cs);
 
116
}
 
117
 
 
118
void HELPER(exception_cause)(CPUXtensaState *env, uint32_t pc, uint32_t cause)
 
119
{
 
120
    uint32_t vector;
 
121
 
 
122
    env->pc = pc;
 
123
    if (env->sregs[PS] & PS_EXCM) {
 
124
        if (env->config->ndepc) {
 
125
            env->sregs[DEPC] = pc;
 
126
        } else {
 
127
            env->sregs[EPC1] = pc;
 
128
        }
 
129
        vector = EXC_DOUBLE;
 
130
    } else {
 
131
        env->sregs[EPC1] = pc;
 
132
        vector = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
 
133
    }
 
134
 
 
135
    env->sregs[EXCCAUSE] = cause;
 
136
    env->sregs[PS] |= PS_EXCM;
 
137
 
 
138
    HELPER(exception)(env, vector);
 
139
}
 
140
 
 
141
void HELPER(exception_cause_vaddr)(CPUXtensaState *env,
 
142
        uint32_t pc, uint32_t cause, uint32_t vaddr)
 
143
{
 
144
    env->sregs[EXCVADDR] = vaddr;
 
145
    HELPER(exception_cause)(env, pc, cause);
 
146
}
 
147
 
 
148
void debug_exception_env(CPUXtensaState *env, uint32_t cause)
 
149
{
 
150
    if (xtensa_get_cintlevel(env) < env->config->debug_level) {
 
151
        HELPER(debug_exception)(env, env->pc, cause);
 
152
    }
 
153
}
 
154
 
 
155
void HELPER(debug_exception)(CPUXtensaState *env, uint32_t pc, uint32_t cause)
 
156
{
 
157
    unsigned level = env->config->debug_level;
 
158
 
 
159
    env->pc = pc;
 
160
    env->sregs[DEBUGCAUSE] = cause;
 
161
    env->sregs[EPC1 + level - 1] = pc;
 
162
    env->sregs[EPS2 + level - 2] = env->sregs[PS];
 
163
    env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) | PS_EXCM |
 
164
        (level << PS_INTLEVEL_SHIFT);
 
165
    HELPER(exception)(env, EXC_DEBUG);
 
166
}
 
167
 
 
168
static void copy_window_from_phys(CPUXtensaState *env,
 
169
        uint32_t window, uint32_t phys, uint32_t n)
 
170
{
 
171
    assert(phys < env->config->nareg);
 
172
    if (phys + n <= env->config->nareg) {
 
173
        memcpy(env->regs + window, env->phys_regs + phys,
 
174
                n * sizeof(uint32_t));
 
175
    } else {
 
176
        uint32_t n1 = env->config->nareg - phys;
 
177
        memcpy(env->regs + window, env->phys_regs + phys,
 
178
                n1 * sizeof(uint32_t));
 
179
        memcpy(env->regs + window + n1, env->phys_regs,
 
180
                (n - n1) * sizeof(uint32_t));
 
181
    }
 
182
}
 
183
 
 
184
static void copy_phys_from_window(CPUXtensaState *env,
 
185
        uint32_t phys, uint32_t window, uint32_t n)
 
186
{
 
187
    assert(phys < env->config->nareg);
 
188
    if (phys + n <= env->config->nareg) {
 
189
        memcpy(env->phys_regs + phys, env->regs + window,
 
190
                n * sizeof(uint32_t));
 
191
    } else {
 
192
        uint32_t n1 = env->config->nareg - phys;
 
193
        memcpy(env->phys_regs + phys, env->regs + window,
 
194
                n1 * sizeof(uint32_t));
 
195
        memcpy(env->phys_regs, env->regs + window + n1,
 
196
                (n - n1) * sizeof(uint32_t));
 
197
    }
 
198
}
 
199
 
 
200
 
 
201
static inline unsigned windowbase_bound(unsigned a, const CPUXtensaState *env)
 
202
{
 
203
    return a & (env->config->nareg / 4 - 1);
 
204
}
 
205
 
 
206
static inline unsigned windowstart_bit(unsigned a, const CPUXtensaState *env)
 
207
{
 
208
    return 1 << windowbase_bound(a, env);
 
209
}
 
210
 
 
211
void xtensa_sync_window_from_phys(CPUXtensaState *env)
 
212
{
 
213
    copy_window_from_phys(env, 0, env->sregs[WINDOW_BASE] * 4, 16);
 
214
}
 
215
 
 
216
void xtensa_sync_phys_from_window(CPUXtensaState *env)
 
217
{
 
218
    copy_phys_from_window(env, env->sregs[WINDOW_BASE] * 4, 0, 16);
 
219
}
 
220
 
 
221
static void rotate_window_abs(CPUXtensaState *env, uint32_t position)
 
222
{
 
223
    xtensa_sync_phys_from_window(env);
 
224
    env->sregs[WINDOW_BASE] = windowbase_bound(position, env);
 
225
    xtensa_sync_window_from_phys(env);
 
226
}
 
227
 
 
228
static void rotate_window(CPUXtensaState *env, uint32_t delta)
 
229
{
 
230
    rotate_window_abs(env, env->sregs[WINDOW_BASE] + delta);
 
231
}
 
232
 
 
233
void HELPER(wsr_windowbase)(CPUXtensaState *env, uint32_t v)
 
234
{
 
235
    rotate_window_abs(env, v);
 
236
}
 
237
 
 
238
void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm)
 
239
{
 
240
    int callinc = (env->sregs[PS] & PS_CALLINC) >> PS_CALLINC_SHIFT;
 
241
    if (s > 3 || ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
 
242
        qemu_log_mask(LOG_GUEST_ERROR, "Illegal entry instruction(pc = %08x), PS = %08x\n",
 
243
                      pc, env->sregs[PS]);
 
244
        HELPER(exception_cause)(env, pc, ILLEGAL_INSTRUCTION_CAUSE);
 
245
    } else {
 
246
        uint32_t windowstart = xtensa_replicate_windowstart(env) >>
 
247
            (env->sregs[WINDOW_BASE] + 1);
 
248
 
 
249
        if (windowstart & ((1 << callinc) - 1)) {
 
250
            HELPER(window_check)(env, pc, callinc);
 
251
        }
 
252
        env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - (imm << 3);
 
253
        rotate_window(env, callinc);
 
254
        env->sregs[WINDOW_START] |=
 
255
            windowstart_bit(env->sregs[WINDOW_BASE], env);
 
256
    }
 
257
}
 
258
 
 
259
void HELPER(window_check)(CPUXtensaState *env, uint32_t pc, uint32_t w)
 
260
{
 
261
    uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
 
262
    uint32_t windowstart = xtensa_replicate_windowstart(env) >>
 
263
        (env->sregs[WINDOW_BASE] + 1);
 
264
    uint32_t n = ctz32(windowstart) + 1;
 
265
 
 
266
    assert(n <= w);
 
267
 
 
268
    rotate_window(env, n);
 
269
    env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
 
270
        (windowbase << PS_OWB_SHIFT) | PS_EXCM;
 
271
    env->sregs[EPC1] = env->pc = pc;
 
272
 
 
273
    switch (ctz32(windowstart >> n)) {
 
274
    case 0:
 
275
        HELPER(exception)(env, EXC_WINDOW_OVERFLOW4);
 
276
        break;
 
277
    case 1:
 
278
        HELPER(exception)(env, EXC_WINDOW_OVERFLOW8);
 
279
        break;
 
280
    default:
 
281
        HELPER(exception)(env, EXC_WINDOW_OVERFLOW12);
 
282
        break;
 
283
    }
 
284
}
 
285
 
 
286
uint32_t HELPER(retw)(CPUXtensaState *env, uint32_t pc)
 
287
{
 
288
    int n = (env->regs[0] >> 30) & 0x3;
 
289
    int m = 0;
 
290
    uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
 
291
    uint32_t windowstart = env->sregs[WINDOW_START];
 
292
    uint32_t ret_pc = 0;
 
293
 
 
294
    if (windowstart & windowstart_bit(windowbase - 1, env)) {
 
295
        m = 1;
 
296
    } else if (windowstart & windowstart_bit(windowbase - 2, env)) {
 
297
        m = 2;
 
298
    } else if (windowstart & windowstart_bit(windowbase - 3, env)) {
 
299
        m = 3;
 
300
    }
 
301
 
 
302
    if (n == 0 || (m != 0 && m != n) ||
 
303
            ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
 
304
        qemu_log_mask(LOG_GUEST_ERROR, "Illegal retw instruction(pc = %08x), "
 
305
                      "PS = %08x, m = %d, n = %d\n",
 
306
                      pc, env->sregs[PS], m, n);
 
307
        HELPER(exception_cause)(env, pc, ILLEGAL_INSTRUCTION_CAUSE);
 
308
    } else {
 
309
        int owb = windowbase;
 
310
 
 
311
        ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff);
 
312
 
 
313
        rotate_window(env, -n);
 
314
        if (windowstart & windowstart_bit(env->sregs[WINDOW_BASE], env)) {
 
315
            env->sregs[WINDOW_START] &= ~windowstart_bit(owb, env);
 
316
        } else {
 
317
            /* window underflow */
 
318
            env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
 
319
                (windowbase << PS_OWB_SHIFT) | PS_EXCM;
 
320
            env->sregs[EPC1] = env->pc = pc;
 
321
 
 
322
            if (n == 1) {
 
323
                HELPER(exception)(env, EXC_WINDOW_UNDERFLOW4);
 
324
            } else if (n == 2) {
 
325
                HELPER(exception)(env, EXC_WINDOW_UNDERFLOW8);
 
326
            } else if (n == 3) {
 
327
                HELPER(exception)(env, EXC_WINDOW_UNDERFLOW12);
 
328
            }
 
329
        }
 
330
    }
 
331
    return ret_pc;
 
332
}
 
333
 
 
334
void HELPER(rotw)(CPUXtensaState *env, uint32_t imm4)
 
335
{
 
336
    rotate_window(env, imm4);
 
337
}
 
338
 
 
339
void HELPER(restore_owb)(CPUXtensaState *env)
 
340
{
 
341
    rotate_window_abs(env, (env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT);
 
342
}
 
343
 
 
344
void HELPER(movsp)(CPUXtensaState *env, uint32_t pc)
 
345
{
 
346
    if ((env->sregs[WINDOW_START] &
 
347
            (windowstart_bit(env->sregs[WINDOW_BASE] - 3, env) |
 
348
             windowstart_bit(env->sregs[WINDOW_BASE] - 2, env) |
 
349
             windowstart_bit(env->sregs[WINDOW_BASE] - 1, env))) == 0) {
 
350
        HELPER(exception_cause)(env, pc, ALLOCA_CAUSE);
 
351
    }
 
352
}
 
353
 
 
354
void HELPER(wsr_lbeg)(CPUXtensaState *env, uint32_t v)
 
355
{
 
356
    if (env->sregs[LBEG] != v) {
 
357
        tb_invalidate_virtual_addr(env, env->sregs[LEND] - 1);
 
358
        env->sregs[LBEG] = v;
 
359
    }
 
360
}
 
361
 
 
362
void HELPER(wsr_lend)(CPUXtensaState *env, uint32_t v)
 
363
{
 
364
    if (env->sregs[LEND] != v) {
 
365
        tb_invalidate_virtual_addr(env, env->sregs[LEND] - 1);
 
366
        env->sregs[LEND] = v;
 
367
        tb_invalidate_virtual_addr(env, env->sregs[LEND] - 1);
 
368
    }
 
369
}
 
370
 
 
371
void HELPER(dump_state)(CPUXtensaState *env)
 
372
{
 
373
    XtensaCPU *cpu = xtensa_env_get_cpu(env);
 
374
 
 
375
    cpu_dump_state(CPU(cpu), stderr, fprintf, 0);
 
376
}
 
377
 
 
378
void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel)
 
379
{
 
380
    CPUState *cpu;
 
381
 
 
382
    env->pc = pc;
 
383
    env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
 
384
        (intlevel << PS_INTLEVEL_SHIFT);
 
385
 
 
386
    qemu_mutex_lock_iothread();
 
387
    check_interrupts(env);
 
388
    qemu_mutex_unlock_iothread();
 
389
 
 
390
    if (env->pending_irq_level) {
 
391
        cpu_loop_exit(CPU(xtensa_env_get_cpu(env)));
 
392
        return;
 
393
    }
 
394
 
 
395
    cpu = CPU(xtensa_env_get_cpu(env));
 
396
    cpu->halted = 1;
 
397
    HELPER(exception)(env, EXCP_HLT);
 
398
}
 
399
 
 
400
void HELPER(update_ccount)(CPUXtensaState *env)
 
401
{
 
402
    uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 
403
 
 
404
    env->ccount_time = now;
 
405
    env->sregs[CCOUNT] = env->ccount_base +
 
406
        (uint32_t)((now - env->time_base) *
 
407
                   env->config->clock_freq_khz / 1000000);
 
408
}
 
409
 
 
410
void HELPER(wsr_ccount)(CPUXtensaState *env, uint32_t v)
 
411
{
 
412
    int i;
 
413
 
 
414
    HELPER(update_ccount)(env);
 
415
    env->ccount_base += v - env->sregs[CCOUNT];
 
416
    for (i = 0; i < env->config->nccompare; ++i) {
 
417
        HELPER(update_ccompare)(env, i);
 
418
    }
 
419
}
 
420
 
 
421
void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i)
 
422
{
 
423
    uint64_t dcc;
 
424
 
 
425
    HELPER(update_ccount)(env);
 
426
    dcc = (uint64_t)(env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] - 1) + 1;
 
427
    timer_mod(env->ccompare[i].timer,
 
428
              env->ccount_time + (dcc * 1000000) / env->config->clock_freq_khz);
 
429
    env->yield_needed = 1;
 
430
}
 
431
 
 
432
void HELPER(check_interrupts)(CPUXtensaState *env)
 
433
{
 
434
    qemu_mutex_lock_iothread();
 
435
    check_interrupts(env);
 
436
    qemu_mutex_unlock_iothread();
 
437
}
 
438
 
 
439
void HELPER(itlb_hit_test)(CPUXtensaState *env, uint32_t vaddr)
 
440
{
 
441
    get_page_addr_code(env, vaddr);
 
442
}
 
443
 
 
444
/*!
 
445
 * Check vaddr accessibility/cache attributes and raise an exception if
 
446
 * specified by the ATOMCTL SR.
 
447
 *
 
448
 * Note: local memory exclusion is not implemented
 
449
 */
 
450
void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr)
 
451
{
 
452
    uint32_t paddr, page_size, access;
 
453
    uint32_t atomctl = env->sregs[ATOMCTL];
 
454
    int rc = xtensa_get_physical_addr(env, true, vaddr, 1,
 
455
            xtensa_get_cring(env), &paddr, &page_size, &access);
 
456
 
 
457
    /*
 
458
     * s32c1i never causes LOAD_PROHIBITED_CAUSE exceptions,
 
459
     * see opcode description in the ISA
 
460
     */
 
461
    if (rc == 0 &&
 
462
            (access & (PAGE_READ | PAGE_WRITE)) != (PAGE_READ | PAGE_WRITE)) {
 
463
        rc = STORE_PROHIBITED_CAUSE;
 
464
    }
 
465
 
 
466
    if (rc) {
 
467
        HELPER(exception_cause_vaddr)(env, pc, rc, vaddr);
 
468
    }
 
469
 
 
470
    /*
 
471
     * When data cache is not configured use ATOMCTL bypass field.
 
472
     * See ISA, 4.3.12.4 The Atomic Operation Control Register (ATOMCTL)
 
473
     * under the Conditional Store Option.
 
474
     */
 
475
    if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) {
 
476
        access = PAGE_CACHE_BYPASS;
 
477
    }
 
478
 
 
479
    switch (access & PAGE_CACHE_MASK) {
 
480
    case PAGE_CACHE_WB:
 
481
        atomctl >>= 2;
 
482
        /* fall through */
 
483
    case PAGE_CACHE_WT:
 
484
        atomctl >>= 2;
 
485
        /* fall through */
 
486
    case PAGE_CACHE_BYPASS:
 
487
        if ((atomctl & 0x3) == 0) {
 
488
            HELPER(exception_cause_vaddr)(env, pc,
 
489
                    LOAD_STORE_ERROR_CAUSE, vaddr);
 
490
        }
 
491
        break;
 
492
 
 
493
    case PAGE_CACHE_ISOLATE:
 
494
        HELPER(exception_cause_vaddr)(env, pc,
 
495
                LOAD_STORE_ERROR_CAUSE, vaddr);
 
496
        break;
 
497
 
 
498
    default:
 
499
        break;
 
500
    }
 
501
}
 
502
 
 
503
void HELPER(wsr_memctl)(CPUXtensaState *env, uint32_t v)
 
504
{
 
505
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_ICACHE)) {
 
506
        if (extract32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN) >
 
507
            env->config->icache_ways) {
 
508
            deposit32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN,
 
509
                      env->config->icache_ways);
 
510
        }
 
511
    }
 
512
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) {
 
513
        if (extract32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN) >
 
514
            env->config->dcache_ways) {
 
515
            deposit32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN,
 
516
                      env->config->dcache_ways);
 
517
        }
 
518
        if (extract32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN) >
 
519
            env->config->dcache_ways) {
 
520
            deposit32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN,
 
521
                      env->config->dcache_ways);
 
522
        }
 
523
    }
 
524
    env->sregs[MEMCTL] = v & env->config->memctl_mask;
 
525
}
 
526
 
 
527
void HELPER(wsr_rasid)(CPUXtensaState *env, uint32_t v)
 
528
{
 
529
    XtensaCPU *cpu = xtensa_env_get_cpu(env);
 
530
 
 
531
    v = (v & 0xffffff00) | 0x1;
 
532
    if (v != env->sregs[RASID]) {
 
533
        env->sregs[RASID] = v;
 
534
        tlb_flush(CPU(cpu));
 
535
    }
 
536
}
 
537
 
 
538
static uint32_t get_page_size(const CPUXtensaState *env, bool dtlb, uint32_t way)
 
539
{
 
540
    uint32_t tlbcfg = env->sregs[dtlb ? DTLBCFG : ITLBCFG];
 
541
 
 
542
    switch (way) {
 
543
    case 4:
 
544
        return (tlbcfg >> 16) & 0x3;
 
545
 
 
546
    case 5:
 
547
        return (tlbcfg >> 20) & 0x1;
 
548
 
 
549
    case 6:
 
550
        return (tlbcfg >> 24) & 0x1;
 
551
 
 
552
    default:
 
553
        return 0;
 
554
    }
 
555
}
 
556
 
 
557
/*!
 
558
 * Get bit mask for the virtual address bits translated by the TLB way
 
559
 */
 
560
uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaState *env, bool dtlb, uint32_t way)
 
561
{
 
562
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 
563
        bool varway56 = dtlb ?
 
564
            env->config->dtlb.varway56 :
 
565
            env->config->itlb.varway56;
 
566
 
 
567
        switch (way) {
 
568
        case 4:
 
569
            return 0xfff00000 << get_page_size(env, dtlb, way) * 2;
 
570
 
 
571
        case 5:
 
572
            if (varway56) {
 
573
                return 0xf8000000 << get_page_size(env, dtlb, way);
 
574
            } else {
 
575
                return 0xf8000000;
 
576
            }
 
577
 
 
578
        case 6:
 
579
            if (varway56) {
 
580
                return 0xf0000000 << (1 - get_page_size(env, dtlb, way));
 
581
            } else {
 
582
                return 0xf0000000;
 
583
            }
 
584
 
 
585
        default:
 
586
            return 0xfffff000;
 
587
        }
 
588
    } else {
 
589
        return REGION_PAGE_MASK;
 
590
    }
 
591
}
 
592
 
 
593
/*!
 
594
 * Get bit mask for the 'VPN without index' field.
 
595
 * See ISA, 4.6.5.6, data format for RxTLB0
 
596
 */
 
597
static uint32_t get_vpn_mask(const CPUXtensaState *env, bool dtlb, uint32_t way)
 
598
{
 
599
    if (way < 4) {
 
600
        bool is32 = (dtlb ?
 
601
                env->config->dtlb.nrefillentries :
 
602
                env->config->itlb.nrefillentries) == 32;
 
603
        return is32 ? 0xffff8000 : 0xffffc000;
 
604
    } else if (way == 4) {
 
605
        return xtensa_tlb_get_addr_mask(env, dtlb, way) << 2;
 
606
    } else if (way <= 6) {
 
607
        uint32_t mask = xtensa_tlb_get_addr_mask(env, dtlb, way);
 
608
        bool varway56 = dtlb ?
 
609
            env->config->dtlb.varway56 :
 
610
            env->config->itlb.varway56;
 
611
 
 
612
        if (varway56) {
 
613
            return mask << (way == 5 ? 2 : 3);
 
614
        } else {
 
615
            return mask << 1;
 
616
        }
 
617
    } else {
 
618
        return 0xfffff000;
 
619
    }
 
620
}
 
621
 
 
622
/*!
 
623
 * Split virtual address into VPN (with index) and entry index
 
624
 * for the given TLB way
 
625
 */
 
626
void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb,
 
627
        uint32_t *vpn, uint32_t wi, uint32_t *ei)
 
628
{
 
629
    bool varway56 = dtlb ?
 
630
        env->config->dtlb.varway56 :
 
631
        env->config->itlb.varway56;
 
632
 
 
633
    if (!dtlb) {
 
634
        wi &= 7;
 
635
    }
 
636
 
 
637
    if (wi < 4) {
 
638
        bool is32 = (dtlb ?
 
639
                env->config->dtlb.nrefillentries :
 
640
                env->config->itlb.nrefillentries) == 32;
 
641
        *ei = (v >> 12) & (is32 ? 0x7 : 0x3);
 
642
    } else {
 
643
        switch (wi) {
 
644
        case 4:
 
645
            {
 
646
                uint32_t eibase = 20 + get_page_size(env, dtlb, wi) * 2;
 
647
                *ei = (v >> eibase) & 0x3;
 
648
            }
 
649
            break;
 
650
 
 
651
        case 5:
 
652
            if (varway56) {
 
653
                uint32_t eibase = 27 + get_page_size(env, dtlb, wi);
 
654
                *ei = (v >> eibase) & 0x3;
 
655
            } else {
 
656
                *ei = (v >> 27) & 0x1;
 
657
            }
 
658
            break;
 
659
 
 
660
        case 6:
 
661
            if (varway56) {
 
662
                uint32_t eibase = 29 - get_page_size(env, dtlb, wi);
 
663
                *ei = (v >> eibase) & 0x7;
 
664
            } else {
 
665
                *ei = (v >> 28) & 0x1;
 
666
            }
 
667
            break;
 
668
 
 
669
        default:
 
670
            *ei = 0;
 
671
            break;
 
672
        }
 
673
    }
 
674
    *vpn = v & xtensa_tlb_get_addr_mask(env, dtlb, wi);
 
675
}
 
676
 
 
677
/*!
 
678
 * Split TLB address into TLB way, entry index and VPN (with index).
 
679
 * See ISA, 4.6.5.5 - 4.6.5.8 for the TLB addressing format
 
680
 */
 
681
static void split_tlb_entry_spec(CPUXtensaState *env, uint32_t v, bool dtlb,
 
682
        uint32_t *vpn, uint32_t *wi, uint32_t *ei)
 
683
{
 
684
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 
685
        *wi = v & (dtlb ? 0xf : 0x7);
 
686
        split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei);
 
687
    } else {
 
688
        *vpn = v & REGION_PAGE_MASK;
 
689
        *wi = 0;
 
690
        *ei = (v >> 29) & 0x7;
 
691
    }
 
692
}
 
693
 
 
694
static xtensa_tlb_entry *get_tlb_entry(CPUXtensaState *env,
 
695
        uint32_t v, bool dtlb, uint32_t *pwi)
 
696
{
 
697
    uint32_t vpn;
 
698
    uint32_t wi;
 
699
    uint32_t ei;
 
700
 
 
701
    split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei);
 
702
    if (pwi) {
 
703
        *pwi = wi;
 
704
    }
 
705
    return xtensa_tlb_get_entry(env, dtlb, wi, ei);
 
706
}
 
707
 
 
708
uint32_t HELPER(rtlb0)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
 
709
{
 
710
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 
711
        uint32_t wi;
 
712
        const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
 
713
        return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
 
714
    } else {
 
715
        return v & REGION_PAGE_MASK;
 
716
    }
 
717
}
 
718
 
 
719
uint32_t HELPER(rtlb1)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
 
720
{
 
721
    const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, NULL);
 
722
    return entry->paddr | entry->attr;
 
723
}
 
724
 
 
725
void HELPER(itlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
 
726
{
 
727
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 
728
        uint32_t wi;
 
729
        xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
 
730
        if (entry->variable && entry->asid) {
 
731
            tlb_flush_page(CPU(xtensa_env_get_cpu(env)), entry->vaddr);
 
732
            entry->asid = 0;
 
733
        }
 
734
    }
 
735
}
 
736
 
 
737
uint32_t HELPER(ptlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
 
738
{
 
739
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 
740
        uint32_t wi;
 
741
        uint32_t ei;
 
742
        uint8_t ring;
 
743
        int res = xtensa_tlb_lookup(env, v, dtlb, &wi, &ei, &ring);
 
744
 
 
745
        switch (res) {
 
746
        case 0:
 
747
            if (ring >= xtensa_get_ring(env)) {
 
748
                return (v & 0xfffff000) | wi | (dtlb ? 0x10 : 0x8);
 
749
            }
 
750
            break;
 
751
 
 
752
        case INST_TLB_MULTI_HIT_CAUSE:
 
753
        case LOAD_STORE_TLB_MULTI_HIT_CAUSE:
 
754
            HELPER(exception_cause_vaddr)(env, env->pc, res, v);
 
755
            break;
 
756
        }
 
757
        return 0;
 
758
    } else {
 
759
        return (v & REGION_PAGE_MASK) | 0x1;
 
760
    }
 
761
}
 
762
 
 
763
void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
 
764
        xtensa_tlb_entry *entry, bool dtlb,
 
765
        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
 
766
{
 
767
    entry->vaddr = vpn;
 
768
    entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi);
 
769
    entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff;
 
770
    entry->attr = pte & 0xf;
 
771
}
 
772
 
 
773
void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
 
774
        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
 
775
{
 
776
    XtensaCPU *cpu = xtensa_env_get_cpu(env);
 
777
    CPUState *cs = CPU(cpu);
 
778
    xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
 
779
 
 
780
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 
781
        if (entry->variable) {
 
782
            if (entry->asid) {
 
783
                tlb_flush_page(cs, entry->vaddr);
 
784
            }
 
785
            xtensa_tlb_set_entry_mmu(env, entry, dtlb, wi, ei, vpn, pte);
 
786
            tlb_flush_page(cs, entry->vaddr);
 
787
        } else {
 
788
            qemu_log_mask(LOG_GUEST_ERROR, "%s %d, %d, %d trying to set immutable entry\n",
 
789
                          __func__, dtlb, wi, ei);
 
790
        }
 
791
    } else {
 
792
        tlb_flush_page(cs, entry->vaddr);
 
793
        if (xtensa_option_enabled(env->config,
 
794
                    XTENSA_OPTION_REGION_TRANSLATION)) {
 
795
            entry->paddr = pte & REGION_PAGE_MASK;
 
796
        }
 
797
        entry->attr = pte & 0xf;
 
798
    }
 
799
}
 
800
 
 
801
void HELPER(wtlb)(CPUXtensaState *env, uint32_t p, uint32_t v, uint32_t dtlb)
 
802
{
 
803
    uint32_t vpn;
 
804
    uint32_t wi;
 
805
    uint32_t ei;
 
806
    split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei);
 
807
    xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p);
 
808
}
 
809
 
 
810
 
 
811
void HELPER(wsr_ibreakenable)(CPUXtensaState *env, uint32_t v)
 
812
{
 
813
    uint32_t change = v ^ env->sregs[IBREAKENABLE];
 
814
    unsigned i;
 
815
 
 
816
    for (i = 0; i < env->config->nibreak; ++i) {
 
817
        if (change & (1 << i)) {
 
818
            tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]);
 
819
        }
 
820
    }
 
821
    env->sregs[IBREAKENABLE] = v & ((1 << env->config->nibreak) - 1);
 
822
}
 
823
 
 
824
void HELPER(wsr_ibreaka)(CPUXtensaState *env, uint32_t i, uint32_t v)
 
825
{
 
826
    if (env->sregs[IBREAKENABLE] & (1 << i) && env->sregs[IBREAKA + i] != v) {
 
827
        tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]);
 
828
        tb_invalidate_virtual_addr(env, v);
 
829
    }
 
830
    env->sregs[IBREAKA + i] = v;
 
831
}
 
832
 
 
833
static void set_dbreak(CPUXtensaState *env, unsigned i, uint32_t dbreaka,
 
834
        uint32_t dbreakc)
 
835
{
 
836
    CPUState *cs = CPU(xtensa_env_get_cpu(env));
 
837
    int flags = BP_CPU | BP_STOP_BEFORE_ACCESS;
 
838
    uint32_t mask = dbreakc | ~DBREAKC_MASK;
 
839
 
 
840
    if (env->cpu_watchpoint[i]) {
 
841
        cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[i]);
 
842
    }
 
843
    if (dbreakc & DBREAKC_SB) {
 
844
        flags |= BP_MEM_WRITE;
 
845
    }
 
846
    if (dbreakc & DBREAKC_LB) {
 
847
        flags |= BP_MEM_READ;
 
848
    }
 
849
    /* contiguous mask after inversion is one less than some power of 2 */
 
850
    if ((~mask + 1) & ~mask) {
 
851
        qemu_log_mask(LOG_GUEST_ERROR, "DBREAKC mask is not contiguous: 0x%08x\n", dbreakc);
 
852
        /* cut mask after the first zero bit */
 
853
        mask = 0xffffffff << (32 - clo32(mask));
 
854
    }
 
855
    if (cpu_watchpoint_insert(cs, dbreaka & mask, ~mask + 1,
 
856
            flags, &env->cpu_watchpoint[i])) {
 
857
        env->cpu_watchpoint[i] = NULL;
 
858
        qemu_log_mask(LOG_GUEST_ERROR, "Failed to set data breakpoint at 0x%08x/%d\n",
 
859
                      dbreaka & mask, ~mask + 1);
 
860
    }
 
861
}
 
862
 
 
863
void HELPER(wsr_dbreaka)(CPUXtensaState *env, uint32_t i, uint32_t v)
 
864
{
 
865
    uint32_t dbreakc = env->sregs[DBREAKC + i];
 
866
 
 
867
    if ((dbreakc & DBREAKC_SB_LB) &&
 
868
            env->sregs[DBREAKA + i] != v) {
 
869
        set_dbreak(env, i, v, dbreakc);
 
870
    }
 
871
    env->sregs[DBREAKA + i] = v;
 
872
}
 
873
 
 
874
void HELPER(wsr_dbreakc)(CPUXtensaState *env, uint32_t i, uint32_t v)
 
875
{
 
876
    if ((env->sregs[DBREAKC + i] ^ v) & (DBREAKC_SB_LB | DBREAKC_MASK)) {
 
877
        if (v & DBREAKC_SB_LB) {
 
878
            set_dbreak(env, i, env->sregs[DBREAKA + i], v);
 
879
        } else {
 
880
            if (env->cpu_watchpoint[i]) {
 
881
                CPUState *cs = CPU(xtensa_env_get_cpu(env));
 
882
 
 
883
                cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[i]);
 
884
                env->cpu_watchpoint[i] = NULL;
 
885
            }
 
886
        }
 
887
    }
 
888
    env->sregs[DBREAKC + i] = v;
 
889
}
 
890
 
 
891
void HELPER(wur_fcr)(CPUXtensaState *env, uint32_t v)
 
892
{
 
893
    static const int rounding_mode[] = {
 
894
        float_round_nearest_even,
 
895
        float_round_to_zero,
 
896
        float_round_up,
 
897
        float_round_down,
 
898
    };
 
899
 
 
900
    env->uregs[FCR] = v & 0xfffff07f;
 
901
    set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status);
 
902
}
 
903
 
 
904
float32 HELPER(abs_s)(float32 v)
 
905
{
 
906
    return float32_abs(v);
 
907
}
 
908
 
 
909
float32 HELPER(neg_s)(float32 v)
 
910
{
 
911
    return float32_chs(v);
 
912
}
 
913
 
 
914
float32 HELPER(add_s)(CPUXtensaState *env, float32 a, float32 b)
 
915
{
 
916
    return float32_add(a, b, &env->fp_status);
 
917
}
 
918
 
 
919
float32 HELPER(sub_s)(CPUXtensaState *env, float32 a, float32 b)
 
920
{
 
921
    return float32_sub(a, b, &env->fp_status);
 
922
}
 
923
 
 
924
float32 HELPER(mul_s)(CPUXtensaState *env, float32 a, float32 b)
 
925
{
 
926
    return float32_mul(a, b, &env->fp_status);
 
927
}
 
928
 
 
929
float32 HELPER(madd_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
 
930
{
 
931
    return float32_muladd(b, c, a, 0,
 
932
            &env->fp_status);
 
933
}
 
934
 
 
935
float32 HELPER(msub_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
 
936
{
 
937
    return float32_muladd(b, c, a, float_muladd_negate_product,
 
938
            &env->fp_status);
 
939
}
 
940
 
 
941
uint32_t HELPER(ftoi)(float32 v, uint32_t rounding_mode, uint32_t scale)
 
942
{
 
943
    float_status fp_status = {0};
 
944
 
 
945
    set_float_rounding_mode(rounding_mode, &fp_status);
 
946
    return float32_to_int32(
 
947
            float32_scalbn(v, scale, &fp_status), &fp_status);
 
948
}
 
949
 
 
950
uint32_t HELPER(ftoui)(float32 v, uint32_t rounding_mode, uint32_t scale)
 
951
{
 
952
    float_status fp_status = {0};
 
953
    float32 res;
 
954
 
 
955
    set_float_rounding_mode(rounding_mode, &fp_status);
 
956
 
 
957
    res = float32_scalbn(v, scale, &fp_status);
 
958
 
 
959
    if (float32_is_neg(v) && !float32_is_any_nan(v)) {
 
960
        return float32_to_int32(res, &fp_status);
 
961
    } else {
 
962
        return float32_to_uint32(res, &fp_status);
 
963
    }
 
964
}
 
965
 
 
966
float32 HELPER(itof)(CPUXtensaState *env, uint32_t v, uint32_t scale)
 
967
{
 
968
    return float32_scalbn(int32_to_float32(v, &env->fp_status),
 
969
            (int32_t)scale, &env->fp_status);
 
970
}
 
971
 
 
972
float32 HELPER(uitof)(CPUXtensaState *env, uint32_t v, uint32_t scale)
 
973
{
 
974
    return float32_scalbn(uint32_to_float32(v, &env->fp_status),
 
975
            (int32_t)scale, &env->fp_status);
 
976
}
 
977
 
 
978
static inline void set_br(CPUXtensaState *env, bool v, uint32_t br)
 
979
{
 
980
    if (v) {
 
981
        env->sregs[BR] |= br;
 
982
    } else {
 
983
        env->sregs[BR] &= ~br;
 
984
    }
 
985
}
 
986
 
 
987
void HELPER(un_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
 
988
{
 
989
    set_br(env, float32_unordered_quiet(a, b, &env->fp_status), br);
 
990
}
 
991
 
 
992
void HELPER(oeq_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
 
993
{
 
994
    set_br(env, float32_eq_quiet(a, b, &env->fp_status), br);
 
995
}
 
996
 
 
997
void HELPER(ueq_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
 
998
{
 
999
    int v = float32_compare_quiet(a, b, &env->fp_status);
 
1000
    set_br(env, v == float_relation_equal || v == float_relation_unordered, br);
 
1001
}
 
1002
 
 
1003
void HELPER(olt_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
 
1004
{
 
1005
    set_br(env, float32_lt_quiet(a, b, &env->fp_status), br);
 
1006
}
 
1007
 
 
1008
void HELPER(ult_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
 
1009
{
 
1010
    int v = float32_compare_quiet(a, b, &env->fp_status);
 
1011
    set_br(env, v == float_relation_less || v == float_relation_unordered, br);
 
1012
}
 
1013
 
 
1014
void HELPER(ole_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
 
1015
{
 
1016
    set_br(env, float32_le_quiet(a, b, &env->fp_status), br);
 
1017
}
 
1018
 
 
1019
void HELPER(ule_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
 
1020
{
 
1021
    int v = float32_compare_quiet(a, b, &env->fp_status);
 
1022
    set_br(env, v != float_relation_greater, br);
 
1023
}
 
1024
 
 
1025
uint32_t HELPER(rer)(CPUXtensaState *env, uint32_t addr)
 
1026
{
 
1027
    return address_space_ldl(env->address_space_er, addr,
 
1028
                             (MemTxAttrs){0}, NULL);
 
1029
}
 
1030
 
 
1031
void HELPER(wer)(CPUXtensaState *env, uint32_t data, uint32_t addr)
 
1032
{
 
1033
    address_space_stl(env->address_space_er, addr, data,
 
1034
                      (MemTxAttrs){0}, NULL);
 
1035
}