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