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