1 /*
2  *  MIPS emulation helpers for qemu.
3  *
4  *  Copyright (c) 2004-2005 Jocelyn Mayer
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "qemu/osdep.h"
20 #include "qemu/main-loop.h"
21 #include "cpu.h"
22 #include "internal.h"
23 #include "qemu/host-utils.h"
24 #include "exec/helper-proto.h"
25 #include "exec/exec-all.h"
26 #include "exec/cpu_ldst.h"
27 #include "sysemu/kvm.h"
28 
29 /*****************************************************************************/
30 /* Exceptions processing helpers */
31 
helper_raise_exception_err(CPUMIPSState * env,uint32_t exception,int error_code)32 void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception,
33                                 int error_code)
34 {
35     do_raise_exception_err(env, exception, error_code, 0);
36 }
37 
helper_raise_exception(CPUMIPSState * env,uint32_t exception)38 void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
39 {
40     do_raise_exception(env, exception, GETPC());
41 }
42 
helper_raise_exception_debug(CPUMIPSState * env)43 void helper_raise_exception_debug(CPUMIPSState *env)
44 {
45     do_raise_exception(env, EXCP_DEBUG, 0);
46 }
47 
raise_exception(CPUMIPSState * env,uint32_t exception)48 static void raise_exception(CPUMIPSState *env, uint32_t exception)
49 {
50     do_raise_exception(env, exception, 0);
51 }
52 
53 #if defined(CONFIG_USER_ONLY)
54 #define HELPER_LD(name, insn, type)                                     \
55 static inline type do_##name(CPUMIPSState *env, target_ulong addr,      \
56                              int mem_idx, uintptr_t retaddr)            \
57 {                                                                       \
58     return (type) cpu_##insn##_data_ra(env, addr, retaddr);             \
59 }
60 #else
61 #define HELPER_LD(name, insn, type)                                     \
62 static inline type do_##name(CPUMIPSState *env, target_ulong addr,      \
63                              int mem_idx, uintptr_t retaddr)            \
64 {                                                                       \
65     switch (mem_idx)                                                    \
66     {                                                                   \
67     case 0: return (type) cpu_##insn##_kernel_ra(env, addr, retaddr);   \
68     case 1: return (type) cpu_##insn##_super_ra(env, addr, retaddr);    \
69     default:                                                            \
70     case 2: return (type) cpu_##insn##_user_ra(env, addr, retaddr);     \
71     case 3: return (type) cpu_##insn##_error_ra(env, addr, retaddr);    \
72     }                                                                   \
73 }
74 #endif
HELPER_LD(lw,ldl,int32_t)75 HELPER_LD(lw, ldl, int32_t)
76 #if defined(TARGET_MIPS64)
77 HELPER_LD(ld, ldq, int64_t)
78 #endif
79 #undef HELPER_LD
80 
81 #if defined(CONFIG_USER_ONLY)
82 #define HELPER_ST(name, insn, type)                                     \
83 static inline void do_##name(CPUMIPSState *env, target_ulong addr,      \
84                              type val, int mem_idx, uintptr_t retaddr)  \
85 {                                                                       \
86     cpu_##insn##_data_ra(env, addr, val, retaddr);                      \
87 }
88 #else
89 #define HELPER_ST(name, insn, type)                                     \
90 static inline void do_##name(CPUMIPSState *env, target_ulong addr,      \
91                              type val, int mem_idx, uintptr_t retaddr)  \
92 {                                                                       \
93     switch (mem_idx)                                                    \
94     {                                                                   \
95     case 0: cpu_##insn##_kernel_ra(env, addr, val, retaddr); break;     \
96     case 1: cpu_##insn##_super_ra(env, addr, val, retaddr); break;      \
97     default:                                                            \
98     case 2: cpu_##insn##_user_ra(env, addr, val, retaddr); break;       \
99     case 3:                                                             \
100         cpu_##insn##_error_ra(env, addr, val, retaddr);                 \
101         break;                                                          \
102     }                                                                   \
103 }
104 #endif
105 HELPER_ST(sb, stb, uint8_t)
106 HELPER_ST(sw, stl, uint32_t)
107 #if defined(TARGET_MIPS64)
108 HELPER_ST(sd, stq, uint64_t)
109 #endif
110 #undef HELPER_ST
111 
112 /* 64 bits arithmetic for 32 bits hosts */
113 static inline uint64_t get_HILO(CPUMIPSState *env)
114 {
115     return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
116 }
117 
set_HIT0_LO(CPUMIPSState * env,uint64_t HILO)118 static inline target_ulong set_HIT0_LO(CPUMIPSState *env, uint64_t HILO)
119 {
120     env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
121     return env->active_tc.HI[0] = (int32_t)(HILO >> 32);
122 }
123 
set_HI_LOT0(CPUMIPSState * env,uint64_t HILO)124 static inline target_ulong set_HI_LOT0(CPUMIPSState *env, uint64_t HILO)
125 {
126     target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
127     env->active_tc.HI[0] = (int32_t)(HILO >> 32);
128     return tmp;
129 }
130 
131 /* Multiplication variants of the vr54xx. */
helper_muls(CPUMIPSState * env,target_ulong arg1,target_ulong arg2)132 target_ulong helper_muls(CPUMIPSState *env, target_ulong arg1,
133                          target_ulong arg2)
134 {
135     return set_HI_LOT0(env, 0 - ((int64_t)(int32_t)arg1 *
136                                  (int64_t)(int32_t)arg2));
137 }
138 
helper_mulsu(CPUMIPSState * env,target_ulong arg1,target_ulong arg2)139 target_ulong helper_mulsu(CPUMIPSState *env, target_ulong arg1,
140                           target_ulong arg2)
141 {
142     return set_HI_LOT0(env, 0 - (uint64_t)(uint32_t)arg1 *
143                        (uint64_t)(uint32_t)arg2);
144 }
145 
helper_macc(CPUMIPSState * env,target_ulong arg1,target_ulong arg2)146 target_ulong helper_macc(CPUMIPSState *env, target_ulong arg1,
147                          target_ulong arg2)
148 {
149     return set_HI_LOT0(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
150                        (int64_t)(int32_t)arg2);
151 }
152 
helper_macchi(CPUMIPSState * env,target_ulong arg1,target_ulong arg2)153 target_ulong helper_macchi(CPUMIPSState *env, target_ulong arg1,
154                            target_ulong arg2)
155 {
156     return set_HIT0_LO(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
157                        (int64_t)(int32_t)arg2);
158 }
159 
helper_maccu(CPUMIPSState * env,target_ulong arg1,target_ulong arg2)160 target_ulong helper_maccu(CPUMIPSState *env, target_ulong arg1,
161                           target_ulong arg2)
162 {
163     return set_HI_LOT0(env, (uint64_t)get_HILO(env) +
164                        (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
165 }
166 
helper_macchiu(CPUMIPSState * env,target_ulong arg1,target_ulong arg2)167 target_ulong helper_macchiu(CPUMIPSState *env, target_ulong arg1,
168                             target_ulong arg2)
169 {
170     return set_HIT0_LO(env, (uint64_t)get_HILO(env) +
171                        (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
172 }
173 
helper_msac(CPUMIPSState * env,target_ulong arg1,target_ulong arg2)174 target_ulong helper_msac(CPUMIPSState *env, target_ulong arg1,
175                          target_ulong arg2)
176 {
177     return set_HI_LOT0(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
178                        (int64_t)(int32_t)arg2);
179 }
180 
helper_msachi(CPUMIPSState * env,target_ulong arg1,target_ulong arg2)181 target_ulong helper_msachi(CPUMIPSState *env, target_ulong arg1,
182                            target_ulong arg2)
183 {
184     return set_HIT0_LO(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
185                        (int64_t)(int32_t)arg2);
186 }
187 
helper_msacu(CPUMIPSState * env,target_ulong arg1,target_ulong arg2)188 target_ulong helper_msacu(CPUMIPSState *env, target_ulong arg1,
189                           target_ulong arg2)
190 {
191     return set_HI_LOT0(env, (uint64_t)get_HILO(env) -
192                        (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
193 }
194 
helper_msachiu(CPUMIPSState * env,target_ulong arg1,target_ulong arg2)195 target_ulong helper_msachiu(CPUMIPSState *env, target_ulong arg1,
196                             target_ulong arg2)
197 {
198     return set_HIT0_LO(env, (uint64_t)get_HILO(env) -
199                        (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
200 }
201 
helper_mulhi(CPUMIPSState * env,target_ulong arg1,target_ulong arg2)202 target_ulong helper_mulhi(CPUMIPSState *env, target_ulong arg1,
203                           target_ulong arg2)
204 {
205     return set_HIT0_LO(env, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
206 }
207 
helper_mulhiu(CPUMIPSState * env,target_ulong arg1,target_ulong arg2)208 target_ulong helper_mulhiu(CPUMIPSState *env, target_ulong arg1,
209                            target_ulong arg2)
210 {
211     return set_HIT0_LO(env, (uint64_t)(uint32_t)arg1 *
212                        (uint64_t)(uint32_t)arg2);
213 }
214 
helper_mulshi(CPUMIPSState * env,target_ulong arg1,target_ulong arg2)215 target_ulong helper_mulshi(CPUMIPSState *env, target_ulong arg1,
216                            target_ulong arg2)
217 {
218     return set_HIT0_LO(env, 0 - (int64_t)(int32_t)arg1 *
219                        (int64_t)(int32_t)arg2);
220 }
221 
helper_mulshiu(CPUMIPSState * env,target_ulong arg1,target_ulong arg2)222 target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
223                             target_ulong arg2)
224 {
225     return set_HIT0_LO(env, 0 - (uint64_t)(uint32_t)arg1 *
226                        (uint64_t)(uint32_t)arg2);
227 }
228 
bitswap(target_ulong v)229 static inline target_ulong bitswap(target_ulong v)
230 {
231     v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) |
232               ((v & (target_ulong)0x5555555555555555ULL) << 1);
233     v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) |
234               ((v & (target_ulong)0x3333333333333333ULL) << 2);
235     v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) |
236               ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4);
237     return v;
238 }
239 
240 #ifdef TARGET_MIPS64
helper_dbitswap(target_ulong rt)241 target_ulong helper_dbitswap(target_ulong rt)
242 {
243     return bitswap(rt);
244 }
245 #endif
246 
helper_bitswap(target_ulong rt)247 target_ulong helper_bitswap(target_ulong rt)
248 {
249     return (int32_t)bitswap(rt);
250 }
251 
helper_rotx(target_ulong rs,uint32_t shift,uint32_t shiftx,uint32_t stripe)252 target_ulong helper_rotx(target_ulong rs, uint32_t shift, uint32_t shiftx,
253                         uint32_t stripe)
254 {
255     int i;
256     uint64_t tmp0 = ((uint64_t)rs) << 32 | ((uint64_t)rs & 0xffffffff);
257     uint64_t tmp1 = tmp0;
258     for (i = 0; i <= 46; i++) {
259         int s;
260         if (i & 0x8) {
261             s = shift;
262         } else {
263             s = shiftx;
264         }
265 
266         if (stripe != 0 && !(i & 0x4)) {
267             s = ~s;
268         }
269         if (s & 0x10) {
270             if (tmp0 & (1LL << (i + 16))) {
271                 tmp1 |= 1LL << i;
272             } else {
273                 tmp1 &= ~(1LL << i);
274             }
275         }
276     }
277 
278     uint64_t tmp2 = tmp1;
279     for (i = 0; i <= 38; i++) {
280         int s;
281         if (i & 0x4) {
282             s = shift;
283         } else {
284             s = shiftx;
285         }
286 
287         if (s & 0x8) {
288             if (tmp1 & (1LL << (i + 8))) {
289                 tmp2 |= 1LL << i;
290             } else {
291                 tmp2 &= ~(1LL << i);
292             }
293         }
294     }
295 
296     uint64_t tmp3 = tmp2;
297     for (i = 0; i <= 34; i++) {
298         int s;
299         if (i & 0x2) {
300             s = shift;
301         } else {
302             s = shiftx;
303         }
304         if (s & 0x4) {
305             if (tmp2 & (1LL << (i + 4))) {
306                 tmp3 |= 1LL << i;
307             } else {
308                 tmp3 &= ~(1LL << i);
309             }
310         }
311     }
312 
313     uint64_t tmp4 = tmp3;
314     for (i = 0; i <= 32; i++) {
315         int s;
316         if (i & 0x1) {
317             s = shift;
318         } else {
319             s = shiftx;
320         }
321         if (s & 0x2) {
322             if (tmp3 & (1LL << (i + 2))) {
323                 tmp4 |= 1LL << i;
324             } else {
325                 tmp4 &= ~(1LL << i);
326             }
327         }
328     }
329 
330     uint64_t tmp5 = tmp4;
331     for (i = 0; i <= 31; i++) {
332         int s;
333         s = shift;
334         if (s & 0x1) {
335             if (tmp4 & (1LL << (i + 1))) {
336                 tmp5 |= 1LL << i;
337             } else {
338                 tmp5 &= ~(1LL << i);
339             }
340         }
341     }
342 
343     return (int64_t)(int32_t)(uint32_t)tmp5;
344 }
345 
346 #ifndef CONFIG_USER_ONLY
347 
do_translate_address(CPUMIPSState * env,target_ulong address,int rw,uintptr_t retaddr)348 static inline hwaddr do_translate_address(CPUMIPSState *env,
349                                                       target_ulong address,
350                                                       int rw, uintptr_t retaddr)
351 {
352     hwaddr lladdr;
353     CPUState *cs = CPU(mips_env_get_cpu(env));
354 
355     lladdr = cpu_mips_translate_address(env, address, rw);
356 
357     if (lladdr == -1LL) {
358         cpu_loop_exit_restore(cs, retaddr);
359     } else {
360         return lladdr;
361     }
362 }
363 
364 #define HELPER_LD_ATOMIC(name, insn, almask)                                  \
365 target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx)  \
366 {                                                                             \
367     if (arg & almask) {                                                       \
368         if (!(env->hflags & MIPS_HFLAG_DM)) {                                 \
369             env->CP0_BadVAddr = arg;                                          \
370         }                                                                     \
371         do_raise_exception(env, EXCP_AdEL, GETPC());                          \
372     }                                                                         \
373     env->lladdr = do_translate_address(env, arg, 0, GETPC());                 \
374     env->llval = do_##insn(env, arg, mem_idx, GETPC());                       \
375     return env->llval;                                                        \
376 }
377 HELPER_LD_ATOMIC(ll, lw, 0x3)
378 #ifdef TARGET_MIPS64
379 HELPER_LD_ATOMIC(lld, ld, 0x7)
380 #endif
381 #undef HELPER_LD_ATOMIC
382 
383 #define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask)                      \
384 target_ulong helper_##name(CPUMIPSState *env, target_ulong arg1,              \
385                            target_ulong arg2, int mem_idx)                    \
386 {                                                                             \
387     target_long tmp;                                                          \
388                                                                               \
389     if (arg2 & almask) {                                                      \
390         if (!(env->hflags & MIPS_HFLAG_DM)) {                                 \
391             env->CP0_BadVAddr = arg2;                                         \
392         }                                                                     \
393         do_raise_exception(env, EXCP_AdES, GETPC());                          \
394     }                                                                         \
395     if (do_translate_address(env, arg2, 1, GETPC()) == env->lladdr) {         \
396         tmp = do_##ld_insn(env, arg2, mem_idx, GETPC());                      \
397         if (tmp == env->llval) {                                              \
398             do_##st_insn(env, arg2, arg1, mem_idx, GETPC());                  \
399             return 1;                                                         \
400         }                                                                     \
401     }                                                                         \
402     return 0;                                                                 \
403 }
404 HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
405 #ifdef TARGET_MIPS64
406 HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
407 #endif
408 #undef HELPER_ST_ATOMIC
409 #endif
410 
411 #ifdef TARGET_WORDS_BIGENDIAN
412 #define GET_LMASK(v) ((v) & 3)
413 #define GET_OFFSET(addr, offset) (addr + (offset))
414 #else
415 #define GET_LMASK(v) (((v) & 3) ^ 3)
416 #define GET_OFFSET(addr, offset) (addr - (offset))
417 #endif
418 
helper_swl(CPUMIPSState * env,target_ulong arg1,target_ulong arg2,int mem_idx)419 void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
420                 int mem_idx)
421 {
422     do_sb(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC());
423 
424     if (GET_LMASK(arg2) <= 2) {
425         do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx,
426               GETPC());
427     }
428 
429     if (GET_LMASK(arg2) <= 1) {
430         do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx,
431               GETPC());
432     }
433 
434     if (GET_LMASK(arg2) == 0) {
435         do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx,
436               GETPC());
437     }
438 }
439 
helper_swr(CPUMIPSState * env,target_ulong arg1,target_ulong arg2,int mem_idx)440 void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
441                 int mem_idx)
442 {
443     do_sb(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
444 
445     if (GET_LMASK(arg2) >= 1) {
446         do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx,
447               GETPC());
448     }
449 
450     if (GET_LMASK(arg2) >= 2) {
451         do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx,
452               GETPC());
453     }
454 
455     if (GET_LMASK(arg2) == 3) {
456         do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx,
457               GETPC());
458     }
459 }
460 
461 #if defined(TARGET_MIPS64)
462 /* "half" load and stores.  We must do the memory access inline,
463    or fault handling won't work.  */
464 
465 #ifdef TARGET_WORDS_BIGENDIAN
466 #define GET_LMASK64(v) ((v) & 7)
467 #else
468 #define GET_LMASK64(v) (((v) & 7) ^ 7)
469 #endif
470 
helper_sdl(CPUMIPSState * env,target_ulong arg1,target_ulong arg2,int mem_idx)471 void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
472                 int mem_idx)
473 {
474     do_sb(env, arg2, (uint8_t)(arg1 >> 56), mem_idx, GETPC());
475 
476     if (GET_LMASK64(arg2) <= 6) {
477         do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx,
478               GETPC());
479     }
480 
481     if (GET_LMASK64(arg2) <= 5) {
482         do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx,
483               GETPC());
484     }
485 
486     if (GET_LMASK64(arg2) <= 4) {
487         do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx,
488               GETPC());
489     }
490 
491     if (GET_LMASK64(arg2) <= 3) {
492         do_sb(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx,
493               GETPC());
494     }
495 
496     if (GET_LMASK64(arg2) <= 2) {
497         do_sb(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx,
498               GETPC());
499     }
500 
501     if (GET_LMASK64(arg2) <= 1) {
502         do_sb(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx,
503               GETPC());
504     }
505 
506     if (GET_LMASK64(arg2) <= 0) {
507         do_sb(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx,
508               GETPC());
509     }
510 }
511 
helper_sdr(CPUMIPSState * env,target_ulong arg1,target_ulong arg2,int mem_idx)512 void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
513                 int mem_idx)
514 {
515     do_sb(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
516 
517     if (GET_LMASK64(arg2) >= 1) {
518         do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx,
519               GETPC());
520     }
521 
522     if (GET_LMASK64(arg2) >= 2) {
523         do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx,
524               GETPC());
525     }
526 
527     if (GET_LMASK64(arg2) >= 3) {
528         do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx,
529               GETPC());
530     }
531 
532     if (GET_LMASK64(arg2) >= 4) {
533         do_sb(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx,
534               GETPC());
535     }
536 
537     if (GET_LMASK64(arg2) >= 5) {
538         do_sb(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx,
539               GETPC());
540     }
541 
542     if (GET_LMASK64(arg2) >= 6) {
543         do_sb(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx,
544               GETPC());
545     }
546 
547     if (GET_LMASK64(arg2) == 7) {
548         do_sb(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx,
549               GETPC());
550     }
551 }
552 #endif /* TARGET_MIPS64 */
553 
554 static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
555 
helper_lwm(CPUMIPSState * env,target_ulong addr,target_ulong reglist,uint32_t mem_idx)556 void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
557                 uint32_t mem_idx)
558 {
559     target_ulong base_reglist = reglist & 0xf;
560     target_ulong do_r31 = reglist & 0x10;
561 
562     if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
563         target_ulong i;
564 
565         for (i = 0; i < base_reglist; i++) {
566             env->active_tc.gpr[multiple_regs[i]] =
567                 (target_long)do_lw(env, addr, mem_idx, GETPC());
568             addr += 4;
569         }
570     }
571 
572     if (do_r31) {
573         env->active_tc.gpr[31] = (target_long)do_lw(env, addr, mem_idx,
574                                                     GETPC());
575     }
576 }
577 
helper_swm(CPUMIPSState * env,target_ulong addr,target_ulong reglist,uint32_t mem_idx)578 void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
579                 uint32_t mem_idx)
580 {
581     target_ulong base_reglist = reglist & 0xf;
582     target_ulong do_r31 = reglist & 0x10;
583 
584     if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
585         target_ulong i;
586 
587         for (i = 0; i < base_reglist; i++) {
588             do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx,
589                   GETPC());
590             addr += 4;
591         }
592     }
593 
594     if (do_r31) {
595         do_sw(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
596     }
597 }
598 
599 #if defined(TARGET_MIPS64)
helper_ldm(CPUMIPSState * env,target_ulong addr,target_ulong reglist,uint32_t mem_idx)600 void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
601                 uint32_t mem_idx)
602 {
603     target_ulong base_reglist = reglist & 0xf;
604     target_ulong do_r31 = reglist & 0x10;
605 
606     if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
607         target_ulong i;
608 
609         for (i = 0; i < base_reglist; i++) {
610             env->active_tc.gpr[multiple_regs[i]] = do_ld(env, addr, mem_idx,
611                                                          GETPC());
612             addr += 8;
613         }
614     }
615 
616     if (do_r31) {
617         env->active_tc.gpr[31] = do_ld(env, addr, mem_idx, GETPC());
618     }
619 }
620 
helper_sdm(CPUMIPSState * env,target_ulong addr,target_ulong reglist,uint32_t mem_idx)621 void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
622                 uint32_t mem_idx)
623 {
624     target_ulong base_reglist = reglist & 0xf;
625     target_ulong do_r31 = reglist & 0x10;
626 
627     if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
628         target_ulong i;
629 
630         for (i = 0; i < base_reglist; i++) {
631             do_sd(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx,
632                   GETPC());
633             addr += 8;
634         }
635     }
636 
637     if (do_r31) {
638         do_sd(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
639     }
640 }
641 #endif
642 
643 #ifndef CONFIG_USER_ONLY
644 /* SMP helpers.  */
mips_vpe_is_wfi(MIPSCPU * c)645 static bool mips_vpe_is_wfi(MIPSCPU *c)
646 {
647     CPUState *cpu = CPU(c);
648     CPUMIPSState *env = &c->env;
649 
650     /* If the VPE is halted but otherwise active, it means it's waiting for
651        an interrupt.  */
652     return cpu->halted && mips_vpe_active(env);
653 }
654 
mips_vp_is_wfi(MIPSCPU * c)655 static bool mips_vp_is_wfi(MIPSCPU *c)
656 {
657     CPUState *cpu = CPU(c);
658     CPUMIPSState *env = &c->env;
659 
660     return cpu->halted && mips_vp_active(env);
661 }
662 
mips_vpe_wake(MIPSCPU * c)663 static inline void mips_vpe_wake(MIPSCPU *c)
664 {
665     /* Don't set ->halted = 0 directly, let it be done via cpu_has_work
666        because there might be other conditions that state that c should
667        be sleeping.  */
668     cpu_interrupt(CPU(c), CPU_INTERRUPT_WAKE);
669 }
670 
mips_vpe_sleep(MIPSCPU * cpu)671 static inline void mips_vpe_sleep(MIPSCPU *cpu)
672 {
673     CPUState *cs = CPU(cpu);
674 
675     /* The VPE was shut off, really go to bed.
676        Reset any old _WAKE requests.  */
677     cs->halted = 1;
678     cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
679 }
680 
mips_tc_wake(MIPSCPU * cpu,int tc)681 static inline void mips_tc_wake(MIPSCPU *cpu, int tc)
682 {
683     CPUMIPSState *c = &cpu->env;
684 
685     /* FIXME: TC reschedule.  */
686     if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) {
687         mips_vpe_wake(cpu);
688     }
689 }
690 
mips_tc_sleep(MIPSCPU * cpu,int tc)691 static inline void mips_tc_sleep(MIPSCPU *cpu, int tc)
692 {
693     CPUMIPSState *c = &cpu->env;
694 
695     /* FIXME: TC reschedule.  */
696     if (!mips_vpe_active(c)) {
697         mips_vpe_sleep(cpu);
698     }
699 }
700 
701 /**
702  * mips_cpu_map_tc:
703  * @env: CPU from which mapping is performed.
704  * @tc: Should point to an int with the value of the global TC index.
705  *
706  * This function will transform @tc into a local index within the
707  * returned #CPUMIPSState.
708  */
709 /* FIXME: This code assumes that all VPEs have the same number of TCs,
710           which depends on runtime setup. Can probably be fixed by
711           walking the list of CPUMIPSStates.  */
mips_cpu_map_tc(CPUMIPSState * env,int * tc)712 static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc)
713 {
714     MIPSCPU *cpu;
715     CPUState *cs;
716     CPUState *other_cs;
717     int vpe_idx;
718     int tc_idx = *tc;
719 
720     if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) {
721         /* Not allowed to address other CPUs.  */
722         *tc = env->current_tc;
723         return env;
724     }
725 
726     cs = CPU(mips_env_get_cpu(env));
727     vpe_idx = tc_idx / cs->nr_threads;
728     *tc = tc_idx % cs->nr_threads;
729     other_cs = qemu_get_cpu(vpe_idx);
730     if (other_cs == NULL) {
731         return env;
732     }
733     cpu = MIPS_CPU(other_cs);
734     return &cpu->env;
735 }
736 
737 /* The per VPE CP0_Status register shares some fields with the per TC
738    CP0_TCStatus registers. These fields are wired to the same registers,
739    so changes to either of them should be reflected on both registers.
740 
741    Also, EntryHi shares the bottom 8 bit ASID with TCStauts.
742 
743    These helper call synchronizes the regs for a given cpu.  */
744 
745 /* Called for updates to CP0_Status.  Defined in "cpu.h" for gdbstub.c.  */
746 /* static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu,
747                                      int tc);  */
748 
749 /* Called for updates to CP0_TCStatus.  */
sync_c0_tcstatus(CPUMIPSState * cpu,int tc,target_ulong v)750 static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc,
751                              target_ulong v)
752 {
753     uint32_t status;
754     uint32_t tcu, tmx, tasid, tksu;
755     uint32_t mask = ((1U << CP0St_CU3)
756                        | (1 << CP0St_CU2)
757                        | (1 << CP0St_CU1)
758                        | (1 << CP0St_CU0)
759                        | (1 << CP0St_MX)
760                        | (3 << CP0St_KSU));
761 
762     tcu = (v >> CP0TCSt_TCU0) & 0xf;
763     tmx = (v >> CP0TCSt_TMX) & 0x1;
764     tasid = v & cpu->CP0_EntryHi_ASID_mask;
765     tksu = (v >> CP0TCSt_TKSU) & 0x3;
766 
767     status = tcu << CP0St_CU0;
768     status |= tmx << CP0St_MX;
769     status |= tksu << CP0St_KSU;
770 
771     cpu->CP0_Status &= ~mask;
772     cpu->CP0_Status |= status;
773 
774     /* Sync the TASID with EntryHi.  */
775     cpu->CP0_EntryHi &= ~cpu->CP0_EntryHi_ASID_mask;
776     cpu->CP0_EntryHi |= tasid;
777 
778     compute_hflags(cpu);
779 }
780 
781 /* Called for updates to CP0_EntryHi.  */
sync_c0_entryhi(CPUMIPSState * cpu,int tc)782 static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
783 {
784     int32_t *tcst;
785     uint32_t asid, v = cpu->CP0_EntryHi;
786 
787     asid = v & cpu->CP0_EntryHi_ASID_mask;
788 
789     if (tc == cpu->current_tc) {
790         tcst = &cpu->active_tc.CP0_TCStatus;
791     } else {
792         tcst = &cpu->tcs[tc].CP0_TCStatus;
793     }
794 
795     *tcst &= ~cpu->CP0_EntryHi_ASID_mask;
796     *tcst |= asid;
797 }
798 
799 /* CP0 helpers */
helper_mfc0_mvpcontrol(CPUMIPSState * env)800 target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env)
801 {
802     return env->mvp->CP0_MVPControl;
803 }
804 
helper_mfc0_mvpconf0(CPUMIPSState * env)805 target_ulong helper_mfc0_mvpconf0(CPUMIPSState *env)
806 {
807     return env->mvp->CP0_MVPConf0;
808 }
809 
helper_mfc0_mvpconf1(CPUMIPSState * env)810 target_ulong helper_mfc0_mvpconf1(CPUMIPSState *env)
811 {
812     return env->mvp->CP0_MVPConf1;
813 }
814 
helper_mfc0_random(CPUMIPSState * env)815 target_ulong helper_mfc0_random(CPUMIPSState *env)
816 {
817     return (int32_t)cpu_mips_get_random(env);
818 }
819 
helper_mfc0_tcstatus(CPUMIPSState * env)820 target_ulong helper_mfc0_tcstatus(CPUMIPSState *env)
821 {
822     return env->active_tc.CP0_TCStatus;
823 }
824 
helper_mftc0_tcstatus(CPUMIPSState * env)825 target_ulong helper_mftc0_tcstatus(CPUMIPSState *env)
826 {
827     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
828     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
829 
830     if (other_tc == other->current_tc)
831         return other->active_tc.CP0_TCStatus;
832     else
833         return other->tcs[other_tc].CP0_TCStatus;
834 }
835 
helper_mfc0_tcbind(CPUMIPSState * env)836 target_ulong helper_mfc0_tcbind(CPUMIPSState *env)
837 {
838     return env->active_tc.CP0_TCBind;
839 }
840 
helper_mftc0_tcbind(CPUMIPSState * env)841 target_ulong helper_mftc0_tcbind(CPUMIPSState *env)
842 {
843     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
844     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
845 
846     if (other_tc == other->current_tc)
847         return other->active_tc.CP0_TCBind;
848     else
849         return other->tcs[other_tc].CP0_TCBind;
850 }
851 
helper_mfc0_tcrestart(CPUMIPSState * env)852 target_ulong helper_mfc0_tcrestart(CPUMIPSState *env)
853 {
854     return env->active_tc.PC;
855 }
856 
helper_mftc0_tcrestart(CPUMIPSState * env)857 target_ulong helper_mftc0_tcrestart(CPUMIPSState *env)
858 {
859     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
860     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
861 
862     if (other_tc == other->current_tc)
863         return other->active_tc.PC;
864     else
865         return other->tcs[other_tc].PC;
866 }
867 
helper_mfc0_tchalt(CPUMIPSState * env)868 target_ulong helper_mfc0_tchalt(CPUMIPSState *env)
869 {
870     return env->active_tc.CP0_TCHalt;
871 }
872 
helper_mftc0_tchalt(CPUMIPSState * env)873 target_ulong helper_mftc0_tchalt(CPUMIPSState *env)
874 {
875     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
876     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
877 
878     if (other_tc == other->current_tc)
879         return other->active_tc.CP0_TCHalt;
880     else
881         return other->tcs[other_tc].CP0_TCHalt;
882 }
883 
helper_mfc0_tccontext(CPUMIPSState * env)884 target_ulong helper_mfc0_tccontext(CPUMIPSState *env)
885 {
886     return env->active_tc.CP0_TCContext;
887 }
888 
helper_mftc0_tccontext(CPUMIPSState * env)889 target_ulong helper_mftc0_tccontext(CPUMIPSState *env)
890 {
891     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
892     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
893 
894     if (other_tc == other->current_tc)
895         return other->active_tc.CP0_TCContext;
896     else
897         return other->tcs[other_tc].CP0_TCContext;
898 }
899 
helper_mfc0_tcschedule(CPUMIPSState * env)900 target_ulong helper_mfc0_tcschedule(CPUMIPSState *env)
901 {
902     return env->active_tc.CP0_TCSchedule;
903 }
904 
helper_mftc0_tcschedule(CPUMIPSState * env)905 target_ulong helper_mftc0_tcschedule(CPUMIPSState *env)
906 {
907     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
908     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
909 
910     if (other_tc == other->current_tc)
911         return other->active_tc.CP0_TCSchedule;
912     else
913         return other->tcs[other_tc].CP0_TCSchedule;
914 }
915 
helper_mfc0_tcschefback(CPUMIPSState * env)916 target_ulong helper_mfc0_tcschefback(CPUMIPSState *env)
917 {
918     return env->active_tc.CP0_TCScheFBack;
919 }
920 
helper_mftc0_tcschefback(CPUMIPSState * env)921 target_ulong helper_mftc0_tcschefback(CPUMIPSState *env)
922 {
923     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
924     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
925 
926     if (other_tc == other->current_tc)
927         return other->active_tc.CP0_TCScheFBack;
928     else
929         return other->tcs[other_tc].CP0_TCScheFBack;
930 }
931 
helper_mfc0_count(CPUMIPSState * env)932 target_ulong helper_mfc0_count(CPUMIPSState *env)
933 {
934     int32_t count;
935     qemu_mutex_lock_iothread();
936     count = (int32_t) cpu_mips_get_count(env);
937     qemu_mutex_unlock_iothread();
938     return count;
939 }
940 
helper_mftc0_entryhi(CPUMIPSState * env)941 target_ulong helper_mftc0_entryhi(CPUMIPSState *env)
942 {
943     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
944     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
945 
946     return other->CP0_EntryHi;
947 }
948 
helper_mftc0_cause(CPUMIPSState * env)949 target_ulong helper_mftc0_cause(CPUMIPSState *env)
950 {
951     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
952     int32_t tccause;
953     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
954 
955     if (other_tc == other->current_tc) {
956         tccause = other->CP0_Cause;
957     } else {
958         tccause = other->CP0_Cause;
959     }
960 
961     return tccause;
962 }
963 
helper_mftc0_status(CPUMIPSState * env)964 target_ulong helper_mftc0_status(CPUMIPSState *env)
965 {
966     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
967     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
968 
969     return other->CP0_Status;
970 }
971 
helper_mfc0_lladdr(CPUMIPSState * env)972 target_ulong helper_mfc0_lladdr(CPUMIPSState *env)
973 {
974     return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
975 }
976 
helper_mfc0_maar(CPUMIPSState * env)977 target_ulong helper_mfc0_maar(CPUMIPSState *env)
978 {
979     return (int32_t) env->CP0_MAAR[env->CP0_MAARI];
980 }
981 
helper_mfhc0_maar(CPUMIPSState * env)982 target_ulong helper_mfhc0_maar(CPUMIPSState *env)
983 {
984     return env->CP0_MAAR[env->CP0_MAARI] >> 32;
985 }
986 
helper_mfc0_watchlo(CPUMIPSState * env,uint32_t sel)987 target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel)
988 {
989     return (int32_t)env->CP0_WatchLo[sel];
990 }
991 
helper_mfc0_watchhi(CPUMIPSState * env,uint32_t sel)992 target_ulong helper_mfc0_watchhi(CPUMIPSState *env, uint32_t sel)
993 {
994     return env->CP0_WatchHi[sel];
995 }
996 
helper_mfc0_debug(CPUMIPSState * env)997 target_ulong helper_mfc0_debug(CPUMIPSState *env)
998 {
999     target_ulong t0 = env->CP0_Debug;
1000     if (env->hflags & MIPS_HFLAG_DM)
1001         t0 |= 1 << CP0DB_DM;
1002 
1003     return t0;
1004 }
1005 
helper_mftc0_debug(CPUMIPSState * env)1006 target_ulong helper_mftc0_debug(CPUMIPSState *env)
1007 {
1008     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1009     int32_t tcstatus;
1010     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1011 
1012     if (other_tc == other->current_tc)
1013         tcstatus = other->active_tc.CP0_Debug_tcstatus;
1014     else
1015         tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
1016 
1017     /* XXX: Might be wrong, check with EJTAG spec. */
1018     return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1019             (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1020 }
1021 
1022 #if defined(TARGET_MIPS64)
helper_dmfc0_tcrestart(CPUMIPSState * env)1023 target_ulong helper_dmfc0_tcrestart(CPUMIPSState *env)
1024 {
1025     return env->active_tc.PC;
1026 }
1027 
helper_dmfc0_tchalt(CPUMIPSState * env)1028 target_ulong helper_dmfc0_tchalt(CPUMIPSState *env)
1029 {
1030     return env->active_tc.CP0_TCHalt;
1031 }
1032 
helper_dmfc0_tccontext(CPUMIPSState * env)1033 target_ulong helper_dmfc0_tccontext(CPUMIPSState *env)
1034 {
1035     return env->active_tc.CP0_TCContext;
1036 }
1037 
helper_dmfc0_tcschedule(CPUMIPSState * env)1038 target_ulong helper_dmfc0_tcschedule(CPUMIPSState *env)
1039 {
1040     return env->active_tc.CP0_TCSchedule;
1041 }
1042 
helper_dmfc0_tcschefback(CPUMIPSState * env)1043 target_ulong helper_dmfc0_tcschefback(CPUMIPSState *env)
1044 {
1045     return env->active_tc.CP0_TCScheFBack;
1046 }
1047 
helper_dmfc0_lladdr(CPUMIPSState * env)1048 target_ulong helper_dmfc0_lladdr(CPUMIPSState *env)
1049 {
1050     return env->lladdr >> env->CP0_LLAddr_shift;
1051 }
1052 
helper_dmfc0_maar(CPUMIPSState * env)1053 target_ulong helper_dmfc0_maar(CPUMIPSState *env)
1054 {
1055     return env->CP0_MAAR[env->CP0_MAARI];
1056 }
1057 
helper_dmfc0_watchlo(CPUMIPSState * env,uint32_t sel)1058 target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
1059 {
1060     return env->CP0_WatchLo[sel];
1061 }
1062 #endif /* TARGET_MIPS64 */
1063 
helper_mtc0_index(CPUMIPSState * env,target_ulong arg1)1064 void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1)
1065 {
1066     uint32_t index_p = env->CP0_Index & 0x80000000;
1067     uint32_t tlb_index = arg1 & 0x7fffffff;
1068     if (tlb_index < env->tlb->nb_tlb) {
1069         if (env->insn_flags & ISA_MIPS32R6) {
1070             index_p |= arg1 & 0x80000000;
1071         }
1072         env->CP0_Index = index_p | tlb_index;
1073     }
1074 }
1075 
helper_mtc0_mvpcontrol(CPUMIPSState * env,target_ulong arg1)1076 void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1)
1077 {
1078     uint32_t mask = 0;
1079     uint32_t newval;
1080 
1081     if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
1082         mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
1083                 (1 << CP0MVPCo_EVP);
1084     if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1085         mask |= (1 << CP0MVPCo_STLB);
1086     newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
1087 
1088     // TODO: Enable/disable shared TLB, enable/disable VPEs.
1089 
1090     env->mvp->CP0_MVPControl = newval;
1091 }
1092 
helper_mtc0_vpecontrol(CPUMIPSState * env,target_ulong arg1)1093 void helper_mtc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
1094 {
1095     uint32_t mask;
1096     uint32_t newval;
1097 
1098     mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
1099            (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
1100     newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
1101 
1102     /* Yield scheduler intercept not implemented. */
1103     /* Gating storage scheduler intercept not implemented. */
1104 
1105     // TODO: Enable/disable TCs.
1106 
1107     env->CP0_VPEControl = newval;
1108 }
1109 
helper_mttc0_vpecontrol(CPUMIPSState * env,target_ulong arg1)1110 void helper_mttc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
1111 {
1112     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1113     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1114     uint32_t mask;
1115     uint32_t newval;
1116 
1117     mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
1118            (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
1119     newval = (other->CP0_VPEControl & ~mask) | (arg1 & mask);
1120 
1121     /* TODO: Enable/disable TCs.  */
1122 
1123     other->CP0_VPEControl = newval;
1124 }
1125 
helper_mftc0_vpecontrol(CPUMIPSState * env)1126 target_ulong helper_mftc0_vpecontrol(CPUMIPSState *env)
1127 {
1128     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1129     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1130     /* FIXME: Mask away return zero on read bits.  */
1131     return other->CP0_VPEControl;
1132 }
1133 
helper_mftc0_vpeconf0(CPUMIPSState * env)1134 target_ulong helper_mftc0_vpeconf0(CPUMIPSState *env)
1135 {
1136     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1137     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1138 
1139     return other->CP0_VPEConf0;
1140 }
1141 
helper_mtc0_vpeconf0(CPUMIPSState * env,target_ulong arg1)1142 void helper_mtc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
1143 {
1144     uint32_t mask = 0;
1145     uint32_t newval;
1146 
1147     if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
1148         if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
1149             mask |= (0xff << CP0VPEC0_XTC);
1150         mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1151     }
1152     newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1153 
1154     // TODO: TC exclusive handling due to ERL/EXL.
1155 
1156     env->CP0_VPEConf0 = newval;
1157 }
1158 
helper_mttc0_vpeconf0(CPUMIPSState * env,target_ulong arg1)1159 void helper_mttc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
1160 {
1161     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1162     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1163     uint32_t mask = 0;
1164     uint32_t newval;
1165 
1166     mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1167     newval = (other->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1168 
1169     /* TODO: TC exclusive handling due to ERL/EXL.  */
1170     other->CP0_VPEConf0 = newval;
1171 }
1172 
helper_mtc0_vpeconf1(CPUMIPSState * env,target_ulong arg1)1173 void helper_mtc0_vpeconf1(CPUMIPSState *env, target_ulong arg1)
1174 {
1175     uint32_t mask = 0;
1176     uint32_t newval;
1177 
1178     if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1179         mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
1180                 (0xff << CP0VPEC1_NCP1);
1181     newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
1182 
1183     /* UDI not implemented. */
1184     /* CP2 not implemented. */
1185 
1186     // TODO: Handle FPU (CP1) binding.
1187 
1188     env->CP0_VPEConf1 = newval;
1189 }
1190 
helper_mtc0_yqmask(CPUMIPSState * env,target_ulong arg1)1191 void helper_mtc0_yqmask(CPUMIPSState *env, target_ulong arg1)
1192 {
1193     /* Yield qualifier inputs not implemented. */
1194     env->CP0_YQMask = 0x00000000;
1195 }
1196 
helper_mtc0_vpeopt(CPUMIPSState * env,target_ulong arg1)1197 void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1)
1198 {
1199     env->CP0_VPEOpt = arg1 & 0x0000ffff;
1200 }
1201 
1202 #define MTC0_ENTRYLO_MASK(env) ((env->PAMask >> 6) & 0x3FFFFFFF)
1203 
helper_mtc0_entrylo0(CPUMIPSState * env,target_ulong arg1)1204 void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
1205 {
1206     /* 1k pages not implemented */
1207     target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
1208     env->CP0_EntryLo0 = (arg1 & MTC0_ENTRYLO_MASK(env))
1209                         | (rxi << (CP0EnLo_XI - 30));
1210 }
1211 
1212 #if defined(TARGET_MIPS64)
1213 #define DMTC0_ENTRYLO_MASK(env) (env->PAMask >> 6)
1214 
helper_dmtc0_entrylo0(CPUMIPSState * env,uint64_t arg1)1215 void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1)
1216 {
1217     uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
1218     env->CP0_EntryLo0 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
1219 }
1220 #endif
1221 
helper_mtc0_tcstatus(CPUMIPSState * env,target_ulong arg1)1222 void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
1223 {
1224     uint32_t mask = env->CP0_TCStatus_rw_bitmask;
1225     uint32_t newval;
1226 
1227     newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
1228 
1229     env->active_tc.CP0_TCStatus = newval;
1230     sync_c0_tcstatus(env, env->current_tc, newval);
1231 }
1232 
helper_mttc0_tcstatus(CPUMIPSState * env,target_ulong arg1)1233 void helper_mttc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
1234 {
1235     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1236     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1237 
1238     if (other_tc == other->current_tc)
1239         other->active_tc.CP0_TCStatus = arg1;
1240     else
1241         other->tcs[other_tc].CP0_TCStatus = arg1;
1242     sync_c0_tcstatus(other, other_tc, arg1);
1243 }
1244 
helper_mtc0_tcbind(CPUMIPSState * env,target_ulong arg1)1245 void helper_mtc0_tcbind(CPUMIPSState *env, target_ulong arg1)
1246 {
1247     uint32_t mask = (1 << CP0TCBd_TBE);
1248     uint32_t newval;
1249 
1250     if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1251         mask |= (1 << CP0TCBd_CurVPE);
1252     newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1253     env->active_tc.CP0_TCBind = newval;
1254 }
1255 
helper_mttc0_tcbind(CPUMIPSState * env,target_ulong arg1)1256 void helper_mttc0_tcbind(CPUMIPSState *env, target_ulong arg1)
1257 {
1258     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1259     uint32_t mask = (1 << CP0TCBd_TBE);
1260     uint32_t newval;
1261     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1262 
1263     if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1264         mask |= (1 << CP0TCBd_CurVPE);
1265     if (other_tc == other->current_tc) {
1266         newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1267         other->active_tc.CP0_TCBind = newval;
1268     } else {
1269         newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
1270         other->tcs[other_tc].CP0_TCBind = newval;
1271     }
1272 }
1273 
helper_mtc0_tcrestart(CPUMIPSState * env,target_ulong arg1)1274 void helper_mtc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
1275 {
1276     env->active_tc.PC = arg1;
1277     env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1278     env->lladdr = 0ULL;
1279     /* MIPS16 not implemented. */
1280 }
1281 
helper_mttc0_tcrestart(CPUMIPSState * env,target_ulong arg1)1282 void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
1283 {
1284     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1285     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1286 
1287     if (other_tc == other->current_tc) {
1288         other->active_tc.PC = arg1;
1289         other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1290         other->lladdr = 0ULL;
1291         /* MIPS16 not implemented. */
1292     } else {
1293         other->tcs[other_tc].PC = arg1;
1294         other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1295         other->lladdr = 0ULL;
1296         /* MIPS16 not implemented. */
1297     }
1298 }
1299 
helper_mtc0_tchalt(CPUMIPSState * env,target_ulong arg1)1300 void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1)
1301 {
1302     MIPSCPU *cpu = mips_env_get_cpu(env);
1303 
1304     env->active_tc.CP0_TCHalt = arg1 & 0x1;
1305 
1306     // TODO: Halt TC / Restart (if allocated+active) TC.
1307     if (env->active_tc.CP0_TCHalt & 1) {
1308         mips_tc_sleep(cpu, env->current_tc);
1309     } else {
1310         mips_tc_wake(cpu, env->current_tc);
1311     }
1312 }
1313 
helper_mttc0_tchalt(CPUMIPSState * env,target_ulong arg1)1314 void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1)
1315 {
1316     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1317     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1318     MIPSCPU *other_cpu = mips_env_get_cpu(other);
1319 
1320     // TODO: Halt TC / Restart (if allocated+active) TC.
1321 
1322     if (other_tc == other->current_tc)
1323         other->active_tc.CP0_TCHalt = arg1;
1324     else
1325         other->tcs[other_tc].CP0_TCHalt = arg1;
1326 
1327     if (arg1 & 1) {
1328         mips_tc_sleep(other_cpu, other_tc);
1329     } else {
1330         mips_tc_wake(other_cpu, other_tc);
1331     }
1332 }
1333 
helper_mtc0_tccontext(CPUMIPSState * env,target_ulong arg1)1334 void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1)
1335 {
1336     env->active_tc.CP0_TCContext = arg1;
1337 }
1338 
helper_mttc0_tccontext(CPUMIPSState * env,target_ulong arg1)1339 void helper_mttc0_tccontext(CPUMIPSState *env, target_ulong arg1)
1340 {
1341     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1342     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1343 
1344     if (other_tc == other->current_tc)
1345         other->active_tc.CP0_TCContext = arg1;
1346     else
1347         other->tcs[other_tc].CP0_TCContext = arg1;
1348 }
1349 
helper_mtc0_tcschedule(CPUMIPSState * env,target_ulong arg1)1350 void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
1351 {
1352     env->active_tc.CP0_TCSchedule = arg1;
1353 }
1354 
helper_mttc0_tcschedule(CPUMIPSState * env,target_ulong arg1)1355 void helper_mttc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
1356 {
1357     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1358     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1359 
1360     if (other_tc == other->current_tc)
1361         other->active_tc.CP0_TCSchedule = arg1;
1362     else
1363         other->tcs[other_tc].CP0_TCSchedule = arg1;
1364 }
1365 
helper_mtc0_tcschefback(CPUMIPSState * env,target_ulong arg1)1366 void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
1367 {
1368     env->active_tc.CP0_TCScheFBack = arg1;
1369 }
1370 
helper_mttc0_tcschefback(CPUMIPSState * env,target_ulong arg1)1371 void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
1372 {
1373     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1374     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1375 
1376     if (other_tc == other->current_tc)
1377         other->active_tc.CP0_TCScheFBack = arg1;
1378     else
1379         other->tcs[other_tc].CP0_TCScheFBack = arg1;
1380 }
1381 
helper_mtc0_entrylo1(CPUMIPSState * env,target_ulong arg1)1382 void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
1383 {
1384     /* 1k pages not implemented */
1385     target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
1386     env->CP0_EntryLo1 = (arg1 & MTC0_ENTRYLO_MASK(env))
1387                         | (rxi << (CP0EnLo_XI - 30));
1388 }
1389 
1390 #if defined(TARGET_MIPS64)
helper_dmtc0_entrylo1(CPUMIPSState * env,uint64_t arg1)1391 void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1)
1392 {
1393     uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
1394     env->CP0_EntryLo1 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
1395 }
1396 #endif
1397 
helper_mtc0_context(CPUMIPSState * env,target_ulong arg1)1398 void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1)
1399 {
1400     env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
1401 }
1402 
helper_mtc0_pagemask(CPUMIPSState * env,target_ulong arg1)1403 void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
1404 {
1405     uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1);
1406     if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) ||
1407         (mask == 0x0000 || mask == 0x0003 || mask == 0x000F ||
1408          mask == 0x003F || mask == 0x00FF || mask == 0x03FF ||
1409          mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) {
1410         env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1411     }
1412 }
1413 
helper_mtc0_pagegrain(CPUMIPSState * env,target_ulong arg1)1414 void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
1415 {
1416     /* SmartMIPS not implemented */
1417     /* 1k pages not implemented */
1418     env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) |
1419                          (env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask);
1420     compute_hflags(env);
1421     restore_pamask(env);
1422 }
1423 
helper_mtc0_segctl0(CPUMIPSState * env,target_ulong arg1)1424 void helper_mtc0_segctl0(CPUMIPSState *env, target_ulong arg1)
1425 {
1426     CPUState *cs = CPU(mips_env_get_cpu(env));
1427 
1428     env->CP0_SegCtl0 = arg1 & CP0SC0_MASK;
1429     tlb_flush(cs);
1430 }
1431 
helper_mtc0_segctl1(CPUMIPSState * env,target_ulong arg1)1432 void helper_mtc0_segctl1(CPUMIPSState *env, target_ulong arg1)
1433 {
1434     CPUState *cs = CPU(mips_env_get_cpu(env));
1435 
1436     env->CP0_SegCtl1 = arg1 & CP0SC1_MASK;
1437     tlb_flush(cs);
1438 }
1439 
helper_mtc0_segctl2(CPUMIPSState * env,target_ulong arg1)1440 void helper_mtc0_segctl2(CPUMIPSState *env, target_ulong arg1)
1441 {
1442     CPUState *cs = CPU(mips_env_get_cpu(env));
1443 
1444     env->CP0_SegCtl2 = arg1 & CP0SC2_MASK;
1445     tlb_flush(cs);
1446 }
1447 
helper_mtc0_wired(CPUMIPSState * env,target_ulong arg1)1448 void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
1449 {
1450     if (env->insn_flags & ISA_MIPS32R6) {
1451         if (arg1 < env->tlb->nb_tlb) {
1452             env->CP0_Wired = arg1;
1453         }
1454     } else {
1455         env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1456     }
1457 }
1458 
helper_mtc0_srsconf0(CPUMIPSState * env,target_ulong arg1)1459 void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1)
1460 {
1461     env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
1462 }
1463 
helper_mtc0_srsconf1(CPUMIPSState * env,target_ulong arg1)1464 void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1)
1465 {
1466     env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
1467 }
1468 
helper_mtc0_srsconf2(CPUMIPSState * env,target_ulong arg1)1469 void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1)
1470 {
1471     env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
1472 }
1473 
helper_mtc0_srsconf3(CPUMIPSState * env,target_ulong arg1)1474 void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1)
1475 {
1476     env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
1477 }
1478 
helper_mtc0_srsconf4(CPUMIPSState * env,target_ulong arg1)1479 void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1)
1480 {
1481     env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
1482 }
1483 
helper_mtc0_hwrena(CPUMIPSState * env,target_ulong arg1)1484 void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
1485 {
1486     uint32_t mask = 0x0000000F;
1487 
1488     if ((env->CP0_Config1 & (1 << CP0C1_PC)) &&
1489         (env->insn_flags & ISA_MIPS32R6)) {
1490         mask |= (1 << 4);
1491     }
1492     if (env->insn_flags & ISA_MIPS32R6) {
1493         mask |= (1 << 5);
1494     }
1495     if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
1496         mask |= (1 << 29);
1497 
1498         if (arg1 & (1 << 29)) {
1499             env->hflags |= MIPS_HFLAG_HWRENA_ULR;
1500         } else {
1501             env->hflags &= ~MIPS_HFLAG_HWRENA_ULR;
1502         }
1503     }
1504 
1505     env->CP0_HWREna = arg1 & mask;
1506 }
1507 
helper_mtc0_count(CPUMIPSState * env,target_ulong arg1)1508 void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
1509 {
1510     qemu_mutex_lock_iothread();
1511     cpu_mips_store_count(env, arg1);
1512     qemu_mutex_unlock_iothread();
1513 }
1514 
helper_mtc0_entryhi(CPUMIPSState * env,target_ulong arg1)1515 void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
1516 {
1517     target_ulong old, val, mask;
1518     mask = (TARGET_PAGE_MASK << 1) | env->CP0_EntryHi_ASID_mask;
1519     if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) {
1520         mask |= 1 << CP0EnHi_EHINV;
1521     }
1522 
1523     /* 1k pages not implemented */
1524 #if defined(TARGET_MIPS64)
1525     if (env->insn_flags & ISA_MIPS32R6) {
1526         int entryhi_r = extract64(arg1, 62, 2);
1527         int config0_at = extract32(env->CP0_Config0, 13, 2);
1528         bool no_supervisor = (env->CP0_Status_rw_bitmask & 0x8) == 0;
1529         if ((entryhi_r == 2) ||
1530             (entryhi_r == 1 && (no_supervisor || config0_at == 1))) {
1531             /* skip EntryHi.R field if new value is reserved */
1532             mask &= ~(0x3ull << 62);
1533         }
1534     }
1535     mask &= env->SEGMask;
1536 #endif
1537     old = env->CP0_EntryHi;
1538     val = (arg1 & mask) | (old & ~mask);
1539     env->CP0_EntryHi = val;
1540     if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1541         sync_c0_entryhi(env, env->current_tc);
1542     }
1543     /* If the ASID changes, flush qemu's TLB.  */
1544     if ((old & env->CP0_EntryHi_ASID_mask) !=
1545         (val & env->CP0_EntryHi_ASID_mask)) {
1546         tlb_flush(CPU(mips_env_get_cpu(env)));
1547     }
1548 }
1549 
helper_mttc0_entryhi(CPUMIPSState * env,target_ulong arg1)1550 void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1)
1551 {
1552     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1553     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1554 
1555     other->CP0_EntryHi = arg1;
1556     sync_c0_entryhi(other, other_tc);
1557 }
1558 
helper_mtc0_compare(CPUMIPSState * env,target_ulong arg1)1559 void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1)
1560 {
1561     qemu_mutex_lock_iothread();
1562     cpu_mips_store_compare(env, arg1);
1563     qemu_mutex_unlock_iothread();
1564 }
1565 
helper_mtc0_status(CPUMIPSState * env,target_ulong arg1)1566 void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
1567 {
1568     MIPSCPU *cpu = mips_env_get_cpu(env);
1569     uint32_t val, old;
1570 
1571     old = env->CP0_Status;
1572     cpu_mips_store_status(env, arg1);
1573     val = env->CP0_Status;
1574 
1575     if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1576         qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1577                 old, old & env->CP0_Cause & CP0Ca_IP_mask,
1578                 val, val & env->CP0_Cause & CP0Ca_IP_mask,
1579                 env->CP0_Cause);
1580         switch (cpu_mmu_index(env, false)) {
1581         case 3:
1582             qemu_log(", ERL\n");
1583             break;
1584         case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1585         case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1586         case MIPS_HFLAG_KM: qemu_log("\n"); break;
1587         default:
1588             cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
1589             break;
1590         }
1591     }
1592 }
1593 
helper_mttc0_status(CPUMIPSState * env,target_ulong arg1)1594 void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1)
1595 {
1596     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1597     uint32_t mask = env->CP0_Status_rw_bitmask & ~0xf1000018;
1598     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1599 
1600     other->CP0_Status = (other->CP0_Status & ~mask) | (arg1 & mask);
1601     sync_c0_status(env, other, other_tc);
1602 }
1603 
helper_mtc0_intctl(CPUMIPSState * env,target_ulong arg1)1604 void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1)
1605 {
1606     env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
1607 }
1608 
helper_mtc0_srsctl(CPUMIPSState * env,target_ulong arg1)1609 void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1)
1610 {
1611     uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1612     env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
1613 }
1614 
helper_mtc0_cause(CPUMIPSState * env,target_ulong arg1)1615 void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1)
1616 {
1617     qemu_mutex_lock_iothread();
1618     cpu_mips_store_cause(env, arg1);
1619     qemu_mutex_unlock_iothread();
1620 }
1621 
helper_mttc0_cause(CPUMIPSState * env,target_ulong arg1)1622 void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1)
1623 {
1624     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1625     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1626 
1627     cpu_mips_store_cause(other, arg1);
1628 }
1629 
helper_mftc0_epc(CPUMIPSState * env)1630 target_ulong helper_mftc0_epc(CPUMIPSState *env)
1631 {
1632     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1633     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1634 
1635     return other->CP0_EPC;
1636 }
1637 
helper_mftc0_ebase(CPUMIPSState * env)1638 target_ulong helper_mftc0_ebase(CPUMIPSState *env)
1639 {
1640     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1641     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1642 
1643     return other->CP0_EBase;
1644 }
1645 
helper_mtc0_ebase(CPUMIPSState * env,target_ulong arg1)1646 void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
1647 {
1648     target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask;
1649     if (arg1 & env->CP0_EBaseWG_rw_bitmask) {
1650         mask |= ~0x3FFFFFFF;
1651     }
1652     env->CP0_EBase = (env->CP0_EBase & ~mask) | (arg1 & mask);
1653 }
1654 
helper_mttc0_ebase(CPUMIPSState * env,target_ulong arg1)1655 void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1)
1656 {
1657     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1658     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1659     target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask;
1660     if (arg1 & env->CP0_EBaseWG_rw_bitmask) {
1661         mask |= ~0x3FFFFFFF;
1662     }
1663     other->CP0_EBase = (other->CP0_EBase & ~mask) | (arg1 & mask);
1664 }
1665 
helper_mftc0_configx(CPUMIPSState * env,target_ulong idx)1666 target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx)
1667 {
1668     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1669     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1670 
1671     switch (idx) {
1672     case 0: return other->CP0_Config0;
1673     case 1: return other->CP0_Config1;
1674     case 2: return other->CP0_Config2;
1675     case 3: return other->CP0_Config3;
1676     /* 4 and 5 are reserved.  */
1677     case 6: return other->CP0_Config6;
1678     case 7: return other->CP0_Config7;
1679     default:
1680         break;
1681     }
1682     return 0;
1683 }
1684 
helper_mtc0_config0(CPUMIPSState * env,target_ulong arg1)1685 void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1)
1686 {
1687     env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
1688 }
1689 
helper_mtc0_config2(CPUMIPSState * env,target_ulong arg1)1690 void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1)
1691 {
1692     /* tertiary/secondary caches not implemented */
1693     env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1694 }
1695 
helper_mtc0_config3(CPUMIPSState * env,target_ulong arg1)1696 void helper_mtc0_config3(CPUMIPSState *env, target_ulong arg1)
1697 {
1698     if (env->insn_flags & ASE_MICROMIPS) {
1699         env->CP0_Config3 = (env->CP0_Config3 & ~(1 << CP0C3_ISA_ON_EXC)) |
1700                            (arg1 & (1 << CP0C3_ISA_ON_EXC));
1701     }
1702 }
1703 
helper_mtc0_config4(CPUMIPSState * env,target_ulong arg1)1704 void helper_mtc0_config4(CPUMIPSState *env, target_ulong arg1)
1705 {
1706     env->CP0_Config4 = (env->CP0_Config4 & (~env->CP0_Config4_rw_bitmask)) |
1707                        (arg1 & env->CP0_Config4_rw_bitmask);
1708 }
1709 
helper_mtc0_config5(CPUMIPSState * env,target_ulong arg1)1710 void helper_mtc0_config5(CPUMIPSState *env, target_ulong arg1)
1711 {
1712     env->CP0_Config5 = (env->CP0_Config5 & (~env->CP0_Config5_rw_bitmask)) |
1713                        (arg1 & env->CP0_Config5_rw_bitmask);
1714     compute_hflags(env);
1715 }
1716 
helper_mtc0_lladdr(CPUMIPSState * env,target_ulong arg1)1717 void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1)
1718 {
1719     target_long mask = env->CP0_LLAddr_rw_bitmask;
1720     arg1 = arg1 << env->CP0_LLAddr_shift;
1721     env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
1722 }
1723 
1724 #define MTC0_MAAR_MASK(env) \
1725         ((0x1ULL << 63) | ((env->PAMask >> 4) & ~0xFFFull) | 0x3)
1726 
helper_mtc0_maar(CPUMIPSState * env,target_ulong arg1)1727 void helper_mtc0_maar(CPUMIPSState *env, target_ulong arg1)
1728 {
1729     env->CP0_MAAR[env->CP0_MAARI] = arg1 & MTC0_MAAR_MASK(env);
1730 }
1731 
helper_mthc0_maar(CPUMIPSState * env,target_ulong arg1)1732 void helper_mthc0_maar(CPUMIPSState *env, target_ulong arg1)
1733 {
1734     env->CP0_MAAR[env->CP0_MAARI] =
1735         (((uint64_t) arg1 << 32) & MTC0_MAAR_MASK(env)) |
1736         (env->CP0_MAAR[env->CP0_MAARI] & 0x00000000ffffffffULL);
1737 }
1738 
helper_mtc0_maari(CPUMIPSState * env,target_ulong arg1)1739 void helper_mtc0_maari(CPUMIPSState *env, target_ulong arg1)
1740 {
1741     int index = arg1 & 0x3f;
1742     if (index == 0x3f) {
1743         /* Software may write all ones to INDEX to determine the
1744            maximum value supported. */
1745         env->CP0_MAARI = MIPS_MAAR_MAX - 1;
1746     } else if (index < MIPS_MAAR_MAX) {
1747         env->CP0_MAARI = index;
1748     }
1749     /* Other than the all ones, if the
1750        value written is not supported, then INDEX is unchanged
1751        from its previous value. */
1752 }
1753 
helper_mtc0_watchlo(CPUMIPSState * env,target_ulong arg1,uint32_t sel)1754 void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1755 {
1756     /* Watch exceptions for instructions, data loads, data stores
1757        not implemented. */
1758     env->CP0_WatchLo[sel] = (arg1 & ~0x7);
1759 }
1760 
helper_mtc0_watchhi(CPUMIPSState * env,target_ulong arg1,uint32_t sel)1761 void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1762 {
1763     int mask = 0x40000FF8 | (env->CP0_EntryHi_ASID_mask << CP0WH_ASID);
1764     env->CP0_WatchHi[sel] = arg1 & mask;
1765     env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
1766 }
1767 
helper_mtc0_xcontext(CPUMIPSState * env,target_ulong arg1)1768 void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1)
1769 {
1770     target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1771     env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
1772 }
1773 
helper_mtc0_framemask(CPUMIPSState * env,target_ulong arg1)1774 void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1)
1775 {
1776     env->CP0_Framemask = arg1; /* XXX */
1777 }
1778 
helper_mtc0_debug(CPUMIPSState * env,target_ulong arg1)1779 void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1)
1780 {
1781     env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1782     if (arg1 & (1 << CP0DB_DM))
1783         env->hflags |= MIPS_HFLAG_DM;
1784     else
1785         env->hflags &= ~MIPS_HFLAG_DM;
1786 }
1787 
helper_mttc0_debug(CPUMIPSState * env,target_ulong arg1)1788 void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1)
1789 {
1790     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1791     uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1792     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1793 
1794     /* XXX: Might be wrong, check with EJTAG spec. */
1795     if (other_tc == other->current_tc)
1796         other->active_tc.CP0_Debug_tcstatus = val;
1797     else
1798         other->tcs[other_tc].CP0_Debug_tcstatus = val;
1799     other->CP0_Debug = (other->CP0_Debug &
1800                      ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1801                      (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1802 }
1803 
helper_mtc0_performance0(CPUMIPSState * env,target_ulong arg1)1804 void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
1805 {
1806     env->CP0_Performance0 = arg1 & 0x000007ff;
1807 }
1808 
helper_mtc0_errctl(CPUMIPSState * env,target_ulong arg1)1809 void helper_mtc0_errctl(CPUMIPSState *env, target_ulong arg1)
1810 {
1811     int32_t wst = arg1 & (1 << CP0EC_WST);
1812     int32_t spr = arg1 & (1 << CP0EC_SPR);
1813     int32_t itc = env->itc_tag ? (arg1 & (1 << CP0EC_ITC)) : 0;
1814 
1815     env->CP0_ErrCtl = wst | spr | itc;
1816 
1817     if (itc && !wst && !spr) {
1818         env->hflags |= MIPS_HFLAG_ITC_CACHE;
1819     } else {
1820         env->hflags &= ~MIPS_HFLAG_ITC_CACHE;
1821     }
1822 }
1823 
helper_mtc0_taglo(CPUMIPSState * env,target_ulong arg1)1824 void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
1825 {
1826     if (env->hflags & MIPS_HFLAG_ITC_CACHE) {
1827         /* If CACHE instruction is configured for ITC tags then make all
1828            CP0.TagLo bits writable. The actual write to ITC Configuration
1829            Tag will take care of the read-only bits. */
1830         env->CP0_TagLo = arg1;
1831     } else {
1832         env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1833     }
1834 }
1835 
helper_mtc0_datalo(CPUMIPSState * env,target_ulong arg1)1836 void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
1837 {
1838     env->CP0_DataLo = arg1; /* XXX */
1839 }
1840 
helper_mtc0_taghi(CPUMIPSState * env,target_ulong arg1)1841 void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1)
1842 {
1843     env->CP0_TagHi = arg1; /* XXX */
1844 }
1845 
helper_mtc0_datahi(CPUMIPSState * env,target_ulong arg1)1846 void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1)
1847 {
1848     env->CP0_DataHi = arg1; /* XXX */
1849 }
1850 
1851 /* MIPS MT functions */
helper_mftgpr(CPUMIPSState * env,uint32_t sel)1852 target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel)
1853 {
1854     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1855     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1856 
1857     if (other_tc == other->current_tc)
1858         return other->active_tc.gpr[sel];
1859     else
1860         return other->tcs[other_tc].gpr[sel];
1861 }
1862 
helper_mftlo(CPUMIPSState * env,uint32_t sel)1863 target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel)
1864 {
1865     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1866     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1867 
1868     if (other_tc == other->current_tc)
1869         return other->active_tc.LO[sel];
1870     else
1871         return other->tcs[other_tc].LO[sel];
1872 }
1873 
helper_mfthi(CPUMIPSState * env,uint32_t sel)1874 target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel)
1875 {
1876     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1877     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1878 
1879     if (other_tc == other->current_tc)
1880         return other->active_tc.HI[sel];
1881     else
1882         return other->tcs[other_tc].HI[sel];
1883 }
1884 
helper_mftacx(CPUMIPSState * env,uint32_t sel)1885 target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel)
1886 {
1887     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1888     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1889 
1890     if (other_tc == other->current_tc)
1891         return other->active_tc.ACX[sel];
1892     else
1893         return other->tcs[other_tc].ACX[sel];
1894 }
1895 
helper_mftdsp(CPUMIPSState * env)1896 target_ulong helper_mftdsp(CPUMIPSState *env)
1897 {
1898     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1899     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1900 
1901     if (other_tc == other->current_tc)
1902         return other->active_tc.DSPControl;
1903     else
1904         return other->tcs[other_tc].DSPControl;
1905 }
1906 
helper_mttgpr(CPUMIPSState * env,target_ulong arg1,uint32_t sel)1907 void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1908 {
1909     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1910     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1911 
1912     if (other_tc == other->current_tc)
1913         other->active_tc.gpr[sel] = arg1;
1914     else
1915         other->tcs[other_tc].gpr[sel] = arg1;
1916 }
1917 
helper_mttlo(CPUMIPSState * env,target_ulong arg1,uint32_t sel)1918 void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1919 {
1920     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1921     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1922 
1923     if (other_tc == other->current_tc)
1924         other->active_tc.LO[sel] = arg1;
1925     else
1926         other->tcs[other_tc].LO[sel] = arg1;
1927 }
1928 
helper_mtthi(CPUMIPSState * env,target_ulong arg1,uint32_t sel)1929 void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1930 {
1931     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1932     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1933 
1934     if (other_tc == other->current_tc)
1935         other->active_tc.HI[sel] = arg1;
1936     else
1937         other->tcs[other_tc].HI[sel] = arg1;
1938 }
1939 
helper_mttacx(CPUMIPSState * env,target_ulong arg1,uint32_t sel)1940 void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1941 {
1942     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1943     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1944 
1945     if (other_tc == other->current_tc)
1946         other->active_tc.ACX[sel] = arg1;
1947     else
1948         other->tcs[other_tc].ACX[sel] = arg1;
1949 }
1950 
helper_mttdsp(CPUMIPSState * env,target_ulong arg1)1951 void helper_mttdsp(CPUMIPSState *env, target_ulong arg1)
1952 {
1953     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1954     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1955 
1956     if (other_tc == other->current_tc)
1957         other->active_tc.DSPControl = arg1;
1958     else
1959         other->tcs[other_tc].DSPControl = arg1;
1960 }
1961 
1962 /* MIPS MT functions */
helper_dmt(void)1963 target_ulong helper_dmt(void)
1964 {
1965     // TODO
1966      return 0;
1967 }
1968 
helper_emt(void)1969 target_ulong helper_emt(void)
1970 {
1971     // TODO
1972     return 0;
1973 }
1974 
helper_dvpe(CPUMIPSState * env)1975 target_ulong helper_dvpe(CPUMIPSState *env)
1976 {
1977     CPUState *other_cs = first_cpu;
1978     target_ulong prev = env->mvp->CP0_MVPControl;
1979 
1980     CPU_FOREACH(other_cs) {
1981         MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1982         /* Turn off all VPEs except the one executing the dvpe.  */
1983         if (&other_cpu->env != env) {
1984             other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
1985             mips_vpe_sleep(other_cpu);
1986         }
1987     }
1988     return prev;
1989 }
1990 
helper_evpe(CPUMIPSState * env)1991 target_ulong helper_evpe(CPUMIPSState *env)
1992 {
1993     CPUState *other_cs = first_cpu;
1994     target_ulong prev = env->mvp->CP0_MVPControl;
1995 
1996     CPU_FOREACH(other_cs) {
1997         MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1998 
1999         if (&other_cpu->env != env
2000             /* If the VPE is WFI, don't disturb its sleep.  */
2001             && !mips_vpe_is_wfi(other_cpu)) {
2002             /* Enable the VPE.  */
2003             other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
2004             mips_vpe_wake(other_cpu); /* And wake it up.  */
2005         }
2006     }
2007     return prev;
2008 }
2009 #endif /* !CONFIG_USER_ONLY */
2010 
helper_fork(target_ulong arg1,target_ulong arg2)2011 void helper_fork(target_ulong arg1, target_ulong arg2)
2012 {
2013     // arg1 = rt, arg2 = rs
2014     // TODO: store to TC register
2015 }
2016 
helper_yield(CPUMIPSState * env,target_ulong arg)2017 target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
2018 {
2019     target_long arg1 = arg;
2020 
2021     if (arg1 < 0) {
2022         /* No scheduling policy implemented. */
2023         if (arg1 != -2) {
2024             if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
2025                 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
2026                 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
2027                 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
2028                 do_raise_exception(env, EXCP_THREAD, GETPC());
2029             }
2030         }
2031     } else if (arg1 == 0) {
2032         if (0 /* TODO: TC underflow */) {
2033             env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
2034             do_raise_exception(env, EXCP_THREAD, GETPC());
2035         } else {
2036             // TODO: Deallocate TC
2037         }
2038     } else if (arg1 > 0) {
2039         /* Yield qualifier inputs not implemented. */
2040         env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
2041         env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
2042         do_raise_exception(env, EXCP_THREAD, GETPC());
2043     }
2044     return env->CP0_YQMask;
2045 }
2046 
2047 /* R6 Multi-threading */
2048 #ifndef CONFIG_USER_ONLY
helper_dvp(CPUMIPSState * env)2049 target_ulong helper_dvp(CPUMIPSState *env)
2050 {
2051     CPUState *other_cs = first_cpu;
2052     target_ulong prev = env->CP0_VPControl;
2053 
2054     if (!((env->CP0_VPControl >> CP0VPCtl_DIS) & 1)) {
2055         CPU_FOREACH(other_cs) {
2056             MIPSCPU *other_cpu = MIPS_CPU(other_cs);
2057             /* Turn off all VPs except the one executing the dvp. */
2058             if (&other_cpu->env != env) {
2059                 mips_vpe_sleep(other_cpu);
2060             }
2061         }
2062         env->CP0_VPControl |= (1 << CP0VPCtl_DIS);
2063     }
2064     return prev;
2065 }
2066 
helper_evp(CPUMIPSState * env)2067 target_ulong helper_evp(CPUMIPSState *env)
2068 {
2069     CPUState *other_cs = first_cpu;
2070     target_ulong prev = env->CP0_VPControl;
2071 
2072     if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) {
2073         CPU_FOREACH(other_cs) {
2074             MIPSCPU *other_cpu = MIPS_CPU(other_cs);
2075             if ((&other_cpu->env != env) && !mips_vp_is_wfi(other_cpu)) {
2076                 /* If the VP is WFI, don't disturb its sleep.
2077                  * Otherwise, wake it up. */
2078                 mips_vpe_wake(other_cpu);
2079             }
2080         }
2081         env->CP0_VPControl &= ~(1 << CP0VPCtl_DIS);
2082     }
2083     return prev;
2084 }
2085 #endif /* !CONFIG_USER_ONLY */
2086 
2087 #ifndef CONFIG_USER_ONLY
2088 /* TLB management */
r4k_mips_tlb_flush_extra(CPUMIPSState * env,int first)2089 static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
2090 {
2091     /* Discard entries from env->tlb[first] onwards.  */
2092     while (env->tlb->tlb_in_use > first) {
2093         r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
2094     }
2095 }
2096 
get_tlb_pfn_from_entrylo(uint64_t entrylo)2097 static inline uint64_t get_tlb_pfn_from_entrylo(uint64_t entrylo)
2098 {
2099 #if defined(TARGET_MIPS64)
2100     return extract64(entrylo, 6, 54);
2101 #else
2102     return extract64(entrylo, 6, 24) | /* PFN */
2103            (extract64(entrylo, 32, 32) << 24); /* PFNX */
2104 #endif
2105 }
2106 
r4k_fill_tlb(CPUMIPSState * env,int idx)2107 static void r4k_fill_tlb(CPUMIPSState *env, int idx)
2108 {
2109     r4k_tlb_t *tlb;
2110     uint64_t mask = env->CP0_PageMask >> (TARGET_PAGE_BITS + 1);
2111 
2112     /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
2113     tlb = &env->tlb->mmu.r4k.tlb[idx];
2114     if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) {
2115         tlb->EHINV = 1;
2116         return;
2117     }
2118     tlb->EHINV = 0;
2119     tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
2120 #if defined(TARGET_MIPS64)
2121     tlb->VPN &= env->SEGMask;
2122 #endif
2123     tlb->ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2124     tlb->PageMask = env->CP0_PageMask;
2125     tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
2126     tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
2127     tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
2128     tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
2129     tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1;
2130     tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1;
2131     tlb->PFN[0] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) & ~mask) << 12;
2132     tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
2133     tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
2134     tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
2135     tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1;
2136     tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1;
2137     tlb->PFN[1] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) & ~mask) << 12;
2138 }
2139 
r4k_helper_tlbinv(CPUMIPSState * env)2140 void r4k_helper_tlbinv(CPUMIPSState *env)
2141 {
2142     int idx;
2143     r4k_tlb_t *tlb;
2144     uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2145 
2146     for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
2147         tlb = &env->tlb->mmu.r4k.tlb[idx];
2148         if (!tlb->G && tlb->ASID == ASID) {
2149             tlb->EHINV = 1;
2150         }
2151     }
2152     cpu_mips_tlb_flush(env);
2153 }
2154 
r4k_helper_tlbinvf(CPUMIPSState * env)2155 void r4k_helper_tlbinvf(CPUMIPSState *env)
2156 {
2157     int idx;
2158 
2159     for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
2160         env->tlb->mmu.r4k.tlb[idx].EHINV = 1;
2161     }
2162     cpu_mips_tlb_flush(env);
2163 }
2164 
r4k_helper_tlbwi(CPUMIPSState * env)2165 void r4k_helper_tlbwi(CPUMIPSState *env)
2166 {
2167     r4k_tlb_t *tlb;
2168     int idx;
2169     target_ulong VPN;
2170     uint16_t ASID;
2171     bool EHINV, G, V0, D0, V1, D1, XI0, XI1, RI0, RI1;
2172 
2173     idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
2174     tlb = &env->tlb->mmu.r4k.tlb[idx];
2175     VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
2176 #if defined(TARGET_MIPS64)
2177     VPN &= env->SEGMask;
2178 #endif
2179     ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2180     EHINV = (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) != 0;
2181     G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
2182     V0 = (env->CP0_EntryLo0 & 2) != 0;
2183     D0 = (env->CP0_EntryLo0 & 4) != 0;
2184     XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) &1;
2185     RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) &1;
2186     V1 = (env->CP0_EntryLo1 & 2) != 0;
2187     D1 = (env->CP0_EntryLo1 & 4) != 0;
2188     XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) &1;
2189     RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) &1;
2190 
2191     /* Discard cached TLB entries, unless tlbwi is just upgrading access
2192        permissions on the current entry. */
2193     if (tlb->VPN != VPN || tlb->ASID != ASID || tlb->G != G ||
2194         (!tlb->EHINV && EHINV) ||
2195         (tlb->V0 && !V0) || (tlb->D0 && !D0) ||
2196         (!tlb->XI0 && XI0) || (!tlb->RI0 && RI0) ||
2197         (tlb->V1 && !V1) || (tlb->D1 && !D1) ||
2198         (!tlb->XI1 && XI1) || (!tlb->RI1 && RI1)) {
2199         r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
2200     }
2201 
2202     r4k_invalidate_tlb(env, idx, 0);
2203     r4k_fill_tlb(env, idx);
2204 }
2205 
r4k_helper_tlbwr(CPUMIPSState * env)2206 void r4k_helper_tlbwr(CPUMIPSState *env)
2207 {
2208     int r = cpu_mips_get_random(env);
2209 
2210     r4k_invalidate_tlb(env, r, 1);
2211     r4k_fill_tlb(env, r);
2212 }
2213 
r4k_helper_tlbp(CPUMIPSState * env)2214 void r4k_helper_tlbp(CPUMIPSState *env)
2215 {
2216     r4k_tlb_t *tlb;
2217     target_ulong mask;
2218     target_ulong tag;
2219     target_ulong VPN;
2220     uint16_t ASID;
2221     int i;
2222 
2223     ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2224     for (i = 0; i < env->tlb->nb_tlb; i++) {
2225         tlb = &env->tlb->mmu.r4k.tlb[i];
2226         /* 1k pages are not supported. */
2227         mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
2228         tag = env->CP0_EntryHi & ~mask;
2229         VPN = tlb->VPN & ~mask;
2230 #if defined(TARGET_MIPS64)
2231         tag &= env->SEGMask;
2232 #endif
2233         /* Check ASID, virtual page number & size */
2234         if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) {
2235             /* TLB match */
2236             env->CP0_Index = i;
2237             break;
2238         }
2239     }
2240     if (i == env->tlb->nb_tlb) {
2241         /* No match.  Discard any shadow entries, if any of them match.  */
2242         for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
2243             tlb = &env->tlb->mmu.r4k.tlb[i];
2244             /* 1k pages are not supported. */
2245             mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
2246             tag = env->CP0_EntryHi & ~mask;
2247             VPN = tlb->VPN & ~mask;
2248 #if defined(TARGET_MIPS64)
2249             tag &= env->SEGMask;
2250 #endif
2251             /* Check ASID, virtual page number & size */
2252             if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
2253                 r4k_mips_tlb_flush_extra (env, i);
2254                 break;
2255             }
2256         }
2257 
2258         env->CP0_Index |= 0x80000000;
2259     }
2260 }
2261 
get_entrylo_pfn_from_tlb(uint64_t tlb_pfn)2262 static inline uint64_t get_entrylo_pfn_from_tlb(uint64_t tlb_pfn)
2263 {
2264 #if defined(TARGET_MIPS64)
2265     return tlb_pfn << 6;
2266 #else
2267     return (extract64(tlb_pfn, 0, 24) << 6) | /* PFN */
2268            (extract64(tlb_pfn, 24, 32) << 32); /* PFNX */
2269 #endif
2270 }
2271 
r4k_helper_tlbr(CPUMIPSState * env)2272 void r4k_helper_tlbr(CPUMIPSState *env)
2273 {
2274     r4k_tlb_t *tlb;
2275     uint16_t ASID;
2276     int idx;
2277 
2278     ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2279     idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
2280     tlb = &env->tlb->mmu.r4k.tlb[idx];
2281 
2282     /* If this will change the current ASID, flush qemu's TLB.  */
2283     if (ASID != tlb->ASID)
2284         cpu_mips_tlb_flush(env);
2285 
2286     r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
2287 
2288     if (tlb->EHINV) {
2289         env->CP0_EntryHi = 1 << CP0EnHi_EHINV;
2290         env->CP0_PageMask = 0;
2291         env->CP0_EntryLo0 = 0;
2292         env->CP0_EntryLo1 = 0;
2293     } else {
2294         env->CP0_EntryHi = tlb->VPN | tlb->ASID;
2295         env->CP0_PageMask = tlb->PageMask;
2296         env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
2297                         ((uint64_t)tlb->RI0 << CP0EnLo_RI) |
2298                         ((uint64_t)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) |
2299                         get_entrylo_pfn_from_tlb(tlb->PFN[0] >> 12);
2300         env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
2301                         ((uint64_t)tlb->RI1 << CP0EnLo_RI) |
2302                         ((uint64_t)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) |
2303                         get_entrylo_pfn_from_tlb(tlb->PFN[1] >> 12);
2304     }
2305 }
2306 
helper_tlbwi(CPUMIPSState * env)2307 void helper_tlbwi(CPUMIPSState *env)
2308 {
2309     env->tlb->helper_tlbwi(env);
2310 }
2311 
helper_tlbwr(CPUMIPSState * env)2312 void helper_tlbwr(CPUMIPSState *env)
2313 {
2314     env->tlb->helper_tlbwr(env);
2315 }
2316 
helper_tlbp(CPUMIPSState * env)2317 void helper_tlbp(CPUMIPSState *env)
2318 {
2319     env->tlb->helper_tlbp(env);
2320 }
2321 
helper_tlbr(CPUMIPSState * env)2322 void helper_tlbr(CPUMIPSState *env)
2323 {
2324     env->tlb->helper_tlbr(env);
2325 }
2326 
helper_tlbinv(CPUMIPSState * env)2327 void helper_tlbinv(CPUMIPSState *env)
2328 {
2329     env->tlb->helper_tlbinv(env);
2330 }
2331 
helper_tlbinvf(CPUMIPSState * env)2332 void helper_tlbinvf(CPUMIPSState *env)
2333 {
2334     env->tlb->helper_tlbinvf(env);
2335 }
2336 
2337 /* Specials */
helper_di(CPUMIPSState * env)2338 target_ulong helper_di(CPUMIPSState *env)
2339 {
2340     target_ulong t0 = env->CP0_Status;
2341 
2342     env->CP0_Status = t0 & ~(1 << CP0St_IE);
2343     return t0;
2344 }
2345 
helper_ei(CPUMIPSState * env)2346 target_ulong helper_ei(CPUMIPSState *env)
2347 {
2348     target_ulong t0 = env->CP0_Status;
2349 
2350     env->CP0_Status = t0 | (1 << CP0St_IE);
2351     return t0;
2352 }
2353 
debug_pre_eret(CPUMIPSState * env)2354 static void debug_pre_eret(CPUMIPSState *env)
2355 {
2356     if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2357         qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2358                 env->active_tc.PC, env->CP0_EPC);
2359         if (env->CP0_Status & (1 << CP0St_ERL))
2360             qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2361         if (env->hflags & MIPS_HFLAG_DM)
2362             qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2363         qemu_log("\n");
2364     }
2365 }
2366 
debug_post_eret(CPUMIPSState * env)2367 static void debug_post_eret(CPUMIPSState *env)
2368 {
2369     MIPSCPU *cpu = mips_env_get_cpu(env);
2370 
2371     if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2372         qemu_log("  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2373                 env->active_tc.PC, env->CP0_EPC);
2374         if (env->CP0_Status & (1 << CP0St_ERL))
2375             qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2376         if (env->hflags & MIPS_HFLAG_DM)
2377             qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2378         switch (cpu_mmu_index(env, false)) {
2379         case 3:
2380             qemu_log(", ERL\n");
2381             break;
2382         case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
2383         case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
2384         case MIPS_HFLAG_KM: qemu_log("\n"); break;
2385         default:
2386             cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
2387             break;
2388         }
2389     }
2390 }
2391 
set_pc(CPUMIPSState * env,target_ulong error_pc)2392 static void set_pc(CPUMIPSState *env, target_ulong error_pc)
2393 {
2394     env->active_tc.PC = error_pc & ~(target_ulong)1;
2395     if (error_pc & 1) {
2396         env->hflags |= MIPS_HFLAG_M16;
2397     } else {
2398         env->hflags &= ~(MIPS_HFLAG_M16);
2399     }
2400 }
2401 
exception_return(CPUMIPSState * env)2402 static inline void exception_return(CPUMIPSState *env)
2403 {
2404     debug_pre_eret(env);
2405     if (env->CP0_Status & (1 << CP0St_ERL)) {
2406         set_pc(env, env->CP0_ErrorEPC);
2407         env->CP0_Status &= ~(1 << CP0St_ERL);
2408     } else {
2409         set_pc(env, env->CP0_EPC);
2410         env->CP0_Status &= ~(1 << CP0St_EXL);
2411     }
2412     compute_hflags(env);
2413     debug_post_eret(env);
2414 }
2415 
helper_eret(CPUMIPSState * env)2416 void helper_eret(CPUMIPSState *env)
2417 {
2418     exception_return(env);
2419     env->lladdr = 1;
2420 }
2421 
helper_eretnc(CPUMIPSState * env)2422 void helper_eretnc(CPUMIPSState *env)
2423 {
2424     exception_return(env);
2425 }
2426 
helper_deret(CPUMIPSState * env)2427 void helper_deret(CPUMIPSState *env)
2428 {
2429     debug_pre_eret(env);
2430 
2431     env->hflags &= ~MIPS_HFLAG_DM;
2432     compute_hflags(env);
2433 
2434     set_pc(env, env->CP0_DEPC);
2435 
2436     debug_post_eret(env);
2437 }
2438 #endif /* !CONFIG_USER_ONLY */
2439 
check_hwrena(CPUMIPSState * env,int reg,uintptr_t pc)2440 static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc)
2441 {
2442     if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) {
2443         return;
2444     }
2445     do_raise_exception(env, EXCP_RI, pc);
2446 }
2447 
helper_rdhwr_cpunum(CPUMIPSState * env)2448 target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
2449 {
2450     check_hwrena(env, 0, GETPC());
2451     return env->CP0_EBase & 0x3ff;
2452 }
2453 
helper_rdhwr_synci_step(CPUMIPSState * env)2454 target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
2455 {
2456     check_hwrena(env, 1, GETPC());
2457     return env->SYNCI_Step;
2458 }
2459 
helper_rdhwr_cc(CPUMIPSState * env)2460 target_ulong helper_rdhwr_cc(CPUMIPSState *env)
2461 {
2462     int32_t count;
2463     check_hwrena(env, 2, GETPC());
2464 #ifdef CONFIG_USER_ONLY
2465     count = env->CP0_Count;
2466 #else
2467     qemu_mutex_lock_iothread();
2468     count = (int32_t)cpu_mips_get_count(env);
2469     qemu_mutex_unlock_iothread();
2470 #endif
2471     return count;
2472 }
2473 
helper_rdhwr_ccres(CPUMIPSState * env)2474 target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
2475 {
2476     check_hwrena(env, 3, GETPC());
2477     return env->CCRes;
2478 }
2479 
helper_rdhwr_performance(CPUMIPSState * env)2480 target_ulong helper_rdhwr_performance(CPUMIPSState *env)
2481 {
2482     check_hwrena(env, 4, GETPC());
2483     return env->CP0_Performance0;
2484 }
2485 
helper_rdhwr_xnp(CPUMIPSState * env)2486 target_ulong helper_rdhwr_xnp(CPUMIPSState *env)
2487 {
2488     check_hwrena(env, 5, GETPC());
2489     return (env->CP0_Config5 >> CP0C5_XNP) & 1;
2490 }
2491 
helper_pmon(CPUMIPSState * env,int function)2492 void helper_pmon(CPUMIPSState *env, int function)
2493 {
2494     function /= 2;
2495     switch (function) {
2496     case 2: /* TODO: char inbyte(int waitflag); */
2497         if (env->active_tc.gpr[4] == 0)
2498             env->active_tc.gpr[2] = -1;
2499         /* Fall through */
2500     case 11: /* TODO: char inbyte (void); */
2501         env->active_tc.gpr[2] = -1;
2502         break;
2503     case 3:
2504     case 12:
2505         printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
2506         break;
2507     case 17:
2508         break;
2509     case 158:
2510         {
2511             unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
2512             printf("%s", fmt);
2513         }
2514         break;
2515     }
2516 }
2517 
helper_wait(CPUMIPSState * env)2518 void helper_wait(CPUMIPSState *env)
2519 {
2520     CPUState *cs = CPU(mips_env_get_cpu(env));
2521 
2522     cs->halted = 1;
2523     cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
2524     /* Last instruction in the block, PC was updated before
2525        - no need to recover PC and icount */
2526     raise_exception(env, EXCP_HLT);
2527 }
2528 
2529 #if !defined(CONFIG_USER_ONLY)
2530 
mips_cpu_do_unaligned_access(CPUState * cs,vaddr addr,MMUAccessType access_type,int mmu_idx,uintptr_t retaddr)2531 void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
2532                                   MMUAccessType access_type,
2533                                   int mmu_idx, uintptr_t retaddr)
2534 {
2535     MIPSCPU *cpu = MIPS_CPU(cs);
2536     CPUMIPSState *env = &cpu->env;
2537     int error_code = 0;
2538     int excp;
2539 
2540     if (!(env->hflags & MIPS_HFLAG_DM)) {
2541         env->CP0_BadVAddr = addr;
2542     }
2543 
2544     if (access_type == MMU_DATA_STORE) {
2545         excp = EXCP_AdES;
2546     } else {
2547         excp = EXCP_AdEL;
2548         if (access_type == MMU_INST_FETCH) {
2549             error_code |= EXCP_INST_NOTAVAIL;
2550         }
2551     }
2552 
2553     do_raise_exception_err(env, excp, error_code, retaddr);
2554 }
2555 
tlb_fill(CPUState * cs,target_ulong addr,int size,MMUAccessType access_type,int mmu_idx,uintptr_t retaddr)2556 void tlb_fill(CPUState *cs, target_ulong addr, int size,
2557               MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
2558 {
2559     int ret;
2560 
2561     ret = mips_cpu_handle_mmu_fault(cs, addr, size, access_type, mmu_idx);
2562     if (ret) {
2563         MIPSCPU *cpu = MIPS_CPU(cs);
2564         CPUMIPSState *env = &cpu->env;
2565 
2566         do_raise_exception_err(env, cs->exception_index,
2567                                env->error_code, retaddr);
2568     }
2569 }
2570 
mips_cpu_unassigned_access(CPUState * cs,hwaddr addr,bool is_write,bool is_exec,int unused,unsigned size)2571 void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
2572                                 bool is_write, bool is_exec, int unused,
2573                                 unsigned size)
2574 {
2575     MIPSCPU *cpu = MIPS_CPU(cs);
2576     CPUMIPSState *env = &cpu->env;
2577 
2578     /*
2579      * Raising an exception with KVM enabled will crash because it won't be from
2580      * the main execution loop so the longjmp won't have a matching setjmp.
2581      * Until we can trigger a bus error exception through KVM lets just ignore
2582      * the access.
2583      */
2584     if (kvm_enabled()) {
2585         return;
2586     }
2587 
2588     if (is_exec) {
2589         raise_exception(env, EXCP_IBE);
2590     } else {
2591         raise_exception(env, EXCP_DBE);
2592     }
2593 }
2594 #endif /* !CONFIG_USER_ONLY */
2595 
2596 /* Complex FPU operations which may need stack space. */
2597 
2598 #define FLOAT_TWO32 make_float32(1 << 30)
2599 #define FLOAT_TWO64 make_float64(1ULL << 62)
2600 
2601 #define FP_TO_INT32_OVERFLOW 0x7fffffff
2602 #define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
2603 
2604 /* convert MIPS rounding mode in FCR31 to IEEE library */
2605 unsigned int ieee_rm[] = {
2606     float_round_nearest_even,
2607     float_round_to_zero,
2608     float_round_up,
2609     float_round_down
2610 };
2611 
helper_cfc1(CPUMIPSState * env,uint32_t reg)2612 target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
2613 {
2614     target_ulong arg1 = 0;
2615 
2616     switch (reg) {
2617     case 0:
2618         arg1 = (int32_t)env->active_fpu.fcr0;
2619         break;
2620     case 1:
2621         /* UFR Support - Read Status FR */
2622         if (env->active_fpu.fcr0 & (1 << FCR0_UFRP)) {
2623             if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2624                 arg1 = (int32_t)
2625                        ((env->CP0_Status & (1  << CP0St_FR)) >> CP0St_FR);
2626             } else {
2627                 do_raise_exception(env, EXCP_RI, GETPC());
2628             }
2629         }
2630         break;
2631     case 5:
2632         /* FRE Support - read Config5.FRE bit */
2633         if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
2634             if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2635                 arg1 = (env->CP0_Config5 >> CP0C5_FRE) & 1;
2636             } else {
2637                 helper_raise_exception(env, EXCP_RI);
2638             }
2639         }
2640         break;
2641     case 25:
2642         arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
2643         break;
2644     case 26:
2645         arg1 = env->active_fpu.fcr31 & 0x0003f07c;
2646         break;
2647     case 28:
2648         arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
2649         break;
2650     default:
2651         arg1 = (int32_t)env->active_fpu.fcr31;
2652         break;
2653     }
2654 
2655     return arg1;
2656 }
2657 
helper_ctc1(CPUMIPSState * env,target_ulong arg1,uint32_t fs,uint32_t rt)2658 void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
2659 {
2660     switch (fs) {
2661     case 1:
2662         /* UFR Alias - Reset Status FR */
2663         if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2664             return;
2665         }
2666         if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2667             env->CP0_Status &= ~(1 << CP0St_FR);
2668             compute_hflags(env);
2669         } else {
2670             do_raise_exception(env, EXCP_RI, GETPC());
2671         }
2672         break;
2673     case 4:
2674         /* UNFR Alias - Set Status FR */
2675         if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2676             return;
2677         }
2678         if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2679             env->CP0_Status |= (1 << CP0St_FR);
2680             compute_hflags(env);
2681         } else {
2682             do_raise_exception(env, EXCP_RI, GETPC());
2683         }
2684         break;
2685     case 5:
2686         /* FRE Support - clear Config5.FRE bit */
2687         if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
2688             return;
2689         }
2690         if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2691             env->CP0_Config5 &= ~(1 << CP0C5_FRE);
2692             compute_hflags(env);
2693         } else {
2694             helper_raise_exception(env, EXCP_RI);
2695         }
2696         break;
2697     case 6:
2698         /* FRE Support - set Config5.FRE bit */
2699         if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
2700             return;
2701         }
2702         if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2703             env->CP0_Config5 |= (1 << CP0C5_FRE);
2704             compute_hflags(env);
2705         } else {
2706             helper_raise_exception(env, EXCP_RI);
2707         }
2708         break;
2709     case 25:
2710         if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) {
2711             return;
2712         }
2713         env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
2714                      ((arg1 & 0x1) << 23);
2715         break;
2716     case 26:
2717         if (arg1 & 0x007c0000)
2718             return;
2719         env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
2720         break;
2721     case 28:
2722         if (arg1 & 0x007c0000)
2723             return;
2724         env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
2725                      ((arg1 & 0x4) << 22);
2726         break;
2727     case 31:
2728         env->active_fpu.fcr31 = (arg1 & env->active_fpu.fcr31_rw_bitmask) |
2729                (env->active_fpu.fcr31 & ~(env->active_fpu.fcr31_rw_bitmask));
2730         break;
2731     default:
2732         if (env->insn_flags & ISA_MIPS32R6) {
2733             do_raise_exception(env, EXCP_RI, GETPC());
2734         }
2735         return;
2736     }
2737     restore_fp_status(env);
2738     set_float_exception_flags(0, &env->active_fpu.fp_status);
2739     if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
2740         do_raise_exception(env, EXCP_FPE, GETPC());
2741 }
2742 
ieee_ex_to_mips(int xcpt)2743 int ieee_ex_to_mips(int xcpt)
2744 {
2745     int ret = 0;
2746     if (xcpt) {
2747         if (xcpt & float_flag_invalid) {
2748             ret |= FP_INVALID;
2749         }
2750         if (xcpt & float_flag_overflow) {
2751             ret |= FP_OVERFLOW;
2752         }
2753         if (xcpt & float_flag_underflow) {
2754             ret |= FP_UNDERFLOW;
2755         }
2756         if (xcpt & float_flag_divbyzero) {
2757             ret |= FP_DIV0;
2758         }
2759         if (xcpt & float_flag_inexact) {
2760             ret |= FP_INEXACT;
2761         }
2762     }
2763     return ret;
2764 }
2765 
update_fcr31(CPUMIPSState * env,uintptr_t pc)2766 static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
2767 {
2768     int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
2769 
2770     SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
2771 
2772     if (tmp) {
2773         set_float_exception_flags(0, &env->active_fpu.fp_status);
2774 
2775         if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
2776             do_raise_exception(env, EXCP_FPE, pc);
2777         } else {
2778             UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2779         }
2780     }
2781 }
2782 
2783 /* Float support.
2784    Single precition routines have a "s" suffix, double precision a
2785    "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2786    paired single lower "pl", paired single upper "pu".  */
2787 
2788 /* unary operations, modifying fp status  */
helper_float_sqrt_d(CPUMIPSState * env,uint64_t fdt0)2789 uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
2790 {
2791     fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2792     update_fcr31(env, GETPC());
2793     return fdt0;
2794 }
2795 
helper_float_sqrt_s(CPUMIPSState * env,uint32_t fst0)2796 uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
2797 {
2798     fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2799     update_fcr31(env, GETPC());
2800     return fst0;
2801 }
2802 
helper_float_cvtd_s(CPUMIPSState * env,uint32_t fst0)2803 uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
2804 {
2805     uint64_t fdt2;
2806 
2807     fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
2808     update_fcr31(env, GETPC());
2809     return fdt2;
2810 }
2811 
helper_float_cvtd_w(CPUMIPSState * env,uint32_t wt0)2812 uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
2813 {
2814     uint64_t fdt2;
2815 
2816     fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2817     update_fcr31(env, GETPC());
2818     return fdt2;
2819 }
2820 
helper_float_cvtd_l(CPUMIPSState * env,uint64_t dt0)2821 uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
2822 {
2823     uint64_t fdt2;
2824 
2825     fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2826     update_fcr31(env, GETPC());
2827     return fdt2;
2828 }
2829 
helper_float_cvt_l_d(CPUMIPSState * env,uint64_t fdt0)2830 uint64_t helper_float_cvt_l_d(CPUMIPSState *env, uint64_t fdt0)
2831 {
2832     uint64_t dt2;
2833 
2834     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2835     if (get_float_exception_flags(&env->active_fpu.fp_status)
2836         & (float_flag_invalid | float_flag_overflow)) {
2837         dt2 = FP_TO_INT64_OVERFLOW;
2838     }
2839     update_fcr31(env, GETPC());
2840     return dt2;
2841 }
2842 
helper_float_cvt_l_s(CPUMIPSState * env,uint32_t fst0)2843 uint64_t helper_float_cvt_l_s(CPUMIPSState *env, uint32_t fst0)
2844 {
2845     uint64_t dt2;
2846 
2847     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2848     if (get_float_exception_flags(&env->active_fpu.fp_status)
2849         & (float_flag_invalid | float_flag_overflow)) {
2850         dt2 = FP_TO_INT64_OVERFLOW;
2851     }
2852     update_fcr31(env, GETPC());
2853     return dt2;
2854 }
2855 
helper_float_cvtps_pw(CPUMIPSState * env,uint64_t dt0)2856 uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
2857 {
2858     uint32_t fst2;
2859     uint32_t fsth2;
2860 
2861     fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2862     fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
2863     update_fcr31(env, GETPC());
2864     return ((uint64_t)fsth2 << 32) | fst2;
2865 }
2866 
helper_float_cvtpw_ps(CPUMIPSState * env,uint64_t fdt0)2867 uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0)
2868 {
2869     uint32_t wt2;
2870     uint32_t wth2;
2871     int excp, excph;
2872 
2873     wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2874     excp = get_float_exception_flags(&env->active_fpu.fp_status);
2875     if (excp & (float_flag_overflow | float_flag_invalid)) {
2876         wt2 = FP_TO_INT32_OVERFLOW;
2877     }
2878 
2879     set_float_exception_flags(0, &env->active_fpu.fp_status);
2880     wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2881     excph = get_float_exception_flags(&env->active_fpu.fp_status);
2882     if (excph & (float_flag_overflow | float_flag_invalid)) {
2883         wth2 = FP_TO_INT32_OVERFLOW;
2884     }
2885 
2886     set_float_exception_flags(excp | excph, &env->active_fpu.fp_status);
2887     update_fcr31(env, GETPC());
2888 
2889     return ((uint64_t)wth2 << 32) | wt2;
2890 }
2891 
helper_float_cvts_d(CPUMIPSState * env,uint64_t fdt0)2892 uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
2893 {
2894     uint32_t fst2;
2895 
2896     fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
2897     update_fcr31(env, GETPC());
2898     return fst2;
2899 }
2900 
helper_float_cvts_w(CPUMIPSState * env,uint32_t wt0)2901 uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
2902 {
2903     uint32_t fst2;
2904 
2905     fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
2906     update_fcr31(env, GETPC());
2907     return fst2;
2908 }
2909 
helper_float_cvts_l(CPUMIPSState * env,uint64_t dt0)2910 uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
2911 {
2912     uint32_t fst2;
2913 
2914     fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
2915     update_fcr31(env, GETPC());
2916     return fst2;
2917 }
2918 
helper_float_cvts_pl(CPUMIPSState * env,uint32_t wt0)2919 uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
2920 {
2921     uint32_t wt2;
2922 
2923     wt2 = wt0;
2924     update_fcr31(env, GETPC());
2925     return wt2;
2926 }
2927 
helper_float_cvts_pu(CPUMIPSState * env,uint32_t wth0)2928 uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
2929 {
2930     uint32_t wt2;
2931 
2932     wt2 = wth0;
2933     update_fcr31(env, GETPC());
2934     return wt2;
2935 }
2936 
helper_float_cvt_w_s(CPUMIPSState * env,uint32_t fst0)2937 uint32_t helper_float_cvt_w_s(CPUMIPSState *env, uint32_t fst0)
2938 {
2939     uint32_t wt2;
2940 
2941     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2942     if (get_float_exception_flags(&env->active_fpu.fp_status)
2943         & (float_flag_invalid | float_flag_overflow)) {
2944         wt2 = FP_TO_INT32_OVERFLOW;
2945     }
2946     update_fcr31(env, GETPC());
2947     return wt2;
2948 }
2949 
helper_float_cvt_w_d(CPUMIPSState * env,uint64_t fdt0)2950 uint32_t helper_float_cvt_w_d(CPUMIPSState *env, uint64_t fdt0)
2951 {
2952     uint32_t wt2;
2953 
2954     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2955     if (get_float_exception_flags(&env->active_fpu.fp_status)
2956         & (float_flag_invalid | float_flag_overflow)) {
2957         wt2 = FP_TO_INT32_OVERFLOW;
2958     }
2959     update_fcr31(env, GETPC());
2960     return wt2;
2961 }
2962 
helper_float_round_l_d(CPUMIPSState * env,uint64_t fdt0)2963 uint64_t helper_float_round_l_d(CPUMIPSState *env, uint64_t fdt0)
2964 {
2965     uint64_t dt2;
2966 
2967     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2968     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2969     restore_rounding_mode(env);
2970     if (get_float_exception_flags(&env->active_fpu.fp_status)
2971         & (float_flag_invalid | float_flag_overflow)) {
2972         dt2 = FP_TO_INT64_OVERFLOW;
2973     }
2974     update_fcr31(env, GETPC());
2975     return dt2;
2976 }
2977 
helper_float_round_l_s(CPUMIPSState * env,uint32_t fst0)2978 uint64_t helper_float_round_l_s(CPUMIPSState *env, uint32_t fst0)
2979 {
2980     uint64_t dt2;
2981 
2982     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2983     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2984     restore_rounding_mode(env);
2985     if (get_float_exception_flags(&env->active_fpu.fp_status)
2986         & (float_flag_invalid | float_flag_overflow)) {
2987         dt2 = FP_TO_INT64_OVERFLOW;
2988     }
2989     update_fcr31(env, GETPC());
2990     return dt2;
2991 }
2992 
helper_float_round_w_d(CPUMIPSState * env,uint64_t fdt0)2993 uint32_t helper_float_round_w_d(CPUMIPSState *env, uint64_t fdt0)
2994 {
2995     uint32_t wt2;
2996 
2997     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2998     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2999     restore_rounding_mode(env);
3000     if (get_float_exception_flags(&env->active_fpu.fp_status)
3001         & (float_flag_invalid | float_flag_overflow)) {
3002         wt2 = FP_TO_INT32_OVERFLOW;
3003     }
3004     update_fcr31(env, GETPC());
3005     return wt2;
3006 }
3007 
helper_float_round_w_s(CPUMIPSState * env,uint32_t fst0)3008 uint32_t helper_float_round_w_s(CPUMIPSState *env, uint32_t fst0)
3009 {
3010     uint32_t wt2;
3011 
3012     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
3013     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3014     restore_rounding_mode(env);
3015     if (get_float_exception_flags(&env->active_fpu.fp_status)
3016         & (float_flag_invalid | float_flag_overflow)) {
3017         wt2 = FP_TO_INT32_OVERFLOW;
3018     }
3019     update_fcr31(env, GETPC());
3020     return wt2;
3021 }
3022 
helper_float_trunc_l_d(CPUMIPSState * env,uint64_t fdt0)3023 uint64_t helper_float_trunc_l_d(CPUMIPSState *env, uint64_t fdt0)
3024 {
3025     uint64_t dt2;
3026 
3027     dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
3028     if (get_float_exception_flags(&env->active_fpu.fp_status)
3029         & (float_flag_invalid | float_flag_overflow)) {
3030         dt2 = FP_TO_INT64_OVERFLOW;
3031     }
3032     update_fcr31(env, GETPC());
3033     return dt2;
3034 }
3035 
helper_float_trunc_l_s(CPUMIPSState * env,uint32_t fst0)3036 uint64_t helper_float_trunc_l_s(CPUMIPSState *env, uint32_t fst0)
3037 {
3038     uint64_t dt2;
3039 
3040     dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
3041     if (get_float_exception_flags(&env->active_fpu.fp_status)
3042         & (float_flag_invalid | float_flag_overflow)) {
3043         dt2 = FP_TO_INT64_OVERFLOW;
3044     }
3045     update_fcr31(env, GETPC());
3046     return dt2;
3047 }
3048 
helper_float_trunc_w_d(CPUMIPSState * env,uint64_t fdt0)3049 uint32_t helper_float_trunc_w_d(CPUMIPSState *env, uint64_t fdt0)
3050 {
3051     uint32_t wt2;
3052 
3053     wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
3054     if (get_float_exception_flags(&env->active_fpu.fp_status)
3055         & (float_flag_invalid | float_flag_overflow)) {
3056         wt2 = FP_TO_INT32_OVERFLOW;
3057     }
3058     update_fcr31(env, GETPC());
3059     return wt2;
3060 }
3061 
helper_float_trunc_w_s(CPUMIPSState * env,uint32_t fst0)3062 uint32_t helper_float_trunc_w_s(CPUMIPSState *env, uint32_t fst0)
3063 {
3064     uint32_t wt2;
3065 
3066     wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
3067     if (get_float_exception_flags(&env->active_fpu.fp_status)
3068         & (float_flag_invalid | float_flag_overflow)) {
3069         wt2 = FP_TO_INT32_OVERFLOW;
3070     }
3071     update_fcr31(env, GETPC());
3072     return wt2;
3073 }
3074 
helper_float_ceil_l_d(CPUMIPSState * env,uint64_t fdt0)3075 uint64_t helper_float_ceil_l_d(CPUMIPSState *env, uint64_t fdt0)
3076 {
3077     uint64_t dt2;
3078 
3079     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3080     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3081     restore_rounding_mode(env);
3082     if (get_float_exception_flags(&env->active_fpu.fp_status)
3083         & (float_flag_invalid | float_flag_overflow)) {
3084         dt2 = FP_TO_INT64_OVERFLOW;
3085     }
3086     update_fcr31(env, GETPC());
3087     return dt2;
3088 }
3089 
helper_float_ceil_l_s(CPUMIPSState * env,uint32_t fst0)3090 uint64_t helper_float_ceil_l_s(CPUMIPSState *env, uint32_t fst0)
3091 {
3092     uint64_t dt2;
3093 
3094     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3095     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3096     restore_rounding_mode(env);
3097     if (get_float_exception_flags(&env->active_fpu.fp_status)
3098         & (float_flag_invalid | float_flag_overflow)) {
3099         dt2 = FP_TO_INT64_OVERFLOW;
3100     }
3101     update_fcr31(env, GETPC());
3102     return dt2;
3103 }
3104 
helper_float_ceil_w_d(CPUMIPSState * env,uint64_t fdt0)3105 uint32_t helper_float_ceil_w_d(CPUMIPSState *env, uint64_t fdt0)
3106 {
3107     uint32_t wt2;
3108 
3109     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3110     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3111     restore_rounding_mode(env);
3112     if (get_float_exception_flags(&env->active_fpu.fp_status)
3113         & (float_flag_invalid | float_flag_overflow)) {
3114         wt2 = FP_TO_INT32_OVERFLOW;
3115     }
3116     update_fcr31(env, GETPC());
3117     return wt2;
3118 }
3119 
helper_float_ceil_w_s(CPUMIPSState * env,uint32_t fst0)3120 uint32_t helper_float_ceil_w_s(CPUMIPSState *env, uint32_t fst0)
3121 {
3122     uint32_t wt2;
3123 
3124     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3125     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3126     restore_rounding_mode(env);
3127     if (get_float_exception_flags(&env->active_fpu.fp_status)
3128         & (float_flag_invalid | float_flag_overflow)) {
3129         wt2 = FP_TO_INT32_OVERFLOW;
3130     }
3131     update_fcr31(env, GETPC());
3132     return wt2;
3133 }
3134 
helper_float_floor_l_d(CPUMIPSState * env,uint64_t fdt0)3135 uint64_t helper_float_floor_l_d(CPUMIPSState *env, uint64_t fdt0)
3136 {
3137     uint64_t dt2;
3138 
3139     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3140     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3141     restore_rounding_mode(env);
3142     if (get_float_exception_flags(&env->active_fpu.fp_status)
3143         & (float_flag_invalid | float_flag_overflow)) {
3144         dt2 = FP_TO_INT64_OVERFLOW;
3145     }
3146     update_fcr31(env, GETPC());
3147     return dt2;
3148 }
3149 
helper_float_floor_l_s(CPUMIPSState * env,uint32_t fst0)3150 uint64_t helper_float_floor_l_s(CPUMIPSState *env, uint32_t fst0)
3151 {
3152     uint64_t dt2;
3153 
3154     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3155     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3156     restore_rounding_mode(env);
3157     if (get_float_exception_flags(&env->active_fpu.fp_status)
3158         & (float_flag_invalid | float_flag_overflow)) {
3159         dt2 = FP_TO_INT64_OVERFLOW;
3160     }
3161     update_fcr31(env, GETPC());
3162     return dt2;
3163 }
3164 
helper_float_floor_w_d(CPUMIPSState * env,uint64_t fdt0)3165 uint32_t helper_float_floor_w_d(CPUMIPSState *env, uint64_t fdt0)
3166 {
3167     uint32_t wt2;
3168 
3169     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3170     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3171     restore_rounding_mode(env);
3172     if (get_float_exception_flags(&env->active_fpu.fp_status)
3173         & (float_flag_invalid | float_flag_overflow)) {
3174         wt2 = FP_TO_INT32_OVERFLOW;
3175     }
3176     update_fcr31(env, GETPC());
3177     return wt2;
3178 }
3179 
helper_float_floor_w_s(CPUMIPSState * env,uint32_t fst0)3180 uint32_t helper_float_floor_w_s(CPUMIPSState *env, uint32_t fst0)
3181 {
3182     uint32_t wt2;
3183 
3184     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3185     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3186     restore_rounding_mode(env);
3187     if (get_float_exception_flags(&env->active_fpu.fp_status)
3188         & (float_flag_invalid | float_flag_overflow)) {
3189         wt2 = FP_TO_INT32_OVERFLOW;
3190     }
3191     update_fcr31(env, GETPC());
3192     return wt2;
3193 }
3194 
helper_float_cvt_2008_l_d(CPUMIPSState * env,uint64_t fdt0)3195 uint64_t helper_float_cvt_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3196 {
3197     uint64_t dt2;
3198 
3199     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3200     if (get_float_exception_flags(&env->active_fpu.fp_status)
3201             & float_flag_invalid) {
3202         if (float64_is_any_nan(fdt0)) {
3203             dt2 = 0;
3204         }
3205     }
3206     update_fcr31(env, GETPC());
3207     return dt2;
3208 }
3209 
helper_float_cvt_2008_l_s(CPUMIPSState * env,uint32_t fst0)3210 uint64_t helper_float_cvt_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3211 {
3212     uint64_t dt2;
3213 
3214     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3215     if (get_float_exception_flags(&env->active_fpu.fp_status)
3216             & float_flag_invalid) {
3217         if (float32_is_any_nan(fst0)) {
3218             dt2 = 0;
3219         }
3220     }
3221     update_fcr31(env, GETPC());
3222     return dt2;
3223 }
3224 
helper_float_cvt_2008_w_d(CPUMIPSState * env,uint64_t fdt0)3225 uint32_t helper_float_cvt_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3226 {
3227     uint32_t wt2;
3228 
3229     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3230     if (get_float_exception_flags(&env->active_fpu.fp_status)
3231             & float_flag_invalid) {
3232         if (float64_is_any_nan(fdt0)) {
3233             wt2 = 0;
3234         }
3235     }
3236     update_fcr31(env, GETPC());
3237     return wt2;
3238 }
3239 
helper_float_cvt_2008_w_s(CPUMIPSState * env,uint32_t fst0)3240 uint32_t helper_float_cvt_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3241 {
3242     uint32_t wt2;
3243 
3244     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3245     if (get_float_exception_flags(&env->active_fpu.fp_status)
3246             & float_flag_invalid) {
3247         if (float32_is_any_nan(fst0)) {
3248             wt2 = 0;
3249         }
3250     }
3251     update_fcr31(env, GETPC());
3252     return wt2;
3253 }
3254 
helper_float_round_2008_l_d(CPUMIPSState * env,uint64_t fdt0)3255 uint64_t helper_float_round_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3256 {
3257     uint64_t dt2;
3258 
3259     set_float_rounding_mode(float_round_nearest_even,
3260             &env->active_fpu.fp_status);
3261     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3262     restore_rounding_mode(env);
3263     if (get_float_exception_flags(&env->active_fpu.fp_status)
3264             & float_flag_invalid) {
3265         if (float64_is_any_nan(fdt0)) {
3266             dt2 = 0;
3267         }
3268     }
3269     update_fcr31(env, GETPC());
3270     return dt2;
3271 }
3272 
helper_float_round_2008_l_s(CPUMIPSState * env,uint32_t fst0)3273 uint64_t helper_float_round_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3274 {
3275     uint64_t dt2;
3276 
3277     set_float_rounding_mode(float_round_nearest_even,
3278             &env->active_fpu.fp_status);
3279     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3280     restore_rounding_mode(env);
3281     if (get_float_exception_flags(&env->active_fpu.fp_status)
3282             & float_flag_invalid) {
3283         if (float32_is_any_nan(fst0)) {
3284             dt2 = 0;
3285         }
3286     }
3287     update_fcr31(env, GETPC());
3288     return dt2;
3289 }
3290 
helper_float_round_2008_w_d(CPUMIPSState * env,uint64_t fdt0)3291 uint32_t helper_float_round_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3292 {
3293     uint32_t wt2;
3294 
3295     set_float_rounding_mode(float_round_nearest_even,
3296             &env->active_fpu.fp_status);
3297     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3298     restore_rounding_mode(env);
3299     if (get_float_exception_flags(&env->active_fpu.fp_status)
3300             & float_flag_invalid) {
3301         if (float64_is_any_nan(fdt0)) {
3302             wt2 = 0;
3303         }
3304     }
3305     update_fcr31(env, GETPC());
3306     return wt2;
3307 }
3308 
helper_float_round_2008_w_s(CPUMIPSState * env,uint32_t fst0)3309 uint32_t helper_float_round_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3310 {
3311     uint32_t wt2;
3312 
3313     set_float_rounding_mode(float_round_nearest_even,
3314             &env->active_fpu.fp_status);
3315     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3316     restore_rounding_mode(env);
3317     if (get_float_exception_flags(&env->active_fpu.fp_status)
3318             & float_flag_invalid) {
3319         if (float32_is_any_nan(fst0)) {
3320             wt2 = 0;
3321         }
3322     }
3323     update_fcr31(env, GETPC());
3324     return wt2;
3325 }
3326 
helper_float_trunc_2008_l_d(CPUMIPSState * env,uint64_t fdt0)3327 uint64_t helper_float_trunc_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3328 {
3329     uint64_t dt2;
3330 
3331     dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
3332     if (get_float_exception_flags(&env->active_fpu.fp_status)
3333             & float_flag_invalid) {
3334         if (float64_is_any_nan(fdt0)) {
3335             dt2 = 0;
3336         }
3337     }
3338     update_fcr31(env, GETPC());
3339     return dt2;
3340 }
3341 
helper_float_trunc_2008_l_s(CPUMIPSState * env,uint32_t fst0)3342 uint64_t helper_float_trunc_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3343 {
3344     uint64_t dt2;
3345 
3346     dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
3347     if (get_float_exception_flags(&env->active_fpu.fp_status)
3348             & float_flag_invalid) {
3349         if (float32_is_any_nan(fst0)) {
3350             dt2 = 0;
3351         }
3352     }
3353     update_fcr31(env, GETPC());
3354     return dt2;
3355 }
3356 
helper_float_trunc_2008_w_d(CPUMIPSState * env,uint64_t fdt0)3357 uint32_t helper_float_trunc_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3358 {
3359     uint32_t wt2;
3360 
3361     wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
3362     if (get_float_exception_flags(&env->active_fpu.fp_status)
3363             & float_flag_invalid) {
3364         if (float64_is_any_nan(fdt0)) {
3365             wt2 = 0;
3366         }
3367     }
3368     update_fcr31(env, GETPC());
3369     return wt2;
3370 }
3371 
helper_float_trunc_2008_w_s(CPUMIPSState * env,uint32_t fst0)3372 uint32_t helper_float_trunc_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3373 {
3374     uint32_t wt2;
3375 
3376     wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
3377     if (get_float_exception_flags(&env->active_fpu.fp_status)
3378             & float_flag_invalid) {
3379         if (float32_is_any_nan(fst0)) {
3380             wt2 = 0;
3381         }
3382     }
3383     update_fcr31(env, GETPC());
3384     return wt2;
3385 }
3386 
helper_float_ceil_2008_l_d(CPUMIPSState * env,uint64_t fdt0)3387 uint64_t helper_float_ceil_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3388 {
3389     uint64_t dt2;
3390 
3391     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3392     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3393     restore_rounding_mode(env);
3394     if (get_float_exception_flags(&env->active_fpu.fp_status)
3395             & float_flag_invalid) {
3396         if (float64_is_any_nan(fdt0)) {
3397             dt2 = 0;
3398         }
3399     }
3400     update_fcr31(env, GETPC());
3401     return dt2;
3402 }
3403 
helper_float_ceil_2008_l_s(CPUMIPSState * env,uint32_t fst0)3404 uint64_t helper_float_ceil_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3405 {
3406     uint64_t dt2;
3407 
3408     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3409     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3410     restore_rounding_mode(env);
3411     if (get_float_exception_flags(&env->active_fpu.fp_status)
3412             & float_flag_invalid) {
3413         if (float32_is_any_nan(fst0)) {
3414             dt2 = 0;
3415         }
3416     }
3417     update_fcr31(env, GETPC());
3418     return dt2;
3419 }
3420 
helper_float_ceil_2008_w_d(CPUMIPSState * env,uint64_t fdt0)3421 uint32_t helper_float_ceil_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3422 {
3423     uint32_t wt2;
3424 
3425     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3426     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3427     restore_rounding_mode(env);
3428     if (get_float_exception_flags(&env->active_fpu.fp_status)
3429             & float_flag_invalid) {
3430         if (float64_is_any_nan(fdt0)) {
3431             wt2 = 0;
3432         }
3433     }
3434     update_fcr31(env, GETPC());
3435     return wt2;
3436 }
3437 
helper_float_ceil_2008_w_s(CPUMIPSState * env,uint32_t fst0)3438 uint32_t helper_float_ceil_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3439 {
3440     uint32_t wt2;
3441 
3442     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3443     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3444     restore_rounding_mode(env);
3445     if (get_float_exception_flags(&env->active_fpu.fp_status)
3446             & float_flag_invalid) {
3447         if (float32_is_any_nan(fst0)) {
3448             wt2 = 0;
3449         }
3450     }
3451     update_fcr31(env, GETPC());
3452     return wt2;
3453 }
3454 
helper_float_floor_2008_l_d(CPUMIPSState * env,uint64_t fdt0)3455 uint64_t helper_float_floor_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3456 {
3457     uint64_t dt2;
3458 
3459     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3460     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3461     restore_rounding_mode(env);
3462     if (get_float_exception_flags(&env->active_fpu.fp_status)
3463             & float_flag_invalid) {
3464         if (float64_is_any_nan(fdt0)) {
3465             dt2 = 0;
3466         }
3467     }
3468     update_fcr31(env, GETPC());
3469     return dt2;
3470 }
3471 
helper_float_floor_2008_l_s(CPUMIPSState * env,uint32_t fst0)3472 uint64_t helper_float_floor_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3473 {
3474     uint64_t dt2;
3475 
3476     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3477     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3478     restore_rounding_mode(env);
3479     if (get_float_exception_flags(&env->active_fpu.fp_status)
3480             & float_flag_invalid) {
3481         if (float32_is_any_nan(fst0)) {
3482             dt2 = 0;
3483         }
3484     }
3485     update_fcr31(env, GETPC());
3486     return dt2;
3487 }
3488 
helper_float_floor_2008_w_d(CPUMIPSState * env,uint64_t fdt0)3489 uint32_t helper_float_floor_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3490 {
3491     uint32_t wt2;
3492 
3493     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3494     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3495     restore_rounding_mode(env);
3496     if (get_float_exception_flags(&env->active_fpu.fp_status)
3497             & float_flag_invalid) {
3498         if (float64_is_any_nan(fdt0)) {
3499             wt2 = 0;
3500         }
3501     }
3502     update_fcr31(env, GETPC());
3503     return wt2;
3504 }
3505 
helper_float_floor_2008_w_s(CPUMIPSState * env,uint32_t fst0)3506 uint32_t helper_float_floor_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3507 {
3508     uint32_t wt2;
3509 
3510     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3511     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3512     restore_rounding_mode(env);
3513     if (get_float_exception_flags(&env->active_fpu.fp_status)
3514             & float_flag_invalid) {
3515         if (float32_is_any_nan(fst0)) {
3516             wt2 = 0;
3517         }
3518     }
3519     update_fcr31(env, GETPC());
3520     return wt2;
3521 }
3522 
3523 /* unary operations, not modifying fp status  */
3524 #define FLOAT_UNOP(name)                                       \
3525 uint64_t helper_float_ ## name ## _d(uint64_t fdt0)                \
3526 {                                                              \
3527     return float64_ ## name(fdt0);                             \
3528 }                                                              \
3529 uint32_t helper_float_ ## name ## _s(uint32_t fst0)                \
3530 {                                                              \
3531     return float32_ ## name(fst0);                             \
3532 }                                                              \
3533 uint64_t helper_float_ ## name ## _ps(uint64_t fdt0)               \
3534 {                                                              \
3535     uint32_t wt0;                                              \
3536     uint32_t wth0;                                             \
3537                                                                \
3538     wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF);                 \
3539     wth0 = float32_ ## name(fdt0 >> 32);                       \
3540     return ((uint64_t)wth0 << 32) | wt0;                       \
3541 }
3542 FLOAT_UNOP(abs)
FLOAT_UNOP(chs)3543 FLOAT_UNOP(chs)
3544 #undef FLOAT_UNOP
3545 
3546 /* MIPS specific unary operations */
3547 uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
3548 {
3549     uint64_t fdt2;
3550 
3551     fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
3552     update_fcr31(env, GETPC());
3553     return fdt2;
3554 }
3555 
helper_float_recip_s(CPUMIPSState * env,uint32_t fst0)3556 uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
3557 {
3558     uint32_t fst2;
3559 
3560     fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
3561     update_fcr31(env, GETPC());
3562     return fst2;
3563 }
3564 
helper_float_rsqrt_d(CPUMIPSState * env,uint64_t fdt0)3565 uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
3566 {
3567     uint64_t fdt2;
3568 
3569     fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
3570     fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
3571     update_fcr31(env, GETPC());
3572     return fdt2;
3573 }
3574 
helper_float_rsqrt_s(CPUMIPSState * env,uint32_t fst0)3575 uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
3576 {
3577     uint32_t fst2;
3578 
3579     fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
3580     fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3581     update_fcr31(env, GETPC());
3582     return fst2;
3583 }
3584 
helper_float_recip1_d(CPUMIPSState * env,uint64_t fdt0)3585 uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
3586 {
3587     uint64_t fdt2;
3588 
3589     fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
3590     update_fcr31(env, GETPC());
3591     return fdt2;
3592 }
3593 
helper_float_recip1_s(CPUMIPSState * env,uint32_t fst0)3594 uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
3595 {
3596     uint32_t fst2;
3597 
3598     fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
3599     update_fcr31(env, GETPC());
3600     return fst2;
3601 }
3602 
helper_float_recip1_ps(CPUMIPSState * env,uint64_t fdt0)3603 uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
3604 {
3605     uint32_t fst2;
3606     uint32_t fsth2;
3607 
3608     fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
3609     fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
3610     update_fcr31(env, GETPC());
3611     return ((uint64_t)fsth2 << 32) | fst2;
3612 }
3613 
helper_float_rsqrt1_d(CPUMIPSState * env,uint64_t fdt0)3614 uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
3615 {
3616     uint64_t fdt2;
3617 
3618     fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
3619     fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
3620     update_fcr31(env, GETPC());
3621     return fdt2;
3622 }
3623 
helper_float_rsqrt1_s(CPUMIPSState * env,uint32_t fst0)3624 uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
3625 {
3626     uint32_t fst2;
3627 
3628     fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
3629     fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3630     update_fcr31(env, GETPC());
3631     return fst2;
3632 }
3633 
helper_float_rsqrt1_ps(CPUMIPSState * env,uint64_t fdt0)3634 uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
3635 {
3636     uint32_t fst2;
3637     uint32_t fsth2;
3638 
3639     fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
3640     fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
3641     fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3642     fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
3643     update_fcr31(env, GETPC());
3644     return ((uint64_t)fsth2 << 32) | fst2;
3645 }
3646 
3647 #define FLOAT_RINT(name, bits)                                              \
3648 uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,                \
3649                                           uint ## bits ## _t fs)            \
3650 {                                                                           \
3651     uint ## bits ## _t fdret;                                               \
3652                                                                             \
3653     fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \
3654     update_fcr31(env, GETPC());                                             \
3655     return fdret;                                                           \
3656 }
3657 
3658 FLOAT_RINT(rint_s, 32)
3659 FLOAT_RINT(rint_d, 64)
3660 #undef FLOAT_RINT
3661 
3662 #define FLOAT_CLASS_SIGNALING_NAN      0x001
3663 #define FLOAT_CLASS_QUIET_NAN          0x002
3664 #define FLOAT_CLASS_NEGATIVE_INFINITY  0x004
3665 #define FLOAT_CLASS_NEGATIVE_NORMAL    0x008
3666 #define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010
3667 #define FLOAT_CLASS_NEGATIVE_ZERO      0x020
3668 #define FLOAT_CLASS_POSITIVE_INFINITY  0x040
3669 #define FLOAT_CLASS_POSITIVE_NORMAL    0x080
3670 #define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100
3671 #define FLOAT_CLASS_POSITIVE_ZERO      0x200
3672 
3673 #define FLOAT_CLASS(name, bits)                                      \
3674 uint ## bits ## _t float_ ## name (uint ## bits ## _t arg,           \
3675                                    float_status *status)             \
3676 {                                                                    \
3677     if (float ## bits ## _is_signaling_nan(arg, status)) {           \
3678         return FLOAT_CLASS_SIGNALING_NAN;                            \
3679     } else if (float ## bits ## _is_quiet_nan(arg, status)) {        \
3680         return FLOAT_CLASS_QUIET_NAN;                                \
3681     } else if (float ## bits ## _is_neg(arg)) {                      \
3682         if (float ## bits ## _is_infinity(arg)) {                    \
3683             return FLOAT_CLASS_NEGATIVE_INFINITY;                    \
3684         } else if (float ## bits ## _is_zero(arg)) {                 \
3685             return FLOAT_CLASS_NEGATIVE_ZERO;                        \
3686         } else if (float ## bits ## _is_zero_or_denormal(arg)) {     \
3687             return FLOAT_CLASS_NEGATIVE_SUBNORMAL;                   \
3688         } else {                                                     \
3689             return FLOAT_CLASS_NEGATIVE_NORMAL;                      \
3690         }                                                            \
3691     } else {                                                         \
3692         if (float ## bits ## _is_infinity(arg)) {                    \
3693             return FLOAT_CLASS_POSITIVE_INFINITY;                    \
3694         } else if (float ## bits ## _is_zero(arg)) {                 \
3695             return FLOAT_CLASS_POSITIVE_ZERO;                        \
3696         } else if (float ## bits ## _is_zero_or_denormal(arg)) {     \
3697             return FLOAT_CLASS_POSITIVE_SUBNORMAL;                   \
3698         } else {                                                     \
3699             return FLOAT_CLASS_POSITIVE_NORMAL;                      \
3700         }                                                            \
3701     }                                                                \
3702 }                                                                    \
3703                                                                      \
3704 uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,         \
3705                                           uint ## bits ## _t arg)    \
3706 {                                                                    \
3707     return float_ ## name(arg, &env->active_fpu.fp_status);          \
3708 }
3709 
3710 FLOAT_CLASS(class_s, 32)
3711 FLOAT_CLASS(class_d, 64)
3712 #undef FLOAT_CLASS
3713 
3714 /* binary operations */
3715 #define FLOAT_BINOP(name)                                          \
3716 uint64_t helper_float_ ## name ## _d(CPUMIPSState *env,            \
3717                                      uint64_t fdt0, uint64_t fdt1) \
3718 {                                                                  \
3719     uint64_t dt2;                                                  \
3720                                                                    \
3721     dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status);     \
3722     update_fcr31(env, GETPC());                                    \
3723     return dt2;                                                    \
3724 }                                                                  \
3725                                                                    \
3726 uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,            \
3727                                      uint32_t fst0, uint32_t fst1) \
3728 {                                                                  \
3729     uint32_t wt2;                                                  \
3730                                                                    \
3731     wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
3732     update_fcr31(env, GETPC());                                    \
3733     return wt2;                                                    \
3734 }                                                                  \
3735                                                                    \
3736 uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env,           \
3737                                       uint64_t fdt0,               \
3738                                       uint64_t fdt1)               \
3739 {                                                                  \
3740     uint32_t fst0 = fdt0 & 0XFFFFFFFF;                             \
3741     uint32_t fsth0 = fdt0 >> 32;                                   \
3742     uint32_t fst1 = fdt1 & 0XFFFFFFFF;                             \
3743     uint32_t fsth1 = fdt1 >> 32;                                   \
3744     uint32_t wt2;                                                  \
3745     uint32_t wth2;                                                 \
3746                                                                    \
3747     wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
3748     wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status);  \
3749     update_fcr31(env, GETPC());                                    \
3750     return ((uint64_t)wth2 << 32) | wt2;                           \
3751 }
3752 
FLOAT_BINOP(add)3753 FLOAT_BINOP(add)
3754 FLOAT_BINOP(sub)
3755 FLOAT_BINOP(mul)
3756 FLOAT_BINOP(div)
3757 #undef FLOAT_BINOP
3758 
3759 /* MIPS specific binary operations */
3760 uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
3761 {
3762     fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3763     fdt2 = float64_chs(float64_sub(fdt2, float64_one, &env->active_fpu.fp_status));
3764     update_fcr31(env, GETPC());
3765     return fdt2;
3766 }
3767 
helper_float_recip2_s(CPUMIPSState * env,uint32_t fst0,uint32_t fst2)3768 uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
3769 {
3770     fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3771     fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
3772     update_fcr31(env, GETPC());
3773     return fst2;
3774 }
3775 
helper_float_recip2_ps(CPUMIPSState * env,uint64_t fdt0,uint64_t fdt2)3776 uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
3777 {
3778     uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3779     uint32_t fsth0 = fdt0 >> 32;
3780     uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3781     uint32_t fsth2 = fdt2 >> 32;
3782 
3783     fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3784     fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3785     fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
3786     fsth2 = float32_chs(float32_sub(fsth2, float32_one, &env->active_fpu.fp_status));
3787     update_fcr31(env, GETPC());
3788     return ((uint64_t)fsth2 << 32) | fst2;
3789 }
3790 
helper_float_rsqrt2_d(CPUMIPSState * env,uint64_t fdt0,uint64_t fdt2)3791 uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
3792 {
3793     fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3794     fdt2 = float64_sub(fdt2, float64_one, &env->active_fpu.fp_status);
3795     fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
3796     update_fcr31(env, GETPC());
3797     return fdt2;
3798 }
3799 
helper_float_rsqrt2_s(CPUMIPSState * env,uint32_t fst0,uint32_t fst2)3800 uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
3801 {
3802     fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3803     fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
3804     fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3805     update_fcr31(env, GETPC());
3806     return fst2;
3807 }
3808 
helper_float_rsqrt2_ps(CPUMIPSState * env,uint64_t fdt0,uint64_t fdt2)3809 uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
3810 {
3811     uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3812     uint32_t fsth0 = fdt0 >> 32;
3813     uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3814     uint32_t fsth2 = fdt2 >> 32;
3815 
3816     fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3817     fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3818     fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
3819     fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
3820     fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3821     fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
3822     update_fcr31(env, GETPC());
3823     return ((uint64_t)fsth2 << 32) | fst2;
3824 }
3825 
helper_float_addr_ps(CPUMIPSState * env,uint64_t fdt0,uint64_t fdt1)3826 uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
3827 {
3828     uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3829     uint32_t fsth0 = fdt0 >> 32;
3830     uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3831     uint32_t fsth1 = fdt1 >> 32;
3832     uint32_t fst2;
3833     uint32_t fsth2;
3834 
3835     fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
3836     fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
3837     update_fcr31(env, GETPC());
3838     return ((uint64_t)fsth2 << 32) | fst2;
3839 }
3840 
helper_float_mulr_ps(CPUMIPSState * env,uint64_t fdt0,uint64_t fdt1)3841 uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
3842 {
3843     uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3844     uint32_t fsth0 = fdt0 >> 32;
3845     uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3846     uint32_t fsth1 = fdt1 >> 32;
3847     uint32_t fst2;
3848     uint32_t fsth2;
3849 
3850     fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
3851     fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
3852     update_fcr31(env, GETPC());
3853     return ((uint64_t)fsth2 << 32) | fst2;
3854 }
3855 
3856 #define FLOAT_MINMAX(name, bits, minmaxfunc)                            \
3857 uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,            \
3858                                           uint ## bits ## _t fs,        \
3859                                           uint ## bits ## _t ft)        \
3860 {                                                                       \
3861     uint ## bits ## _t fdret;                                           \
3862                                                                         \
3863     fdret = float ## bits ## _ ## minmaxfunc(fs, ft,                    \
3864                                            &env->active_fpu.fp_status); \
3865     update_fcr31(env, GETPC());                                         \
3866     return fdret;                                                       \
3867 }
3868 
3869 FLOAT_MINMAX(max_s, 32, maxnum)
3870 FLOAT_MINMAX(max_d, 64, maxnum)
3871 FLOAT_MINMAX(maxa_s, 32, maxnummag)
3872 FLOAT_MINMAX(maxa_d, 64, maxnummag)
3873 
3874 FLOAT_MINMAX(min_s, 32, minnum)
3875 FLOAT_MINMAX(min_d, 64, minnum)
3876 FLOAT_MINMAX(mina_s, 32, minnummag)
3877 FLOAT_MINMAX(mina_d, 64, minnummag)
3878 #undef FLOAT_MINMAX
3879 
3880 /* ternary operations */
3881 #define UNFUSED_FMA(prefix, a, b, c, flags)                          \
3882 {                                                                    \
3883     a = prefix##_mul(a, b, &env->active_fpu.fp_status);              \
3884     if ((flags) & float_muladd_negate_c) {                           \
3885         a = prefix##_sub(a, c, &env->active_fpu.fp_status);          \
3886     } else {                                                         \
3887         a = prefix##_add(a, c, &env->active_fpu.fp_status);          \
3888     }                                                                \
3889     if ((flags) & float_muladd_negate_result) {                      \
3890         a = prefix##_chs(a);                                         \
3891     }                                                                \
3892 }
3893 
3894 /* FMA based operations */
3895 #define FLOAT_FMA(name, type)                                        \
3896 uint64_t helper_float_ ## name ## _d(CPUMIPSState *env,              \
3897                                      uint64_t fdt0, uint64_t fdt1,   \
3898                                      uint64_t fdt2)                  \
3899 {                                                                    \
3900     UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type);                    \
3901     update_fcr31(env, GETPC());                                      \
3902     return fdt0;                                                     \
3903 }                                                                    \
3904                                                                      \
3905 uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,              \
3906                                      uint32_t fst0, uint32_t fst1,   \
3907                                      uint32_t fst2)                  \
3908 {                                                                    \
3909     UNFUSED_FMA(float32, fst0, fst1, fst2, type);                    \
3910     update_fcr31(env, GETPC());                                      \
3911     return fst0;                                                     \
3912 }                                                                    \
3913                                                                      \
3914 uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env,             \
3915                                       uint64_t fdt0, uint64_t fdt1,  \
3916                                       uint64_t fdt2)                 \
3917 {                                                                    \
3918     uint32_t fst0 = fdt0 & 0XFFFFFFFF;                               \
3919     uint32_t fsth0 = fdt0 >> 32;                                     \
3920     uint32_t fst1 = fdt1 & 0XFFFFFFFF;                               \
3921     uint32_t fsth1 = fdt1 >> 32;                                     \
3922     uint32_t fst2 = fdt2 & 0XFFFFFFFF;                               \
3923     uint32_t fsth2 = fdt2 >> 32;                                     \
3924                                                                      \
3925     UNFUSED_FMA(float32, fst0, fst1, fst2, type);                    \
3926     UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type);                 \
3927     update_fcr31(env, GETPC());                                      \
3928     return ((uint64_t)fsth0 << 32) | fst0;                           \
3929 }
3930 FLOAT_FMA(madd, 0)
FLOAT_FMA(msub,float_muladd_negate_c)3931 FLOAT_FMA(msub, float_muladd_negate_c)
3932 FLOAT_FMA(nmadd, float_muladd_negate_result)
3933 FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c)
3934 #undef FLOAT_FMA
3935 
3936 #define FLOAT_FMADDSUB(name, bits, muladd_arg)                          \
3937 uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,            \
3938                                           uint ## bits ## _t fs,        \
3939                                           uint ## bits ## _t ft,        \
3940                                           uint ## bits ## _t fd)        \
3941 {                                                                       \
3942     uint ## bits ## _t fdret;                                           \
3943                                                                         \
3944     fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg,            \
3945                                      &env->active_fpu.fp_status);       \
3946     update_fcr31(env, GETPC());                                         \
3947     return fdret;                                                       \
3948 }
3949 
3950 FLOAT_FMADDSUB(maddf_s, 32, 0)
3951 FLOAT_FMADDSUB(maddf_d, 64, 0)
3952 FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product)
3953 FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product)
3954 #undef FLOAT_FMADDSUB
3955 
3956 /* compare operations */
3957 #define FOP_COND_D(op, cond)                                   \
3958 void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
3959                          uint64_t fdt1, int cc)                \
3960 {                                                              \
3961     int c;                                                     \
3962     c = cond;                                                  \
3963     update_fcr31(env, GETPC());                                \
3964     if (c)                                                     \
3965         SET_FP_COND(cc, env->active_fpu);                      \
3966     else                                                       \
3967         CLEAR_FP_COND(cc, env->active_fpu);                    \
3968 }                                                              \
3969 void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
3970                             uint64_t fdt1, int cc)             \
3971 {                                                              \
3972     int c;                                                     \
3973     fdt0 = float64_abs(fdt0);                                  \
3974     fdt1 = float64_abs(fdt1);                                  \
3975     c = cond;                                                  \
3976     update_fcr31(env, GETPC());                                \
3977     if (c)                                                     \
3978         SET_FP_COND(cc, env->active_fpu);                      \
3979     else                                                       \
3980         CLEAR_FP_COND(cc, env->active_fpu);                    \
3981 }
3982 
3983 /* NOTE: the comma operator will make "cond" to eval to false,
3984  * but float64_unordered_quiet() is still called. */
3985 FOP_COND_D(f,   (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3986 FOP_COND_D(un,  float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
3987 FOP_COND_D(eq,  float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3988 FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3989 FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3990 FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3991 FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3992 FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3993 /* NOTE: the comma operator will make "cond" to eval to false,
3994  * but float64_unordered() is still called. */
3995 FOP_COND_D(sf,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3996 FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
3997 FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3998 FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3999 FOP_COND_D(lt,  float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
4000 FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
4001 FOP_COND_D(le,  float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
4002 FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
4003 
4004 #define FOP_COND_S(op, cond)                                   \
4005 void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0,     \
4006                          uint32_t fst1, int cc)                \
4007 {                                                              \
4008     int c;                                                     \
4009     c = cond;                                                  \
4010     update_fcr31(env, GETPC());                                \
4011     if (c)                                                     \
4012         SET_FP_COND(cc, env->active_fpu);                      \
4013     else                                                       \
4014         CLEAR_FP_COND(cc, env->active_fpu);                    \
4015 }                                                              \
4016 void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0,  \
4017                             uint32_t fst1, int cc)             \
4018 {                                                              \
4019     int c;                                                     \
4020     fst0 = float32_abs(fst0);                                  \
4021     fst1 = float32_abs(fst1);                                  \
4022     c = cond;                                                  \
4023     update_fcr31(env, GETPC());                                \
4024     if (c)                                                     \
4025         SET_FP_COND(cc, env->active_fpu);                      \
4026     else                                                       \
4027         CLEAR_FP_COND(cc, env->active_fpu);                    \
4028 }
4029 
4030 /* NOTE: the comma operator will make "cond" to eval to false,
4031  * but float32_unordered_quiet() is still called. */
4032 FOP_COND_S(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
4033 FOP_COND_S(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
4034 FOP_COND_S(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
4035 FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
4036 FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
4037 FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
4038 FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
4039 FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
4040 /* NOTE: the comma operator will make "cond" to eval to false,
4041  * but float32_unordered() is still called. */
4042 FOP_COND_S(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
4043 FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
4044 FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
4045 FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
4046 FOP_COND_S(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status))
4047 FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
4048 FOP_COND_S(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status))
4049 FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
4050 
4051 #define FOP_COND_PS(op, condl, condh)                           \
4052 void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
4053                           uint64_t fdt1, int cc)                \
4054 {                                                               \
4055     uint32_t fst0, fsth0, fst1, fsth1;                          \
4056     int ch, cl;                                                 \
4057     fst0 = fdt0 & 0XFFFFFFFF;                                   \
4058     fsth0 = fdt0 >> 32;                                         \
4059     fst1 = fdt1 & 0XFFFFFFFF;                                   \
4060     fsth1 = fdt1 >> 32;                                         \
4061     cl = condl;                                                 \
4062     ch = condh;                                                 \
4063     update_fcr31(env, GETPC());                                 \
4064     if (cl)                                                     \
4065         SET_FP_COND(cc, env->active_fpu);                       \
4066     else                                                        \
4067         CLEAR_FP_COND(cc, env->active_fpu);                     \
4068     if (ch)                                                     \
4069         SET_FP_COND(cc + 1, env->active_fpu);                   \
4070     else                                                        \
4071         CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
4072 }                                                               \
4073 void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
4074                              uint64_t fdt1, int cc)             \
4075 {                                                               \
4076     uint32_t fst0, fsth0, fst1, fsth1;                          \
4077     int ch, cl;                                                 \
4078     fst0 = float32_abs(fdt0 & 0XFFFFFFFF);                      \
4079     fsth0 = float32_abs(fdt0 >> 32);                            \
4080     fst1 = float32_abs(fdt1 & 0XFFFFFFFF);                      \
4081     fsth1 = float32_abs(fdt1 >> 32);                            \
4082     cl = condl;                                                 \
4083     ch = condh;                                                 \
4084     update_fcr31(env, GETPC());                                 \
4085     if (cl)                                                     \
4086         SET_FP_COND(cc, env->active_fpu);                       \
4087     else                                                        \
4088         CLEAR_FP_COND(cc, env->active_fpu);                     \
4089     if (ch)                                                     \
4090         SET_FP_COND(cc + 1, env->active_fpu);                   \
4091     else                                                        \
4092         CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
4093 }
4094 
4095 /* NOTE: the comma operator will make "cond" to eval to false,
4096  * but float32_unordered_quiet() is still called. */
4097 FOP_COND_PS(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
4098                  (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
4099 FOP_COND_PS(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
4100                  float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
4101 FOP_COND_PS(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
4102                  float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4103 FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
4104                  float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4105 FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
4106                  float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4107 FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
4108                  float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4109 FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
4110                  float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4111 FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
4112                  float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4113 /* NOTE: the comma operator will make "cond" to eval to false,
4114  * but float32_unordered() is still called. */
4115 FOP_COND_PS(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
4116                  (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
4117 FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
4118                  float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
4119 FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
4120                  float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
4121 FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
4122                  float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
4123 FOP_COND_PS(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status),
4124                  float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
4125 FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
4126                  float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
4127 FOP_COND_PS(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status),
4128                  float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
4129 FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
4130                  float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
4131 
4132 /* R6 compare operations */
4133 #define FOP_CONDN_D(op, cond)                                       \
4134 uint64_t helper_r6_cmp_d_ ## op(CPUMIPSState * env, uint64_t fdt0,  \
4135                          uint64_t fdt1)                             \
4136 {                                                                   \
4137     uint64_t c;                                                     \
4138     c = cond;                                                       \
4139     update_fcr31(env, GETPC());                                     \
4140     if (c) {                                                        \
4141         return -1;                                                  \
4142     } else {                                                        \
4143         return 0;                                                   \
4144     }                                                               \
4145 }
4146 
4147 /* NOTE: the comma operator will make "cond" to eval to false,
4148  * but float64_unordered_quiet() is still called. */
4149 FOP_CONDN_D(af,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
4150 FOP_CONDN_D(un,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)))
4151 FOP_CONDN_D(eq,  (float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4152 FOP_CONDN_D(ueq, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4153                   || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4154 FOP_CONDN_D(lt,  (float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4155 FOP_CONDN_D(ult, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4156                   || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4157 FOP_CONDN_D(le,  (float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4158 FOP_CONDN_D(ule, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4159                   || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4160 /* NOTE: the comma operator will make "cond" to eval to false,
4161  * but float64_unordered() is still called. */
4162 FOP_CONDN_D(saf,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
4163 FOP_CONDN_D(sun,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)))
4164 FOP_CONDN_D(seq,  (float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
4165 FOP_CONDN_D(sueq, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4166                    || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
4167 FOP_CONDN_D(slt,  (float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4168 FOP_CONDN_D(sult, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4169                    || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4170 FOP_CONDN_D(sle,  (float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4171 FOP_CONDN_D(sule, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4172                    || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4173 FOP_CONDN_D(or,   (float64_le_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4174                    || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4175 FOP_CONDN_D(une,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4176                    || float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4177                    || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4178 FOP_CONDN_D(ne,   (float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4179                    || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4180 FOP_CONDN_D(sor,  (float64_le(fdt1, fdt0, &env->active_fpu.fp_status)
4181                    || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4182 FOP_CONDN_D(sune, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4183                    || float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
4184                    || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4185 FOP_CONDN_D(sne,  (float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
4186                    || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4187 
4188 #define FOP_CONDN_S(op, cond)                                       \
4189 uint32_t helper_r6_cmp_s_ ## op(CPUMIPSState * env, uint32_t fst0,  \
4190                          uint32_t fst1)                             \
4191 {                                                                   \
4192     uint64_t c;                                                     \
4193     c = cond;                                                       \
4194     update_fcr31(env, GETPC());                                     \
4195     if (c) {                                                        \
4196         return -1;                                                  \
4197     } else {                                                        \
4198         return 0;                                                   \
4199     }                                                               \
4200 }
4201 
4202 /* NOTE: the comma operator will make "cond" to eval to false,
4203  * but float32_unordered_quiet() is still called. */
4204 FOP_CONDN_S(af,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
4205 FOP_CONDN_S(un,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)))
4206 FOP_CONDN_S(eq,   (float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4207 FOP_CONDN_S(ueq,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4208                    || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4209 FOP_CONDN_S(lt,   (float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4210 FOP_CONDN_S(ult,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4211                    || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4212 FOP_CONDN_S(le,   (float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4213 FOP_CONDN_S(ule,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4214                    || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4215 /* NOTE: the comma operator will make "cond" to eval to false,
4216  * but float32_unordered() is still called. */
4217 FOP_CONDN_S(saf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
4218 FOP_CONDN_S(sun,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)))
4219 FOP_CONDN_S(seq,  (float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
4220 FOP_CONDN_S(sueq, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4221                    || float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
4222 FOP_CONDN_S(slt,  (float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4223 FOP_CONDN_S(sult, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4224                    || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4225 FOP_CONDN_S(sle,  (float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4226 FOP_CONDN_S(sule, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4227                    || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4228 FOP_CONDN_S(or,   (float32_le_quiet(fst1, fst0, &env->active_fpu.fp_status)
4229                    || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4230 FOP_CONDN_S(une,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4231                    || float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
4232                    || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4233 FOP_CONDN_S(ne,   (float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
4234                    || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4235 FOP_CONDN_S(sor,  (float32_le(fst1, fst0, &env->active_fpu.fp_status)
4236                    || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4237 FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4238                    || float32_lt(fst1, fst0, &env->active_fpu.fp_status)
4239                    || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4240 FOP_CONDN_S(sne,  (float32_lt(fst1, fst0, &env->active_fpu.fp_status)
4241                    || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4242 
4243 /* MSA */
4244 /* Data format min and max values */
4245 #define DF_BITS(df) (1 << ((df) + 3))
4246 
4247 /* Element-by-element access macros */
4248 #define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df))
4249 
4250 #if !defined(CONFIG_USER_ONLY)
4251 #define MEMOP_IDX(DF)                                           \
4252         TCGMemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN,  \
4253                                         cpu_mmu_index(env, false));
4254 #else
4255 #define MEMOP_IDX(DF)
4256 #endif
4257 
4258 #define MSA_LD_DF(DF, TYPE, LD_INSN, ...)                               \
4259 void helper_msa_ld_ ## TYPE(CPUMIPSState *env, uint32_t wd,             \
4260                             target_ulong addr)                          \
4261 {                                                                       \
4262     wr_t *pwd = &(env->active_fpu.fpr[wd].wr);                          \
4263     wr_t wx;                                                            \
4264     int i;                                                              \
4265     MEMOP_IDX(DF)                                                       \
4266     for (i = 0; i < DF_ELEMENTS(DF); i++) {                             \
4267         wx.TYPE[i] = LD_INSN(env, addr + (i << DF), ##__VA_ARGS__);     \
4268     }                                                                   \
4269     memcpy(pwd, &wx, sizeof(wr_t));                                     \
4270 }
4271 
4272 #if !defined(CONFIG_USER_ONLY)
4273 MSA_LD_DF(DF_BYTE,   b, helper_ret_ldub_mmu, oi, GETPC())
4274 MSA_LD_DF(DF_HALF,   h, helper_ret_lduw_mmu, oi, GETPC())
4275 MSA_LD_DF(DF_WORD,   w, helper_ret_ldul_mmu, oi, GETPC())
4276 MSA_LD_DF(DF_DOUBLE, d, helper_ret_ldq_mmu,  oi, GETPC())
4277 #else
4278 MSA_LD_DF(DF_BYTE,   b, cpu_ldub_data)
4279 MSA_LD_DF(DF_HALF,   h, cpu_lduw_data)
4280 MSA_LD_DF(DF_WORD,   w, cpu_ldl_data)
4281 MSA_LD_DF(DF_DOUBLE, d, cpu_ldq_data)
4282 #endif
4283 
4284 #define MSA_PAGESPAN(x) \
4285         ((((x) & ~TARGET_PAGE_MASK) + MSA_WRLEN/8 - 1) >= TARGET_PAGE_SIZE)
4286 
4287 static inline void ensure_writable_pages(CPUMIPSState *env,
4288                                          target_ulong addr,
4289                                          int mmu_idx,
4290                                          uintptr_t retaddr)
4291 {
4292 #if !defined(CONFIG_USER_ONLY)
4293     target_ulong page_addr;
4294     if (unlikely(MSA_PAGESPAN(addr))) {
4295         /* first page */
4296         probe_write(env, addr, 0, mmu_idx, retaddr);
4297         /* second page */
4298         page_addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
4299         probe_write(env, page_addr, 0, mmu_idx, retaddr);
4300     }
4301 #endif
4302 }
4303 
4304 #define MSA_ST_DF(DF, TYPE, ST_INSN, ...)                               \
4305 void helper_msa_st_ ## TYPE(CPUMIPSState *env, uint32_t wd,             \
4306                             target_ulong addr)                          \
4307 {                                                                       \
4308     wr_t *pwd = &(env->active_fpu.fpr[wd].wr);                          \
4309     int mmu_idx = cpu_mmu_index(env, false);				\
4310     int i;                                                              \
4311     MEMOP_IDX(DF)                                                       \
4312     ensure_writable_pages(env, addr, mmu_idx, GETPC());                 \
4313     for (i = 0; i < DF_ELEMENTS(DF); i++) {                             \
4314         ST_INSN(env, addr + (i << DF), pwd->TYPE[i], ##__VA_ARGS__);    \
4315     }                                                                   \
4316 }
4317 
4318 #if !defined(CONFIG_USER_ONLY)
MSA_ST_DF(DF_BYTE,b,helper_ret_stb_mmu,oi,GETPC ())4319 MSA_ST_DF(DF_BYTE,   b, helper_ret_stb_mmu, oi, GETPC())
4320 MSA_ST_DF(DF_HALF,   h, helper_ret_stw_mmu, oi, GETPC())
4321 MSA_ST_DF(DF_WORD,   w, helper_ret_stl_mmu, oi, GETPC())
4322 MSA_ST_DF(DF_DOUBLE, d, helper_ret_stq_mmu, oi, GETPC())
4323 #else
4324 MSA_ST_DF(DF_BYTE,   b, cpu_stb_data)
4325 MSA_ST_DF(DF_HALF,   h, cpu_stw_data)
4326 MSA_ST_DF(DF_WORD,   w, cpu_stl_data)
4327 MSA_ST_DF(DF_DOUBLE, d, cpu_stq_data)
4328 #endif
4329 
4330 void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op)
4331 {
4332 #ifndef CONFIG_USER_ONLY
4333     target_ulong index = addr & 0x1fffffff;
4334     if (op == 9) {
4335         /* Index Store Tag */
4336         memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo,
4337                                      8, MEMTXATTRS_UNSPECIFIED);
4338     } else if (op == 5) {
4339         /* Index Load Tag */
4340         memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo,
4341                                     8, MEMTXATTRS_UNSPECIFIED);
4342     }
4343 #endif
4344 }
4345