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