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