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