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