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