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