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