]> git.proxmox.com Git - qemu.git/blob - target-mips/op_helper.c
Merge remote-tracking branch 'spice/spice.v54' into staging
[qemu.git] / target-mips / op_helper.c
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 <stdlib.h>
20 #include "cpu.h"
21 #include "dyngen-exec.h"
22
23 #include "host-utils.h"
24
25 #include "helper.h"
26
27 #if !defined(CONFIG_USER_ONLY)
28 #include "softmmu_exec.h"
29 #endif /* !defined(CONFIG_USER_ONLY) */
30
31 #ifndef CONFIG_USER_ONLY
32 static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global);
33 #endif
34
35 static inline void compute_hflags(CPUMIPSState *env)
36 {
37 env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
38 MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
39 MIPS_HFLAG_UX);
40 if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
41 !(env->CP0_Status & (1 << CP0St_ERL)) &&
42 !(env->hflags & MIPS_HFLAG_DM)) {
43 env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU;
44 }
45 #if defined(TARGET_MIPS64)
46 if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) ||
47 (env->CP0_Status & (1 << CP0St_PX)) ||
48 (env->CP0_Status & (1 << CP0St_UX))) {
49 env->hflags |= MIPS_HFLAG_64;
50 }
51 if (env->CP0_Status & (1 << CP0St_UX)) {
52 env->hflags |= MIPS_HFLAG_UX;
53 }
54 #endif
55 if ((env->CP0_Status & (1 << CP0St_CU0)) ||
56 !(env->hflags & MIPS_HFLAG_KSU)) {
57 env->hflags |= MIPS_HFLAG_CP0;
58 }
59 if (env->CP0_Status & (1 << CP0St_CU1)) {
60 env->hflags |= MIPS_HFLAG_FPU;
61 }
62 if (env->CP0_Status & (1 << CP0St_FR)) {
63 env->hflags |= MIPS_HFLAG_F64;
64 }
65 if (env->insn_flags & ISA_MIPS32R2) {
66 if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
67 env->hflags |= MIPS_HFLAG_COP1X;
68 }
69 } else if (env->insn_flags & ISA_MIPS32) {
70 if (env->hflags & MIPS_HFLAG_64) {
71 env->hflags |= MIPS_HFLAG_COP1X;
72 }
73 } else if (env->insn_flags & ISA_MIPS4) {
74 /* All supported MIPS IV CPUs use the XX (CU3) to enable
75 and disable the MIPS IV extensions to the MIPS III ISA.
76 Some other MIPS IV CPUs ignore the bit, so the check here
77 would be too restrictive for them. */
78 if (env->CP0_Status & (1 << CP0St_CU3)) {
79 env->hflags |= MIPS_HFLAG_COP1X;
80 }
81 }
82 }
83
84 /*****************************************************************************/
85 /* Exceptions processing helpers */
86
87 void helper_raise_exception_err (uint32_t exception, int error_code)
88 {
89 #if 1
90 if (exception < 0x100)
91 qemu_log("%s: %d %d\n", __func__, exception, error_code);
92 #endif
93 env->exception_index = exception;
94 env->error_code = error_code;
95 cpu_loop_exit(env);
96 }
97
98 void helper_raise_exception (uint32_t exception)
99 {
100 helper_raise_exception_err(exception, 0);
101 }
102
103 #if !defined(CONFIG_USER_ONLY)
104 static void do_restore_state(uintptr_t pc)
105 {
106 TranslationBlock *tb;
107
108 tb = tb_find_pc (pc);
109 if (tb) {
110 cpu_restore_state(tb, env, pc);
111 }
112 }
113 #endif
114
115 #if defined(CONFIG_USER_ONLY)
116 #define HELPER_LD(name, insn, type) \
117 static inline type do_##name(target_ulong addr, int mem_idx) \
118 { \
119 return (type) insn##_raw(addr); \
120 }
121 #else
122 #define HELPER_LD(name, insn, type) \
123 static inline type do_##name(target_ulong addr, int mem_idx) \
124 { \
125 switch (mem_idx) \
126 { \
127 case 0: return (type) insn##_kernel(addr); break; \
128 case 1: return (type) insn##_super(addr); break; \
129 default: \
130 case 2: return (type) insn##_user(addr); break; \
131 } \
132 }
133 #endif
134 HELPER_LD(lbu, ldub, uint8_t)
135 HELPER_LD(lw, ldl, int32_t)
136 #ifdef TARGET_MIPS64
137 HELPER_LD(ld, ldq, int64_t)
138 #endif
139 #undef HELPER_LD
140
141 #if defined(CONFIG_USER_ONLY)
142 #define HELPER_ST(name, insn, type) \
143 static inline void do_##name(target_ulong addr, type val, int mem_idx) \
144 { \
145 insn##_raw(addr, val); \
146 }
147 #else
148 #define HELPER_ST(name, insn, type) \
149 static inline void do_##name(target_ulong addr, type val, int mem_idx) \
150 { \
151 switch (mem_idx) \
152 { \
153 case 0: insn##_kernel(addr, val); break; \
154 case 1: insn##_super(addr, val); break; \
155 default: \
156 case 2: insn##_user(addr, val); break; \
157 } \
158 }
159 #endif
160 HELPER_ST(sb, stb, uint8_t)
161 HELPER_ST(sw, stl, uint32_t)
162 #ifdef TARGET_MIPS64
163 HELPER_ST(sd, stq, uint64_t)
164 #endif
165 #undef HELPER_ST
166
167 target_ulong helper_clo (target_ulong arg1)
168 {
169 return clo32(arg1);
170 }
171
172 target_ulong helper_clz (target_ulong arg1)
173 {
174 return clz32(arg1);
175 }
176
177 #if defined(TARGET_MIPS64)
178 target_ulong helper_dclo (target_ulong arg1)
179 {
180 return clo64(arg1);
181 }
182
183 target_ulong helper_dclz (target_ulong arg1)
184 {
185 return clz64(arg1);
186 }
187 #endif /* TARGET_MIPS64 */
188
189 /* 64 bits arithmetic for 32 bits hosts */
190 static inline uint64_t get_HILO (void)
191 {
192 return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
193 }
194
195 static inline void set_HIT0_LO (target_ulong arg1, uint64_t HILO)
196 {
197 env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
198 arg1 = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
199 }
200
201 static inline void set_HI_LOT0 (target_ulong arg1, uint64_t HILO)
202 {
203 arg1 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
204 env->active_tc.HI[0] = (int32_t)(HILO >> 32);
205 }
206
207 /* Multiplication variants of the vr54xx. */
208 target_ulong helper_muls (target_ulong arg1, target_ulong arg2)
209 {
210 set_HI_LOT0(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
211
212 return arg1;
213 }
214
215 target_ulong helper_mulsu (target_ulong arg1, target_ulong arg2)
216 {
217 set_HI_LOT0(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
218
219 return arg1;
220 }
221
222 target_ulong helper_macc (target_ulong arg1, target_ulong arg2)
223 {
224 set_HI_LOT0(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
225
226 return arg1;
227 }
228
229 target_ulong helper_macchi (target_ulong arg1, target_ulong arg2)
230 {
231 set_HIT0_LO(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
232
233 return arg1;
234 }
235
236 target_ulong helper_maccu (target_ulong arg1, target_ulong arg2)
237 {
238 set_HI_LOT0(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
239
240 return arg1;
241 }
242
243 target_ulong helper_macchiu (target_ulong arg1, target_ulong arg2)
244 {
245 set_HIT0_LO(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
246
247 return arg1;
248 }
249
250 target_ulong helper_msac (target_ulong arg1, target_ulong arg2)
251 {
252 set_HI_LOT0(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
253
254 return arg1;
255 }
256
257 target_ulong helper_msachi (target_ulong arg1, target_ulong arg2)
258 {
259 set_HIT0_LO(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
260
261 return arg1;
262 }
263
264 target_ulong helper_msacu (target_ulong arg1, target_ulong arg2)
265 {
266 set_HI_LOT0(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
267
268 return arg1;
269 }
270
271 target_ulong helper_msachiu (target_ulong arg1, target_ulong arg2)
272 {
273 set_HIT0_LO(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
274
275 return arg1;
276 }
277
278 target_ulong helper_mulhi (target_ulong arg1, target_ulong arg2)
279 {
280 set_HIT0_LO(arg1, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
281
282 return arg1;
283 }
284
285 target_ulong helper_mulhiu (target_ulong arg1, target_ulong arg2)
286 {
287 set_HIT0_LO(arg1, (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
288
289 return arg1;
290 }
291
292 target_ulong helper_mulshi (target_ulong arg1, target_ulong arg2)
293 {
294 set_HIT0_LO(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
295
296 return arg1;
297 }
298
299 target_ulong helper_mulshiu (target_ulong arg1, target_ulong arg2)
300 {
301 set_HIT0_LO(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
302
303 return arg1;
304 }
305
306 #ifdef TARGET_MIPS64
307 void helper_dmult (target_ulong arg1, target_ulong arg2)
308 {
309 muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
310 }
311
312 void helper_dmultu (target_ulong arg1, target_ulong arg2)
313 {
314 mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
315 }
316 #endif
317
318 #ifndef CONFIG_USER_ONLY
319
320 static inline target_phys_addr_t do_translate_address(target_ulong address, int rw)
321 {
322 target_phys_addr_t lladdr;
323
324 lladdr = cpu_mips_translate_address(env, address, rw);
325
326 if (lladdr == -1LL) {
327 cpu_loop_exit(env);
328 } else {
329 return lladdr;
330 }
331 }
332
333 #define HELPER_LD_ATOMIC(name, insn) \
334 target_ulong helper_##name(target_ulong arg, int mem_idx) \
335 { \
336 env->lladdr = do_translate_address(arg, 0); \
337 env->llval = do_##insn(arg, mem_idx); \
338 return env->llval; \
339 }
340 HELPER_LD_ATOMIC(ll, lw)
341 #ifdef TARGET_MIPS64
342 HELPER_LD_ATOMIC(lld, ld)
343 #endif
344 #undef HELPER_LD_ATOMIC
345
346 #define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask) \
347 target_ulong helper_##name(target_ulong arg1, target_ulong arg2, int mem_idx) \
348 { \
349 target_long tmp; \
350 \
351 if (arg2 & almask) { \
352 env->CP0_BadVAddr = arg2; \
353 helper_raise_exception(EXCP_AdES); \
354 } \
355 if (do_translate_address(arg2, 1) == env->lladdr) { \
356 tmp = do_##ld_insn(arg2, mem_idx); \
357 if (tmp == env->llval) { \
358 do_##st_insn(arg2, arg1, mem_idx); \
359 return 1; \
360 } \
361 } \
362 return 0; \
363 }
364 HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
365 #ifdef TARGET_MIPS64
366 HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
367 #endif
368 #undef HELPER_ST_ATOMIC
369 #endif
370
371 #ifdef TARGET_WORDS_BIGENDIAN
372 #define GET_LMASK(v) ((v) & 3)
373 #define GET_OFFSET(addr, offset) (addr + (offset))
374 #else
375 #define GET_LMASK(v) (((v) & 3) ^ 3)
376 #define GET_OFFSET(addr, offset) (addr - (offset))
377 #endif
378
379 target_ulong helper_lwl(target_ulong arg1, target_ulong arg2, int mem_idx)
380 {
381 target_ulong tmp;
382
383 tmp = do_lbu(arg2, mem_idx);
384 arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
385
386 if (GET_LMASK(arg2) <= 2) {
387 tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
388 arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
389 }
390
391 if (GET_LMASK(arg2) <= 1) {
392 tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
393 arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
394 }
395
396 if (GET_LMASK(arg2) == 0) {
397 tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
398 arg1 = (arg1 & 0xFFFFFF00) | tmp;
399 }
400 return (int32_t)arg1;
401 }
402
403 target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx)
404 {
405 target_ulong tmp;
406
407 tmp = do_lbu(arg2, mem_idx);
408 arg1 = (arg1 & 0xFFFFFF00) | tmp;
409
410 if (GET_LMASK(arg2) >= 1) {
411 tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
412 arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
413 }
414
415 if (GET_LMASK(arg2) >= 2) {
416 tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
417 arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
418 }
419
420 if (GET_LMASK(arg2) == 3) {
421 tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
422 arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
423 }
424 return (int32_t)arg1;
425 }
426
427 void helper_swl(target_ulong arg1, target_ulong arg2, int mem_idx)
428 {
429 do_sb(arg2, (uint8_t)(arg1 >> 24), mem_idx);
430
431 if (GET_LMASK(arg2) <= 2)
432 do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx);
433
434 if (GET_LMASK(arg2) <= 1)
435 do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx);
436
437 if (GET_LMASK(arg2) == 0)
438 do_sb(GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
439 }
440
441 void helper_swr(target_ulong arg1, target_ulong arg2, int mem_idx)
442 {
443 do_sb(arg2, (uint8_t)arg1, mem_idx);
444
445 if (GET_LMASK(arg2) >= 1)
446 do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
447
448 if (GET_LMASK(arg2) >= 2)
449 do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
450
451 if (GET_LMASK(arg2) == 3)
452 do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
453 }
454
455 #if defined(TARGET_MIPS64)
456 /* "half" load and stores. We must do the memory access inline,
457 or fault handling won't work. */
458
459 #ifdef TARGET_WORDS_BIGENDIAN
460 #define GET_LMASK64(v) ((v) & 7)
461 #else
462 #define GET_LMASK64(v) (((v) & 7) ^ 7)
463 #endif
464
465 target_ulong helper_ldl(target_ulong arg1, target_ulong arg2, int mem_idx)
466 {
467 uint64_t tmp;
468
469 tmp = do_lbu(arg2, mem_idx);
470 arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
471
472 if (GET_LMASK64(arg2) <= 6) {
473 tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
474 arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
475 }
476
477 if (GET_LMASK64(arg2) <= 5) {
478 tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
479 arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
480 }
481
482 if (GET_LMASK64(arg2) <= 4) {
483 tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
484 arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
485 }
486
487 if (GET_LMASK64(arg2) <= 3) {
488 tmp = do_lbu(GET_OFFSET(arg2, 4), mem_idx);
489 arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
490 }
491
492 if (GET_LMASK64(arg2) <= 2) {
493 tmp = do_lbu(GET_OFFSET(arg2, 5), mem_idx);
494 arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
495 }
496
497 if (GET_LMASK64(arg2) <= 1) {
498 tmp = do_lbu(GET_OFFSET(arg2, 6), mem_idx);
499 arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
500 }
501
502 if (GET_LMASK64(arg2) == 0) {
503 tmp = do_lbu(GET_OFFSET(arg2, 7), mem_idx);
504 arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
505 }
506
507 return arg1;
508 }
509
510 target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx)
511 {
512 uint64_t tmp;
513
514 tmp = do_lbu(arg2, mem_idx);
515 arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
516
517 if (GET_LMASK64(arg2) >= 1) {
518 tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
519 arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
520 }
521
522 if (GET_LMASK64(arg2) >= 2) {
523 tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
524 arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
525 }
526
527 if (GET_LMASK64(arg2) >= 3) {
528 tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
529 arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
530 }
531
532 if (GET_LMASK64(arg2) >= 4) {
533 tmp = do_lbu(GET_OFFSET(arg2, -4), mem_idx);
534 arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
535 }
536
537 if (GET_LMASK64(arg2) >= 5) {
538 tmp = do_lbu(GET_OFFSET(arg2, -5), mem_idx);
539 arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
540 }
541
542 if (GET_LMASK64(arg2) >= 6) {
543 tmp = do_lbu(GET_OFFSET(arg2, -6), mem_idx);
544 arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
545 }
546
547 if (GET_LMASK64(arg2) == 7) {
548 tmp = do_lbu(GET_OFFSET(arg2, -7), mem_idx);
549 arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
550 }
551
552 return arg1;
553 }
554
555 void helper_sdl(target_ulong arg1, target_ulong arg2, int mem_idx)
556 {
557 do_sb(arg2, (uint8_t)(arg1 >> 56), mem_idx);
558
559 if (GET_LMASK64(arg2) <= 6)
560 do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx);
561
562 if (GET_LMASK64(arg2) <= 5)
563 do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx);
564
565 if (GET_LMASK64(arg2) <= 4)
566 do_sb(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx);
567
568 if (GET_LMASK64(arg2) <= 3)
569 do_sb(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx);
570
571 if (GET_LMASK64(arg2) <= 2)
572 do_sb(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx);
573
574 if (GET_LMASK64(arg2) <= 1)
575 do_sb(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx);
576
577 if (GET_LMASK64(arg2) <= 0)
578 do_sb(GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
579 }
580
581 void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx)
582 {
583 do_sb(arg2, (uint8_t)arg1, mem_idx);
584
585 if (GET_LMASK64(arg2) >= 1)
586 do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
587
588 if (GET_LMASK64(arg2) >= 2)
589 do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
590
591 if (GET_LMASK64(arg2) >= 3)
592 do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
593
594 if (GET_LMASK64(arg2) >= 4)
595 do_sb(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
596
597 if (GET_LMASK64(arg2) >= 5)
598 do_sb(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
599
600 if (GET_LMASK64(arg2) >= 6)
601 do_sb(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
602
603 if (GET_LMASK64(arg2) == 7)
604 do_sb(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
605 }
606 #endif /* TARGET_MIPS64 */
607
608 static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
609
610 void helper_lwm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
611 {
612 target_ulong base_reglist = reglist & 0xf;
613 target_ulong do_r31 = reglist & 0x10;
614 #ifdef CONFIG_USER_ONLY
615 #undef ldfun
616 #define ldfun ldl_raw
617 #else
618 uint32_t (*ldfun)(target_ulong);
619
620 switch (mem_idx)
621 {
622 case 0: ldfun = ldl_kernel; break;
623 case 1: ldfun = ldl_super; break;
624 default:
625 case 2: ldfun = ldl_user; break;
626 }
627 #endif
628
629 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
630 target_ulong i;
631
632 for (i = 0; i < base_reglist; i++) {
633 env->active_tc.gpr[multiple_regs[i]] = (target_long) ldfun(addr);
634 addr += 4;
635 }
636 }
637
638 if (do_r31) {
639 env->active_tc.gpr[31] = (target_long) ldfun(addr);
640 }
641 }
642
643 void helper_swm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
644 {
645 target_ulong base_reglist = reglist & 0xf;
646 target_ulong do_r31 = reglist & 0x10;
647 #ifdef CONFIG_USER_ONLY
648 #undef stfun
649 #define stfun stl_raw
650 #else
651 void (*stfun)(target_ulong, uint32_t);
652
653 switch (mem_idx)
654 {
655 case 0: stfun = stl_kernel; break;
656 case 1: stfun = stl_super; break;
657 default:
658 case 2: stfun = stl_user; break;
659 }
660 #endif
661
662 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
663 target_ulong i;
664
665 for (i = 0; i < base_reglist; i++) {
666 stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
667 addr += 4;
668 }
669 }
670
671 if (do_r31) {
672 stfun(addr, env->active_tc.gpr[31]);
673 }
674 }
675
676 #if defined(TARGET_MIPS64)
677 void helper_ldm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
678 {
679 target_ulong base_reglist = reglist & 0xf;
680 target_ulong do_r31 = reglist & 0x10;
681 #ifdef CONFIG_USER_ONLY
682 #undef ldfun
683 #define ldfun ldq_raw
684 #else
685 uint64_t (*ldfun)(target_ulong);
686
687 switch (mem_idx)
688 {
689 case 0: ldfun = ldq_kernel; break;
690 case 1: ldfun = ldq_super; break;
691 default:
692 case 2: ldfun = ldq_user; break;
693 }
694 #endif
695
696 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
697 target_ulong i;
698
699 for (i = 0; i < base_reglist; i++) {
700 env->active_tc.gpr[multiple_regs[i]] = ldfun(addr);
701 addr += 8;
702 }
703 }
704
705 if (do_r31) {
706 env->active_tc.gpr[31] = ldfun(addr);
707 }
708 }
709
710 void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
711 {
712 target_ulong base_reglist = reglist & 0xf;
713 target_ulong do_r31 = reglist & 0x10;
714 #ifdef CONFIG_USER_ONLY
715 #undef stfun
716 #define stfun stq_raw
717 #else
718 void (*stfun)(target_ulong, uint64_t);
719
720 switch (mem_idx)
721 {
722 case 0: stfun = stq_kernel; break;
723 case 1: stfun = stq_super; break;
724 default:
725 case 2: stfun = stq_user; break;
726 }
727 #endif
728
729 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
730 target_ulong i;
731
732 for (i = 0; i < base_reglist; i++) {
733 stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
734 addr += 8;
735 }
736 }
737
738 if (do_r31) {
739 stfun(addr, env->active_tc.gpr[31]);
740 }
741 }
742 #endif
743
744 #ifndef CONFIG_USER_ONLY
745 /* SMP helpers. */
746 static int mips_vpe_is_wfi(CPUMIPSState *c)
747 {
748 /* If the VPE is halted but otherwise active, it means it's waiting for
749 an interrupt. */
750 return c->halted && mips_vpe_active(c);
751 }
752
753 static inline void mips_vpe_wake(CPUMIPSState *c)
754 {
755 /* Dont set ->halted = 0 directly, let it be done via cpu_has_work
756 because there might be other conditions that state that c should
757 be sleeping. */
758 cpu_interrupt(c, CPU_INTERRUPT_WAKE);
759 }
760
761 static inline void mips_vpe_sleep(CPUMIPSState *c)
762 {
763 /* The VPE was shut off, really go to bed.
764 Reset any old _WAKE requests. */
765 c->halted = 1;
766 cpu_reset_interrupt(c, CPU_INTERRUPT_WAKE);
767 }
768
769 static inline void mips_tc_wake(CPUMIPSState *c, int tc)
770 {
771 /* FIXME: TC reschedule. */
772 if (mips_vpe_active(c) && !mips_vpe_is_wfi(c)) {
773 mips_vpe_wake(c);
774 }
775 }
776
777 static inline void mips_tc_sleep(CPUMIPSState *c, int tc)
778 {
779 /* FIXME: TC reschedule. */
780 if (!mips_vpe_active(c)) {
781 mips_vpe_sleep(c);
782 }
783 }
784
785 /* tc should point to an int with the value of the global TC index.
786 This function will transform it into a local index within the
787 returned CPUMIPSState.
788
789 FIXME: This code assumes that all VPEs have the same number of TCs,
790 which depends on runtime setup. Can probably be fixed by
791 walking the list of CPUMIPSStates. */
792 static CPUMIPSState *mips_cpu_map_tc(int *tc)
793 {
794 CPUMIPSState *other;
795 int vpe_idx, nr_threads = env->nr_threads;
796 int tc_idx = *tc;
797
798 if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) {
799 /* Not allowed to address other CPUs. */
800 *tc = env->current_tc;
801 return env;
802 }
803
804 vpe_idx = tc_idx / nr_threads;
805 *tc = tc_idx % nr_threads;
806 other = qemu_get_cpu(vpe_idx);
807 return other ? other : env;
808 }
809
810 /* The per VPE CP0_Status register shares some fields with the per TC
811 CP0_TCStatus registers. These fields are wired to the same registers,
812 so changes to either of them should be reflected on both registers.
813
814 Also, EntryHi shares the bottom 8 bit ASID with TCStauts.
815
816 These helper call synchronizes the regs for a given cpu. */
817
818 /* Called for updates to CP0_Status. */
819 static void sync_c0_status(CPUMIPSState *cpu, int tc)
820 {
821 int32_t tcstatus, *tcst;
822 uint32_t v = cpu->CP0_Status;
823 uint32_t cu, mx, asid, ksu;
824 uint32_t mask = ((1 << CP0TCSt_TCU3)
825 | (1 << CP0TCSt_TCU2)
826 | (1 << CP0TCSt_TCU1)
827 | (1 << CP0TCSt_TCU0)
828 | (1 << CP0TCSt_TMX)
829 | (3 << CP0TCSt_TKSU)
830 | (0xff << CP0TCSt_TASID));
831
832 cu = (v >> CP0St_CU0) & 0xf;
833 mx = (v >> CP0St_MX) & 0x1;
834 ksu = (v >> CP0St_KSU) & 0x3;
835 asid = env->CP0_EntryHi & 0xff;
836
837 tcstatus = cu << CP0TCSt_TCU0;
838 tcstatus |= mx << CP0TCSt_TMX;
839 tcstatus |= ksu << CP0TCSt_TKSU;
840 tcstatus |= asid;
841
842 if (tc == cpu->current_tc) {
843 tcst = &cpu->active_tc.CP0_TCStatus;
844 } else {
845 tcst = &cpu->tcs[tc].CP0_TCStatus;
846 }
847
848 *tcst &= ~mask;
849 *tcst |= tcstatus;
850 compute_hflags(cpu);
851 }
852
853 /* Called for updates to CP0_TCStatus. */
854 static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc, target_ulong v)
855 {
856 uint32_t status;
857 uint32_t tcu, tmx, tasid, tksu;
858 uint32_t mask = ((1 << CP0St_CU3)
859 | (1 << CP0St_CU2)
860 | (1 << CP0St_CU1)
861 | (1 << CP0St_CU0)
862 | (1 << CP0St_MX)
863 | (3 << CP0St_KSU));
864
865 tcu = (v >> CP0TCSt_TCU0) & 0xf;
866 tmx = (v >> CP0TCSt_TMX) & 0x1;
867 tasid = v & 0xff;
868 tksu = (v >> CP0TCSt_TKSU) & 0x3;
869
870 status = tcu << CP0St_CU0;
871 status |= tmx << CP0St_MX;
872 status |= tksu << CP0St_KSU;
873
874 cpu->CP0_Status &= ~mask;
875 cpu->CP0_Status |= status;
876
877 /* Sync the TASID with EntryHi. */
878 cpu->CP0_EntryHi &= ~0xff;
879 cpu->CP0_EntryHi = tasid;
880
881 compute_hflags(cpu);
882 }
883
884 /* Called for updates to CP0_EntryHi. */
885 static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
886 {
887 int32_t *tcst;
888 uint32_t asid, v = cpu->CP0_EntryHi;
889
890 asid = v & 0xff;
891
892 if (tc == cpu->current_tc) {
893 tcst = &cpu->active_tc.CP0_TCStatus;
894 } else {
895 tcst = &cpu->tcs[tc].CP0_TCStatus;
896 }
897
898 *tcst &= ~0xff;
899 *tcst |= asid;
900 }
901
902 /* CP0 helpers */
903 target_ulong helper_mfc0_mvpcontrol (void)
904 {
905 return env->mvp->CP0_MVPControl;
906 }
907
908 target_ulong helper_mfc0_mvpconf0 (void)
909 {
910 return env->mvp->CP0_MVPConf0;
911 }
912
913 target_ulong helper_mfc0_mvpconf1 (void)
914 {
915 return env->mvp->CP0_MVPConf1;
916 }
917
918 target_ulong helper_mfc0_random (void)
919 {
920 return (int32_t)cpu_mips_get_random(env);
921 }
922
923 target_ulong helper_mfc0_tcstatus (void)
924 {
925 return env->active_tc.CP0_TCStatus;
926 }
927
928 target_ulong helper_mftc0_tcstatus(void)
929 {
930 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
931 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
932
933 if (other_tc == other->current_tc)
934 return other->active_tc.CP0_TCStatus;
935 else
936 return other->tcs[other_tc].CP0_TCStatus;
937 }
938
939 target_ulong helper_mfc0_tcbind (void)
940 {
941 return env->active_tc.CP0_TCBind;
942 }
943
944 target_ulong helper_mftc0_tcbind(void)
945 {
946 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
947 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
948
949 if (other_tc == other->current_tc)
950 return other->active_tc.CP0_TCBind;
951 else
952 return other->tcs[other_tc].CP0_TCBind;
953 }
954
955 target_ulong helper_mfc0_tcrestart (void)
956 {
957 return env->active_tc.PC;
958 }
959
960 target_ulong helper_mftc0_tcrestart(void)
961 {
962 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
963 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
964
965 if (other_tc == other->current_tc)
966 return other->active_tc.PC;
967 else
968 return other->tcs[other_tc].PC;
969 }
970
971 target_ulong helper_mfc0_tchalt (void)
972 {
973 return env->active_tc.CP0_TCHalt;
974 }
975
976 target_ulong helper_mftc0_tchalt(void)
977 {
978 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
979 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
980
981 if (other_tc == other->current_tc)
982 return other->active_tc.CP0_TCHalt;
983 else
984 return other->tcs[other_tc].CP0_TCHalt;
985 }
986
987 target_ulong helper_mfc0_tccontext (void)
988 {
989 return env->active_tc.CP0_TCContext;
990 }
991
992 target_ulong helper_mftc0_tccontext(void)
993 {
994 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
995 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
996
997 if (other_tc == other->current_tc)
998 return other->active_tc.CP0_TCContext;
999 else
1000 return other->tcs[other_tc].CP0_TCContext;
1001 }
1002
1003 target_ulong helper_mfc0_tcschedule (void)
1004 {
1005 return env->active_tc.CP0_TCSchedule;
1006 }
1007
1008 target_ulong helper_mftc0_tcschedule(void)
1009 {
1010 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1011 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1012
1013 if (other_tc == other->current_tc)
1014 return other->active_tc.CP0_TCSchedule;
1015 else
1016 return other->tcs[other_tc].CP0_TCSchedule;
1017 }
1018
1019 target_ulong helper_mfc0_tcschefback (void)
1020 {
1021 return env->active_tc.CP0_TCScheFBack;
1022 }
1023
1024 target_ulong helper_mftc0_tcschefback(void)
1025 {
1026 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1027 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1028
1029 if (other_tc == other->current_tc)
1030 return other->active_tc.CP0_TCScheFBack;
1031 else
1032 return other->tcs[other_tc].CP0_TCScheFBack;
1033 }
1034
1035 target_ulong helper_mfc0_count (void)
1036 {
1037 return (int32_t)cpu_mips_get_count(env);
1038 }
1039
1040 target_ulong helper_mftc0_entryhi(void)
1041 {
1042 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1043 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1044
1045 return other->CP0_EntryHi;
1046 }
1047
1048 target_ulong helper_mftc0_cause(void)
1049 {
1050 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1051 int32_t tccause;
1052 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1053
1054 if (other_tc == other->current_tc) {
1055 tccause = other->CP0_Cause;
1056 } else {
1057 tccause = other->CP0_Cause;
1058 }
1059
1060 return tccause;
1061 }
1062
1063 target_ulong helper_mftc0_status(void)
1064 {
1065 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1066 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1067
1068 return other->CP0_Status;
1069 }
1070
1071 target_ulong helper_mfc0_lladdr (void)
1072 {
1073 return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
1074 }
1075
1076 target_ulong helper_mfc0_watchlo (uint32_t sel)
1077 {
1078 return (int32_t)env->CP0_WatchLo[sel];
1079 }
1080
1081 target_ulong helper_mfc0_watchhi (uint32_t sel)
1082 {
1083 return env->CP0_WatchHi[sel];
1084 }
1085
1086 target_ulong helper_mfc0_debug (void)
1087 {
1088 target_ulong t0 = env->CP0_Debug;
1089 if (env->hflags & MIPS_HFLAG_DM)
1090 t0 |= 1 << CP0DB_DM;
1091
1092 return t0;
1093 }
1094
1095 target_ulong helper_mftc0_debug(void)
1096 {
1097 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1098 int32_t tcstatus;
1099 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1100
1101 if (other_tc == other->current_tc)
1102 tcstatus = other->active_tc.CP0_Debug_tcstatus;
1103 else
1104 tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
1105
1106 /* XXX: Might be wrong, check with EJTAG spec. */
1107 return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1108 (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1109 }
1110
1111 #if defined(TARGET_MIPS64)
1112 target_ulong helper_dmfc0_tcrestart (void)
1113 {
1114 return env->active_tc.PC;
1115 }
1116
1117 target_ulong helper_dmfc0_tchalt (void)
1118 {
1119 return env->active_tc.CP0_TCHalt;
1120 }
1121
1122 target_ulong helper_dmfc0_tccontext (void)
1123 {
1124 return env->active_tc.CP0_TCContext;
1125 }
1126
1127 target_ulong helper_dmfc0_tcschedule (void)
1128 {
1129 return env->active_tc.CP0_TCSchedule;
1130 }
1131
1132 target_ulong helper_dmfc0_tcschefback (void)
1133 {
1134 return env->active_tc.CP0_TCScheFBack;
1135 }
1136
1137 target_ulong helper_dmfc0_lladdr (void)
1138 {
1139 return env->lladdr >> env->CP0_LLAddr_shift;
1140 }
1141
1142 target_ulong helper_dmfc0_watchlo (uint32_t sel)
1143 {
1144 return env->CP0_WatchLo[sel];
1145 }
1146 #endif /* TARGET_MIPS64 */
1147
1148 void helper_mtc0_index (target_ulong arg1)
1149 {
1150 int num = 1;
1151 unsigned int tmp = env->tlb->nb_tlb;
1152
1153 do {
1154 tmp >>= 1;
1155 num <<= 1;
1156 } while (tmp);
1157 env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
1158 }
1159
1160 void helper_mtc0_mvpcontrol (target_ulong arg1)
1161 {
1162 uint32_t mask = 0;
1163 uint32_t newval;
1164
1165 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
1166 mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
1167 (1 << CP0MVPCo_EVP);
1168 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1169 mask |= (1 << CP0MVPCo_STLB);
1170 newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
1171
1172 // TODO: Enable/disable shared TLB, enable/disable VPEs.
1173
1174 env->mvp->CP0_MVPControl = newval;
1175 }
1176
1177 void helper_mtc0_vpecontrol (target_ulong arg1)
1178 {
1179 uint32_t mask;
1180 uint32_t newval;
1181
1182 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
1183 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
1184 newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
1185
1186 /* Yield scheduler intercept not implemented. */
1187 /* Gating storage scheduler intercept not implemented. */
1188
1189 // TODO: Enable/disable TCs.
1190
1191 env->CP0_VPEControl = newval;
1192 }
1193
1194 void helper_mttc0_vpecontrol(target_ulong arg1)
1195 {
1196 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1197 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1198 uint32_t mask;
1199 uint32_t newval;
1200
1201 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
1202 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
1203 newval = (other->CP0_VPEControl & ~mask) | (arg1 & mask);
1204
1205 /* TODO: Enable/disable TCs. */
1206
1207 other->CP0_VPEControl = newval;
1208 }
1209
1210 target_ulong helper_mftc0_vpecontrol(void)
1211 {
1212 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1213 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1214 /* FIXME: Mask away return zero on read bits. */
1215 return other->CP0_VPEControl;
1216 }
1217
1218 target_ulong helper_mftc0_vpeconf0(void)
1219 {
1220 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1221 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1222
1223 return other->CP0_VPEConf0;
1224 }
1225
1226 void helper_mtc0_vpeconf0 (target_ulong arg1)
1227 {
1228 uint32_t mask = 0;
1229 uint32_t newval;
1230
1231 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
1232 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
1233 mask |= (0xff << CP0VPEC0_XTC);
1234 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1235 }
1236 newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1237
1238 // TODO: TC exclusive handling due to ERL/EXL.
1239
1240 env->CP0_VPEConf0 = newval;
1241 }
1242
1243 void helper_mttc0_vpeconf0(target_ulong arg1)
1244 {
1245 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1246 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1247 uint32_t mask = 0;
1248 uint32_t newval;
1249
1250 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1251 newval = (other->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1252
1253 /* TODO: TC exclusive handling due to ERL/EXL. */
1254 other->CP0_VPEConf0 = newval;
1255 }
1256
1257 void helper_mtc0_vpeconf1 (target_ulong arg1)
1258 {
1259 uint32_t mask = 0;
1260 uint32_t newval;
1261
1262 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1263 mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
1264 (0xff << CP0VPEC1_NCP1);
1265 newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
1266
1267 /* UDI not implemented. */
1268 /* CP2 not implemented. */
1269
1270 // TODO: Handle FPU (CP1) binding.
1271
1272 env->CP0_VPEConf1 = newval;
1273 }
1274
1275 void helper_mtc0_yqmask (target_ulong arg1)
1276 {
1277 /* Yield qualifier inputs not implemented. */
1278 env->CP0_YQMask = 0x00000000;
1279 }
1280
1281 void helper_mtc0_vpeopt (target_ulong arg1)
1282 {
1283 env->CP0_VPEOpt = arg1 & 0x0000ffff;
1284 }
1285
1286 void helper_mtc0_entrylo0 (target_ulong arg1)
1287 {
1288 /* Large physaddr (PABITS) not implemented */
1289 /* 1k pages not implemented */
1290 env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF;
1291 }
1292
1293 void helper_mtc0_tcstatus (target_ulong arg1)
1294 {
1295 uint32_t mask = env->CP0_TCStatus_rw_bitmask;
1296 uint32_t newval;
1297
1298 newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
1299
1300 env->active_tc.CP0_TCStatus = newval;
1301 sync_c0_tcstatus(env, env->current_tc, newval);
1302 }
1303
1304 void helper_mttc0_tcstatus (target_ulong arg1)
1305 {
1306 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1307 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1308
1309 if (other_tc == other->current_tc)
1310 other->active_tc.CP0_TCStatus = arg1;
1311 else
1312 other->tcs[other_tc].CP0_TCStatus = arg1;
1313 sync_c0_tcstatus(other, other_tc, arg1);
1314 }
1315
1316 void helper_mtc0_tcbind (target_ulong arg1)
1317 {
1318 uint32_t mask = (1 << CP0TCBd_TBE);
1319 uint32_t newval;
1320
1321 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1322 mask |= (1 << CP0TCBd_CurVPE);
1323 newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1324 env->active_tc.CP0_TCBind = newval;
1325 }
1326
1327 void helper_mttc0_tcbind (target_ulong arg1)
1328 {
1329 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1330 uint32_t mask = (1 << CP0TCBd_TBE);
1331 uint32_t newval;
1332 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1333
1334 if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1335 mask |= (1 << CP0TCBd_CurVPE);
1336 if (other_tc == other->current_tc) {
1337 newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1338 other->active_tc.CP0_TCBind = newval;
1339 } else {
1340 newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
1341 other->tcs[other_tc].CP0_TCBind = newval;
1342 }
1343 }
1344
1345 void helper_mtc0_tcrestart (target_ulong arg1)
1346 {
1347 env->active_tc.PC = arg1;
1348 env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1349 env->lladdr = 0ULL;
1350 /* MIPS16 not implemented. */
1351 }
1352
1353 void helper_mttc0_tcrestart (target_ulong arg1)
1354 {
1355 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1356 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1357
1358 if (other_tc == other->current_tc) {
1359 other->active_tc.PC = arg1;
1360 other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1361 other->lladdr = 0ULL;
1362 /* MIPS16 not implemented. */
1363 } else {
1364 other->tcs[other_tc].PC = arg1;
1365 other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1366 other->lladdr = 0ULL;
1367 /* MIPS16 not implemented. */
1368 }
1369 }
1370
1371 void helper_mtc0_tchalt (target_ulong arg1)
1372 {
1373 env->active_tc.CP0_TCHalt = arg1 & 0x1;
1374
1375 // TODO: Halt TC / Restart (if allocated+active) TC.
1376 if (env->active_tc.CP0_TCHalt & 1) {
1377 mips_tc_sleep(env, env->current_tc);
1378 } else {
1379 mips_tc_wake(env, env->current_tc);
1380 }
1381 }
1382
1383 void helper_mttc0_tchalt (target_ulong arg1)
1384 {
1385 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1386 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1387
1388 // TODO: Halt TC / Restart (if allocated+active) TC.
1389
1390 if (other_tc == other->current_tc)
1391 other->active_tc.CP0_TCHalt = arg1;
1392 else
1393 other->tcs[other_tc].CP0_TCHalt = arg1;
1394
1395 if (arg1 & 1) {
1396 mips_tc_sleep(other, other_tc);
1397 } else {
1398 mips_tc_wake(other, other_tc);
1399 }
1400 }
1401
1402 void helper_mtc0_tccontext (target_ulong arg1)
1403 {
1404 env->active_tc.CP0_TCContext = arg1;
1405 }
1406
1407 void helper_mttc0_tccontext (target_ulong arg1)
1408 {
1409 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1410 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1411
1412 if (other_tc == other->current_tc)
1413 other->active_tc.CP0_TCContext = arg1;
1414 else
1415 other->tcs[other_tc].CP0_TCContext = arg1;
1416 }
1417
1418 void helper_mtc0_tcschedule (target_ulong arg1)
1419 {
1420 env->active_tc.CP0_TCSchedule = arg1;
1421 }
1422
1423 void helper_mttc0_tcschedule (target_ulong arg1)
1424 {
1425 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1426 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1427
1428 if (other_tc == other->current_tc)
1429 other->active_tc.CP0_TCSchedule = arg1;
1430 else
1431 other->tcs[other_tc].CP0_TCSchedule = arg1;
1432 }
1433
1434 void helper_mtc0_tcschefback (target_ulong arg1)
1435 {
1436 env->active_tc.CP0_TCScheFBack = arg1;
1437 }
1438
1439 void helper_mttc0_tcschefback (target_ulong arg1)
1440 {
1441 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1442 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1443
1444 if (other_tc == other->current_tc)
1445 other->active_tc.CP0_TCScheFBack = arg1;
1446 else
1447 other->tcs[other_tc].CP0_TCScheFBack = arg1;
1448 }
1449
1450 void helper_mtc0_entrylo1 (target_ulong arg1)
1451 {
1452 /* Large physaddr (PABITS) not implemented */
1453 /* 1k pages not implemented */
1454 env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF;
1455 }
1456
1457 void helper_mtc0_context (target_ulong arg1)
1458 {
1459 env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
1460 }
1461
1462 void helper_mtc0_pagemask (target_ulong arg1)
1463 {
1464 /* 1k pages not implemented */
1465 env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1466 }
1467
1468 void helper_mtc0_pagegrain (target_ulong arg1)
1469 {
1470 /* SmartMIPS not implemented */
1471 /* Large physaddr (PABITS) not implemented */
1472 /* 1k pages not implemented */
1473 env->CP0_PageGrain = 0;
1474 }
1475
1476 void helper_mtc0_wired (target_ulong arg1)
1477 {
1478 env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1479 }
1480
1481 void helper_mtc0_srsconf0 (target_ulong arg1)
1482 {
1483 env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
1484 }
1485
1486 void helper_mtc0_srsconf1 (target_ulong arg1)
1487 {
1488 env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
1489 }
1490
1491 void helper_mtc0_srsconf2 (target_ulong arg1)
1492 {
1493 env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
1494 }
1495
1496 void helper_mtc0_srsconf3 (target_ulong arg1)
1497 {
1498 env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
1499 }
1500
1501 void helper_mtc0_srsconf4 (target_ulong arg1)
1502 {
1503 env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
1504 }
1505
1506 void helper_mtc0_hwrena (target_ulong arg1)
1507 {
1508 env->CP0_HWREna = arg1 & 0x0000000F;
1509 }
1510
1511 void helper_mtc0_count (target_ulong arg1)
1512 {
1513 cpu_mips_store_count(env, arg1);
1514 }
1515
1516 void helper_mtc0_entryhi (target_ulong arg1)
1517 {
1518 target_ulong old, val;
1519
1520 /* 1k pages not implemented */
1521 val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF);
1522 #if defined(TARGET_MIPS64)
1523 val &= env->SEGMask;
1524 #endif
1525 old = env->CP0_EntryHi;
1526 env->CP0_EntryHi = val;
1527 if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1528 sync_c0_entryhi(env, env->current_tc);
1529 }
1530 /* If the ASID changes, flush qemu's TLB. */
1531 if ((old & 0xFF) != (val & 0xFF))
1532 cpu_mips_tlb_flush(env, 1);
1533 }
1534
1535 void helper_mttc0_entryhi(target_ulong arg1)
1536 {
1537 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1538 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1539
1540 other->CP0_EntryHi = arg1;
1541 sync_c0_entryhi(other, other_tc);
1542 }
1543
1544 void helper_mtc0_compare (target_ulong arg1)
1545 {
1546 cpu_mips_store_compare(env, arg1);
1547 }
1548
1549 void helper_mtc0_status (target_ulong arg1)
1550 {
1551 uint32_t val, old;
1552 uint32_t mask = env->CP0_Status_rw_bitmask;
1553
1554 val = arg1 & mask;
1555 old = env->CP0_Status;
1556 env->CP0_Status = (env->CP0_Status & ~mask) | val;
1557 if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1558 sync_c0_status(env, env->current_tc);
1559 } else {
1560 compute_hflags(env);
1561 }
1562
1563 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1564 qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1565 old, old & env->CP0_Cause & CP0Ca_IP_mask,
1566 val, val & env->CP0_Cause & CP0Ca_IP_mask,
1567 env->CP0_Cause);
1568 switch (env->hflags & MIPS_HFLAG_KSU) {
1569 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1570 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1571 case MIPS_HFLAG_KM: qemu_log("\n"); break;
1572 default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1573 }
1574 }
1575 }
1576
1577 void helper_mttc0_status(target_ulong arg1)
1578 {
1579 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1580 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1581
1582 other->CP0_Status = arg1 & ~0xf1000018;
1583 sync_c0_status(other, other_tc);
1584 }
1585
1586 void helper_mtc0_intctl (target_ulong arg1)
1587 {
1588 /* vectored interrupts not implemented, no performance counters. */
1589 env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
1590 }
1591
1592 void helper_mtc0_srsctl (target_ulong arg1)
1593 {
1594 uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1595 env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
1596 }
1597
1598 static void mtc0_cause(CPUMIPSState *cpu, target_ulong arg1)
1599 {
1600 uint32_t mask = 0x00C00300;
1601 uint32_t old = cpu->CP0_Cause;
1602 int i;
1603
1604 if (cpu->insn_flags & ISA_MIPS32R2) {
1605 mask |= 1 << CP0Ca_DC;
1606 }
1607
1608 cpu->CP0_Cause = (cpu->CP0_Cause & ~mask) | (arg1 & mask);
1609
1610 if ((old ^ cpu->CP0_Cause) & (1 << CP0Ca_DC)) {
1611 if (cpu->CP0_Cause & (1 << CP0Ca_DC)) {
1612 cpu_mips_stop_count(cpu);
1613 } else {
1614 cpu_mips_start_count(cpu);
1615 }
1616 }
1617
1618 /* Set/reset software interrupts */
1619 for (i = 0 ; i < 2 ; i++) {
1620 if ((old ^ cpu->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
1621 cpu_mips_soft_irq(cpu, i, cpu->CP0_Cause & (1 << (CP0Ca_IP + i)));
1622 }
1623 }
1624 }
1625
1626 void helper_mtc0_cause(target_ulong arg1)
1627 {
1628 mtc0_cause(env, arg1);
1629 }
1630
1631 void helper_mttc0_cause(target_ulong arg1)
1632 {
1633 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1634 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1635
1636 mtc0_cause(other, arg1);
1637 }
1638
1639 target_ulong helper_mftc0_epc(void)
1640 {
1641 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1642 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1643
1644 return other->CP0_EPC;
1645 }
1646
1647 target_ulong helper_mftc0_ebase(void)
1648 {
1649 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1650 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1651
1652 return other->CP0_EBase;
1653 }
1654
1655 void helper_mtc0_ebase (target_ulong arg1)
1656 {
1657 /* vectored interrupts not implemented */
1658 env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
1659 }
1660
1661 void helper_mttc0_ebase(target_ulong arg1)
1662 {
1663 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1664 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1665 other->CP0_EBase = (other->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
1666 }
1667
1668 target_ulong helper_mftc0_configx(target_ulong idx)
1669 {
1670 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1671 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1672
1673 switch (idx) {
1674 case 0: return other->CP0_Config0;
1675 case 1: return other->CP0_Config1;
1676 case 2: return other->CP0_Config2;
1677 case 3: return other->CP0_Config3;
1678 /* 4 and 5 are reserved. */
1679 case 6: return other->CP0_Config6;
1680 case 7: return other->CP0_Config7;
1681 default:
1682 break;
1683 }
1684 return 0;
1685 }
1686
1687 void helper_mtc0_config0 (target_ulong arg1)
1688 {
1689 env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
1690 }
1691
1692 void helper_mtc0_config2 (target_ulong arg1)
1693 {
1694 /* tertiary/secondary caches not implemented */
1695 env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1696 }
1697
1698 void helper_mtc0_lladdr (target_ulong arg1)
1699 {
1700 target_long mask = env->CP0_LLAddr_rw_bitmask;
1701 arg1 = arg1 << env->CP0_LLAddr_shift;
1702 env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
1703 }
1704
1705 void helper_mtc0_watchlo (target_ulong arg1, uint32_t sel)
1706 {
1707 /* Watch exceptions for instructions, data loads, data stores
1708 not implemented. */
1709 env->CP0_WatchLo[sel] = (arg1 & ~0x7);
1710 }
1711
1712 void helper_mtc0_watchhi (target_ulong arg1, uint32_t sel)
1713 {
1714 env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
1715 env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
1716 }
1717
1718 void helper_mtc0_xcontext (target_ulong arg1)
1719 {
1720 target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1721 env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
1722 }
1723
1724 void helper_mtc0_framemask (target_ulong arg1)
1725 {
1726 env->CP0_Framemask = arg1; /* XXX */
1727 }
1728
1729 void helper_mtc0_debug (target_ulong arg1)
1730 {
1731 env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1732 if (arg1 & (1 << CP0DB_DM))
1733 env->hflags |= MIPS_HFLAG_DM;
1734 else
1735 env->hflags &= ~MIPS_HFLAG_DM;
1736 }
1737
1738 void helper_mttc0_debug(target_ulong arg1)
1739 {
1740 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1741 uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1742 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1743
1744 /* XXX: Might be wrong, check with EJTAG spec. */
1745 if (other_tc == other->current_tc)
1746 other->active_tc.CP0_Debug_tcstatus = val;
1747 else
1748 other->tcs[other_tc].CP0_Debug_tcstatus = val;
1749 other->CP0_Debug = (other->CP0_Debug &
1750 ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1751 (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1752 }
1753
1754 void helper_mtc0_performance0 (target_ulong arg1)
1755 {
1756 env->CP0_Performance0 = arg1 & 0x000007ff;
1757 }
1758
1759 void helper_mtc0_taglo (target_ulong arg1)
1760 {
1761 env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1762 }
1763
1764 void helper_mtc0_datalo (target_ulong arg1)
1765 {
1766 env->CP0_DataLo = arg1; /* XXX */
1767 }
1768
1769 void helper_mtc0_taghi (target_ulong arg1)
1770 {
1771 env->CP0_TagHi = arg1; /* XXX */
1772 }
1773
1774 void helper_mtc0_datahi (target_ulong arg1)
1775 {
1776 env->CP0_DataHi = arg1; /* XXX */
1777 }
1778
1779 /* MIPS MT functions */
1780 target_ulong helper_mftgpr(uint32_t sel)
1781 {
1782 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1783 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1784
1785 if (other_tc == other->current_tc)
1786 return other->active_tc.gpr[sel];
1787 else
1788 return other->tcs[other_tc].gpr[sel];
1789 }
1790
1791 target_ulong helper_mftlo(uint32_t sel)
1792 {
1793 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1794 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1795
1796 if (other_tc == other->current_tc)
1797 return other->active_tc.LO[sel];
1798 else
1799 return other->tcs[other_tc].LO[sel];
1800 }
1801
1802 target_ulong helper_mfthi(uint32_t sel)
1803 {
1804 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1805 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1806
1807 if (other_tc == other->current_tc)
1808 return other->active_tc.HI[sel];
1809 else
1810 return other->tcs[other_tc].HI[sel];
1811 }
1812
1813 target_ulong helper_mftacx(uint32_t sel)
1814 {
1815 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1816 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1817
1818 if (other_tc == other->current_tc)
1819 return other->active_tc.ACX[sel];
1820 else
1821 return other->tcs[other_tc].ACX[sel];
1822 }
1823
1824 target_ulong helper_mftdsp(void)
1825 {
1826 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1827 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1828
1829 if (other_tc == other->current_tc)
1830 return other->active_tc.DSPControl;
1831 else
1832 return other->tcs[other_tc].DSPControl;
1833 }
1834
1835 void helper_mttgpr(target_ulong arg1, uint32_t sel)
1836 {
1837 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1838 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1839
1840 if (other_tc == other->current_tc)
1841 other->active_tc.gpr[sel] = arg1;
1842 else
1843 other->tcs[other_tc].gpr[sel] = arg1;
1844 }
1845
1846 void helper_mttlo(target_ulong arg1, uint32_t sel)
1847 {
1848 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1849 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1850
1851 if (other_tc == other->current_tc)
1852 other->active_tc.LO[sel] = arg1;
1853 else
1854 other->tcs[other_tc].LO[sel] = arg1;
1855 }
1856
1857 void helper_mtthi(target_ulong arg1, uint32_t sel)
1858 {
1859 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1860 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1861
1862 if (other_tc == other->current_tc)
1863 other->active_tc.HI[sel] = arg1;
1864 else
1865 other->tcs[other_tc].HI[sel] = arg1;
1866 }
1867
1868 void helper_mttacx(target_ulong arg1, uint32_t sel)
1869 {
1870 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1871 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1872
1873 if (other_tc == other->current_tc)
1874 other->active_tc.ACX[sel] = arg1;
1875 else
1876 other->tcs[other_tc].ACX[sel] = arg1;
1877 }
1878
1879 void helper_mttdsp(target_ulong arg1)
1880 {
1881 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1882 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
1883
1884 if (other_tc == other->current_tc)
1885 other->active_tc.DSPControl = arg1;
1886 else
1887 other->tcs[other_tc].DSPControl = arg1;
1888 }
1889
1890 /* MIPS MT functions */
1891 target_ulong helper_dmt(void)
1892 {
1893 // TODO
1894 return 0;
1895 }
1896
1897 target_ulong helper_emt(void)
1898 {
1899 // TODO
1900 return 0;
1901 }
1902
1903 target_ulong helper_dvpe(void)
1904 {
1905 CPUMIPSState *other_cpu = first_cpu;
1906 target_ulong prev = env->mvp->CP0_MVPControl;
1907
1908 do {
1909 /* Turn off all VPEs except the one executing the dvpe. */
1910 if (other_cpu != env) {
1911 other_cpu->mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
1912 mips_vpe_sleep(other_cpu);
1913 }
1914 other_cpu = other_cpu->next_cpu;
1915 } while (other_cpu);
1916 return prev;
1917 }
1918
1919 target_ulong helper_evpe(void)
1920 {
1921 CPUMIPSState *other_cpu = first_cpu;
1922 target_ulong prev = env->mvp->CP0_MVPControl;
1923
1924 do {
1925 if (other_cpu != env
1926 /* If the VPE is WFI, don't disturb its sleep. */
1927 && !mips_vpe_is_wfi(other_cpu)) {
1928 /* Enable the VPE. */
1929 other_cpu->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
1930 mips_vpe_wake(other_cpu); /* And wake it up. */
1931 }
1932 other_cpu = other_cpu->next_cpu;
1933 } while (other_cpu);
1934 return prev;
1935 }
1936 #endif /* !CONFIG_USER_ONLY */
1937
1938 void helper_fork(target_ulong arg1, target_ulong arg2)
1939 {
1940 // arg1 = rt, arg2 = rs
1941 arg1 = 0;
1942 // TODO: store to TC register
1943 }
1944
1945 target_ulong helper_yield(target_ulong arg)
1946 {
1947 target_long arg1 = arg;
1948
1949 if (arg1 < 0) {
1950 /* No scheduling policy implemented. */
1951 if (arg1 != -2) {
1952 if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
1953 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
1954 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1955 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
1956 helper_raise_exception(EXCP_THREAD);
1957 }
1958 }
1959 } else if (arg1 == 0) {
1960 if (0 /* TODO: TC underflow */) {
1961 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1962 helper_raise_exception(EXCP_THREAD);
1963 } else {
1964 // TODO: Deallocate TC
1965 }
1966 } else if (arg1 > 0) {
1967 /* Yield qualifier inputs not implemented. */
1968 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1969 env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
1970 helper_raise_exception(EXCP_THREAD);
1971 }
1972 return env->CP0_YQMask;
1973 }
1974
1975 #ifndef CONFIG_USER_ONLY
1976 /* TLB management */
1977 static void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global)
1978 {
1979 /* Flush qemu's TLB and discard all shadowed entries. */
1980 tlb_flush (env, flush_global);
1981 env->tlb->tlb_in_use = env->tlb->nb_tlb;
1982 }
1983
1984 static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
1985 {
1986 /* Discard entries from env->tlb[first] onwards. */
1987 while (env->tlb->tlb_in_use > first) {
1988 r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
1989 }
1990 }
1991
1992 static void r4k_fill_tlb (int idx)
1993 {
1994 r4k_tlb_t *tlb;
1995
1996 /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
1997 tlb = &env->tlb->mmu.r4k.tlb[idx];
1998 tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1999 #if defined(TARGET_MIPS64)
2000 tlb->VPN &= env->SEGMask;
2001 #endif
2002 tlb->ASID = env->CP0_EntryHi & 0xFF;
2003 tlb->PageMask = env->CP0_PageMask;
2004 tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
2005 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
2006 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
2007 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
2008 tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
2009 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
2010 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
2011 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
2012 tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
2013 }
2014
2015 void r4k_helper_tlbwi (void)
2016 {
2017 int idx;
2018
2019 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
2020
2021 /* Discard cached TLB entries. We could avoid doing this if the
2022 tlbwi is just upgrading access permissions on the current entry;
2023 that might be a further win. */
2024 r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
2025
2026 r4k_invalidate_tlb(env, idx, 0);
2027 r4k_fill_tlb(idx);
2028 }
2029
2030 void r4k_helper_tlbwr (void)
2031 {
2032 int r = cpu_mips_get_random(env);
2033
2034 r4k_invalidate_tlb(env, r, 1);
2035 r4k_fill_tlb(r);
2036 }
2037
2038 void r4k_helper_tlbp (void)
2039 {
2040 r4k_tlb_t *tlb;
2041 target_ulong mask;
2042 target_ulong tag;
2043 target_ulong VPN;
2044 uint8_t ASID;
2045 int i;
2046
2047 ASID = env->CP0_EntryHi & 0xFF;
2048 for (i = 0; i < env->tlb->nb_tlb; i++) {
2049 tlb = &env->tlb->mmu.r4k.tlb[i];
2050 /* 1k pages are not supported. */
2051 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
2052 tag = env->CP0_EntryHi & ~mask;
2053 VPN = tlb->VPN & ~mask;
2054 /* Check ASID, virtual page number & size */
2055 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
2056 /* TLB match */
2057 env->CP0_Index = i;
2058 break;
2059 }
2060 }
2061 if (i == env->tlb->nb_tlb) {
2062 /* No match. Discard any shadow entries, if any of them match. */
2063 for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
2064 tlb = &env->tlb->mmu.r4k.tlb[i];
2065 /* 1k pages are not supported. */
2066 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
2067 tag = env->CP0_EntryHi & ~mask;
2068 VPN = tlb->VPN & ~mask;
2069 /* Check ASID, virtual page number & size */
2070 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
2071 r4k_mips_tlb_flush_extra (env, i);
2072 break;
2073 }
2074 }
2075
2076 env->CP0_Index |= 0x80000000;
2077 }
2078 }
2079
2080 void r4k_helper_tlbr (void)
2081 {
2082 r4k_tlb_t *tlb;
2083 uint8_t ASID;
2084 int idx;
2085
2086 ASID = env->CP0_EntryHi & 0xFF;
2087 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
2088 tlb = &env->tlb->mmu.r4k.tlb[idx];
2089
2090 /* If this will change the current ASID, flush qemu's TLB. */
2091 if (ASID != tlb->ASID)
2092 cpu_mips_tlb_flush (env, 1);
2093
2094 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
2095
2096 env->CP0_EntryHi = tlb->VPN | tlb->ASID;
2097 env->CP0_PageMask = tlb->PageMask;
2098 env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
2099 (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
2100 env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
2101 (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
2102 }
2103
2104 void helper_tlbwi(void)
2105 {
2106 env->tlb->helper_tlbwi();
2107 }
2108
2109 void helper_tlbwr(void)
2110 {
2111 env->tlb->helper_tlbwr();
2112 }
2113
2114 void helper_tlbp(void)
2115 {
2116 env->tlb->helper_tlbp();
2117 }
2118
2119 void helper_tlbr(void)
2120 {
2121 env->tlb->helper_tlbr();
2122 }
2123
2124 /* Specials */
2125 target_ulong helper_di (void)
2126 {
2127 target_ulong t0 = env->CP0_Status;
2128
2129 env->CP0_Status = t0 & ~(1 << CP0St_IE);
2130 return t0;
2131 }
2132
2133 target_ulong helper_ei (void)
2134 {
2135 target_ulong t0 = env->CP0_Status;
2136
2137 env->CP0_Status = t0 | (1 << CP0St_IE);
2138 return t0;
2139 }
2140
2141 static void debug_pre_eret (void)
2142 {
2143 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2144 qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2145 env->active_tc.PC, env->CP0_EPC);
2146 if (env->CP0_Status & (1 << CP0St_ERL))
2147 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2148 if (env->hflags & MIPS_HFLAG_DM)
2149 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2150 qemu_log("\n");
2151 }
2152 }
2153
2154 static void debug_post_eret (void)
2155 {
2156 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2157 qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2158 env->active_tc.PC, env->CP0_EPC);
2159 if (env->CP0_Status & (1 << CP0St_ERL))
2160 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2161 if (env->hflags & MIPS_HFLAG_DM)
2162 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2163 switch (env->hflags & MIPS_HFLAG_KSU) {
2164 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
2165 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
2166 case MIPS_HFLAG_KM: qemu_log("\n"); break;
2167 default: cpu_abort(env, "Invalid MMU mode!\n"); break;
2168 }
2169 }
2170 }
2171
2172 static void set_pc (target_ulong error_pc)
2173 {
2174 env->active_tc.PC = error_pc & ~(target_ulong)1;
2175 if (error_pc & 1) {
2176 env->hflags |= MIPS_HFLAG_M16;
2177 } else {
2178 env->hflags &= ~(MIPS_HFLAG_M16);
2179 }
2180 }
2181
2182 void helper_eret (void)
2183 {
2184 debug_pre_eret();
2185 if (env->CP0_Status & (1 << CP0St_ERL)) {
2186 set_pc(env->CP0_ErrorEPC);
2187 env->CP0_Status &= ~(1 << CP0St_ERL);
2188 } else {
2189 set_pc(env->CP0_EPC);
2190 env->CP0_Status &= ~(1 << CP0St_EXL);
2191 }
2192 compute_hflags(env);
2193 debug_post_eret();
2194 env->lladdr = 1;
2195 }
2196
2197 void helper_deret (void)
2198 {
2199 debug_pre_eret();
2200 set_pc(env->CP0_DEPC);
2201
2202 env->hflags &= MIPS_HFLAG_DM;
2203 compute_hflags(env);
2204 debug_post_eret();
2205 env->lladdr = 1;
2206 }
2207 #endif /* !CONFIG_USER_ONLY */
2208
2209 target_ulong helper_rdhwr_cpunum(void)
2210 {
2211 if ((env->hflags & MIPS_HFLAG_CP0) ||
2212 (env->CP0_HWREna & (1 << 0)))
2213 return env->CP0_EBase & 0x3ff;
2214 else
2215 helper_raise_exception(EXCP_RI);
2216
2217 return 0;
2218 }
2219
2220 target_ulong helper_rdhwr_synci_step(void)
2221 {
2222 if ((env->hflags & MIPS_HFLAG_CP0) ||
2223 (env->CP0_HWREna & (1 << 1)))
2224 return env->SYNCI_Step;
2225 else
2226 helper_raise_exception(EXCP_RI);
2227
2228 return 0;
2229 }
2230
2231 target_ulong helper_rdhwr_cc(void)
2232 {
2233 if ((env->hflags & MIPS_HFLAG_CP0) ||
2234 (env->CP0_HWREna & (1 << 2)))
2235 return env->CP0_Count;
2236 else
2237 helper_raise_exception(EXCP_RI);
2238
2239 return 0;
2240 }
2241
2242 target_ulong helper_rdhwr_ccres(void)
2243 {
2244 if ((env->hflags & MIPS_HFLAG_CP0) ||
2245 (env->CP0_HWREna & (1 << 3)))
2246 return env->CCRes;
2247 else
2248 helper_raise_exception(EXCP_RI);
2249
2250 return 0;
2251 }
2252
2253 void helper_pmon (int function)
2254 {
2255 function /= 2;
2256 switch (function) {
2257 case 2: /* TODO: char inbyte(int waitflag); */
2258 if (env->active_tc.gpr[4] == 0)
2259 env->active_tc.gpr[2] = -1;
2260 /* Fall through */
2261 case 11: /* TODO: char inbyte (void); */
2262 env->active_tc.gpr[2] = -1;
2263 break;
2264 case 3:
2265 case 12:
2266 printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
2267 break;
2268 case 17:
2269 break;
2270 case 158:
2271 {
2272 unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
2273 printf("%s", fmt);
2274 }
2275 break;
2276 }
2277 }
2278
2279 void helper_wait (void)
2280 {
2281 env->halted = 1;
2282 cpu_reset_interrupt(env, CPU_INTERRUPT_WAKE);
2283 helper_raise_exception(EXCP_HLT);
2284 }
2285
2286 #if !defined(CONFIG_USER_ONLY)
2287
2288 static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
2289 int is_user, uintptr_t retaddr);
2290
2291 #define MMUSUFFIX _mmu
2292 #define ALIGNED_ONLY
2293
2294 #define SHIFT 0
2295 #include "softmmu_template.h"
2296
2297 #define SHIFT 1
2298 #include "softmmu_template.h"
2299
2300 #define SHIFT 2
2301 #include "softmmu_template.h"
2302
2303 #define SHIFT 3
2304 #include "softmmu_template.h"
2305
2306 static void do_unaligned_access(target_ulong addr, int is_write,
2307 int is_user, uintptr_t retaddr)
2308 {
2309 env->CP0_BadVAddr = addr;
2310 do_restore_state (retaddr);
2311 helper_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
2312 }
2313
2314 void tlb_fill(CPUMIPSState *env1, target_ulong addr, int is_write, int mmu_idx,
2315 uintptr_t retaddr)
2316 {
2317 TranslationBlock *tb;
2318 CPUMIPSState *saved_env;
2319 int ret;
2320
2321 saved_env = env;
2322 env = env1;
2323 ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx);
2324 if (ret) {
2325 if (retaddr) {
2326 /* now we have a real cpu fault */
2327 tb = tb_find_pc(retaddr);
2328 if (tb) {
2329 /* the PC is inside the translated code. It means that we have
2330 a virtual CPU fault */
2331 cpu_restore_state(tb, env, retaddr);
2332 }
2333 }
2334 helper_raise_exception_err(env->exception_index, env->error_code);
2335 }
2336 env = saved_env;
2337 }
2338
2339 void cpu_unassigned_access(CPUMIPSState *env1, target_phys_addr_t addr,
2340 int is_write, int is_exec, int unused, int size)
2341 {
2342 env = env1;
2343
2344 if (is_exec)
2345 helper_raise_exception(EXCP_IBE);
2346 else
2347 helper_raise_exception(EXCP_DBE);
2348 }
2349 #endif /* !CONFIG_USER_ONLY */
2350
2351 /* Complex FPU operations which may need stack space. */
2352
2353 #define FLOAT_ONE32 make_float32(0x3f8 << 20)
2354 #define FLOAT_ONE64 make_float64(0x3ffULL << 52)
2355 #define FLOAT_TWO32 make_float32(1 << 30)
2356 #define FLOAT_TWO64 make_float64(1ULL << 62)
2357 #define FLOAT_QNAN32 0x7fbfffff
2358 #define FLOAT_QNAN64 0x7ff7ffffffffffffULL
2359 #define FLOAT_SNAN32 0x7fffffff
2360 #define FLOAT_SNAN64 0x7fffffffffffffffULL
2361
2362 /* convert MIPS rounding mode in FCR31 to IEEE library */
2363 static unsigned int ieee_rm[] = {
2364 float_round_nearest_even,
2365 float_round_to_zero,
2366 float_round_up,
2367 float_round_down
2368 };
2369
2370 #define RESTORE_ROUNDING_MODE \
2371 set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status)
2372
2373 #define RESTORE_FLUSH_MODE \
2374 set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status);
2375
2376 target_ulong helper_cfc1 (uint32_t reg)
2377 {
2378 target_ulong arg1;
2379
2380 switch (reg) {
2381 case 0:
2382 arg1 = (int32_t)env->active_fpu.fcr0;
2383 break;
2384 case 25:
2385 arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
2386 break;
2387 case 26:
2388 arg1 = env->active_fpu.fcr31 & 0x0003f07c;
2389 break;
2390 case 28:
2391 arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
2392 break;
2393 default:
2394 arg1 = (int32_t)env->active_fpu.fcr31;
2395 break;
2396 }
2397
2398 return arg1;
2399 }
2400
2401 void helper_ctc1 (target_ulong arg1, uint32_t reg)
2402 {
2403 switch(reg) {
2404 case 25:
2405 if (arg1 & 0xffffff00)
2406 return;
2407 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
2408 ((arg1 & 0x1) << 23);
2409 break;
2410 case 26:
2411 if (arg1 & 0x007c0000)
2412 return;
2413 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
2414 break;
2415 case 28:
2416 if (arg1 & 0x007c0000)
2417 return;
2418 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
2419 ((arg1 & 0x4) << 22);
2420 break;
2421 case 31:
2422 if (arg1 & 0x007c0000)
2423 return;
2424 env->active_fpu.fcr31 = arg1;
2425 break;
2426 default:
2427 return;
2428 }
2429 /* set rounding mode */
2430 RESTORE_ROUNDING_MODE;
2431 /* set flush-to-zero mode */
2432 RESTORE_FLUSH_MODE;
2433 set_float_exception_flags(0, &env->active_fpu.fp_status);
2434 if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
2435 helper_raise_exception(EXCP_FPE);
2436 }
2437
2438 static inline int ieee_ex_to_mips(int xcpt)
2439 {
2440 int ret = 0;
2441 if (xcpt) {
2442 if (xcpt & float_flag_invalid) {
2443 ret |= FP_INVALID;
2444 }
2445 if (xcpt & float_flag_overflow) {
2446 ret |= FP_OVERFLOW;
2447 }
2448 if (xcpt & float_flag_underflow) {
2449 ret |= FP_UNDERFLOW;
2450 }
2451 if (xcpt & float_flag_divbyzero) {
2452 ret |= FP_DIV0;
2453 }
2454 if (xcpt & float_flag_inexact) {
2455 ret |= FP_INEXACT;
2456 }
2457 }
2458 return ret;
2459 }
2460
2461 static inline void update_fcr31(void)
2462 {
2463 int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
2464
2465 SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
2466 if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp)
2467 helper_raise_exception(EXCP_FPE);
2468 else
2469 UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2470 }
2471
2472 /* Float support.
2473 Single precition routines have a "s" suffix, double precision a
2474 "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2475 paired single lower "pl", paired single upper "pu". */
2476
2477 /* unary operations, modifying fp status */
2478 uint64_t helper_float_sqrt_d(uint64_t fdt0)
2479 {
2480 return float64_sqrt(fdt0, &env->active_fpu.fp_status);
2481 }
2482
2483 uint32_t helper_float_sqrt_s(uint32_t fst0)
2484 {
2485 return float32_sqrt(fst0, &env->active_fpu.fp_status);
2486 }
2487
2488 uint64_t helper_float_cvtd_s(uint32_t fst0)
2489 {
2490 uint64_t fdt2;
2491
2492 set_float_exception_flags(0, &env->active_fpu.fp_status);
2493 fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
2494 update_fcr31();
2495 return fdt2;
2496 }
2497
2498 uint64_t helper_float_cvtd_w(uint32_t wt0)
2499 {
2500 uint64_t fdt2;
2501
2502 set_float_exception_flags(0, &env->active_fpu.fp_status);
2503 fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2504 update_fcr31();
2505 return fdt2;
2506 }
2507
2508 uint64_t helper_float_cvtd_l(uint64_t dt0)
2509 {
2510 uint64_t fdt2;
2511
2512 set_float_exception_flags(0, &env->active_fpu.fp_status);
2513 fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2514 update_fcr31();
2515 return fdt2;
2516 }
2517
2518 uint64_t helper_float_cvtl_d(uint64_t fdt0)
2519 {
2520 uint64_t dt2;
2521
2522 set_float_exception_flags(0, &env->active_fpu.fp_status);
2523 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2524 update_fcr31();
2525 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2526 dt2 = FLOAT_SNAN64;
2527 return dt2;
2528 }
2529
2530 uint64_t helper_float_cvtl_s(uint32_t fst0)
2531 {
2532 uint64_t dt2;
2533
2534 set_float_exception_flags(0, &env->active_fpu.fp_status);
2535 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2536 update_fcr31();
2537 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2538 dt2 = FLOAT_SNAN64;
2539 return dt2;
2540 }
2541
2542 uint64_t helper_float_cvtps_pw(uint64_t dt0)
2543 {
2544 uint32_t fst2;
2545 uint32_t fsth2;
2546
2547 set_float_exception_flags(0, &env->active_fpu.fp_status);
2548 fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2549 fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
2550 update_fcr31();
2551 return ((uint64_t)fsth2 << 32) | fst2;
2552 }
2553
2554 uint64_t helper_float_cvtpw_ps(uint64_t fdt0)
2555 {
2556 uint32_t wt2;
2557 uint32_t wth2;
2558
2559 set_float_exception_flags(0, &env->active_fpu.fp_status);
2560 wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2561 wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2562 update_fcr31();
2563 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) {
2564 wt2 = FLOAT_SNAN32;
2565 wth2 = FLOAT_SNAN32;
2566 }
2567 return ((uint64_t)wth2 << 32) | wt2;
2568 }
2569
2570 uint32_t helper_float_cvts_d(uint64_t fdt0)
2571 {
2572 uint32_t fst2;
2573
2574 set_float_exception_flags(0, &env->active_fpu.fp_status);
2575 fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
2576 update_fcr31();
2577 return fst2;
2578 }
2579
2580 uint32_t helper_float_cvts_w(uint32_t wt0)
2581 {
2582 uint32_t fst2;
2583
2584 set_float_exception_flags(0, &env->active_fpu.fp_status);
2585 fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
2586 update_fcr31();
2587 return fst2;
2588 }
2589
2590 uint32_t helper_float_cvts_l(uint64_t dt0)
2591 {
2592 uint32_t fst2;
2593
2594 set_float_exception_flags(0, &env->active_fpu.fp_status);
2595 fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
2596 update_fcr31();
2597 return fst2;
2598 }
2599
2600 uint32_t helper_float_cvts_pl(uint32_t wt0)
2601 {
2602 uint32_t wt2;
2603
2604 set_float_exception_flags(0, &env->active_fpu.fp_status);
2605 wt2 = wt0;
2606 update_fcr31();
2607 return wt2;
2608 }
2609
2610 uint32_t helper_float_cvts_pu(uint32_t wth0)
2611 {
2612 uint32_t wt2;
2613
2614 set_float_exception_flags(0, &env->active_fpu.fp_status);
2615 wt2 = wth0;
2616 update_fcr31();
2617 return wt2;
2618 }
2619
2620 uint32_t helper_float_cvtw_s(uint32_t fst0)
2621 {
2622 uint32_t wt2;
2623
2624 set_float_exception_flags(0, &env->active_fpu.fp_status);
2625 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2626 update_fcr31();
2627 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2628 wt2 = FLOAT_SNAN32;
2629 return wt2;
2630 }
2631
2632 uint32_t helper_float_cvtw_d(uint64_t fdt0)
2633 {
2634 uint32_t wt2;
2635
2636 set_float_exception_flags(0, &env->active_fpu.fp_status);
2637 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2638 update_fcr31();
2639 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2640 wt2 = FLOAT_SNAN32;
2641 return wt2;
2642 }
2643
2644 uint64_t helper_float_roundl_d(uint64_t fdt0)
2645 {
2646 uint64_t dt2;
2647
2648 set_float_exception_flags(0, &env->active_fpu.fp_status);
2649 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2650 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2651 RESTORE_ROUNDING_MODE;
2652 update_fcr31();
2653 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2654 dt2 = FLOAT_SNAN64;
2655 return dt2;
2656 }
2657
2658 uint64_t helper_float_roundl_s(uint32_t fst0)
2659 {
2660 uint64_t dt2;
2661
2662 set_float_exception_flags(0, &env->active_fpu.fp_status);
2663 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2664 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2665 RESTORE_ROUNDING_MODE;
2666 update_fcr31();
2667 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2668 dt2 = FLOAT_SNAN64;
2669 return dt2;
2670 }
2671
2672 uint32_t helper_float_roundw_d(uint64_t fdt0)
2673 {
2674 uint32_t wt2;
2675
2676 set_float_exception_flags(0, &env->active_fpu.fp_status);
2677 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2678 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2679 RESTORE_ROUNDING_MODE;
2680 update_fcr31();
2681 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2682 wt2 = FLOAT_SNAN32;
2683 return wt2;
2684 }
2685
2686 uint32_t helper_float_roundw_s(uint32_t fst0)
2687 {
2688 uint32_t wt2;
2689
2690 set_float_exception_flags(0, &env->active_fpu.fp_status);
2691 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2692 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2693 RESTORE_ROUNDING_MODE;
2694 update_fcr31();
2695 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2696 wt2 = FLOAT_SNAN32;
2697 return wt2;
2698 }
2699
2700 uint64_t helper_float_truncl_d(uint64_t fdt0)
2701 {
2702 uint64_t dt2;
2703
2704 set_float_exception_flags(0, &env->active_fpu.fp_status);
2705 dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
2706 update_fcr31();
2707 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2708 dt2 = FLOAT_SNAN64;
2709 return dt2;
2710 }
2711
2712 uint64_t helper_float_truncl_s(uint32_t fst0)
2713 {
2714 uint64_t dt2;
2715
2716 set_float_exception_flags(0, &env->active_fpu.fp_status);
2717 dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
2718 update_fcr31();
2719 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2720 dt2 = FLOAT_SNAN64;
2721 return dt2;
2722 }
2723
2724 uint32_t helper_float_truncw_d(uint64_t fdt0)
2725 {
2726 uint32_t wt2;
2727
2728 set_float_exception_flags(0, &env->active_fpu.fp_status);
2729 wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
2730 update_fcr31();
2731 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2732 wt2 = FLOAT_SNAN32;
2733 return wt2;
2734 }
2735
2736 uint32_t helper_float_truncw_s(uint32_t fst0)
2737 {
2738 uint32_t wt2;
2739
2740 set_float_exception_flags(0, &env->active_fpu.fp_status);
2741 wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
2742 update_fcr31();
2743 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2744 wt2 = FLOAT_SNAN32;
2745 return wt2;
2746 }
2747
2748 uint64_t helper_float_ceill_d(uint64_t fdt0)
2749 {
2750 uint64_t dt2;
2751
2752 set_float_exception_flags(0, &env->active_fpu.fp_status);
2753 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2754 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2755 RESTORE_ROUNDING_MODE;
2756 update_fcr31();
2757 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2758 dt2 = FLOAT_SNAN64;
2759 return dt2;
2760 }
2761
2762 uint64_t helper_float_ceill_s(uint32_t fst0)
2763 {
2764 uint64_t dt2;
2765
2766 set_float_exception_flags(0, &env->active_fpu.fp_status);
2767 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2768 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2769 RESTORE_ROUNDING_MODE;
2770 update_fcr31();
2771 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2772 dt2 = FLOAT_SNAN64;
2773 return dt2;
2774 }
2775
2776 uint32_t helper_float_ceilw_d(uint64_t fdt0)
2777 {
2778 uint32_t wt2;
2779
2780 set_float_exception_flags(0, &env->active_fpu.fp_status);
2781 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2782 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2783 RESTORE_ROUNDING_MODE;
2784 update_fcr31();
2785 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2786 wt2 = FLOAT_SNAN32;
2787 return wt2;
2788 }
2789
2790 uint32_t helper_float_ceilw_s(uint32_t fst0)
2791 {
2792 uint32_t wt2;
2793
2794 set_float_exception_flags(0, &env->active_fpu.fp_status);
2795 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2796 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2797 RESTORE_ROUNDING_MODE;
2798 update_fcr31();
2799 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2800 wt2 = FLOAT_SNAN32;
2801 return wt2;
2802 }
2803
2804 uint64_t helper_float_floorl_d(uint64_t fdt0)
2805 {
2806 uint64_t dt2;
2807
2808 set_float_exception_flags(0, &env->active_fpu.fp_status);
2809 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2810 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2811 RESTORE_ROUNDING_MODE;
2812 update_fcr31();
2813 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2814 dt2 = FLOAT_SNAN64;
2815 return dt2;
2816 }
2817
2818 uint64_t helper_float_floorl_s(uint32_t fst0)
2819 {
2820 uint64_t dt2;
2821
2822 set_float_exception_flags(0, &env->active_fpu.fp_status);
2823 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2824 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2825 RESTORE_ROUNDING_MODE;
2826 update_fcr31();
2827 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2828 dt2 = FLOAT_SNAN64;
2829 return dt2;
2830 }
2831
2832 uint32_t helper_float_floorw_d(uint64_t fdt0)
2833 {
2834 uint32_t wt2;
2835
2836 set_float_exception_flags(0, &env->active_fpu.fp_status);
2837 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2838 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2839 RESTORE_ROUNDING_MODE;
2840 update_fcr31();
2841 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2842 wt2 = FLOAT_SNAN32;
2843 return wt2;
2844 }
2845
2846 uint32_t helper_float_floorw_s(uint32_t fst0)
2847 {
2848 uint32_t wt2;
2849
2850 set_float_exception_flags(0, &env->active_fpu.fp_status);
2851 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2852 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2853 RESTORE_ROUNDING_MODE;
2854 update_fcr31();
2855 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2856 wt2 = FLOAT_SNAN32;
2857 return wt2;
2858 }
2859
2860 /* unary operations, not modifying fp status */
2861 #define FLOAT_UNOP(name) \
2862 uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \
2863 { \
2864 return float64_ ## name(fdt0); \
2865 } \
2866 uint32_t helper_float_ ## name ## _s(uint32_t fst0) \
2867 { \
2868 return float32_ ## name(fst0); \
2869 } \
2870 uint64_t helper_float_ ## name ## _ps(uint64_t fdt0) \
2871 { \
2872 uint32_t wt0; \
2873 uint32_t wth0; \
2874 \
2875 wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \
2876 wth0 = float32_ ## name(fdt0 >> 32); \
2877 return ((uint64_t)wth0 << 32) | wt0; \
2878 }
2879 FLOAT_UNOP(abs)
2880 FLOAT_UNOP(chs)
2881 #undef FLOAT_UNOP
2882
2883 /* MIPS specific unary operations */
2884 uint64_t helper_float_recip_d(uint64_t fdt0)
2885 {
2886 uint64_t fdt2;
2887
2888 set_float_exception_flags(0, &env->active_fpu.fp_status);
2889 fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
2890 update_fcr31();
2891 return fdt2;
2892 }
2893
2894 uint32_t helper_float_recip_s(uint32_t fst0)
2895 {
2896 uint32_t fst2;
2897
2898 set_float_exception_flags(0, &env->active_fpu.fp_status);
2899 fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
2900 update_fcr31();
2901 return fst2;
2902 }
2903
2904 uint64_t helper_float_rsqrt_d(uint64_t fdt0)
2905 {
2906 uint64_t fdt2;
2907
2908 set_float_exception_flags(0, &env->active_fpu.fp_status);
2909 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2910 fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
2911 update_fcr31();
2912 return fdt2;
2913 }
2914
2915 uint32_t helper_float_rsqrt_s(uint32_t fst0)
2916 {
2917 uint32_t fst2;
2918
2919 set_float_exception_flags(0, &env->active_fpu.fp_status);
2920 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2921 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2922 update_fcr31();
2923 return fst2;
2924 }
2925
2926 uint64_t helper_float_recip1_d(uint64_t fdt0)
2927 {
2928 uint64_t fdt2;
2929
2930 set_float_exception_flags(0, &env->active_fpu.fp_status);
2931 fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
2932 update_fcr31();
2933 return fdt2;
2934 }
2935
2936 uint32_t helper_float_recip1_s(uint32_t fst0)
2937 {
2938 uint32_t fst2;
2939
2940 set_float_exception_flags(0, &env->active_fpu.fp_status);
2941 fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
2942 update_fcr31();
2943 return fst2;
2944 }
2945
2946 uint64_t helper_float_recip1_ps(uint64_t fdt0)
2947 {
2948 uint32_t fst2;
2949 uint32_t fsth2;
2950
2951 set_float_exception_flags(0, &env->active_fpu.fp_status);
2952 fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2953 fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->active_fpu.fp_status);
2954 update_fcr31();
2955 return ((uint64_t)fsth2 << 32) | fst2;
2956 }
2957
2958 uint64_t helper_float_rsqrt1_d(uint64_t fdt0)
2959 {
2960 uint64_t fdt2;
2961
2962 set_float_exception_flags(0, &env->active_fpu.fp_status);
2963 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2964 fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
2965 update_fcr31();
2966 return fdt2;
2967 }
2968
2969 uint32_t helper_float_rsqrt1_s(uint32_t fst0)
2970 {
2971 uint32_t fst2;
2972
2973 set_float_exception_flags(0, &env->active_fpu.fp_status);
2974 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2975 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2976 update_fcr31();
2977 return fst2;
2978 }
2979
2980 uint64_t helper_float_rsqrt1_ps(uint64_t fdt0)
2981 {
2982 uint32_t fst2;
2983 uint32_t fsth2;
2984
2985 set_float_exception_flags(0, &env->active_fpu.fp_status);
2986 fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2987 fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
2988 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2989 fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->active_fpu.fp_status);
2990 update_fcr31();
2991 return ((uint64_t)fsth2 << 32) | fst2;
2992 }
2993
2994 #define FLOAT_OP(name, p) void helper_float_##name##_##p(void)
2995
2996 /* binary operations */
2997 #define FLOAT_BINOP(name) \
2998 uint64_t helper_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1) \
2999 { \
3000 uint64_t dt2; \
3001 \
3002 set_float_exception_flags(0, &env->active_fpu.fp_status); \
3003 dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status); \
3004 update_fcr31(); \
3005 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \
3006 dt2 = FLOAT_QNAN64; \
3007 return dt2; \
3008 } \
3009 \
3010 uint32_t helper_float_ ## name ## _s(uint32_t fst0, uint32_t fst1) \
3011 { \
3012 uint32_t wt2; \
3013 \
3014 set_float_exception_flags(0, &env->active_fpu.fp_status); \
3015 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
3016 update_fcr31(); \
3017 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \
3018 wt2 = FLOAT_QNAN32; \
3019 return wt2; \
3020 } \
3021 \
3022 uint64_t helper_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1) \
3023 { \
3024 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
3025 uint32_t fsth0 = fdt0 >> 32; \
3026 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
3027 uint32_t fsth1 = fdt1 >> 32; \
3028 uint32_t wt2; \
3029 uint32_t wth2; \
3030 \
3031 set_float_exception_flags(0, &env->active_fpu.fp_status); \
3032 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
3033 wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status); \
3034 update_fcr31(); \
3035 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) { \
3036 wt2 = FLOAT_QNAN32; \
3037 wth2 = FLOAT_QNAN32; \
3038 } \
3039 return ((uint64_t)wth2 << 32) | wt2; \
3040 }
3041
3042 FLOAT_BINOP(add)
3043 FLOAT_BINOP(sub)
3044 FLOAT_BINOP(mul)
3045 FLOAT_BINOP(div)
3046 #undef FLOAT_BINOP
3047
3048 /* ternary operations */
3049 #define FLOAT_TERNOP(name1, name2) \
3050 uint64_t helper_float_ ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
3051 uint64_t fdt2) \
3052 { \
3053 fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status); \
3054 return float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status); \
3055 } \
3056 \
3057 uint32_t helper_float_ ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
3058 uint32_t fst2) \
3059 { \
3060 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
3061 return float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
3062 } \
3063 \
3064 uint64_t helper_float_ ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1, \
3065 uint64_t fdt2) \
3066 { \
3067 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
3068 uint32_t fsth0 = fdt0 >> 32; \
3069 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
3070 uint32_t fsth1 = fdt1 >> 32; \
3071 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
3072 uint32_t fsth2 = fdt2 >> 32; \
3073 \
3074 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
3075 fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status); \
3076 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
3077 fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status); \
3078 return ((uint64_t)fsth2 << 32) | fst2; \
3079 }
3080
3081 FLOAT_TERNOP(mul, add)
3082 FLOAT_TERNOP(mul, sub)
3083 #undef FLOAT_TERNOP
3084
3085 /* negated ternary operations */
3086 #define FLOAT_NTERNOP(name1, name2) \
3087 uint64_t helper_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
3088 uint64_t fdt2) \
3089 { \
3090 fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status); \
3091 fdt2 = float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status); \
3092 return float64_chs(fdt2); \
3093 } \
3094 \
3095 uint32_t helper_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
3096 uint32_t fst2) \
3097 { \
3098 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
3099 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
3100 return float32_chs(fst2); \
3101 } \
3102 \
3103 uint64_t helper_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\
3104 uint64_t fdt2) \
3105 { \
3106 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
3107 uint32_t fsth0 = fdt0 >> 32; \
3108 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
3109 uint32_t fsth1 = fdt1 >> 32; \
3110 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
3111 uint32_t fsth2 = fdt2 >> 32; \
3112 \
3113 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
3114 fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status); \
3115 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
3116 fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status); \
3117 fst2 = float32_chs(fst2); \
3118 fsth2 = float32_chs(fsth2); \
3119 return ((uint64_t)fsth2 << 32) | fst2; \
3120 }
3121
3122 FLOAT_NTERNOP(mul, add)
3123 FLOAT_NTERNOP(mul, sub)
3124 #undef FLOAT_NTERNOP
3125
3126 /* MIPS specific binary operations */
3127 uint64_t helper_float_recip2_d(uint64_t fdt0, uint64_t fdt2)
3128 {
3129 set_float_exception_flags(0, &env->active_fpu.fp_status);
3130 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3131 fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status));
3132 update_fcr31();
3133 return fdt2;
3134 }
3135
3136 uint32_t helper_float_recip2_s(uint32_t fst0, uint32_t fst2)
3137 {
3138 set_float_exception_flags(0, &env->active_fpu.fp_status);
3139 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3140 fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
3141 update_fcr31();
3142 return fst2;
3143 }
3144
3145 uint64_t helper_float_recip2_ps(uint64_t fdt0, uint64_t fdt2)
3146 {
3147 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3148 uint32_t fsth0 = fdt0 >> 32;
3149 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3150 uint32_t fsth2 = fdt2 >> 32;
3151
3152 set_float_exception_flags(0, &env->active_fpu.fp_status);
3153 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3154 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3155 fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
3156 fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status));
3157 update_fcr31();
3158 return ((uint64_t)fsth2 << 32) | fst2;
3159 }
3160
3161 uint64_t helper_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2)
3162 {
3163 set_float_exception_flags(0, &env->active_fpu.fp_status);
3164 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3165 fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status);
3166 fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
3167 update_fcr31();
3168 return fdt2;
3169 }
3170
3171 uint32_t helper_float_rsqrt2_s(uint32_t fst0, uint32_t fst2)
3172 {
3173 set_float_exception_flags(0, &env->active_fpu.fp_status);
3174 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3175 fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
3176 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3177 update_fcr31();
3178 return fst2;
3179 }
3180
3181 uint64_t helper_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2)
3182 {
3183 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3184 uint32_t fsth0 = fdt0 >> 32;
3185 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3186 uint32_t fsth2 = fdt2 >> 32;
3187
3188 set_float_exception_flags(0, &env->active_fpu.fp_status);
3189 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3190 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3191 fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
3192 fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status);
3193 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3194 fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
3195 update_fcr31();
3196 return ((uint64_t)fsth2 << 32) | fst2;
3197 }
3198
3199 uint64_t helper_float_addr_ps(uint64_t fdt0, uint64_t fdt1)
3200 {
3201 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3202 uint32_t fsth0 = fdt0 >> 32;
3203 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3204 uint32_t fsth1 = fdt1 >> 32;
3205 uint32_t fst2;
3206 uint32_t fsth2;
3207
3208 set_float_exception_flags(0, &env->active_fpu.fp_status);
3209 fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
3210 fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
3211 update_fcr31();
3212 return ((uint64_t)fsth2 << 32) | fst2;
3213 }
3214
3215 uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1)
3216 {
3217 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3218 uint32_t fsth0 = fdt0 >> 32;
3219 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3220 uint32_t fsth1 = fdt1 >> 32;
3221 uint32_t fst2;
3222 uint32_t fsth2;
3223
3224 set_float_exception_flags(0, &env->active_fpu.fp_status);
3225 fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
3226 fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
3227 update_fcr31();
3228 return ((uint64_t)fsth2 << 32) | fst2;
3229 }
3230
3231 /* compare operations */
3232 #define FOP_COND_D(op, cond) \
3233 void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
3234 { \
3235 int c; \
3236 set_float_exception_flags(0, &env->active_fpu.fp_status); \
3237 c = cond; \
3238 update_fcr31(); \
3239 if (c) \
3240 SET_FP_COND(cc, env->active_fpu); \
3241 else \
3242 CLEAR_FP_COND(cc, env->active_fpu); \
3243 } \
3244 void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
3245 { \
3246 int c; \
3247 set_float_exception_flags(0, &env->active_fpu.fp_status); \
3248 fdt0 = float64_abs(fdt0); \
3249 fdt1 = float64_abs(fdt1); \
3250 c = cond; \
3251 update_fcr31(); \
3252 if (c) \
3253 SET_FP_COND(cc, env->active_fpu); \
3254 else \
3255 CLEAR_FP_COND(cc, env->active_fpu); \
3256 }
3257
3258 /* NOTE: the comma operator will make "cond" to eval to false,
3259 * but float64_unordered_quiet() is still called. */
3260 FOP_COND_D(f, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3261 FOP_COND_D(un, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
3262 FOP_COND_D(eq, float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3263 FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3264 FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3265 FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3266 FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3267 FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3268 /* NOTE: the comma operator will make "cond" to eval to false,
3269 * but float64_unordered() is still called. */
3270 FOP_COND_D(sf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3271 FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
3272 FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3273 FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3274 FOP_COND_D(lt, float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3275 FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3276 FOP_COND_D(le, float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3277 FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3278
3279 #define FOP_COND_S(op, cond) \
3280 void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
3281 { \
3282 int c; \
3283 set_float_exception_flags(0, &env->active_fpu.fp_status); \
3284 c = cond; \
3285 update_fcr31(); \
3286 if (c) \
3287 SET_FP_COND(cc, env->active_fpu); \
3288 else \
3289 CLEAR_FP_COND(cc, env->active_fpu); \
3290 } \
3291 void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
3292 { \
3293 int c; \
3294 set_float_exception_flags(0, &env->active_fpu.fp_status); \
3295 fst0 = float32_abs(fst0); \
3296 fst1 = float32_abs(fst1); \
3297 c = cond; \
3298 update_fcr31(); \
3299 if (c) \
3300 SET_FP_COND(cc, env->active_fpu); \
3301 else \
3302 CLEAR_FP_COND(cc, env->active_fpu); \
3303 }
3304
3305 /* NOTE: the comma operator will make "cond" to eval to false,
3306 * but float32_unordered_quiet() is still called. */
3307 FOP_COND_S(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
3308 FOP_COND_S(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
3309 FOP_COND_S(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3310 FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3311 FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3312 FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3313 FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
3314 FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
3315 /* NOTE: the comma operator will make "cond" to eval to false,
3316 * but float32_unordered() is still called. */
3317 FOP_COND_S(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
3318 FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
3319 FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3320 FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3321 FOP_COND_S(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3322 FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3323 FOP_COND_S(le, float32_le(fst0, fst1, &env->active_fpu.fp_status))
3324 FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status))
3325
3326 #define FOP_COND_PS(op, condl, condh) \
3327 void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
3328 { \
3329 uint32_t fst0, fsth0, fst1, fsth1; \
3330 int ch, cl; \
3331 set_float_exception_flags(0, &env->active_fpu.fp_status); \
3332 fst0 = fdt0 & 0XFFFFFFFF; \
3333 fsth0 = fdt0 >> 32; \
3334 fst1 = fdt1 & 0XFFFFFFFF; \
3335 fsth1 = fdt1 >> 32; \
3336 cl = condl; \
3337 ch = condh; \
3338 update_fcr31(); \
3339 if (cl) \
3340 SET_FP_COND(cc, env->active_fpu); \
3341 else \
3342 CLEAR_FP_COND(cc, env->active_fpu); \
3343 if (ch) \
3344 SET_FP_COND(cc + 1, env->active_fpu); \
3345 else \
3346 CLEAR_FP_COND(cc + 1, env->active_fpu); \
3347 } \
3348 void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
3349 { \
3350 uint32_t fst0, fsth0, fst1, fsth1; \
3351 int ch, cl; \
3352 fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \
3353 fsth0 = float32_abs(fdt0 >> 32); \
3354 fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \
3355 fsth1 = float32_abs(fdt1 >> 32); \
3356 cl = condl; \
3357 ch = condh; \
3358 update_fcr31(); \
3359 if (cl) \
3360 SET_FP_COND(cc, env->active_fpu); \
3361 else \
3362 CLEAR_FP_COND(cc, env->active_fpu); \
3363 if (ch) \
3364 SET_FP_COND(cc + 1, env->active_fpu); \
3365 else \
3366 CLEAR_FP_COND(cc + 1, env->active_fpu); \
3367 }
3368
3369 /* NOTE: the comma operator will make "cond" to eval to false,
3370 * but float32_unordered_quiet() is still called. */
3371 FOP_COND_PS(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
3372 (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3373 FOP_COND_PS(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
3374 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
3375 FOP_COND_PS(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3376 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3377 FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3378 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3379 FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3380 float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3381 FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3382 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3383 FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3384 float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3385 FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3386 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3387 /* NOTE: the comma operator will make "cond" to eval to false,
3388 * but float32_unordered() is still called. */
3389 FOP_COND_PS(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
3390 (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3391 FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
3392 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
3393 FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3394 float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3395 FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3396 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3397 FOP_COND_PS(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3398 float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3399 FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3400 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3401 FOP_COND_PS(le, float32_le(fst0, fst1, &env->active_fpu.fp_status),
3402 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3403 FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status),
3404 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))