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