]> Git Repo - qemu.git/blame - target-mips/op_helper.c
cputlb: Change tlb_flush() argument to CPUState
[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 1789{
00c8cb0a
AF
1790 MIPSCPU *cpu = mips_env_get_cpu(env);
1791
814b9a47 1792 /* Flush qemu's TLB and discard all shadowed entries. */
00c8cb0a 1793 tlb_flush(CPU(cpu), flush_global);
ead9360e 1794 env->tlb->tlb_in_use = env->tlb->nb_tlb;
814b9a47
TS
1795}
1796
7db13fae 1797static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
814b9a47
TS
1798{
1799 /* Discard entries from env->tlb[first] onwards. */
ead9360e
TS
1800 while (env->tlb->tlb_in_use > first) {
1801 r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
814b9a47
TS
1802 }
1803}
1804
895c2d04 1805static void r4k_fill_tlb(CPUMIPSState *env, int idx)
6af0bf9c 1806{
c227f099 1807 r4k_tlb_t *tlb;
6af0bf9c
FB
1808
1809 /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
ead9360e 1810 tlb = &env->tlb->mmu.r4k.tlb[idx];
f2e9ebef 1811 tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
d26bc211 1812#if defined(TARGET_MIPS64)
e034e2c3 1813 tlb->VPN &= env->SEGMask;
100ce988 1814#endif
98c1b82b 1815 tlb->ASID = env->CP0_EntryHi & 0xFF;
3b1c8be4 1816 tlb->PageMask = env->CP0_PageMask;
6af0bf9c 1817 tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
98c1b82b
PB
1818 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
1819 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
1820 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
6af0bf9c 1821 tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
98c1b82b
PB
1822 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
1823 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
1824 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
6af0bf9c
FB
1825 tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
1826}
1827
895c2d04 1828void r4k_helper_tlbwi(CPUMIPSState *env)
6af0bf9c 1829{
286d52eb 1830 r4k_tlb_t *tlb;
bbc0d79c 1831 int idx;
286d52eb
AJ
1832 target_ulong VPN;
1833 uint8_t ASID;
1834 bool G, V0, D0, V1, D1;
bbc0d79c
AJ
1835
1836 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
286d52eb
AJ
1837 tlb = &env->tlb->mmu.r4k.tlb[idx];
1838 VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1839#if defined(TARGET_MIPS64)
1840 VPN &= env->SEGMask;
1841#endif
1842 ASID = env->CP0_EntryHi & 0xff;
1843 G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1844 V0 = (env->CP0_EntryLo0 & 2) != 0;
1845 D0 = (env->CP0_EntryLo0 & 4) != 0;
1846 V1 = (env->CP0_EntryLo1 & 2) != 0;
1847 D1 = (env->CP0_EntryLo1 & 4) != 0;
1848
1849 /* Discard cached TLB entries, unless tlbwi is just upgrading access
1850 permissions on the current entry. */
1851 if (tlb->VPN != VPN || tlb->ASID != ASID || tlb->G != G ||
1852 (tlb->V0 && !V0) || (tlb->D0 && !D0) ||
1853 (tlb->V1 && !V1) || (tlb->D1 && !D1)) {
1854 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
1855 }
814b9a47 1856
bbc0d79c 1857 r4k_invalidate_tlb(env, idx, 0);
895c2d04 1858 r4k_fill_tlb(env, idx);
6af0bf9c
FB
1859}
1860
895c2d04 1861void r4k_helper_tlbwr(CPUMIPSState *env)
6af0bf9c
FB
1862{
1863 int r = cpu_mips_get_random(env);
1864
29929e34 1865 r4k_invalidate_tlb(env, r, 1);
895c2d04 1866 r4k_fill_tlb(env, r);
6af0bf9c
FB
1867}
1868
895c2d04 1869void r4k_helper_tlbp(CPUMIPSState *env)
6af0bf9c 1870{
c227f099 1871 r4k_tlb_t *tlb;
f2e9ebef 1872 target_ulong mask;
6af0bf9c 1873 target_ulong tag;
f2e9ebef 1874 target_ulong VPN;
6af0bf9c
FB
1875 uint8_t ASID;
1876 int i;
1877
3d9fb9fe 1878 ASID = env->CP0_EntryHi & 0xFF;
ead9360e
TS
1879 for (i = 0; i < env->tlb->nb_tlb; i++) {
1880 tlb = &env->tlb->mmu.r4k.tlb[i];
f2e9ebef
TS
1881 /* 1k pages are not supported. */
1882 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1883 tag = env->CP0_EntryHi & ~mask;
1884 VPN = tlb->VPN & ~mask;
bc3e45e1
AJ
1885#if defined(TARGET_MIPS64)
1886 tag &= env->SEGMask;
1887#endif
6af0bf9c 1888 /* Check ASID, virtual page number & size */
f2e9ebef 1889 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
6af0bf9c 1890 /* TLB match */
9c2149c8 1891 env->CP0_Index = i;
6af0bf9c
FB
1892 break;
1893 }
1894 }
ead9360e 1895 if (i == env->tlb->nb_tlb) {
814b9a47 1896 /* No match. Discard any shadow entries, if any of them match. */
ead9360e 1897 for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
6958549d
AJ
1898 tlb = &env->tlb->mmu.r4k.tlb[i];
1899 /* 1k pages are not supported. */
1900 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1901 tag = env->CP0_EntryHi & ~mask;
1902 VPN = tlb->VPN & ~mask;
bc3e45e1
AJ
1903#if defined(TARGET_MIPS64)
1904 tag &= env->SEGMask;
1905#endif
6958549d
AJ
1906 /* Check ASID, virtual page number & size */
1907 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
29929e34 1908 r4k_mips_tlb_flush_extra (env, i);
6958549d
AJ
1909 break;
1910 }
1911 }
814b9a47 1912
9c2149c8 1913 env->CP0_Index |= 0x80000000;
6af0bf9c
FB
1914 }
1915}
1916
895c2d04 1917void r4k_helper_tlbr(CPUMIPSState *env)
6af0bf9c 1918{
c227f099 1919 r4k_tlb_t *tlb;
09c56b84 1920 uint8_t ASID;
bbc0d79c 1921 int idx;
6af0bf9c 1922
09c56b84 1923 ASID = env->CP0_EntryHi & 0xFF;
bbc0d79c
AJ
1924 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1925 tlb = &env->tlb->mmu.r4k.tlb[idx];
4ad40f36
FB
1926
1927 /* If this will change the current ASID, flush qemu's TLB. */
814b9a47
TS
1928 if (ASID != tlb->ASID)
1929 cpu_mips_tlb_flush (env, 1);
1930
ead9360e 1931 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
4ad40f36 1932
6af0bf9c 1933 env->CP0_EntryHi = tlb->VPN | tlb->ASID;
3b1c8be4 1934 env->CP0_PageMask = tlb->PageMask;
7495fd0f
TS
1935 env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
1936 (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
1937 env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
1938 (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
6af0bf9c 1939}
6af0bf9c 1940
895c2d04 1941void helper_tlbwi(CPUMIPSState *env)
a7812ae4 1942{
895c2d04 1943 env->tlb->helper_tlbwi(env);
a7812ae4
PB
1944}
1945
895c2d04 1946void helper_tlbwr(CPUMIPSState *env)
a7812ae4 1947{
895c2d04 1948 env->tlb->helper_tlbwr(env);
a7812ae4
PB
1949}
1950
895c2d04 1951void helper_tlbp(CPUMIPSState *env)
a7812ae4 1952{
895c2d04 1953 env->tlb->helper_tlbp(env);
a7812ae4
PB
1954}
1955
895c2d04 1956void helper_tlbr(CPUMIPSState *env)
a7812ae4 1957{
895c2d04 1958 env->tlb->helper_tlbr(env);
a7812ae4
PB
1959}
1960
2b0233ab 1961/* Specials */
895c2d04 1962target_ulong helper_di(CPUMIPSState *env)
2b0233ab 1963{
2796188e
TS
1964 target_ulong t0 = env->CP0_Status;
1965
be24bb4f 1966 env->CP0_Status = t0 & ~(1 << CP0St_IE);
be24bb4f 1967 return t0;
2b0233ab
TS
1968}
1969
895c2d04 1970target_ulong helper_ei(CPUMIPSState *env)
2b0233ab 1971{
2796188e
TS
1972 target_ulong t0 = env->CP0_Status;
1973
be24bb4f 1974 env->CP0_Status = t0 | (1 << CP0St_IE);
be24bb4f 1975 return t0;
2b0233ab
TS
1976}
1977
895c2d04 1978static void debug_pre_eret(CPUMIPSState *env)
6af0bf9c 1979{
8fec2b8c 1980 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
93fcfe39
AL
1981 qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1982 env->active_tc.PC, env->CP0_EPC);
1983 if (env->CP0_Status & (1 << CP0St_ERL))
1984 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1985 if (env->hflags & MIPS_HFLAG_DM)
1986 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1987 qemu_log("\n");
1988 }
f41c52f1
TS
1989}
1990
895c2d04 1991static void debug_post_eret(CPUMIPSState *env)
f41c52f1 1992{
a47dddd7
AF
1993 MIPSCPU *cpu = mips_env_get_cpu(env);
1994
8fec2b8c 1995 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
93fcfe39
AL
1996 qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1997 env->active_tc.PC, env->CP0_EPC);
1998 if (env->CP0_Status & (1 << CP0St_ERL))
1999 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2000 if (env->hflags & MIPS_HFLAG_DM)
2001 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2002 switch (env->hflags & MIPS_HFLAG_KSU) {
2003 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
2004 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
2005 case MIPS_HFLAG_KM: qemu_log("\n"); break;
a47dddd7
AF
2006 default:
2007 cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
2008 break;
93fcfe39 2009 }
623a930e 2010 }
6af0bf9c
FB
2011}
2012
895c2d04 2013static void set_pc(CPUMIPSState *env, target_ulong error_pc)
32188a03
NF
2014{
2015 env->active_tc.PC = error_pc & ~(target_ulong)1;
2016 if (error_pc & 1) {
2017 env->hflags |= MIPS_HFLAG_M16;
2018 } else {
2019 env->hflags &= ~(MIPS_HFLAG_M16);
2020 }
2021}
2022
895c2d04 2023void helper_eret(CPUMIPSState *env)
2b0233ab 2024{
895c2d04 2025 debug_pre_eret(env);
2b0233ab 2026 if (env->CP0_Status & (1 << CP0St_ERL)) {
895c2d04 2027 set_pc(env, env->CP0_ErrorEPC);
2b0233ab
TS
2028 env->CP0_Status &= ~(1 << CP0St_ERL);
2029 } else {
895c2d04 2030 set_pc(env, env->CP0_EPC);
2b0233ab
TS
2031 env->CP0_Status &= ~(1 << CP0St_EXL);
2032 }
2033 compute_hflags(env);
895c2d04 2034 debug_post_eret(env);
5499b6ff 2035 env->lladdr = 1;
2b0233ab
TS
2036}
2037
895c2d04 2038void helper_deret(CPUMIPSState *env)
2b0233ab 2039{
895c2d04
BS
2040 debug_pre_eret(env);
2041 set_pc(env, env->CP0_DEPC);
32188a03 2042
2b0233ab
TS
2043 env->hflags &= MIPS_HFLAG_DM;
2044 compute_hflags(env);
895c2d04 2045 debug_post_eret(env);
5499b6ff 2046 env->lladdr = 1;
2b0233ab 2047}
0eaef5aa 2048#endif /* !CONFIG_USER_ONLY */
2b0233ab 2049
895c2d04 2050target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
2b0233ab
TS
2051{
2052 if ((env->hflags & MIPS_HFLAG_CP0) ||
2053 (env->CP0_HWREna & (1 << 0)))
2796188e 2054 return env->CP0_EBase & 0x3ff;
2b0233ab 2055 else
895c2d04 2056 helper_raise_exception(env, EXCP_RI);
be24bb4f 2057
2796188e 2058 return 0;
2b0233ab
TS
2059}
2060
895c2d04 2061target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
2b0233ab
TS
2062{
2063 if ((env->hflags & MIPS_HFLAG_CP0) ||
2064 (env->CP0_HWREna & (1 << 1)))
2796188e 2065 return env->SYNCI_Step;
2b0233ab 2066 else
895c2d04 2067 helper_raise_exception(env, EXCP_RI);
be24bb4f 2068
2796188e 2069 return 0;
2b0233ab
TS
2070}
2071
895c2d04 2072target_ulong helper_rdhwr_cc(CPUMIPSState *env)
2b0233ab
TS
2073{
2074 if ((env->hflags & MIPS_HFLAG_CP0) ||
2075 (env->CP0_HWREna & (1 << 2)))
2796188e 2076 return env->CP0_Count;
2b0233ab 2077 else
895c2d04 2078 helper_raise_exception(env, EXCP_RI);
be24bb4f 2079
2796188e 2080 return 0;
2b0233ab
TS
2081}
2082
895c2d04 2083target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
2b0233ab
TS
2084{
2085 if ((env->hflags & MIPS_HFLAG_CP0) ||
2086 (env->CP0_HWREna & (1 << 3)))
2796188e 2087 return env->CCRes;
2b0233ab 2088 else
895c2d04 2089 helper_raise_exception(env, EXCP_RI);
be24bb4f 2090
2796188e 2091 return 0;
2b0233ab
TS
2092}
2093
895c2d04 2094void helper_pmon(CPUMIPSState *env, int function)
6af0bf9c
FB
2095{
2096 function /= 2;
2097 switch (function) {
2098 case 2: /* TODO: char inbyte(int waitflag); */
b5dc7732
TS
2099 if (env->active_tc.gpr[4] == 0)
2100 env->active_tc.gpr[2] = -1;
6af0bf9c
FB
2101 /* Fall through */
2102 case 11: /* TODO: char inbyte (void); */
b5dc7732 2103 env->active_tc.gpr[2] = -1;
6af0bf9c
FB
2104 break;
2105 case 3:
2106 case 12:
b5dc7732 2107 printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
6af0bf9c
FB
2108 break;
2109 case 17:
2110 break;
2111 case 158:
2112 {
b69e48a8 2113 unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
6af0bf9c
FB
2114 printf("%s", fmt);
2115 }
2116 break;
2117 }
2118}
e37e863f 2119
895c2d04 2120void helper_wait(CPUMIPSState *env)
08ba7963 2121{
259186a7
AF
2122 CPUState *cs = CPU(mips_env_get_cpu(env));
2123
2124 cs->halted = 1;
d8ed887b 2125 cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
895c2d04 2126 helper_raise_exception(env, EXCP_HLT);
08ba7963
TS
2127}
2128
5fafdf24 2129#if !defined(CONFIG_USER_ONLY)
e37e863f 2130
895c2d04
BS
2131static void QEMU_NORETURN do_unaligned_access(CPUMIPSState *env,
2132 target_ulong addr, int is_write,
20503968 2133 int is_user, uintptr_t retaddr);
4ad40f36 2134
e37e863f 2135#define MMUSUFFIX _mmu
4ad40f36 2136#define ALIGNED_ONLY
e37e863f
FB
2137
2138#define SHIFT 0
022c62cb 2139#include "exec/softmmu_template.h"
e37e863f
FB
2140
2141#define SHIFT 1
022c62cb 2142#include "exec/softmmu_template.h"
e37e863f
FB
2143
2144#define SHIFT 2
022c62cb 2145#include "exec/softmmu_template.h"
e37e863f
FB
2146
2147#define SHIFT 3
022c62cb 2148#include "exec/softmmu_template.h"
e37e863f 2149
895c2d04
BS
2150static void do_unaligned_access(CPUMIPSState *env, target_ulong addr,
2151 int is_write, int is_user, uintptr_t retaddr)
4ad40f36
FB
2152{
2153 env->CP0_BadVAddr = addr;
5f7319cd 2154 do_raise_exception(env, (is_write == 1) ? EXCP_AdES : EXCP_AdEL, retaddr);
4ad40f36
FB
2155}
2156
d5a11fef 2157void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
20503968 2158 uintptr_t retaddr)
e37e863f 2159{
e37e863f
FB
2160 int ret;
2161
27103424 2162 ret = mips_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
e37e863f 2163 if (ret) {
d5a11fef
AF
2164 MIPSCPU *cpu = MIPS_CPU(cs);
2165 CPUMIPSState *env = &cpu->env;
2166
27103424 2167 do_raise_exception_err(env, cs->exception_index,
5f7319cd 2168 env->error_code, retaddr);
e37e863f 2169 }
e37e863f
FB
2170}
2171
c658b94f
AF
2172void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
2173 bool is_write, bool is_exec, int unused,
2174 unsigned size)
647de6ca 2175{
c658b94f
AF
2176 MIPSCPU *cpu = MIPS_CPU(cs);
2177 CPUMIPSState *env = &cpu->env;
2178
2179 if (is_exec) {
895c2d04 2180 helper_raise_exception(env, EXCP_IBE);
c658b94f 2181 } else {
895c2d04 2182 helper_raise_exception(env, EXCP_DBE);
c658b94f 2183 }
647de6ca 2184}
f1aa6320 2185#endif /* !CONFIG_USER_ONLY */
fd4a04eb
TS
2186
2187/* Complex FPU operations which may need stack space. */
2188
f090c9d4
PB
2189#define FLOAT_TWO32 make_float32(1 << 30)
2190#define FLOAT_TWO64 make_float64(1ULL << 62)
05993cd0
AJ
2191#define FP_TO_INT32_OVERFLOW 0x7fffffff
2192#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
8dfdb87c 2193
fd4a04eb 2194/* convert MIPS rounding mode in FCR31 to IEEE library */
6f4fc367 2195static unsigned int ieee_rm[] = {
fd4a04eb
TS
2196 float_round_nearest_even,
2197 float_round_to_zero,
2198 float_round_up,
2199 float_round_down
2200};
2201
e320d05a
SW
2202static inline void restore_rounding_mode(CPUMIPSState *env)
2203{
2204 set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3],
2205 &env->active_fpu.fp_status);
2206}
fd4a04eb 2207
e320d05a
SW
2208static inline void restore_flush_mode(CPUMIPSState *env)
2209{
2210 set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0,
2211 &env->active_fpu.fp_status);
2212}
41e0c701 2213
895c2d04 2214target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
fd4a04eb 2215{
736d120a 2216 target_ulong arg1 = 0;
6c5c1e20 2217
ead9360e
TS
2218 switch (reg) {
2219 case 0:
d9bea114 2220 arg1 = (int32_t)env->active_fpu.fcr0;
ead9360e 2221 break;
736d120a
PJ
2222 case 1:
2223 /* UFR Support - Read Status FR */
2224 if (env->active_fpu.fcr0 & (1 << FCR0_UFRP)) {
2225 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2226 arg1 = (int32_t)
2227 ((env->CP0_Status & (1 << CP0St_FR)) >> CP0St_FR);
2228 } else {
2229 helper_raise_exception(env, EXCP_RI);
2230 }
2231 }
2232 break;
ead9360e 2233 case 25:
d9bea114 2234 arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
ead9360e
TS
2235 break;
2236 case 26:
d9bea114 2237 arg1 = env->active_fpu.fcr31 & 0x0003f07c;
ead9360e
TS
2238 break;
2239 case 28:
d9bea114 2240 arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
ead9360e
TS
2241 break;
2242 default:
d9bea114 2243 arg1 = (int32_t)env->active_fpu.fcr31;
ead9360e
TS
2244 break;
2245 }
be24bb4f 2246
d9bea114 2247 return arg1;
ead9360e
TS
2248}
2249
736d120a 2250void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
ead9360e 2251{
736d120a
PJ
2252 switch (fs) {
2253 case 1:
2254 /* UFR Alias - Reset Status FR */
2255 if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2256 return;
2257 }
2258 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2259 env->CP0_Status &= ~(1 << CP0St_FR);
2260 compute_hflags(env);
2261 } else {
2262 helper_raise_exception(env, EXCP_RI);
2263 }
2264 break;
2265 case 4:
2266 /* UNFR Alias - Set Status FR */
2267 if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2268 return;
2269 }
2270 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2271 env->CP0_Status |= (1 << CP0St_FR);
2272 compute_hflags(env);
2273 } else {
2274 helper_raise_exception(env, EXCP_RI);
2275 }
2276 break;
fd4a04eb 2277 case 25:
d9bea114 2278 if (arg1 & 0xffffff00)
fd4a04eb 2279 return;
d9bea114
AJ
2280 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
2281 ((arg1 & 0x1) << 23);
fd4a04eb
TS
2282 break;
2283 case 26:
d9bea114 2284 if (arg1 & 0x007c0000)
fd4a04eb 2285 return;
d9bea114 2286 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
fd4a04eb
TS
2287 break;
2288 case 28:
d9bea114 2289 if (arg1 & 0x007c0000)
fd4a04eb 2290 return;
d9bea114
AJ
2291 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
2292 ((arg1 & 0x4) << 22);
fd4a04eb
TS
2293 break;
2294 case 31:
d9bea114 2295 if (arg1 & 0x007c0000)
fd4a04eb 2296 return;
d9bea114 2297 env->active_fpu.fcr31 = arg1;
fd4a04eb
TS
2298 break;
2299 default:
2300 return;
2301 }
2302 /* set rounding mode */
e320d05a 2303 restore_rounding_mode(env);
41e0c701 2304 /* set flush-to-zero mode */
e320d05a 2305 restore_flush_mode(env);
f01be154
TS
2306 set_float_exception_flags(0, &env->active_fpu.fp_status);
2307 if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
5f7319cd 2308 do_raise_exception(env, EXCP_FPE, GETPC());
fd4a04eb
TS
2309}
2310
353ebb7a 2311static inline int ieee_ex_to_mips(int xcpt)
fd4a04eb 2312{
353ebb7a
AJ
2313 int ret = 0;
2314 if (xcpt) {
2315 if (xcpt & float_flag_invalid) {
2316 ret |= FP_INVALID;
2317 }
2318 if (xcpt & float_flag_overflow) {
2319 ret |= FP_OVERFLOW;
2320 }
2321 if (xcpt & float_flag_underflow) {
2322 ret |= FP_UNDERFLOW;
2323 }
2324 if (xcpt & float_flag_divbyzero) {
2325 ret |= FP_DIV0;
2326 }
2327 if (xcpt & float_flag_inexact) {
2328 ret |= FP_INEXACT;
2329 }
2330 }
2331 return ret;
fd4a04eb
TS
2332}
2333
5f7319cd 2334static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
fd4a04eb 2335{
f01be154 2336 int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
fd4a04eb 2337
f01be154 2338 SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
4a587b2c
AJ
2339
2340 if (tmp) {
2341 set_float_exception_flags(0, &env->active_fpu.fp_status);
2342
2343 if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
5f7319cd 2344 do_raise_exception(env, EXCP_FPE, pc);
4a587b2c
AJ
2345 } else {
2346 UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2347 }
2348 }
fd4a04eb
TS
2349}
2350
a16336e4
TS
2351/* Float support.
2352 Single precition routines have a "s" suffix, double precision a
2353 "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2354 paired single lower "pl", paired single upper "pu". */
2355
a16336e4 2356/* unary operations, modifying fp status */
895c2d04 2357uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
b6d96bed 2358{
5dbe90bb 2359 fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
5f7319cd 2360 update_fcr31(env, GETPC());
5dbe90bb 2361 return fdt0;
b6d96bed
TS
2362}
2363
895c2d04 2364uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
b6d96bed 2365{
5dbe90bb 2366 fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
5f7319cd 2367 update_fcr31(env, GETPC());
5dbe90bb 2368 return fst0;
b6d96bed 2369}
a16336e4 2370
895c2d04 2371uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2372{
b6d96bed
TS
2373 uint64_t fdt2;
2374
f01be154 2375 fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
5f7319cd 2376 update_fcr31(env, GETPC());
b6d96bed 2377 return fdt2;
fd4a04eb 2378}
b6d96bed 2379
895c2d04 2380uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2381{
b6d96bed
TS
2382 uint64_t fdt2;
2383
f01be154 2384 fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
5f7319cd 2385 update_fcr31(env, GETPC());
b6d96bed 2386 return fdt2;
fd4a04eb 2387}
b6d96bed 2388
895c2d04 2389uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2390{
b6d96bed
TS
2391 uint64_t fdt2;
2392
f01be154 2393 fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
5f7319cd 2394 update_fcr31(env, GETPC());
b6d96bed 2395 return fdt2;
fd4a04eb 2396}
b6d96bed 2397
895c2d04 2398uint64_t helper_float_cvtl_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2399{
b6d96bed
TS
2400 uint64_t dt2;
2401
f01be154 2402 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2403 if (get_float_exception_flags(&env->active_fpu.fp_status)
2404 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2405 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2406 }
5f7319cd 2407 update_fcr31(env, GETPC());
b6d96bed 2408 return dt2;
fd4a04eb 2409}
b6d96bed 2410
895c2d04 2411uint64_t helper_float_cvtl_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2412{
b6d96bed
TS
2413 uint64_t dt2;
2414
f01be154 2415 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2416 if (get_float_exception_flags(&env->active_fpu.fp_status)
2417 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2418 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2419 }
5f7319cd 2420 update_fcr31(env, GETPC());
b6d96bed 2421 return dt2;
fd4a04eb
TS
2422}
2423
895c2d04 2424uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2425{
b6d96bed
TS
2426 uint32_t fst2;
2427 uint32_t fsth2;
2428
f01be154
TS
2429 fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2430 fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
5f7319cd 2431 update_fcr31(env, GETPC());
b6d96bed 2432 return ((uint64_t)fsth2 << 32) | fst2;
fd4a04eb 2433}
b6d96bed 2434
895c2d04 2435uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2436{
b6d96bed
TS
2437 uint32_t wt2;
2438 uint32_t wth2;
5dbe90bb 2439 int excp, excph;
b6d96bed 2440
f01be154 2441 wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
5dbe90bb
AJ
2442 excp = get_float_exception_flags(&env->active_fpu.fp_status);
2443 if (excp & (float_flag_overflow | float_flag_invalid)) {
05993cd0 2444 wt2 = FP_TO_INT32_OVERFLOW;
5dbe90bb
AJ
2445 }
2446
2447 set_float_exception_flags(0, &env->active_fpu.fp_status);
2448 wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2449 excph = get_float_exception_flags(&env->active_fpu.fp_status);
2450 if (excph & (float_flag_overflow | float_flag_invalid)) {
05993cd0 2451 wth2 = FP_TO_INT32_OVERFLOW;
b6d96bed 2452 }
5dbe90bb
AJ
2453
2454 set_float_exception_flags(excp | excph, &env->active_fpu.fp_status);
5f7319cd 2455 update_fcr31(env, GETPC());
5dbe90bb 2456
b6d96bed 2457 return ((uint64_t)wth2 << 32) | wt2;
fd4a04eb 2458}
b6d96bed 2459
895c2d04 2460uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2461{
b6d96bed
TS
2462 uint32_t fst2;
2463
f01be154 2464 fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
5f7319cd 2465 update_fcr31(env, GETPC());
b6d96bed 2466 return fst2;
fd4a04eb 2467}
b6d96bed 2468
895c2d04 2469uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2470{
b6d96bed
TS
2471 uint32_t fst2;
2472
f01be154 2473 fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
5f7319cd 2474 update_fcr31(env, GETPC());
b6d96bed 2475 return fst2;
fd4a04eb 2476}
b6d96bed 2477
895c2d04 2478uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2479{
b6d96bed
TS
2480 uint32_t fst2;
2481
f01be154 2482 fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
5f7319cd 2483 update_fcr31(env, GETPC());
b6d96bed 2484 return fst2;
fd4a04eb 2485}
b6d96bed 2486
895c2d04 2487uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2488{
b6d96bed
TS
2489 uint32_t wt2;
2490
b6d96bed 2491 wt2 = wt0;
5f7319cd 2492 update_fcr31(env, GETPC());
b6d96bed 2493 return wt2;
fd4a04eb 2494}
b6d96bed 2495
895c2d04 2496uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
fd4a04eb 2497{
b6d96bed
TS
2498 uint32_t wt2;
2499
b6d96bed 2500 wt2 = wth0;
5f7319cd 2501 update_fcr31(env, GETPC());
b6d96bed 2502 return wt2;
fd4a04eb 2503}
b6d96bed 2504
895c2d04 2505uint32_t helper_float_cvtw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2506{
b6d96bed
TS
2507 uint32_t wt2;
2508
f01be154 2509 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
5f7319cd 2510 update_fcr31(env, GETPC());
4cc2e5f9
AJ
2511 if (get_float_exception_flags(&env->active_fpu.fp_status)
2512 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2513 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2514 }
b6d96bed 2515 return wt2;
fd4a04eb 2516}
b6d96bed 2517
895c2d04 2518uint32_t helper_float_cvtw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2519{
b6d96bed
TS
2520 uint32_t wt2;
2521
f01be154 2522 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2523 if (get_float_exception_flags(&env->active_fpu.fp_status)
2524 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2525 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2526 }
5f7319cd 2527 update_fcr31(env, GETPC());
b6d96bed 2528 return wt2;
fd4a04eb
TS
2529}
2530
895c2d04 2531uint64_t helper_float_roundl_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2532{
b6d96bed
TS
2533 uint64_t dt2;
2534
f01be154
TS
2535 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2536 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 2537 restore_rounding_mode(env);
4cc2e5f9
AJ
2538 if (get_float_exception_flags(&env->active_fpu.fp_status)
2539 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2540 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2541 }
5f7319cd 2542 update_fcr31(env, GETPC());
b6d96bed 2543 return dt2;
fd4a04eb 2544}
b6d96bed 2545
895c2d04 2546uint64_t helper_float_roundl_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2547{
b6d96bed
TS
2548 uint64_t dt2;
2549
f01be154
TS
2550 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2551 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 2552 restore_rounding_mode(env);
4cc2e5f9
AJ
2553 if (get_float_exception_flags(&env->active_fpu.fp_status)
2554 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2555 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2556 }
5f7319cd 2557 update_fcr31(env, GETPC());
b6d96bed 2558 return dt2;
fd4a04eb 2559}
b6d96bed 2560
895c2d04 2561uint32_t helper_float_roundw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2562{
b6d96bed
TS
2563 uint32_t wt2;
2564
f01be154
TS
2565 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2566 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 2567 restore_rounding_mode(env);
4cc2e5f9
AJ
2568 if (get_float_exception_flags(&env->active_fpu.fp_status)
2569 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2570 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2571 }
5f7319cd 2572 update_fcr31(env, GETPC());
b6d96bed 2573 return wt2;
fd4a04eb 2574}
b6d96bed 2575
895c2d04 2576uint32_t helper_float_roundw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2577{
b6d96bed
TS
2578 uint32_t wt2;
2579
f01be154
TS
2580 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2581 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 2582 restore_rounding_mode(env);
4cc2e5f9
AJ
2583 if (get_float_exception_flags(&env->active_fpu.fp_status)
2584 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2585 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2586 }
5f7319cd 2587 update_fcr31(env, GETPC());
b6d96bed 2588 return wt2;
fd4a04eb
TS
2589}
2590
895c2d04 2591uint64_t helper_float_truncl_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2592{
b6d96bed
TS
2593 uint64_t dt2;
2594
f01be154 2595 dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2596 if (get_float_exception_flags(&env->active_fpu.fp_status)
2597 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2598 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2599 }
5f7319cd 2600 update_fcr31(env, GETPC());
b6d96bed 2601 return dt2;
fd4a04eb 2602}
b6d96bed 2603
895c2d04 2604uint64_t helper_float_truncl_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2605{
b6d96bed
TS
2606 uint64_t dt2;
2607
f01be154 2608 dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2609 if (get_float_exception_flags(&env->active_fpu.fp_status)
2610 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2611 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2612 }
5f7319cd 2613 update_fcr31(env, GETPC());
b6d96bed 2614 return dt2;
fd4a04eb 2615}
b6d96bed 2616
895c2d04 2617uint32_t helper_float_truncw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2618{
b6d96bed
TS
2619 uint32_t wt2;
2620
f01be154 2621 wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2622 if (get_float_exception_flags(&env->active_fpu.fp_status)
2623 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2624 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2625 }
5f7319cd 2626 update_fcr31(env, GETPC());
b6d96bed 2627 return wt2;
fd4a04eb 2628}
b6d96bed 2629
895c2d04 2630uint32_t helper_float_truncw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2631{
b6d96bed
TS
2632 uint32_t wt2;
2633
f01be154 2634 wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2635 if (get_float_exception_flags(&env->active_fpu.fp_status)
2636 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2637 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2638 }
5f7319cd 2639 update_fcr31(env, GETPC());
b6d96bed 2640 return wt2;
fd4a04eb
TS
2641}
2642
895c2d04 2643uint64_t helper_float_ceill_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2644{
b6d96bed
TS
2645 uint64_t dt2;
2646
f01be154
TS
2647 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2648 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 2649 restore_rounding_mode(env);
4cc2e5f9
AJ
2650 if (get_float_exception_flags(&env->active_fpu.fp_status)
2651 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2652 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2653 }
5f7319cd 2654 update_fcr31(env, GETPC());
b6d96bed 2655 return dt2;
fd4a04eb 2656}
b6d96bed 2657
895c2d04 2658uint64_t helper_float_ceill_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2659{
b6d96bed
TS
2660 uint64_t dt2;
2661
f01be154
TS
2662 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2663 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 2664 restore_rounding_mode(env);
4cc2e5f9
AJ
2665 if (get_float_exception_flags(&env->active_fpu.fp_status)
2666 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2667 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2668 }
5f7319cd 2669 update_fcr31(env, GETPC());
b6d96bed 2670 return dt2;
fd4a04eb 2671}
b6d96bed 2672
895c2d04 2673uint32_t helper_float_ceilw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2674{
b6d96bed
TS
2675 uint32_t wt2;
2676
f01be154
TS
2677 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2678 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 2679 restore_rounding_mode(env);
4cc2e5f9
AJ
2680 if (get_float_exception_flags(&env->active_fpu.fp_status)
2681 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2682 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2683 }
5f7319cd 2684 update_fcr31(env, GETPC());
b6d96bed 2685 return wt2;
fd4a04eb 2686}
b6d96bed 2687
895c2d04 2688uint32_t helper_float_ceilw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2689{
b6d96bed
TS
2690 uint32_t wt2;
2691
f01be154
TS
2692 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2693 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 2694 restore_rounding_mode(env);
4cc2e5f9
AJ
2695 if (get_float_exception_flags(&env->active_fpu.fp_status)
2696 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2697 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2698 }
5f7319cd 2699 update_fcr31(env, GETPC());
b6d96bed 2700 return wt2;
fd4a04eb
TS
2701}
2702
895c2d04 2703uint64_t helper_float_floorl_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2704{
b6d96bed
TS
2705 uint64_t dt2;
2706
f01be154
TS
2707 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2708 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 2709 restore_rounding_mode(env);
4cc2e5f9
AJ
2710 if (get_float_exception_flags(&env->active_fpu.fp_status)
2711 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2712 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2713 }
5f7319cd 2714 update_fcr31(env, GETPC());
b6d96bed 2715 return dt2;
fd4a04eb 2716}
b6d96bed 2717
895c2d04 2718uint64_t helper_float_floorl_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2719{
b6d96bed
TS
2720 uint64_t dt2;
2721
f01be154
TS
2722 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2723 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 2724 restore_rounding_mode(env);
4cc2e5f9
AJ
2725 if (get_float_exception_flags(&env->active_fpu.fp_status)
2726 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2727 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2728 }
5f7319cd 2729 update_fcr31(env, GETPC());
b6d96bed 2730 return dt2;
fd4a04eb 2731}
b6d96bed 2732
895c2d04 2733uint32_t helper_float_floorw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2734{
b6d96bed
TS
2735 uint32_t wt2;
2736
f01be154
TS
2737 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2738 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 2739 restore_rounding_mode(env);
4cc2e5f9
AJ
2740 if (get_float_exception_flags(&env->active_fpu.fp_status)
2741 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2742 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2743 }
5f7319cd 2744 update_fcr31(env, GETPC());
b6d96bed 2745 return wt2;
fd4a04eb 2746}
b6d96bed 2747
895c2d04 2748uint32_t helper_float_floorw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2749{
b6d96bed
TS
2750 uint32_t wt2;
2751
f01be154
TS
2752 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2753 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 2754 restore_rounding_mode(env);
4cc2e5f9
AJ
2755 if (get_float_exception_flags(&env->active_fpu.fp_status)
2756 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2757 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2758 }
5f7319cd 2759 update_fcr31(env, GETPC());
b6d96bed 2760 return wt2;
fd4a04eb
TS
2761}
2762
a16336e4 2763/* unary operations, not modifying fp status */
b6d96bed 2764#define FLOAT_UNOP(name) \
c01fccd2 2765uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \
b6d96bed
TS
2766{ \
2767 return float64_ ## name(fdt0); \
2768} \
c01fccd2 2769uint32_t helper_float_ ## name ## _s(uint32_t fst0) \
b6d96bed
TS
2770{ \
2771 return float32_ ## name(fst0); \
2772} \
c01fccd2 2773uint64_t helper_float_ ## name ## _ps(uint64_t fdt0) \
b6d96bed
TS
2774{ \
2775 uint32_t wt0; \
2776 uint32_t wth0; \
2777 \
2778 wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \
2779 wth0 = float32_ ## name(fdt0 >> 32); \
2780 return ((uint64_t)wth0 << 32) | wt0; \
a16336e4
TS
2781}
2782FLOAT_UNOP(abs)
2783FLOAT_UNOP(chs)
2784#undef FLOAT_UNOP
2785
8dfdb87c 2786/* MIPS specific unary operations */
895c2d04 2787uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2788{
b6d96bed
TS
2789 uint64_t fdt2;
2790
05993cd0 2791 fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
5f7319cd 2792 update_fcr31(env, GETPC());
b6d96bed 2793 return fdt2;
8dfdb87c 2794}
b6d96bed 2795
895c2d04 2796uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 2797{
b6d96bed
TS
2798 uint32_t fst2;
2799
05993cd0 2800 fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
5f7319cd 2801 update_fcr31(env, GETPC());
b6d96bed 2802 return fst2;
57fa1fb3 2803}
57fa1fb3 2804
895c2d04 2805uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2806{
b6d96bed
TS
2807 uint64_t fdt2;
2808
f01be154 2809 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
05993cd0 2810 fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
5f7319cd 2811 update_fcr31(env, GETPC());
b6d96bed 2812 return fdt2;
8dfdb87c 2813}
b6d96bed 2814
895c2d04 2815uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 2816{
b6d96bed
TS
2817 uint32_t fst2;
2818
f01be154 2819 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
05993cd0 2820 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
5f7319cd 2821 update_fcr31(env, GETPC());
b6d96bed 2822 return fst2;
8dfdb87c
TS
2823}
2824
895c2d04 2825uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2826{
b6d96bed
TS
2827 uint64_t fdt2;
2828
05993cd0 2829 fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
5f7319cd 2830 update_fcr31(env, GETPC());
b6d96bed 2831 return fdt2;
8dfdb87c 2832}
b6d96bed 2833
895c2d04 2834uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 2835{
b6d96bed
TS
2836 uint32_t fst2;
2837
05993cd0 2838 fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
5f7319cd 2839 update_fcr31(env, GETPC());
b6d96bed 2840 return fst2;
8dfdb87c 2841}
b6d96bed 2842
895c2d04 2843uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2844{
b6d96bed
TS
2845 uint32_t fst2;
2846 uint32_t fsth2;
2847
05993cd0
AJ
2848 fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2849 fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
5f7319cd 2850 update_fcr31(env, GETPC());
b6d96bed 2851 return ((uint64_t)fsth2 << 32) | fst2;
8dfdb87c
TS
2852}
2853
895c2d04 2854uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2855{
b6d96bed
TS
2856 uint64_t fdt2;
2857
f01be154 2858 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
05993cd0 2859 fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
5f7319cd 2860 update_fcr31(env, GETPC());
b6d96bed 2861 return fdt2;
8dfdb87c 2862}
b6d96bed 2863
895c2d04 2864uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 2865{
b6d96bed
TS
2866 uint32_t fst2;
2867
f01be154 2868 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
05993cd0 2869 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
5f7319cd 2870 update_fcr31(env, GETPC());
b6d96bed 2871 return fst2;
8dfdb87c 2872}
b6d96bed 2873
895c2d04 2874uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2875{
b6d96bed
TS
2876 uint32_t fst2;
2877 uint32_t fsth2;
2878
f01be154
TS
2879 fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2880 fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
05993cd0
AJ
2881 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
2882 fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
5f7319cd 2883 update_fcr31(env, GETPC());
b6d96bed 2884 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3 2885}
57fa1fb3 2886
895c2d04 2887#define FLOAT_OP(name, p) void helper_float_##name##_##p(CPUMIPSState *env)
b6d96bed 2888
fd4a04eb 2889/* binary operations */
b6d96bed 2890#define FLOAT_BINOP(name) \
895c2d04
BS
2891uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
2892 uint64_t fdt0, uint64_t fdt1) \
b6d96bed
TS
2893{ \
2894 uint64_t dt2; \
2895 \
f01be154 2896 dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status); \
5f7319cd 2897 update_fcr31(env, GETPC()); \
b6d96bed
TS
2898 return dt2; \
2899} \
2900 \
895c2d04
BS
2901uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
2902 uint32_t fst0, uint32_t fst1) \
b6d96bed
TS
2903{ \
2904 uint32_t wt2; \
2905 \
f01be154 2906 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
5f7319cd 2907 update_fcr31(env, GETPC()); \
b6d96bed
TS
2908 return wt2; \
2909} \
2910 \
895c2d04
BS
2911uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
2912 uint64_t fdt0, \
2913 uint64_t fdt1) \
b6d96bed
TS
2914{ \
2915 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
2916 uint32_t fsth0 = fdt0 >> 32; \
2917 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
2918 uint32_t fsth1 = fdt1 >> 32; \
2919 uint32_t wt2; \
2920 uint32_t wth2; \
2921 \
f01be154
TS
2922 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
2923 wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status); \
5f7319cd 2924 update_fcr31(env, GETPC()); \
b6d96bed 2925 return ((uint64_t)wth2 << 32) | wt2; \
fd4a04eb 2926}
b6d96bed 2927
fd4a04eb
TS
2928FLOAT_BINOP(add)
2929FLOAT_BINOP(sub)
2930FLOAT_BINOP(mul)
2931FLOAT_BINOP(div)
2932#undef FLOAT_BINOP
2933
f54c35d1
RS
2934#define UNFUSED_FMA(prefix, a, b, c, flags) \
2935{ \
2936 a = prefix##_mul(a, b, &env->active_fpu.fp_status); \
2937 if ((flags) & float_muladd_negate_c) { \
2938 a = prefix##_sub(a, c, &env->active_fpu.fp_status); \
2939 } else { \
2940 a = prefix##_add(a, c, &env->active_fpu.fp_status); \
2941 } \
2942 if ((flags) & float_muladd_negate_result) { \
2943 a = prefix##_chs(a); \
2944 } \
2945}
2946
b3d6cd44
AJ
2947/* FMA based operations */
2948#define FLOAT_FMA(name, type) \
2949uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
2950 uint64_t fdt0, uint64_t fdt1, \
2951 uint64_t fdt2) \
2952{ \
f54c35d1 2953 UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type); \
5f7319cd 2954 update_fcr31(env, GETPC()); \
b3d6cd44
AJ
2955 return fdt0; \
2956} \
2957 \
2958uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
2959 uint32_t fst0, uint32_t fst1, \
2960 uint32_t fst2) \
2961{ \
f54c35d1 2962 UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
5f7319cd 2963 update_fcr31(env, GETPC()); \
b3d6cd44
AJ
2964 return fst0; \
2965} \
2966 \
2967uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
2968 uint64_t fdt0, uint64_t fdt1, \
2969 uint64_t fdt2) \
2970{ \
2971 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
2972 uint32_t fsth0 = fdt0 >> 32; \
2973 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
2974 uint32_t fsth1 = fdt1 >> 32; \
2975 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
2976 uint32_t fsth2 = fdt2 >> 32; \
2977 \
f54c35d1
RS
2978 UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
2979 UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type); \
5f7319cd 2980 update_fcr31(env, GETPC()); \
b3d6cd44
AJ
2981 return ((uint64_t)fsth0 << 32) | fst0; \
2982}
2983FLOAT_FMA(madd, 0)
2984FLOAT_FMA(msub, float_muladd_negate_c)
2985FLOAT_FMA(nmadd, float_muladd_negate_result)
2986FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c)
2987#undef FLOAT_FMA
a16336e4 2988
8dfdb87c 2989/* MIPS specific binary operations */
895c2d04 2990uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 2991{
f01be154 2992 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
05993cd0 2993 fdt2 = float64_chs(float64_sub(fdt2, float64_one, &env->active_fpu.fp_status));
5f7319cd 2994 update_fcr31(env, GETPC());
b6d96bed 2995 return fdt2;
8dfdb87c 2996}
b6d96bed 2997
895c2d04 2998uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
8dfdb87c 2999{
f01be154 3000 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
05993cd0 3001 fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
5f7319cd 3002 update_fcr31(env, GETPC());
b6d96bed 3003 return fst2;
8dfdb87c 3004}
b6d96bed 3005
895c2d04 3006uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3007{
b6d96bed
TS
3008 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3009 uint32_t fsth0 = fdt0 >> 32;
3010 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3011 uint32_t fsth2 = fdt2 >> 32;
3012
f01be154
TS
3013 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3014 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
05993cd0
AJ
3015 fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
3016 fsth2 = float32_chs(float32_sub(fsth2, float32_one, &env->active_fpu.fp_status));
5f7319cd 3017 update_fcr31(env, GETPC());
b6d96bed 3018 return ((uint64_t)fsth2 << 32) | fst2;
8dfdb87c
TS
3019}
3020
895c2d04 3021uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3022{
f01be154 3023 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
05993cd0 3024 fdt2 = float64_sub(fdt2, float64_one, &env->active_fpu.fp_status);
f01be154 3025 fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
5f7319cd 3026 update_fcr31(env, GETPC());
b6d96bed 3027 return fdt2;
8dfdb87c 3028}
b6d96bed 3029
895c2d04 3030uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
8dfdb87c 3031{
f01be154 3032 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
05993cd0 3033 fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
f01be154 3034 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
5f7319cd 3035 update_fcr31(env, GETPC());
b6d96bed 3036 return fst2;
8dfdb87c 3037}
b6d96bed 3038
895c2d04 3039uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3040{
b6d96bed
TS
3041 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3042 uint32_t fsth0 = fdt0 >> 32;
3043 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3044 uint32_t fsth2 = fdt2 >> 32;
3045
f01be154
TS
3046 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3047 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
05993cd0
AJ
3048 fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
3049 fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
f01be154
TS
3050 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3051 fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
5f7319cd 3052 update_fcr31(env, GETPC());
b6d96bed 3053 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3 3054}
57fa1fb3 3055
895c2d04 3056uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
fd4a04eb 3057{
b6d96bed
TS
3058 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3059 uint32_t fsth0 = fdt0 >> 32;
3060 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3061 uint32_t fsth1 = fdt1 >> 32;
3062 uint32_t fst2;
3063 uint32_t fsth2;
3064
f01be154
TS
3065 fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
3066 fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
5f7319cd 3067 update_fcr31(env, GETPC());
b6d96bed 3068 return ((uint64_t)fsth2 << 32) | fst2;
fd4a04eb
TS
3069}
3070
895c2d04 3071uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
57fa1fb3 3072{
b6d96bed
TS
3073 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3074 uint32_t fsth0 = fdt0 >> 32;
3075 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3076 uint32_t fsth1 = fdt1 >> 32;
3077 uint32_t fst2;
3078 uint32_t fsth2;
3079
f01be154
TS
3080 fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
3081 fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
5f7319cd 3082 update_fcr31(env, GETPC());
b6d96bed 3083 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3
TS
3084}
3085
8dfdb87c 3086/* compare operations */
b6d96bed 3087#define FOP_COND_D(op, cond) \
895c2d04
BS
3088void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3089 uint64_t fdt1, int cc) \
b6d96bed 3090{ \
6a385343 3091 int c; \
6a385343 3092 c = cond; \
5f7319cd 3093 update_fcr31(env, GETPC()); \
b6d96bed 3094 if (c) \
f01be154 3095 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3096 else \
f01be154 3097 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3098} \
895c2d04
BS
3099void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3100 uint64_t fdt1, int cc) \
b6d96bed
TS
3101{ \
3102 int c; \
3103 fdt0 = float64_abs(fdt0); \
3104 fdt1 = float64_abs(fdt1); \
3105 c = cond; \
5f7319cd 3106 update_fcr31(env, GETPC()); \
b6d96bed 3107 if (c) \
f01be154 3108 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3109 else \
f01be154 3110 CLEAR_FP_COND(cc, env->active_fpu); \
fd4a04eb
TS
3111}
3112
fd4a04eb 3113/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3114 * but float64_unordered_quiet() is still called. */
3115FOP_COND_D(f, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3116FOP_COND_D(un, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
06a0e6b1 3117FOP_COND_D(eq, float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
211315fb 3118FOP_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
3119FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3120FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3121FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3122FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
fd4a04eb 3123/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3124 * but float64_unordered() is still called. */
3125FOP_COND_D(sf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3126FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3127FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3128FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3129FOP_COND_D(lt, float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3a599383 3130FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
06a0e6b1 3131FOP_COND_D(le, float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3a599383 3132FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
b6d96bed
TS
3133
3134#define FOP_COND_S(op, cond) \
895c2d04
BS
3135void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0, \
3136 uint32_t fst1, int cc) \
b6d96bed 3137{ \
6a385343 3138 int c; \
6a385343 3139 c = cond; \
5f7319cd 3140 update_fcr31(env, GETPC()); \
b6d96bed 3141 if (c) \
f01be154 3142 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3143 else \
f01be154 3144 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3145} \
895c2d04
BS
3146void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0, \
3147 uint32_t fst1, int cc) \
b6d96bed
TS
3148{ \
3149 int c; \
3150 fst0 = float32_abs(fst0); \
3151 fst1 = float32_abs(fst1); \
3152 c = cond; \
5f7319cd 3153 update_fcr31(env, GETPC()); \
b6d96bed 3154 if (c) \
f01be154 3155 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3156 else \
f01be154 3157 CLEAR_FP_COND(cc, env->active_fpu); \
fd4a04eb
TS
3158}
3159
fd4a04eb 3160/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3161 * but float32_unordered_quiet() is still called. */
3162FOP_COND_S(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
3163FOP_COND_S(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
06a0e6b1 3164FOP_COND_S(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
211315fb 3165FOP_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
3166FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3167FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3168FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
3169FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
fd4a04eb 3170/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3171 * but float32_unordered() is still called. */
3172FOP_COND_S(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
3173FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3174FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3175FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3176FOP_COND_S(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3a599383 3177FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
06a0e6b1 3178FOP_COND_S(le, float32_le(fst0, fst1, &env->active_fpu.fp_status))
3a599383 3179FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status))
b6d96bed
TS
3180
3181#define FOP_COND_PS(op, condl, condh) \
895c2d04
BS
3182void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3183 uint64_t fdt1, int cc) \
b6d96bed 3184{ \
6a385343
AJ
3185 uint32_t fst0, fsth0, fst1, fsth1; \
3186 int ch, cl; \
6a385343
AJ
3187 fst0 = fdt0 & 0XFFFFFFFF; \
3188 fsth0 = fdt0 >> 32; \
3189 fst1 = fdt1 & 0XFFFFFFFF; \
3190 fsth1 = fdt1 >> 32; \
3191 cl = condl; \
3192 ch = condh; \
5f7319cd 3193 update_fcr31(env, GETPC()); \
b6d96bed 3194 if (cl) \
f01be154 3195 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3196 else \
f01be154 3197 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3198 if (ch) \
f01be154 3199 SET_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3200 else \
f01be154 3201 CLEAR_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3202} \
895c2d04
BS
3203void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3204 uint64_t fdt1, int cc) \
b6d96bed 3205{ \
6a385343
AJ
3206 uint32_t fst0, fsth0, fst1, fsth1; \
3207 int ch, cl; \
3208 fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \
3209 fsth0 = float32_abs(fdt0 >> 32); \
3210 fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \
3211 fsth1 = float32_abs(fdt1 >> 32); \
3212 cl = condl; \
3213 ch = condh; \
5f7319cd 3214 update_fcr31(env, GETPC()); \
b6d96bed 3215 if (cl) \
f01be154 3216 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3217 else \
f01be154 3218 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3219 if (ch) \
f01be154 3220 SET_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3221 else \
f01be154 3222 CLEAR_FP_COND(cc + 1, env->active_fpu); \
fd4a04eb
TS
3223}
3224
3225/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3226 * but float32_unordered_quiet() is still called. */
3227FOP_COND_PS(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
3228 (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3229FOP_COND_PS(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
3230 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3231FOP_COND_PS(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3232 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
211315fb
AJ
3233FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3234 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
06a0e6b1
AJ
3235FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3236 float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3237FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3238 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3239FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3240 float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3241FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3242 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
fd4a04eb 3243/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3244 * but float32_unordered() is still called. */
3245FOP_COND_PS(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
3246 (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3247FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
3248 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3249FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3250 float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3251FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3252 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3253FOP_COND_PS(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3254 float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3a599383
AJ
3255FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3256 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
06a0e6b1
AJ
3257FOP_COND_PS(le, float32_le(fst0, fst1, &env->active_fpu.fp_status),
3258 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3a599383
AJ
3259FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status),
3260 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
This page took 1.352966 seconds and 4 git commands to generate.