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