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