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