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