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