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