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